diff --git a/internal/install/execution/installevents_reporter_integration_test.go b/internal/install/execution/installevents_reporter_integration_test.go index 71df2f472..362977a98 100644 --- a/internal/install/execution/installevents_reporter_integration_test.go +++ b/internal/install/execution/installevents_reporter_integration_test.go @@ -13,6 +13,7 @@ import ( "github.com/newrelic/newrelic-cli/internal/install/types" "github.com/newrelic/newrelic-client-go/v2/newrelic" "github.com/newrelic/newrelic-client-go/v2/pkg/config" + "github.com/newrelic/newrelic-client-go/v2/pkg/workloads" ) func TestInstallEventsReporter_Basic(t *testing.T) { @@ -52,3 +53,13 @@ func TestInstallEventsReporter_Basic(t *testing.T) { err = r.RecipeInstalled(status, evt) require.NoError(t, err) } + +func createEntity(t *testing.T, accountID int, c *newrelic.NewRelic) string { + i := workloads.WorkloadCreateInput{ + Name: "testEntity", + } + e, err := c.Workloads.WorkloadCreate(accountID, i) + require.NoError(t, err) + + return string(e.GUID) +} diff --git a/internal/install/execution/mock_nerdstorage_client.go b/internal/install/execution/mock_nerdstorage_client.go deleted file mode 100644 index 039b547ba..000000000 --- a/internal/install/execution/mock_nerdstorage_client.go +++ /dev/null @@ -1,39 +0,0 @@ -package execution - -import "github.com/newrelic/newrelic-client-go/v2/pkg/nerdstorage" - -type MockNerdStorageClient struct { - WriteDocumentWithUserScopeVal interface{} - WriteDocumentWithEntityScopeVal interface{} - WriteDocumentWithAccountScopeVal interface{} - WriteDocumentWithUserScopeErr error - WriteDocumentWithEntityScopeErr error - WriteDocumentWithAccountScopeErr error - writeDocumentWithUserScopeCallCount int - writeDocumentWithEntityScopeCallCount int - writeDocumentWithAccountScopeCallCount int -} - -func NewMockNerdStorageClient() *MockNerdStorageClient { - return &MockNerdStorageClient{ - WriteDocumentWithUserScopeVal: struct{}{}, - WriteDocumentWithEntityScopeVal: struct{}{}, - WriteDocumentWithUserScopeErr: nil, - WriteDocumentWithEntityScopeErr: nil, - } -} - -func (c *MockNerdStorageClient) WriteDocumentWithUserScope(nerdstorage.WriteDocumentInput) (interface{}, error) { - c.writeDocumentWithUserScopeCallCount++ - return c.WriteDocumentWithUserScopeVal, c.WriteDocumentWithUserScopeErr -} - -func (c *MockNerdStorageClient) WriteDocumentWithEntityScope(string, nerdstorage.WriteDocumentInput) (interface{}, error) { - c.writeDocumentWithEntityScopeCallCount++ - return c.WriteDocumentWithEntityScopeVal, c.WriteDocumentWithEntityScopeErr -} - -func (c *MockNerdStorageClient) WriteDocumentWithAccountScope(int, nerdstorage.WriteDocumentInput) (interface{}, error) { - c.writeDocumentWithAccountScopeCallCount++ - return c.WriteDocumentWithAccountScopeVal, c.WriteDocumentWithAccountScopeErr -} diff --git a/internal/install/execution/nerdstorage_client.go b/internal/install/execution/nerdstorage_client.go deleted file mode 100644 index 90c60bfa8..000000000 --- a/internal/install/execution/nerdstorage_client.go +++ /dev/null @@ -1,11 +0,0 @@ -package execution - -import ( - "github.com/newrelic/newrelic-client-go/v2/pkg/nerdstorage" -) - -type NerdStorageClient interface { - WriteDocumentWithUserScope(nerdstorage.WriteDocumentInput) (interface{}, error) - WriteDocumentWithEntityScope(string, nerdstorage.WriteDocumentInput) (interface{}, error) - WriteDocumentWithAccountScope(int, nerdstorage.WriteDocumentInput) (interface{}, error) -} diff --git a/internal/install/execution/nerdstorage_status_reporter.go b/internal/install/execution/nerdstorage_status_reporter.go deleted file mode 100644 index 824fb3e39..000000000 --- a/internal/install/execution/nerdstorage_status_reporter.go +++ /dev/null @@ -1,116 +0,0 @@ -package execution - -import ( - log "github.com/sirupsen/logrus" - - "github.com/newrelic/newrelic-cli/internal/install/types" - "github.com/newrelic/newrelic-client-go/v2/pkg/nerdstorage" -) - -const ( - packageID = "00000000-0000-0000-0000-000000000000" - collectionID = "openInstallLibrary" -) - -// NerdstorageStatusReporter is an implementation of the ExecutionStatusReporter -// interface that reports execution status into NerdStorage. -type NerdstorageStatusReporter struct { - client NerdStorageClient -} - -// NewNerdStorageStatusReporter returns a new instance of NerdStorageExecutionStatusReporter. -func NewNerdStorageStatusReporter(client NerdStorageClient) *NerdstorageStatusReporter { - r := NerdstorageStatusReporter{ - client: client, - } - - return &r -} - -func (r NerdstorageStatusReporter) RecipeDetected(status *InstallStatus, event RecipeStatusEvent) error { - return nil -} - -func (r NerdstorageStatusReporter) RecipesSelected(status *InstallStatus, recipes []types.OpenInstallationRecipe) error { - return nil -} - -// RecipeAvailable reports that a recipe is available for installation on -// the underlying host. -func (r NerdstorageStatusReporter) RecipeAvailable(status *InstallStatus, event RecipeStatusEvent) error { - return r.writeStatus(status) -} - -func (r NerdstorageStatusReporter) RecipeCanceled(status *InstallStatus, event RecipeStatusEvent) error { - return r.writeStatus(status) -} - -func (r NerdstorageStatusReporter) RecipeFailed(status *InstallStatus, event RecipeStatusEvent) error { - return r.writeStatus(status) -} - -func (r NerdstorageStatusReporter) RecipeInstalling(status *InstallStatus, event RecipeStatusEvent) error { - return r.writeStatus(status) -} - -func (r NerdstorageStatusReporter) RecipeInstalled(status *InstallStatus, event RecipeStatusEvent) error { - return r.writeStatus(status) -} - -func (r NerdstorageStatusReporter) RecipeRecommended(status *InstallStatus, event RecipeStatusEvent) error { - return r.writeStatus(status) -} - -func (r NerdstorageStatusReporter) RecipeSkipped(status *InstallStatus, event RecipeStatusEvent) error { - return r.writeStatus(status) -} - -func (r NerdstorageStatusReporter) InstallStarted(status *InstallStatus) error { - return r.writeStatus(status) -} - -func (r NerdstorageStatusReporter) InstallComplete(status *InstallStatus) error { - return r.writeStatus(status) -} - -func (r NerdstorageStatusReporter) InstallCanceled(status *InstallStatus) error { - return r.writeStatus(status) -} - -func (r NerdstorageStatusReporter) RecipeUnsupported(status *InstallStatus, event RecipeStatusEvent) error { - return r.writeStatus(status) -} - -func (r NerdstorageStatusReporter) DiscoveryComplete(status *InstallStatus, dm types.DiscoveryManifest) error { - return r.writeStatus(status) -} - -func (r NerdstorageStatusReporter) UpdateRequired(status *InstallStatus) error { - return nil -} - -func (r NerdstorageStatusReporter) writeStatus(status *InstallStatus) error { - i := r.buildExecutionStatusDocument(status) - - for _, g := range status.EntityGUIDs { - _, err := r.client.WriteDocumentWithEntityScope(g, i) - if err != nil { - return err - } - } - - if len(status.EntityGUIDs) == 0 { - log.Debug("no entity GUIDs available, skipping entity-scoped status updates") - } - - return nil -} - -func (r NerdstorageStatusReporter) buildExecutionStatusDocument(status *InstallStatus) nerdstorage.WriteDocumentInput { - return nerdstorage.WriteDocumentInput{ - PackageID: packageID, - Collection: collectionID, - DocumentID: status.DocumentID, - Document: status, - } -} diff --git a/internal/install/execution/nerdstorage_status_reporter_integration_test.go b/internal/install/execution/nerdstorage_status_reporter_integration_test.go deleted file mode 100644 index bd719d91a..000000000 --- a/internal/install/execution/nerdstorage_status_reporter_integration_test.go +++ /dev/null @@ -1,186 +0,0 @@ -//go:build integration -// +build integration - -package execution - -import ( - "os" - "strconv" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/newrelic/newrelic-client-go/v2/newrelic" - "github.com/newrelic/newrelic-client-go/v2/pkg/common" - "github.com/newrelic/newrelic-client-go/v2/pkg/config" - "github.com/newrelic/newrelic-client-go/v2/pkg/nerdstorage" - "github.com/newrelic/newrelic-client-go/v2/pkg/workloads" - - "github.com/newrelic/newrelic-cli/internal/install/types" -) - -func TestReportRecipeSucceeded_SingleEntityGUID(t *testing.T) { - apiKey := os.Getenv("NEW_RELIC_API_KEY") - accountID := os.Getenv("NEW_RELIC_ACCOUNT_ID") - if apiKey == "" || accountID == "" { - t.Skipf("NEW_RELIC_API_KEY and NEW_RELIC_ACCOUNT_ID are required to run this test") - } - - cfg := config.Config{ - PersonalAPIKey: apiKey, - } - c, err := newrelic.New(newrelic.ConfigPersonalAPIKey(cfg.PersonalAPIKey)) - if err != nil { - t.Fatalf("error creating integration test client") - } - - a, err := strconv.Atoi(accountID) - if err != nil { - t.Fatalf("error parsing account ID") - } - - entityGUID := createEntity(t, a, c) - - r := NewNerdStorageStatusReporter(&c.NerdStorage) - status := NewInstallStatus(types.InstallerContext{}, []StatusSubscriber{r}, NewPlatformLinkGenerator()) - status.withEntityGUID(entityGUID) - - defer deleteUserStatusCollection(t, c.NerdStorage) - defer deleteEntityStatusCollection(t, entityGUID, c.NerdStorage) - defer deleteEntity(t, entityGUID, c) - defer deleteAccountStatusCollection(t, a, c.NerdStorage) - - rec := types.OpenInstallationRecipe{Name: "testName"} - evt := RecipeStatusEvent{ - Recipe: rec, - EntityGUID: entityGUID, - } - - err = r.RecipeInstalled(status, evt) - require.NoError(t, err) - - time.Sleep(10 * time.Second) - - // Should not write to user collection - s, err := getUserStatusCollection(t, c.NerdStorage) - require.NoError(t, err) - require.Empty(t, s) - - // Should write to entity collection - s, err = getEntityStatusCollection(t, entityGUID, c.NerdStorage) - require.NoError(t, err) - require.NotEmpty(t, s) -} - -func TestReportRecipeSucceeded_NoEntityGUIDs(t *testing.T) { - apiKey := os.Getenv("NEW_RELIC_API_KEY") - accountID := os.Getenv("NEW_RELIC_ACCOUNT_ID") - if apiKey == "" || accountID == "" { - t.Skipf("NEW_RELIC_API_KEY and NEW_RELIC_ACCOUNT_ID are required to run this test") - } - - cfg := config.Config{ - PersonalAPIKey: apiKey, - } - c, err := newrelic.New(newrelic.ConfigPersonalAPIKey(cfg.PersonalAPIKey)) - if err != nil { - t.Fatalf("error creating integration test client") - } - - a, err := strconv.Atoi(accountID) - if err != nil { - t.Fatalf("error parsing account ID") - } - - entityGUID := createEntity(t, a, c) - - r := NewNerdStorageStatusReporter(&c.NerdStorage) - status := NewInstallStatus(types.InstallerContext{}, []StatusSubscriber{r}, NewPlatformLinkGenerator()) - - defer deleteUserStatusCollection(t, c.NerdStorage) - defer deleteEntityStatusCollection(t, entityGUID, c.NerdStorage) - defer deleteEntity(t, entityGUID, c) - defer deleteAccountStatusCollection(t, a, c.NerdStorage) - - rec := types.OpenInstallationRecipe{Name: "testName"} - evt := RecipeStatusEvent{ - Recipe: rec, - } - - err = r.RecipeInstalled(status, evt) - require.NoError(t, err) - - // Should not write to user collection - s, err := getUserStatusCollection(t, c.NerdStorage) - require.NoError(t, err) - require.Empty(t, s) - - // Should not write to entity collection - s, err = getEntityStatusCollection(t, entityGUID, c.NerdStorage) - require.NoError(t, err) - require.Empty(t, s) -} - -func getUserStatusCollection(t *testing.T, c nerdstorage.NerdStorage) ([]interface{}, error) { - getCollectionInput := nerdstorage.GetCollectionInput{ - PackageID: packageID, - Collection: collectionID, - } - - return c.GetCollectionWithUserScope(getCollectionInput) -} - -func getEntityStatusCollection(t *testing.T, guid string, c nerdstorage.NerdStorage) ([]interface{}, error) { - getCollectionInput := nerdstorage.GetCollectionInput{ - PackageID: packageID, - Collection: collectionID, - } - - return c.GetCollectionWithEntityScope(guid, getCollectionInput) -} - -// TODO: remove after 5/20/23 since we are no longer writing to these collections. -func deleteAccountStatusCollection(t *testing.T, accountID int, c nerdstorage.NerdStorage) { - di := nerdstorage.DeleteCollectionInput{ - Collection: collectionID, - PackageID: packageID, - } - _, err := c.DeleteCollectionWithAccountScope(accountID, di) - require.NoError(t, err) -} - -// TODO: remove after 5/20/23 since we are no longer writing to these collections. -func deleteUserStatusCollection(t *testing.T, c nerdstorage.NerdStorage) { - di := nerdstorage.DeleteCollectionInput{ - Collection: collectionID, - PackageID: packageID, - } - _, err := c.DeleteCollectionWithUserScope(di) - require.NoError(t, err) -} - -// TODO: remove after we stop writing to entity storage (NR-99441) -func deleteEntityStatusCollection(t *testing.T, guid string, c nerdstorage.NerdStorage) { - di := nerdstorage.DeleteCollectionInput{ - Collection: collectionID, - PackageID: packageID, - } - _, err := c.DeleteCollectionWithEntityScope(guid, di) - require.NoError(t, err) -} - -func createEntity(t *testing.T, accountID int, c *newrelic.NewRelic) string { - i := workloads.WorkloadCreateInput{ - Name: "testEntity", - } - e, err := c.Workloads.WorkloadCreate(accountID, i) - require.NoError(t, err) - - return string(e.GUID) -} - -func deleteEntity(t *testing.T, guid string, c *newrelic.NewRelic) { - _, err := c.Workloads.WorkloadDelete(common.EntityGUID(guid)) - require.NoError(t, err) -} diff --git a/internal/install/execution/nerdstorage_status_reporter_unit_test.go b/internal/install/execution/nerdstorage_status_reporter_unit_test.go deleted file mode 100644 index 1879a3854..000000000 --- a/internal/install/execution/nerdstorage_status_reporter_unit_test.go +++ /dev/null @@ -1,166 +0,0 @@ -//go:build unit -// +build unit - -package execution - -import ( - "errors" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/newrelic/newrelic-cli/internal/install/types" -) - -func TestRecipeAvailable_Basic(t *testing.T) { - c := NewMockNerdStorageClient() - r := NewNerdStorageStatusReporter(c) - slg := NewPlatformLinkGenerator() - status := NewInstallStatus(types.InstallerContext{}, []StatusSubscriber{}, slg) - - err := r.RecipeAvailable(status, NewRecipeStatusEvent(&types.OpenInstallationRecipe{})) - require.NoError(t, err) -} - -func TestRecipeInstalled_SingleEntityGUID(t *testing.T) { - c := NewMockNerdStorageClient() - r := NewNerdStorageStatusReporter(c) - slg := NewPlatformLinkGenerator() - status := NewInstallStatus(types.InstallerContext{}, []StatusSubscriber{}, slg) - status.withEntityGUID("testGuid") - e := RecipeStatusEvent{} - - err := r.RecipeInstalled(status, e) - require.NoError(t, err) - require.Equal(t, 0, c.writeDocumentWithUserScopeCallCount) - require.Equal(t, 1, c.writeDocumentWithEntityScopeCallCount) - require.Equal(t, 0, c.writeDocumentWithAccountScopeCallCount) -} - -func TestRecipeInstalled_NoEntityGUIDs(t *testing.T) { - c := NewMockNerdStorageClient() - r := NewNerdStorageStatusReporter(c) - slg := NewPlatformLinkGenerator() - status := NewInstallStatus(types.InstallerContext{}, []StatusSubscriber{}, slg) - e := RecipeStatusEvent{} - - err := r.RecipeInstalled(status, e) - require.NoError(t, err) - require.Equal(t, 0, c.writeDocumentWithUserScopeCallCount) - require.Equal(t, 0, c.writeDocumentWithEntityScopeCallCount) - require.Equal(t, 0, c.writeDocumentWithAccountScopeCallCount) -} - -func TestRecipeInstalled_MultipleEntityGUIDs(t *testing.T) { - c := NewMockNerdStorageClient() - r := NewNerdStorageStatusReporter(c) - slg := NewPlatformLinkGenerator() - status := NewInstallStatus(types.InstallerContext{}, []StatusSubscriber{}, slg) - status.withEntityGUID("testGuid") - status.withEntityGUID("testGuid2") - e := RecipeStatusEvent{} - - err := r.RecipeInstalled(status, e) - require.NoError(t, err) - require.Equal(t, 0, c.writeDocumentWithUserScopeCallCount) - require.Equal(t, 2, c.writeDocumentWithEntityScopeCallCount) - require.Equal(t, 0, c.writeDocumentWithAccountScopeCallCount) -} - -func TestRecipeInstalled_EntityScopeError(t *testing.T) { - c := NewMockNerdStorageClient() - r := NewNerdStorageStatusReporter(c) - slg := NewPlatformLinkGenerator() - status := NewInstallStatus(types.InstallerContext{}, []StatusSubscriber{}, slg) - status.withEntityGUID("testGuid") - e := RecipeStatusEvent{} - - c.WriteDocumentWithEntityScopeErr = errors.New("error") - - err := r.RecipeInstalled(status, e) - require.Error(t, err) -} - -func TestRecipeFailed_SingleEntityGUID(t *testing.T) { - c := NewMockNerdStorageClient() - r := NewNerdStorageStatusReporter(c) - slg := NewPlatformLinkGenerator() - status := NewInstallStatus(types.InstallerContext{}, []StatusSubscriber{}, slg) - status.withEntityGUID("testGuid") - e := RecipeStatusEvent{} - - err := r.RecipeFailed(status, e) - require.NoError(t, err) - require.Equal(t, 0, c.writeDocumentWithUserScopeCallCount) - require.Equal(t, 1, c.writeDocumentWithEntityScopeCallCount) - require.Equal(t, 0, c.writeDocumentWithAccountScopeCallCount) -} - -func TestRecipeFailed_NoEntityGUIDs(t *testing.T) { - c := NewMockNerdStorageClient() - r := NewNerdStorageStatusReporter(c) - slg := NewPlatformLinkGenerator() - status := NewInstallStatus(types.InstallerContext{}, []StatusSubscriber{}, slg) - - e := RecipeStatusEvent{} - - err := r.RecipeFailed(status, e) - require.NoError(t, err) - require.Equal(t, 0, c.writeDocumentWithUserScopeCallCount) - require.Equal(t, 0, c.writeDocumentWithEntityScopeCallCount) - require.Equal(t, 0, c.writeDocumentWithAccountScopeCallCount) -} - -func TestRecipeFailed_EntityScopeError(t *testing.T) { - c := NewMockNerdStorageClient() - r := NewNerdStorageStatusReporter(c) - slg := NewPlatformLinkGenerator() - status := NewInstallStatus(types.InstallerContext{}, []StatusSubscriber{}, slg) - status.withEntityGUID("testGuid") - e := RecipeStatusEvent{} - - c.WriteDocumentWithEntityScopeErr = errors.New("error") - - err := r.RecipeFailed(status, e) - require.Error(t, err) -} - -func TestInstallComplete_Basic(t *testing.T) { - c := NewMockNerdStorageClient() - r := NewNerdStorageStatusReporter(c) - slg := NewPlatformLinkGenerator() - status := NewInstallStatus(types.InstallerContext{}, []StatusSubscriber{}, slg) - status.withEntityGUID("testGuid") - - err := r.InstallComplete(status) - require.NoError(t, err) - require.Equal(t, 0, c.writeDocumentWithUserScopeCallCount) - require.Equal(t, 1, c.writeDocumentWithEntityScopeCallCount) - require.Equal(t, 0, c.writeDocumentWithAccountScopeCallCount) -} - -func TestInstallCanceled_Basic(t *testing.T) { - c := NewMockNerdStorageClient() - r := NewNerdStorageStatusReporter(c) - slg := NewPlatformLinkGenerator() - status := NewInstallStatus(types.InstallerContext{}, []StatusSubscriber{}, slg) - - err := r.InstallCanceled(status) - require.NoError(t, err) - require.Equal(t, 0, c.writeDocumentWithUserScopeCallCount) - require.Equal(t, 0, c.writeDocumentWithEntityScopeCallCount) - require.Equal(t, 0, c.writeDocumentWithAccountScopeCallCount) -} - -func TestDiscoveryComplete_Basic(t *testing.T) { - c := NewMockNerdStorageClient() - r := NewNerdStorageStatusReporter(c) - slg := NewPlatformLinkGenerator() - status := NewInstallStatus(types.InstallerContext{}, []StatusSubscriber{}, slg) - - err := r.DiscoveryComplete(status, types.DiscoveryManifest{}) - require.NoError(t, err) - require.Equal(t, 0, c.writeDocumentWithUserScopeCallCount) - require.Equal(t, 0, c.writeDocumentWithEntityScopeCallCount) - require.Equal(t, 0, c.writeDocumentWithAccountScopeCallCount) -} diff --git a/internal/install/recipe_installer.go b/internal/install/recipe_installer.go index ee9f7530e..28a6df21e 100644 --- a/internal/install/recipe_installer.go +++ b/internal/install/recipe_installer.go @@ -71,7 +71,6 @@ func NewRecipeInstaller(ic types.InstallerContext, nrClient *newrelic.NewRelic, ff := recipes.NewRecipeFileFetcher([]string{}) lf := execution.NewRecipeLogForwarder() ers := []execution.StatusSubscriber{ - execution.NewNerdStorageStatusReporter(&nrClient.NerdStorage), execution.NewTerminalStatusReporter(), execution.NewInstallEventsReporter(&nrClient.InstallEvents), execution.NewSegmentReporter(sg),