Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Xray usage event report #1046

Merged
merged 9 commits into from
Nov 29, 2023
52 changes: 52 additions & 0 deletions utils/usage/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import (
"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
xrayutils "github.com/jfrog/jfrog-cli-core/v2/xray/utils"
"github.com/jfrog/jfrog-client-go/artifactory/usage"
clientutils "github.com/jfrog/jfrog-client-go/utils"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/log"
ecosysusage "github.com/jfrog/jfrog-client-go/utils/usage"
xrayusage "github.com/jfrog/jfrog-client-go/xray/usage"

"golang.org/x/sync/errgroup"
)

Expand Down Expand Up @@ -46,6 +49,7 @@ func NewUsageReporter(productId string, serverDetails *config.ServerDetails) *Us
serverDetails: serverDetails,
reportWaitGroup: new(errgroup.Group),
sendToEcosystem: true,
sendToXray: true,
sendToArtifactory: true,
}
}
Expand Down Expand Up @@ -89,6 +93,14 @@ func (ur *UsageReporter) Report(features ...ReportFeature) {
return
})
}
if ur.sendToXray {
ur.reportWaitGroup.Go(func() (err error) {
if err = ur.reportToXray(features...); err != nil {
err = fmt.Errorf("xray, %s", err.Error())
attiasas marked this conversation as resolved.
Show resolved Hide resolved
}
return
})
}
if ur.sendToArtifactory {
ur.reportWaitGroup.Go(func() (err error) {
if err = ur.reportToArtifactory(features...); err != nil {
Expand Down Expand Up @@ -122,6 +134,23 @@ func (ur *UsageReporter) reportToEcosystem(features ...ReportFeature) (err error
return ecosysusage.SendEcosystemUsageReports(reports...)
}

func (ur *UsageReporter) reportToXray(features ...ReportFeature) (err error) {
if ur.serverDetails.XrayUrl == "" {
err = errorutils.CheckErrorf("Xray Url is not set.")
return
}
serviceManager, err := xrayutils.CreateXrayServiceManager(ur.serverDetails)
if err != nil {
return
}
events := ur.convertAttributesToXrayEvents(features...)
if len(events) == 0 {
err = errorutils.CheckErrorf("Nothing to send.")
return
}
attiasas marked this conversation as resolved.
Show resolved Hide resolved
return xrayusage.SendXrayUsageEvents(*serviceManager, events...)
}

func (ur *UsageReporter) reportToArtifactory(features ...ReportFeature) (err error) {
if ur.serverDetails.ArtifactoryUrl == "" {
err = errorutils.CheckErrorf("Artifactory URL is not set")
Expand Down Expand Up @@ -164,6 +193,29 @@ func (ur *UsageReporter) convertAttributesToArtifactoryFeatures(reportFeatures .
return
}

func (ur *UsageReporter) convertAttributesToXrayEvents(reportFeatures ...ReportFeature) (events []xrayusage.ReportXrayEventData) {
for _, feature := range reportFeatures {
convertedAttributes := []xrayusage.ReportUsageAttribute{}
for _, attribute := range feature.Attributes {
convertedAttributes = append(convertedAttributes, xrayusage.ReportUsageAttribute{
AttributeName: attribute.AttributeName,
AttributeValue: attribute.AttributeValue,
})
}
if feature.ClientId != "" {
// Add clientId as attribute
convertedAttributes = append(convertedAttributes, xrayusage.ReportUsageAttribute{
AttributeName: clientIdAttributeName,
AttributeValue: feature.ClientId,
})
}
events = append(events, xrayusage.CreateUsageEvent(
ur.ProductId, feature.FeatureId, convertedAttributes...,
))
}
return
}

func (ur *UsageReporter) convertAttributesToEcosystemReports(reportFeatures ...ReportFeature) (reports []ecosysusage.ReportEcosystemUsageData, err error) {
accountId := ur.serverDetails.Url
clientToFeaturesMap := map[string][]string{}
Expand Down
60 changes: 60 additions & 0 deletions utils/usage/usage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-client-go/artifactory/usage"
ecosysusage "github.com/jfrog/jfrog-client-go/utils/usage"
xrayusage "github.com/jfrog/jfrog-client-go/xray/usage"

"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -129,6 +131,64 @@ func createArtifactoryUsageHandler(t *testing.T, productName, commandName string
}
}

func TestReportXrayUsage(t *testing.T) {
const productName = "test-product"
const commandName = "test-command"
const clientName = "test-client"

server := httptest.NewServer(createXrayUsageHandler(t, productName, commandName, clientName))
defer server.Close()
serverDetails := &config.ServerDetails{XrayUrl: server.URL + "/"}

reporter := NewUsageReporter(productName, serverDetails).SetSendToEcosystem(false).SetSendToArtifactory(false)

reporter.Report(ReportFeature{
FeatureId: commandName,
ClientId: clientName,
})
assert.NoError(t, reporter.WaitForResponses())
}

func TestReportXrayError(t *testing.T) {
reporter := NewUsageReporter("", &config.ServerDetails{}).SetSendToEcosystem(false).SetSendToArtifactory(false)
reporter.Report(ReportFeature{
FeatureId: "",
})
attiasas marked this conversation as resolved.
Show resolved Hide resolved
assert.Error(t, reporter.WaitForResponses())

server := httptest.NewServer(create404UsageHandler(t))
defer server.Close()
reporter = NewUsageReporter("", &config.ServerDetails{ArtifactoryUrl: server.URL + "/"}).SetSendToEcosystem(false).SetSendToArtifactory(false)
reporter.Report(ReportFeature{
FeatureId: "",
})
attiasas marked this conversation as resolved.
Show resolved Hide resolved
assert.Error(t, reporter.WaitForResponses())
}

func createXrayUsageHandler(t *testing.T, productId, commandName, clientId string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.RequestURI == "/api/v1/system/version" {
w.WriteHeader(http.StatusOK)
_, err := w.Write([]byte(`{"xray_version":"6.9.0"}`))
assert.NoError(t, err)
return
}
if r.RequestURI == "/api/v1/usage/events/send" {
// Check request
buf := new(bytes.Buffer)
_, err := buf.ReadFrom(r.Body)
assert.NoError(t, err)
featureId := xrayusage.GetExpectedXrayEventName(productId, commandName)
assert.Equal(t, fmt.Sprintf(`[{"data":{"clientId":"%s"},"product_name":"%s","event_name":"%s","origin":"API_CLI"}]`, clientId, productId, featureId), buf.String())

// Send response OK
w.WriteHeader(http.StatusOK)
_, err = w.Write([]byte("{}"))
assert.NoError(t, err)
}
attiasas marked this conversation as resolved.
Show resolved Hide resolved
}
}

func TestReportEcosystemUsageError(t *testing.T) {
// No features
reporter := NewUsageReporter("", &config.ServerDetails{}).SetSendToArtifactory(false).SetSendToXray(false)
Expand Down
Loading