diff --git a/pkg/entities/entity.go b/pkg/entities/entity.go index c47c6190..ff8b4653 100644 --- a/pkg/entities/entity.go +++ b/pkg/entities/entity.go @@ -8,32 +8,85 @@ import ( type Entity struct { AccountID int `json:"accountId,omitempty"` Domain EntityDomainType `json:"domain,omitempty"` - EntityType EntityType `json:"entityType,omitempty"` + EntityType EntityType `json:"entityType,omitempty"` // Full Type (ie APM_APPLICATION_ENTITY) GUID string `json:"guid,omitempty"` Name string `json:"name,omitempty"` Permalink string `json:"permalink,omitempty"` Reporting bool `json:"reporting,omitempty"` - Type string `json:"type,omitempty"` + Type Type `json:"type,omitempty"` - // Not always returned. Only returned from ApmApplicationEntityOutline - ApplicationID *int `json:"applicationId,omitempty"` + // ApmApplicationEntity, BrowserApplicationEntity + AlertSeverity *EntityAlertSeverityType `json:"alertSeverity,omitempty"` + ApplicationID *int `json:"applicationId,omitempty"` + + // Stitch in other structs + ApmApplicationEntity + BrowserApplicationEntity +} + +// ApmApplicationEntity represents the unique fields returned on the ApmApplicationEntity interface +type ApmApplicationEntity struct { + Language *string `json:"language,omitempty"` + RunningAgentVersions *ApmApplicationEntityOutlineRunningAgentVersions `json:"runningAgentVersions,omitempty"` + Settings *ApmApplicationEntityOutlineSettings `json:"settings,omitempty"` +} + +type ApmApplicationEntityOutlineSettings struct { + ApdexTarget *float64 `json:"apdexTarget,omitempty"` + ServerSideConfig *bool `json:"serverSideConfig"` +} + +type ApmApplicationEntityOutlineRunningAgentVersions struct { + MaxVersion *string `json:"maxVersion,omitempty"` + MinVersion *string `json:"minVersion,omitempty"` } -// EntityType represents a New Relic One entity type. +// BrowserApplicationEntity represents the unique fields returned on the BrowserApplicationEntity interface +type BrowserApplicationEntity struct { + ServingApmApplicationID *int `json:"servingApmApplicationId,omitempty"` +} + +// EntityType represents a New Relic One entity type (full) type EntityType string +// Type represents a New Relic One entity type (short) +type Type string + +var ( + // Types specifies the possible types for a New Relic One entity. + Types = struct { + Application Type + Dashboard Type + Host Type + Monitor Type + Workload Type + }{ + Application: "APPLICATION", + Dashboard: "DASHBOARD", + Host: "HOST", + Monitor: "MONITOR", + Workload: "WORKLOAD", + } +) + var ( // EntityTypes specifies the possible types for a New Relic One entity. EntityTypes = struct { Application EntityType + Browser EntityType Dashboard EntityType Host EntityType + Mobile EntityType Monitor EntityType + Workload EntityType }{ - Application: "APPLICATION", - Dashboard: "DASHBOARD", - Host: "HOST", - Monitor: "MONITOR", + Application: "APM_APPLICATION_ENTITY", + Browser: "BROWSER_APPLICATION_ENTITY", + Dashboard: "DASHBOARD_ENTITY", + Host: "INFRASTRUCTURE_HOST_ENTITY", + Mobile: "MOBILE_APPLICATION_ENTITY", + Monitor: "SYNTHETIC_MONITOR_ENTITY", + Workload: "WORKLOAD_ENTITY", } ) @@ -47,13 +100,17 @@ var ( Browser EntityDomainType Infrastructure EntityDomainType Mobile EntityDomainType + Nr1 EntityDomainType Synthetics EntityDomainType + Visualization EntityDomainType }{ APM: "APM", Browser: "BROWSER", Infrastructure: "INFRA", Mobile: "MOBILE", + Nr1: "NR1", Synthetics: "SYNTH", + Visualization: "VIZ", } ) @@ -68,7 +125,7 @@ var ( NotConfigured EntityAlertSeverityType Warning EntityAlertSeverityType }{ - Critical: "APM", + Critical: "CRITICAL", NotAlerting: "NOT_ALERTING", NotConfigured: "NOT_CONFIGURED", Warning: "WARNING", @@ -147,10 +204,9 @@ func (e *Entities) GetEntity(guid string) (*Entity, error) { } const ( - getEntitiesQuery = ` - query($guids: [String!]!) { - actor { - entities(guids: $guids) { + // graphqlEntityStructFields is the set of fields that we want returned on entity queries, + // and should map back directly to the Entity struct + graphqlEntityStructFields = ` accountId domain entityType @@ -159,50 +215,75 @@ const ( permalink reporting type - } - } - } - ` - getEntityQuery = ` - query($guid: String!) { - actor { - entity(guid: $guid) { - accountId - domain - entityType - guid - name - permalink - reporting - type - } - } - } - ` +` + + graphqlApmApplicationEntityFields = ` + ... on ApmApplicationEntity { + applicationId + alertSeverity + language + runningAgentVersions { + maxVersion + minVersion + } + settings { + apdexTarget + serverSideConfig + } + }` + + graphqlApmApplicationEntityOutlineFields = ` + ... on ApmApplicationEntityOutline { + applicationId + alertSeverity + language + runningAgentVersions { + maxVersion + minVersion + } + settings { + apdexTarget + serverSideConfig + } + }` + + graphqlBrowserApplicationEntityFields = ` + ... on BrowserApplicationEntity { + alertSeverity + applicationId + servingApmApplicationId + }` + + graphqlBrowserApplicationEntityOutlineFields = ` + ... on BrowserApplicationEntityOutline { + alertSeverity + applicationId + servingApmApplicationId + }` + + getEntitiesQuery = `query($guids: [String!]!) { actor { entities(guids: $guids) {` + + graphqlEntityStructFields + + graphqlApmApplicationEntityFields + + graphqlBrowserApplicationEntityFields + + ` } } }` + + getEntityQuery = `query($guid: String!) { actor { entity(guid: $guid) {` + + graphqlEntityStructFields + + graphqlApmApplicationEntityFields + + graphqlBrowserApplicationEntityFields + + ` } } }` + searchEntitiesQuery = ` query($queryBuilder: EntitySearchQueryBuilder, $cursor: String) { actor { entitySearch(queryBuilder: $queryBuilder) { results(cursor: $cursor) { nextCursor - entities { - accountId - domain - entityType - guid - name - permalink - reporting - type - ... on ApmApplicationEntityOutline { - applicationId - } - } - } - } - } - } - ` + entities {` + + graphqlEntityStructFields + + graphqlApmApplicationEntityOutlineFields + + graphqlBrowserApplicationEntityOutlineFields + + ` } } } } }` ) type searchEntitiesResponse struct { diff --git a/pkg/entities/entity_integration_test.go b/pkg/entities/entity_integration_test.go index a2483d67..68efb947 100644 --- a/pkg/entities/entity_integration_test.go +++ b/pkg/entities/entity_integration_test.go @@ -6,8 +6,10 @@ import ( "os" "testing" - "github.com/newrelic/newrelic-client-go/pkg/config" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/newrelic/newrelic-client-go/pkg/config" ) func TestIntegrationSearchEntities(t *testing.T) { @@ -58,12 +60,48 @@ func TestIntegrationGetEntities(t *testing.T) { func TestIntegrationGetEntity(t *testing.T) { t.Parallel() + entityGUID := "MjUyMDUyOHxBUE18QVBQTElDQVRJT058MjE1MDM3Nzk1" + client := newIntegrationTestClient(t) + + actual, err := client.GetEntity(entityGUID) + + require.NoError(t, err) + require.NotNil(t, actual) + + // These are a bit fragile, if the above GUID ever changes... + assert.Equal(t, 2520528, actual.AccountID) + assert.Equal(t, EntityDomainType("APM"), actual.Domain) + assert.Equal(t, EntityType("APM_APPLICATION_ENTITY"), actual.EntityType) + assert.Equal(t, entityGUID, actual.GUID) + assert.Equal(t, "Dummy App", actual.Name) + assert.Equal(t, "https://one.newrelic.com/redirect/entity/"+entityGUID, actual.Permalink) + assert.Equal(t, true, actual.Reporting) + assert.Equal(t, Type("APPLICATION"), actual.Type) +} + +// Looking at an APM Application, and the result set here. +func TestIntegrationGetEntity_ApmEntityOutline(t *testing.T) { + t.Parallel() + client := newIntegrationTestClient(t) actual, err := client.GetEntity("MjUyMDUyOHxBUE18QVBQTElDQVRJT058MjE1MDM3Nzk1") require.NoError(t, err) require.NotNil(t, actual) + + // These are a bit fragile, if the above GUID ever changes... + // from ApmApplicationEntity / ApmApplicationEntityOutline + assert.Equal(t, 215037795, *actual.ApplicationID) + assert.Equal(t, EntityAlertSeverityType("NOT_ALERTING"), *actual.AlertSeverity) + assert.Equal(t, "nodejs", *actual.Language) + assert.NotNil(t, actual.RunningAgentVersions) + assert.NotNil(t, actual.RunningAgentVersions.MinVersion) + assert.NotNil(t, actual.RunningAgentVersions.MaxVersion) + assert.NotNil(t, actual.Settings) + assert.NotNil(t, actual.Settings.ApdexTarget) + assert.NotNil(t, actual.Settings.ServerSideConfig) + } // nolint