From a2ac83acc5669db6c6ff45ba5f86be00b981badc Mon Sep 17 00:00:00 2001 From: Filipe C Menezes Date: Tue, 5 Nov 2024 14:27:57 +0000 Subject: [PATCH 01/10] CLOUDP-279255 Accept both new and old format of atlas search commands for both atlas and local deployments --- .../cli/deployments/search/indexes/create.go | 145 +++++-- .../deployments/search/indexes/create_test.go | 18 +- .../cli/deployments/search/indexes/delete.go | 2 +- .../deployments/search/indexes/delete_test.go | 2 +- .../deployments/search/indexes/describe.go | 2 +- .../search/indexes/describe_test.go | 2 +- .../cli/deployments/search/indexes/list.go | 2 +- .../deployments/search/indexes/list_test.go | 2 +- internal/cli/search/create.go | 32 +- internal/cli/search/create_test.go | 21 +- internal/cli/search/delete.go | 2 +- internal/cli/search/delete_test.go | 2 +- internal/cli/search/describe.go | 2 +- internal/cli/search/describe_test.go | 2 +- internal/cli/search/index_opts.go | 104 ++++- internal/cli/search/list.go | 2 +- internal/cli/search/list_test.go | 2 +- internal/cli/search/update.go | 29 +- internal/cli/search/update_test.go | 8 +- internal/decryption/log_record.go | 2 +- internal/mocks/mock_search.go | 172 +++++++- internal/mocks/mock_search_deprecated.go | 254 +++++++++++ internal/store/search.go | 44 +- internal/store/search_deprecated.go | 76 ++++ test/e2e/atlas/search_test.go | 408 +++++++++++++++++- 25 files changed, 1203 insertions(+), 134 deletions(-) create mode 100644 internal/mocks/mock_search_deprecated.go create mode 100644 internal/store/search_deprecated.go diff --git a/internal/cli/deployments/search/indexes/create.go b/internal/cli/deployments/search/indexes/create.go index 45f21190e2..66763caa63 100644 --- a/internal/cli/deployments/search/indexes/create.go +++ b/internal/cli/deployments/search/indexes/create.go @@ -27,6 +27,7 @@ import ( "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/search" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/config" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/flag" + "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/log" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/mongodbclient" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/store" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/telemetry" @@ -43,7 +44,18 @@ const ( notFoundState = "NOT_FOUND" ) -var ErrSearchIndexDuplicated = errors.New("search index is duplicated") +var ( + ErrSearchIndexDuplicated = errors.New("search index is duplicated") + errInvalidIndex = errors.New("invalid index") +) + +type IndexID struct { + ID string + Name string + Collection string + Database string + Index any +} type CreateOpts struct { cli.WatchOpts @@ -53,8 +65,8 @@ type CreateOpts struct { search.IndexOpts mongodbClient mongodbclient.MongoDBClient connectionString string - index *admin.ClusterSearchIndex - store store.SearchIndexCreator + store store.SearchIndexCreatorDescriber + indexID IndexID } func (opts *CreateOpts) initStore(ctx context.Context) func() error { @@ -84,34 +96,60 @@ func (opts *CreateOpts) RunLocal(ctx context.Context) error { _ = opts.mongodbClient.Disconnect(ctx) }() - opts.index, err = opts.NewSearchIndex() + idx, err := opts.CreateSearchIndex() if err != nil { return err } - telemetry.AppendOption(telemetry.WithSearchIndexType(opts.index.GetType())) + var definition any + var idxType *string - coll := opts.mongodbClient.Database(opts.index.Database).Collection(opts.index.CollectionName) - if idx, _ := coll.SearchIndexByName(ctx, opts.index.Name); idx != nil { - return ErrSearchIndexDuplicated + switch index := idx.(type) { + case *admin.SearchIndexCreateRequest: + idxType = index.Type + + opts.indexID.Database = index.Database + opts.indexID.Collection = index.CollectionName + opts.indexID.Name = index.Name + + definition = index.Definition + case *admin.ClusterSearchIndex: + _, _ = log.Warningln("you're using an old search index definition") + + opts.indexID.Database = index.Database + opts.indexID.Collection = index.CollectionName + opts.indexID.Name = index.Name + + definition, err = buildIndexDefinition(index) + if err != nil { + return err + } + default: + return errInvalidIndex } - if opts.index.Type == nil { + if idxType == nil { defaultType := search.DefaultType - opts.index.Type = &defaultType + idxType = &defaultType } - definition, err := buildIndexDefinition(opts.index) - if err != nil { - return err + telemetry.AppendOption(telemetry.WithSearchIndexType(*idxType)) + + coll := opts.mongodbClient.Database(opts.indexID.Database).Collection(opts.indexID.Collection) + if idx, _ := coll.SearchIndexByName(ctx, opts.indexID.Name); idx != nil { + return ErrSearchIndexDuplicated } - result, err := coll.CreateSearchIndex(ctx, opts.index.Name, *opts.index.Type, definition) + result, err := coll.CreateSearchIndex(ctx, opts.indexID.Name, *idxType, definition) if err != nil { return err } - opts.index.IndexID = result.IndexID + opts.indexID.Index = result + + if result.IndexID != nil { + opts.indexID.ID = *result.IndexID + } return nil } @@ -152,15 +190,56 @@ func (opts *CreateOpts) RunAtlas() error { return err } - index, err := opts.NewSearchIndex() + idx, err := opts.CreateSearchIndex() if err != nil { return err } - telemetry.AppendOption(telemetry.WithSearchIndexType(opts.index.GetType())) + switch index := idx.(type) { + case *admin.SearchIndexCreateRequest: + telemetry.AppendOption(telemetry.WithSearchIndexType(index.GetType())) + r, err := opts.store.CreateSearchIndexes(opts.ConfigProjectID(), opts.DeploymentName, index) + if err != nil { + return err + } - opts.index, err = opts.store.CreateSearchIndexes(opts.ConfigProjectID(), opts.DeploymentName, index) - return err + if r.Database != nil { + opts.indexID.Database = *r.Database + } + if r.CollectionName != nil { + opts.indexID.Collection = *r.CollectionName + } + if r.Name != nil { + opts.indexID.Name = *r.Name + } + if r.IndexID != nil { + opts.indexID.ID = *r.IndexID + } + + opts.indexID.Index = r + + return nil + case *admin.ClusterSearchIndex: + _, _ = log.Warningln("you're using an old search index definition") + telemetry.AppendOption(telemetry.WithSearchIndexType(index.GetType())) + r, err := opts.store.CreateSearchIndexesDeprecated(opts.ConfigProjectID(), opts.DeploymentName, index) + if err != nil { + return err + } + + opts.indexID.Database = r.Database + opts.indexID.Collection = r.CollectionName + opts.indexID.Name = r.Name + if r.IndexID != nil { + opts.indexID.ID = *r.IndexID + } + + opts.indexID.Index = r + + return nil + default: + return errInvalidIndex + } } func (opts *CreateOpts) Run(ctx context.Context) error { @@ -181,39 +260,39 @@ func (opts *CreateOpts) initMongoDBClient() error { return nil } -func (opts *CreateOpts) status(ctx context.Context) (string, error) { +func (opts *CreateOpts) status(ctx context.Context) (*mongodbclient.SearchIndexDefinition, string, error) { if err := opts.mongodbClient.Connect(ctx, opts.connectionString, connectWaitSeconds); err != nil { - return notFoundState, err + return nil, notFoundState, err } defer func() { _ = opts.mongodbClient.Disconnect(ctx) }() - coll := opts.mongodbClient.Database(opts.index.Database).Collection(opts.index.CollectionName) - index, err := coll.SearchIndexByName(ctx, opts.index.Name) + coll := opts.mongodbClient.Database(opts.indexID.Database).Collection(opts.indexID.Collection) + index, err := coll.SearchIndexByName(ctx, opts.indexID.Name) if err != nil { - return notFoundState, nil + return index, notFoundState, nil } if index.Status == nil { - return notFoundState, nil + return index, notFoundState, nil } - return *index.Status, nil + return index, *index.Status, nil } func (opts *CreateOpts) watchLocal(ctx context.Context) (any, bool, error) { - state, err := opts.status(ctx) + index, state, err := opts.status(ctx) if err != nil { return nil, false, err } if state == "READY" { - opts.index.Status = &state - return opts.index, true, nil + index.Status = &state + return index, true, nil } return nil, false, nil } func (opts *CreateOpts) watchAtlas(_ context.Context) (any, bool, error) { - index, err := opts.store.SearchIndex(opts.ConfigProjectID(), opts.DeploymentName, *opts.index.IndexID) + index, err := opts.store.SearchIndexDeprecated(opts.ConfigProjectID(), opts.DeploymentName, opts.indexID.ID) if err != nil { return nil, false, err } @@ -226,7 +305,7 @@ func (opts *CreateOpts) watchAtlas(_ context.Context) (any, bool, error) { func (opts *CreateOpts) PostRun(ctx context.Context) error { opts.AppendDeploymentType() if !opts.EnableWatch { - return opts.Print(opts.index) + return opts.Print(opts.indexID.Index) } watch := opts.watchLocal @@ -241,9 +320,7 @@ func (opts *CreateOpts) PostRun(ctx context.Context) error { if err != nil { return err } - opts.index = watchResult.(*admin.ClusterSearchIndex) - - if err := opts.Print(opts.index); err != nil { + if err := opts.Print(watchResult); err != nil { return err } return opts.PostRunMessages() diff --git a/internal/cli/deployments/search/indexes/create_test.go b/internal/cli/deployments/search/indexes/create_test.go index 238a162021..c7e0136116 100644 --- a/internal/cli/deployments/search/indexes/create_test.go +++ b/internal/cli/deployments/search/indexes/create_test.go @@ -255,7 +255,7 @@ func TestCreate_Duplicated(t *testing.T) { func TestCreate_RunAtlas(t *testing.T) { ctrl := gomock.NewController(t) - mockIndexStore := mocks.NewMockSearchIndexCreator(ctrl) + mockIndexStore := mocks.NewMockSearchIndexCreatorDescriber(ctrl) ctx := context.Background() buf := new(bytes.Buffer) @@ -278,19 +278,13 @@ func TestCreate_RunAtlas(t *testing.T) { store: mockIndexStore, } - index, err := opts.NewSearchIndex() + index, err := opts.CreateSearchIndex() require.NoError(t, err) - indexWithID := &atlasv2.ClusterSearchIndex{ - CollectionName: opts.Collection, - Database: opts.DBName, - Analyzer: &opts.Analyzer, - Mappings: &atlasv2.ApiAtlasFTSMappings{ - Dynamic: &opts.Dynamic, - Fields: nil, - }, - SearchAnalyzer: &opts.SearchAnalyzer, - Name: opts.Name, + indexWithID := &atlasv2.SearchIndexResponse{ + CollectionName: &opts.Collection, + Database: &opts.DBName, + Name: &opts.Name, IndexID: &indexID, } diff --git a/internal/cli/deployments/search/indexes/delete.go b/internal/cli/deployments/search/indexes/delete.go index b5559f15df..f96e294622 100644 --- a/internal/cli/deployments/search/indexes/delete.go +++ b/internal/cli/deployments/search/indexes/delete.go @@ -67,7 +67,7 @@ func (opts *DeleteOpts) Run(ctx context.Context) error { } func (opts *DeleteOpts) RunAtlas() error { - return opts.Delete(opts.store.DeleteSearchIndex, opts.ConfigProjectID(), opts.DeploymentName) + return opts.Delete(opts.store.DeleteSearchIndexDeprecated, opts.ConfigProjectID(), opts.DeploymentName) } func (opts *DeleteOpts) RunLocal(ctx context.Context) error { diff --git a/internal/cli/deployments/search/indexes/delete_test.go b/internal/cli/deployments/search/indexes/delete_test.go index d0a0476914..a3e1866675 100644 --- a/internal/cli/deployments/search/indexes/delete_test.go +++ b/internal/cli/deployments/search/indexes/delete_test.go @@ -159,7 +159,7 @@ func TestDelete_RunAtlas(t *testing.T) { mockStore. EXPECT(). - DeleteSearchIndex(opts.ProjectID, opts.DeploymentName, opts.Entry). + DeleteSearchIndexDeprecated(opts.ProjectID, opts.DeploymentName, opts.Entry). Return(nil). Times(1) diff --git a/internal/cli/deployments/search/indexes/describe.go b/internal/cli/deployments/search/indexes/describe.go index d2442b109a..294553e066 100644 --- a/internal/cli/deployments/search/indexes/describe.go +++ b/internal/cli/deployments/search/indexes/describe.go @@ -62,7 +62,7 @@ func (opts *DescribeOpts) Run(ctx context.Context) error { } func (opts *DescribeOpts) RunAtlas() error { - r, err := opts.store.SearchIndex(opts.ConfigProjectID(), opts.DeploymentName, opts.indexID) + r, err := opts.store.SearchIndexDeprecated(opts.ConfigProjectID(), opts.DeploymentName, opts.indexID) if err != nil { return err } diff --git a/internal/cli/deployments/search/indexes/describe_test.go b/internal/cli/deployments/search/indexes/describe_test.go index 99d6f1592b..01a2c64284 100644 --- a/internal/cli/deployments/search/indexes/describe_test.go +++ b/internal/cli/deployments/search/indexes/describe_test.go @@ -155,7 +155,7 @@ func TestDescribe_RunAtlas(t *testing.T) { mockStore. EXPECT(). - SearchIndex(opts.ProjectID, opts.DeploymentName, opts.indexID). + SearchIndexDeprecated(opts.ProjectID, opts.DeploymentName, opts.indexID). Return(&atlasv2.ClusterSearchIndex{ Name: name, Database: database, diff --git a/internal/cli/deployments/search/indexes/list.go b/internal/cli/deployments/search/indexes/list.go index b3370be660..83f622f416 100644 --- a/internal/cli/deployments/search/indexes/list.go +++ b/internal/cli/deployments/search/indexes/list.go @@ -59,7 +59,7 @@ func (opts *ListOpts) Run(ctx context.Context) error { } func (opts *ListOpts) RunAtlas() error { - r, err := opts.store.SearchIndexes(opts.ConfigProjectID(), opts.DeploymentName, opts.DBName, opts.Collection) + r, err := opts.store.SearchIndexesDeprecated(opts.ConfigProjectID(), opts.DeploymentName, opts.DBName, opts.Collection) if err != nil { return err } diff --git a/internal/cli/deployments/search/indexes/list_test.go b/internal/cli/deployments/search/indexes/list_test.go index 07991f775c..6fa26af069 100644 --- a/internal/cli/deployments/search/indexes/list_test.go +++ b/internal/cli/deployments/search/indexes/list_test.go @@ -185,7 +185,7 @@ func TestList_RunAtlas(t *testing.T) { mockStore. EXPECT(). - SearchIndexes(opts.ProjectID, opts.DeploymentName, opts.DBName, opts.Collection). + SearchIndexesDeprecated(opts.ProjectID, opts.DeploymentName, opts.DBName, opts.Collection). Return([]atlasv2.ClusterSearchIndex{ { Name: expectedName, diff --git a/internal/cli/search/create.go b/internal/cli/search/create.go index 3379f05a61..a1fc45b62f 100644 --- a/internal/cli/search/create.go +++ b/internal/cli/search/create.go @@ -23,13 +23,17 @@ import ( "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/require" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/config" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/flag" + "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/log" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/store" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/telemetry" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/usage" "github.com/spf13/afero" "github.com/spf13/cobra" + "go.mongodb.org/atlas-sdk/v20240805005/admin" ) +var errInvalidIndex = errors.New("invalid index") + type CreateOpts struct { cli.GlobalOpts cli.OutputOpts @@ -49,18 +53,32 @@ func (opts *CreateOpts) initStore(ctx context.Context) func() error { var createTemplate = "Index {{.Name}} created.\n" func (opts *CreateOpts) Run() error { - index, err := opts.NewSearchIndex() + i, err := opts.CreateSearchIndex() if err != nil { return err } - telemetry.AppendOption(telemetry.WithSearchIndexType(index.GetType())) - r, err := opts.store.CreateSearchIndexes(opts.ConfigProjectID(), opts.clusterName, index) - if err != nil { - return err + switch index := i.(type) { + case *admin.SearchIndexCreateRequest: + telemetry.AppendOption(telemetry.WithSearchIndexType(index.GetType())) + r, err := opts.store.CreateSearchIndexes(opts.ConfigProjectID(), opts.clusterName, index) + if err != nil { + return err + } + + return opts.Print(r) + case *admin.ClusterSearchIndex: + _, _ = log.Warningln("you're using an old search index definition") + telemetry.AppendOption(telemetry.WithSearchIndexType(index.GetType())) + r, err := opts.store.CreateSearchIndexesDeprecated(opts.ConfigProjectID(), opts.clusterName, index) + if err != nil { + return err + } + + return opts.Print(r) + default: + return errInvalidIndex } - - return opts.Print(r) } // CreateBuilder diff --git a/internal/cli/search/create_test.go b/internal/cli/search/create_test.go index 8f0c22bbcd..d6bd33139b 100644 --- a/internal/cli/search/create_test.go +++ b/internal/cli/search/create_test.go @@ -17,7 +17,7 @@ package search import ( - "strings" + "errors" "testing" "github.com/golang/mock/gomock" @@ -41,11 +41,11 @@ func TestCreateOpts_Run(t *testing.T) { } opts.Name = testName - request, err := opts.NewSearchIndex() + request, err := opts.CreateSearchIndex() if err != nil { t.Fatalf("newSearchIndex() unexpected error: %v", err) } - expected := &atlasv2.ClusterSearchIndex{} + expected := &atlasv2.SearchIndexResponse{} mockStore. EXPECT(). CreateSearchIndexes(opts.ProjectID, opts.clusterName, request). @@ -69,13 +69,13 @@ func TestCreateOpts_Run(t *testing.T) { opts.Fs = appFS expected := &atlasv2.ClusterSearchIndex{} - request, err := opts.NewSearchIndex() + request, err := opts.CreateSearchIndex() if err != nil { - t.Fatalf("newSearchIndex() unexpected error: %v", err) + t.Fatalf("CreateSearchIndex() unexpected error: %v", err) } mockStore. EXPECT(). - CreateSearchIndexes(opts.ProjectID, opts.clusterName, request).Return(expected, nil). + CreateSearchIndexesDeprecated(opts.ProjectID, opts.clusterName, request).Return(expected, nil). Times(1) if err := opts.Run(); err != nil { t.Fatalf("Run() unexpected error: %v", err) @@ -93,14 +93,13 @@ func TestCreateOpts_Run(t *testing.T) { opts.Filename = fileName opts.Fs = appFS - _, err := opts.NewSearchIndex() + _, err := opts.CreateSearchIndex() if err == nil { - t.Fatalf("newSearchIndex() expected error") + t.Fatalf("CreateSearchIndex() expected error") } - expectedError := "failed to parse JSON file due to" - if !strings.Contains(err.Error(), expectedError) { - t.Fatalf("newSearchIndex() unexpected error: %v expected: %s", err, expectedError) + if !errors.Is(err, errFailedToLoadIndexMessage) { + t.Fatalf("CreateSearchIndex() unexpected error: %v expected: %s", err, errFailedToLoadIndexMessage) } }) } diff --git a/internal/cli/search/delete.go b/internal/cli/search/delete.go index ba52fe88f8..0587a9e86f 100644 --- a/internal/cli/search/delete.go +++ b/internal/cli/search/delete.go @@ -44,7 +44,7 @@ func (opts *DeleteOpts) initStore(ctx context.Context) func() error { } func (opts *DeleteOpts) Run() error { - return opts.Delete(opts.store.DeleteSearchIndex, opts.ConfigProjectID(), opts.clusterName) + return opts.Delete(opts.store.DeleteSearchIndexDeprecated, opts.ConfigProjectID(), opts.clusterName) } // atlas cluster(s) search(s) index(es) delete [--clusterName name][--projectId projectId][--force]. diff --git a/internal/cli/search/delete_test.go b/internal/cli/search/delete_test.go index 69730662b9..e3e4757c2a 100644 --- a/internal/cli/search/delete_test.go +++ b/internal/cli/search/delete_test.go @@ -38,7 +38,7 @@ func TestDelete_Run(t *testing.T) { mockStore. EXPECT(). - DeleteSearchIndex(deleteOpts.ProjectID, deleteOpts.clusterName, deleteOpts.Entry). + DeleteSearchIndexDeprecated(deleteOpts.ProjectID, deleteOpts.clusterName, deleteOpts.Entry). Return(nil). Times(1) diff --git a/internal/cli/search/describe.go b/internal/cli/search/describe.go index 3762ca5ffd..7bfeb2b101 100644 --- a/internal/cli/search/describe.go +++ b/internal/cli/search/describe.go @@ -50,7 +50,7 @@ var describeTemplate = `ID NAME DATABASE COLLECTION TYPE ` func (opts *DescribeOpts) Run() error { - r, err := opts.store.SearchIndex(opts.ConfigProjectID(), opts.clusterName, opts.indexID) + r, err := opts.store.SearchIndexDeprecated(opts.ConfigProjectID(), opts.clusterName, opts.indexID) if err != nil { return err } diff --git a/internal/cli/search/describe_test.go b/internal/cli/search/describe_test.go index d3ebdba38d..b23462ab47 100644 --- a/internal/cli/search/describe_test.go +++ b/internal/cli/search/describe_test.go @@ -40,7 +40,7 @@ func TestDescribe_Run(t *testing.T) { } mockStore. EXPECT(). - SearchIndex(describeOpts.ProjectID, describeOpts.clusterName, describeOpts.indexID). + SearchIndexDeprecated(describeOpts.ProjectID, describeOpts.clusterName, describeOpts.indexID). Return(expected, nil). Times(1) diff --git a/internal/cli/search/index_opts.go b/internal/cli/search/index_opts.go index 8a4ac60cf7..41c3c8675f 100644 --- a/internal/cli/search/index_opts.go +++ b/internal/cli/search/index_opts.go @@ -25,12 +25,15 @@ import ( atlasv2 "go.mongodb.org/atlas-sdk/v20240805005/admin" ) -const DefaultAnalyzer = "lucene.standard" -const deprecatedFlagMessage = "please use --file instead" -const failedToLoadIndexMessage = "failed to parse JSON file due to %s" -const SearchIndexType = "search" -const VectorSearchIndexType = "vectorSearch" -const DefaultType = SearchIndexType +const ( + DefaultAnalyzer = "lucene.standard" + deprecatedFlagMessage = "please use --file instead" + SearchIndexType = "search" + VectorSearchIndexType = "vectorSearch" + DefaultType = SearchIndexType +) + +var errFailedToLoadIndexMessage = errors.New("failed to parse JSON file") type IndexOpts struct { Name string @@ -78,11 +81,30 @@ func (opts *IndexOpts) validateOpts() error { return nil } -func (opts *IndexOpts) NewSearchIndex() (*atlasv2.ClusterSearchIndex, error) { +func (opts *IndexOpts) CreateSearchIndex() (any, error) { if len(opts.Filename) > 0 { + var m map[string]any + if err := file.Load(opts.Fs, opts.Filename, &m); err != nil { + return nil, fmt.Errorf("%w: %w", errFailedToLoadIndexMessage, err) + } + + _, ok := m["definition"] + if ok { + index := &atlasv2.SearchIndexCreateRequest{} + if err := file.Load(opts.Fs, opts.Filename, index); err != nil { + return nil, fmt.Errorf("%w: %w", errFailedToLoadIndexMessage, err) + } + + if index.Type == nil { + index.Type = pointer.Get(DefaultType) + } + + return index, nil + } + index := &atlasv2.ClusterSearchIndex{} if err := file.Load(opts.Fs, opts.Filename, index); err != nil { - return nil, fmt.Errorf(failedToLoadIndexMessage, err.Error()) + return nil, fmt.Errorf("%w: %w", errFailedToLoadIndexMessage, err) } if index.Type == nil { @@ -101,17 +123,69 @@ func (opts *IndexOpts) NewSearchIndex() (*atlasv2.ClusterSearchIndex, error) { opts.SearchAnalyzer = DefaultAnalyzer } - i := &atlasv2.ClusterSearchIndex{ + i := &atlasv2.SearchIndexCreateRequest{ CollectionName: opts.Collection, Database: opts.DBName, Name: opts.Name, - // only search indexes can be created using flags Type: pointer.Get(SearchIndexType), - Analyzer: &opts.Analyzer, - SearchAnalyzer: &opts.SearchAnalyzer, - Mappings: &atlasv2.ApiAtlasFTSMappings{ - Dynamic: &opts.Dynamic, - Fields: f, + Definition: &atlasv2.BaseSearchIndexCreateRequestDefinition{ + Analyzer: &opts.Analyzer, + SearchAnalyzer: &opts.SearchAnalyzer, + Mappings: &atlasv2.SearchMappings{ + Dynamic: &opts.Dynamic, + Fields: f, + }, + }, + } + return i, nil +} + +func (opts *IndexOpts) UpdateSearchIndex() (any, error) { + if len(opts.Filename) > 0 { + var m map[string]any + if err := file.Load(opts.Fs, opts.Filename, &m); err != nil { + return nil, fmt.Errorf("%w: %w", errFailedToLoadIndexMessage, err) + } + + _, ok := m["definition"] + if ok { + index := &atlasv2.SearchIndexUpdateRequest{} + if err := file.Load(opts.Fs, opts.Filename, index); err != nil { + return nil, fmt.Errorf("%w: %w", errFailedToLoadIndexMessage, err) + } + + return index, nil + } + + index := &atlasv2.ClusterSearchIndex{} + if err := file.Load(opts.Fs, opts.Filename, index); err != nil { + return nil, fmt.Errorf("%w: %w", errFailedToLoadIndexMessage, err) + } + + if index.Type == nil { + index.Type = pointer.Get(DefaultType) + } + + return index, nil + } + + f, err := opts.indexFields() + if err != nil { + return nil, err + } + + if opts.SearchAnalyzer == "" { + opts.SearchAnalyzer = DefaultAnalyzer + } + + i := &atlasv2.SearchIndexUpdateRequest{ + Definition: atlasv2.SearchIndexUpdateRequestDefinition{ + Analyzer: &opts.Analyzer, + SearchAnalyzer: &opts.SearchAnalyzer, + Mappings: &atlasv2.SearchMappings{ + Dynamic: &opts.Dynamic, + Fields: f, + }, }, } return i, nil diff --git a/internal/cli/search/list.go b/internal/cli/search/list.go index c3528d9574..de1ea1b1bc 100644 --- a/internal/cli/search/list.go +++ b/internal/cli/search/list.go @@ -50,7 +50,7 @@ var listTemplate = `ID NAME DATABASE COLLECTION TYPE{{range valueOrEmptySlice .} ` func (opts *ListOpts) Run() error { - r, err := opts.store.SearchIndexes(opts.ConfigProjectID(), opts.clusterName, opts.dbName, opts.collName) + r, err := opts.store.SearchIndexesDeprecated(opts.ConfigProjectID(), opts.clusterName, opts.dbName, opts.collName) if err != nil { return err } diff --git a/internal/cli/search/list_test.go b/internal/cli/search/list_test.go index c2da85fe7d..92997e7dfb 100644 --- a/internal/cli/search/list_test.go +++ b/internal/cli/search/list_test.go @@ -42,7 +42,7 @@ func TestList_Run(t *testing.T) { mockStore. EXPECT(). - SearchIndexes(listOpts.ProjectID, listOpts.clusterName, listOpts.dbName, listOpts.collName). + SearchIndexesDeprecated(listOpts.ProjectID, listOpts.clusterName, listOpts.dbName, listOpts.collName). Return(expected, nil). Times(1) diff --git a/internal/cli/search/update.go b/internal/cli/search/update.go index 7158edbd69..a6e8057a72 100644 --- a/internal/cli/search/update.go +++ b/internal/cli/search/update.go @@ -22,11 +22,13 @@ import ( "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/require" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/config" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/flag" + "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/log" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/store" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/telemetry" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/usage" "github.com/spf13/afero" "github.com/spf13/cobra" + "go.mongodb.org/atlas-sdk/v20240805005/admin" ) type UpdateOpts struct { @@ -49,18 +51,31 @@ func (opts *UpdateOpts) initStore(ctx context.Context) func() error { var updateTemplate = "Index {{.Name}} updated.\n" func (opts *UpdateOpts) Run() error { - index, err := opts.NewSearchIndex() + i, err := opts.UpdateSearchIndex() if err != nil { return err } - telemetry.AppendOption(telemetry.WithSearchIndexType(index.GetType())) - r, err := opts.store.UpdateSearchIndexes(opts.ConfigProjectID(), opts.clusterName, opts.id, index) - if err != nil { - return err + switch index := i.(type) { + case *admin.SearchIndexUpdateRequest: + r, err := opts.store.UpdateSearchIndexes(opts.ConfigProjectID(), opts.clusterName, opts.id, index) + if err != nil { + return err + } + + return opts.Print(r) + case *admin.ClusterSearchIndex: + _, _ = log.Warningln("you're using an old search index definition") + telemetry.AppendOption(telemetry.WithSearchIndexType(index.GetType())) + r, err := opts.store.UpdateSearchIndexesDeprecated(opts.ConfigProjectID(), opts.clusterName, opts.id, index) + if err != nil { + return err + } + + return opts.Print(r) + default: + return errInvalidIndex } - - return opts.Print(r) } // UpdateBuilder diff --git a/internal/cli/search/update_test.go b/internal/cli/search/update_test.go index 95636f10d8..06bd21810d 100644 --- a/internal/cli/search/update_test.go +++ b/internal/cli/search/update_test.go @@ -37,9 +37,9 @@ func TestUpdateOpts_Run(t *testing.T) { updateOpts.Name = testName updateOpts.id = "1" - expected := &atlasv2.ClusterSearchIndex{} + expected := &atlasv2.SearchIndexResponse{} - request, err := updateOpts.NewSearchIndex() + request, err := updateOpts.UpdateSearchIndex() require.NoError(t, err) mockStore. EXPECT(). @@ -65,11 +65,11 @@ func TestUpdateOpts_Run(t *testing.T) { expected := &atlasv2.ClusterSearchIndex{} - request, err := updateOpts.NewSearchIndex() + request, err := updateOpts.UpdateSearchIndex() require.NoError(t, err) mockStore. EXPECT(). - UpdateSearchIndexes(updateOpts.ConfigProjectID(), updateOpts.clusterName, updateOpts.id, request). + UpdateSearchIndexesDeprecated(updateOpts.ConfigProjectID(), updateOpts.clusterName, updateOpts.id, request). Return(expected, nil). Times(1) diff --git a/internal/decryption/log_record.go b/internal/decryption/log_record.go index aa536ba8c9..f80ae94d8b 100644 --- a/internal/decryption/log_record.go +++ b/internal/decryption/log_record.go @@ -106,7 +106,7 @@ func (logLine *AuditLogLine) logAdditionalAuthData() []byte { const AADByteSize = 8 additionalAuthData := make([]byte, AADByteSize) - //nolint:gosec + binary.LittleEndian.PutUint64(additionalAuthData, uint64(logLine.TS.UnixMilli())) return additionalAuthData } diff --git a/internal/mocks/mock_search.go b/internal/mocks/mock_search.go index dc8323c7bb..458c413b58 100644 --- a/internal/mocks/mock_search.go +++ b/internal/mocks/mock_search.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/mongodb/mongodb-atlas-cli/atlascli/internal/store (interfaces: SearchIndexLister,SearchIndexCreator,SearchIndexDescriber,SearchIndexUpdater,SearchIndexDeleter) +// Source: github.com/mongodb/mongodb-atlas-cli/atlascli/internal/store (interfaces: SearchIndexLister,SearchIndexCreator,SearchIndexDescriber,SearchIndexUpdater,SearchIndexDeleter,SearchIndexCreatorDescriber) // Package mocks is a generated GoMock package. package mocks @@ -35,10 +35,10 @@ func (m *MockSearchIndexLister) EXPECT() *MockSearchIndexListerMockRecorder { } // SearchIndexes mocks base method. -func (m *MockSearchIndexLister) SearchIndexes(arg0, arg1, arg2, arg3 string) ([]admin.ClusterSearchIndex, error) { +func (m *MockSearchIndexLister) SearchIndexes(arg0, arg1, arg2, arg3 string) ([]admin.SearchIndexResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SearchIndexes", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].([]admin.ClusterSearchIndex) + ret0, _ := ret[0].([]admin.SearchIndexResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -49,6 +49,21 @@ func (mr *MockSearchIndexListerMockRecorder) SearchIndexes(arg0, arg1, arg2, arg return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchIndexes", reflect.TypeOf((*MockSearchIndexLister)(nil).SearchIndexes), arg0, arg1, arg2, arg3) } +// SearchIndexesDeprecated mocks base method. +func (m *MockSearchIndexLister) SearchIndexesDeprecated(arg0, arg1, arg2, arg3 string) ([]admin.ClusterSearchIndex, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchIndexesDeprecated", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].([]admin.ClusterSearchIndex) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SearchIndexesDeprecated indicates an expected call of SearchIndexesDeprecated. +func (mr *MockSearchIndexListerMockRecorder) SearchIndexesDeprecated(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchIndexesDeprecated", reflect.TypeOf((*MockSearchIndexLister)(nil).SearchIndexesDeprecated), arg0, arg1, arg2, arg3) +} + // MockSearchIndexCreator is a mock of SearchIndexCreator interface. type MockSearchIndexCreator struct { ctrl *gomock.Controller @@ -73,10 +88,10 @@ func (m *MockSearchIndexCreator) EXPECT() *MockSearchIndexCreatorMockRecorder { } // CreateSearchIndexes mocks base method. -func (m *MockSearchIndexCreator) CreateSearchIndexes(arg0, arg1 string, arg2 *admin.ClusterSearchIndex) (*admin.ClusterSearchIndex, error) { +func (m *MockSearchIndexCreator) CreateSearchIndexes(arg0, arg1 string, arg2 *admin.SearchIndexCreateRequest) (*admin.SearchIndexResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "CreateSearchIndexes", arg0, arg1, arg2) - ret0, _ := ret[0].(*admin.ClusterSearchIndex) + ret0, _ := ret[0].(*admin.SearchIndexResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -87,19 +102,19 @@ func (mr *MockSearchIndexCreatorMockRecorder) CreateSearchIndexes(arg0, arg1, ar return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSearchIndexes", reflect.TypeOf((*MockSearchIndexCreator)(nil).CreateSearchIndexes), arg0, arg1, arg2) } -// SearchIndex mocks base method. -func (m *MockSearchIndexCreator) SearchIndex(arg0, arg1, arg2 string) (*admin.ClusterSearchIndex, error) { +// CreateSearchIndexesDeprecated mocks base method. +func (m *MockSearchIndexCreator) CreateSearchIndexesDeprecated(arg0, arg1 string, arg2 *admin.ClusterSearchIndex) (*admin.ClusterSearchIndex, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SearchIndex", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "CreateSearchIndexesDeprecated", arg0, arg1, arg2) ret0, _ := ret[0].(*admin.ClusterSearchIndex) ret1, _ := ret[1].(error) return ret0, ret1 } -// SearchIndex indicates an expected call of SearchIndex. -func (mr *MockSearchIndexCreatorMockRecorder) SearchIndex(arg0, arg1, arg2 interface{}) *gomock.Call { +// CreateSearchIndexesDeprecated indicates an expected call of CreateSearchIndexesDeprecated. +func (mr *MockSearchIndexCreatorMockRecorder) CreateSearchIndexesDeprecated(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchIndex", reflect.TypeOf((*MockSearchIndexCreator)(nil).SearchIndex), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSearchIndexesDeprecated", reflect.TypeOf((*MockSearchIndexCreator)(nil).CreateSearchIndexesDeprecated), arg0, arg1, arg2) } // MockSearchIndexDescriber is a mock of SearchIndexDescriber interface. @@ -126,10 +141,10 @@ func (m *MockSearchIndexDescriber) EXPECT() *MockSearchIndexDescriberMockRecorde } // SearchIndex mocks base method. -func (m *MockSearchIndexDescriber) SearchIndex(arg0, arg1, arg2 string) (*admin.ClusterSearchIndex, error) { +func (m *MockSearchIndexDescriber) SearchIndex(arg0, arg1, arg2 string) (*admin.SearchIndexResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SearchIndex", arg0, arg1, arg2) - ret0, _ := ret[0].(*admin.ClusterSearchIndex) + ret0, _ := ret[0].(*admin.SearchIndexResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -140,6 +155,21 @@ func (mr *MockSearchIndexDescriberMockRecorder) SearchIndex(arg0, arg1, arg2 int return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchIndex", reflect.TypeOf((*MockSearchIndexDescriber)(nil).SearchIndex), arg0, arg1, arg2) } +// SearchIndexDeprecated mocks base method. +func (m *MockSearchIndexDescriber) SearchIndexDeprecated(arg0, arg1, arg2 string) (*admin.ClusterSearchIndex, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchIndexDeprecated", arg0, arg1, arg2) + ret0, _ := ret[0].(*admin.ClusterSearchIndex) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SearchIndexDeprecated indicates an expected call of SearchIndexDeprecated. +func (mr *MockSearchIndexDescriberMockRecorder) SearchIndexDeprecated(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchIndexDeprecated", reflect.TypeOf((*MockSearchIndexDescriber)(nil).SearchIndexDeprecated), arg0, arg1, arg2) +} + // MockSearchIndexUpdater is a mock of SearchIndexUpdater interface. type MockSearchIndexUpdater struct { ctrl *gomock.Controller @@ -164,10 +194,10 @@ func (m *MockSearchIndexUpdater) EXPECT() *MockSearchIndexUpdaterMockRecorder { } // UpdateSearchIndexes mocks base method. -func (m *MockSearchIndexUpdater) UpdateSearchIndexes(arg0, arg1, arg2 string, arg3 *admin.ClusterSearchIndex) (*admin.ClusterSearchIndex, error) { +func (m *MockSearchIndexUpdater) UpdateSearchIndexes(arg0, arg1, arg2 string, arg3 *admin.SearchIndexUpdateRequest) (*admin.SearchIndexResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateSearchIndexes", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].(*admin.ClusterSearchIndex) + ret0, _ := ret[0].(*admin.SearchIndexResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -178,6 +208,21 @@ func (mr *MockSearchIndexUpdaterMockRecorder) UpdateSearchIndexes(arg0, arg1, ar return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateSearchIndexes", reflect.TypeOf((*MockSearchIndexUpdater)(nil).UpdateSearchIndexes), arg0, arg1, arg2, arg3) } +// UpdateSearchIndexesDeprecated mocks base method. +func (m *MockSearchIndexUpdater) UpdateSearchIndexesDeprecated(arg0, arg1, arg2 string, arg3 *admin.ClusterSearchIndex) (*admin.ClusterSearchIndex, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateSearchIndexesDeprecated", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*admin.ClusterSearchIndex) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateSearchIndexesDeprecated indicates an expected call of UpdateSearchIndexesDeprecated. +func (mr *MockSearchIndexUpdaterMockRecorder) UpdateSearchIndexesDeprecated(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateSearchIndexesDeprecated", reflect.TypeOf((*MockSearchIndexUpdater)(nil).UpdateSearchIndexesDeprecated), arg0, arg1, arg2, arg3) +} + // MockSearchIndexDeleter is a mock of SearchIndexDeleter interface. type MockSearchIndexDeleter struct { ctrl *gomock.Controller @@ -214,3 +259,100 @@ func (mr *MockSearchIndexDeleterMockRecorder) DeleteSearchIndex(arg0, arg1, arg2 mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSearchIndex", reflect.TypeOf((*MockSearchIndexDeleter)(nil).DeleteSearchIndex), arg0, arg1, arg2) } + +// DeleteSearchIndexDeprecated mocks base method. +func (m *MockSearchIndexDeleter) DeleteSearchIndexDeprecated(arg0, arg1, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteSearchIndexDeprecated", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteSearchIndexDeprecated indicates an expected call of DeleteSearchIndexDeprecated. +func (mr *MockSearchIndexDeleterMockRecorder) DeleteSearchIndexDeprecated(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSearchIndexDeprecated", reflect.TypeOf((*MockSearchIndexDeleter)(nil).DeleteSearchIndexDeprecated), arg0, arg1, arg2) +} + +// MockSearchIndexCreatorDescriber is a mock of SearchIndexCreatorDescriber interface. +type MockSearchIndexCreatorDescriber struct { + ctrl *gomock.Controller + recorder *MockSearchIndexCreatorDescriberMockRecorder +} + +// MockSearchIndexCreatorDescriberMockRecorder is the mock recorder for MockSearchIndexCreatorDescriber. +type MockSearchIndexCreatorDescriberMockRecorder struct { + mock *MockSearchIndexCreatorDescriber +} + +// NewMockSearchIndexCreatorDescriber creates a new mock instance. +func NewMockSearchIndexCreatorDescriber(ctrl *gomock.Controller) *MockSearchIndexCreatorDescriber { + mock := &MockSearchIndexCreatorDescriber{ctrl: ctrl} + mock.recorder = &MockSearchIndexCreatorDescriberMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockSearchIndexCreatorDescriber) EXPECT() *MockSearchIndexCreatorDescriberMockRecorder { + return m.recorder +} + +// CreateSearchIndexes mocks base method. +func (m *MockSearchIndexCreatorDescriber) CreateSearchIndexes(arg0, arg1 string, arg2 *admin.SearchIndexCreateRequest) (*admin.SearchIndexResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateSearchIndexes", arg0, arg1, arg2) + ret0, _ := ret[0].(*admin.SearchIndexResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateSearchIndexes indicates an expected call of CreateSearchIndexes. +func (mr *MockSearchIndexCreatorDescriberMockRecorder) CreateSearchIndexes(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSearchIndexes", reflect.TypeOf((*MockSearchIndexCreatorDescriber)(nil).CreateSearchIndexes), arg0, arg1, arg2) +} + +// CreateSearchIndexesDeprecated mocks base method. +func (m *MockSearchIndexCreatorDescriber) CreateSearchIndexesDeprecated(arg0, arg1 string, arg2 *admin.ClusterSearchIndex) (*admin.ClusterSearchIndex, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateSearchIndexesDeprecated", arg0, arg1, arg2) + ret0, _ := ret[0].(*admin.ClusterSearchIndex) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateSearchIndexesDeprecated indicates an expected call of CreateSearchIndexesDeprecated. +func (mr *MockSearchIndexCreatorDescriberMockRecorder) CreateSearchIndexesDeprecated(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSearchIndexesDeprecated", reflect.TypeOf((*MockSearchIndexCreatorDescriber)(nil).CreateSearchIndexesDeprecated), arg0, arg1, arg2) +} + +// SearchIndex mocks base method. +func (m *MockSearchIndexCreatorDescriber) SearchIndex(arg0, arg1, arg2 string) (*admin.SearchIndexResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchIndex", arg0, arg1, arg2) + ret0, _ := ret[0].(*admin.SearchIndexResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SearchIndex indicates an expected call of SearchIndex. +func (mr *MockSearchIndexCreatorDescriberMockRecorder) SearchIndex(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchIndex", reflect.TypeOf((*MockSearchIndexCreatorDescriber)(nil).SearchIndex), arg0, arg1, arg2) +} + +// SearchIndexDeprecated mocks base method. +func (m *MockSearchIndexCreatorDescriber) SearchIndexDeprecated(arg0, arg1, arg2 string) (*admin.ClusterSearchIndex, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchIndexDeprecated", arg0, arg1, arg2) + ret0, _ := ret[0].(*admin.ClusterSearchIndex) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SearchIndexDeprecated indicates an expected call of SearchIndexDeprecated. +func (mr *MockSearchIndexCreatorDescriberMockRecorder) SearchIndexDeprecated(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchIndexDeprecated", reflect.TypeOf((*MockSearchIndexCreatorDescriber)(nil).SearchIndexDeprecated), arg0, arg1, arg2) +} diff --git a/internal/mocks/mock_search_deprecated.go b/internal/mocks/mock_search_deprecated.go new file mode 100644 index 0000000000..e93cb21c97 --- /dev/null +++ b/internal/mocks/mock_search_deprecated.go @@ -0,0 +1,254 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/mongodb/mongodb-atlas-cli/atlascli/internal/store (interfaces: SearchIndexListerDeprecated,SearchIndexCreatorDeprecated,SearchIndexDescriberDeprecated,SearchIndexUpdaterDeprecated,SearchIndexDeleterDeprecated,SearchIndexCreatorDescriberDeprecated) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + admin "go.mongodb.org/atlas-sdk/v20240805005/admin" +) + +// MockSearchIndexListerDeprecated is a mock of SearchIndexListerDeprecated interface. +type MockSearchIndexListerDeprecated struct { + ctrl *gomock.Controller + recorder *MockSearchIndexListerDeprecatedMockRecorder +} + +// MockSearchIndexListerDeprecatedMockRecorder is the mock recorder for MockSearchIndexListerDeprecated. +type MockSearchIndexListerDeprecatedMockRecorder struct { + mock *MockSearchIndexListerDeprecated +} + +// NewMockSearchIndexListerDeprecated creates a new mock instance. +func NewMockSearchIndexListerDeprecated(ctrl *gomock.Controller) *MockSearchIndexListerDeprecated { + mock := &MockSearchIndexListerDeprecated{ctrl: ctrl} + mock.recorder = &MockSearchIndexListerDeprecatedMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockSearchIndexListerDeprecated) EXPECT() *MockSearchIndexListerDeprecatedMockRecorder { + return m.recorder +} + +// SearchIndexesDeprecated mocks base method. +func (m *MockSearchIndexListerDeprecated) SearchIndexesDeprecated(arg0, arg1, arg2, arg3 string) ([]admin.ClusterSearchIndex, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchIndexesDeprecated", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].([]admin.ClusterSearchIndex) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SearchIndexesDeprecated indicates an expected call of SearchIndexesDeprecated. +func (mr *MockSearchIndexListerDeprecatedMockRecorder) SearchIndexesDeprecated(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchIndexesDeprecated", reflect.TypeOf((*MockSearchIndexListerDeprecated)(nil).SearchIndexesDeprecated), arg0, arg1, arg2, arg3) +} + +// MockSearchIndexCreatorDeprecated is a mock of SearchIndexCreatorDeprecated interface. +type MockSearchIndexCreatorDeprecated struct { + ctrl *gomock.Controller + recorder *MockSearchIndexCreatorDeprecatedMockRecorder +} + +// MockSearchIndexCreatorDeprecatedMockRecorder is the mock recorder for MockSearchIndexCreatorDeprecated. +type MockSearchIndexCreatorDeprecatedMockRecorder struct { + mock *MockSearchIndexCreatorDeprecated +} + +// NewMockSearchIndexCreatorDeprecated creates a new mock instance. +func NewMockSearchIndexCreatorDeprecated(ctrl *gomock.Controller) *MockSearchIndexCreatorDeprecated { + mock := &MockSearchIndexCreatorDeprecated{ctrl: ctrl} + mock.recorder = &MockSearchIndexCreatorDeprecatedMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockSearchIndexCreatorDeprecated) EXPECT() *MockSearchIndexCreatorDeprecatedMockRecorder { + return m.recorder +} + +// CreateSearchIndexesDeprecated mocks base method. +func (m *MockSearchIndexCreatorDeprecated) CreateSearchIndexesDeprecated(arg0, arg1 string, arg2 *admin.ClusterSearchIndex) (*admin.ClusterSearchIndex, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateSearchIndexesDeprecated", arg0, arg1, arg2) + ret0, _ := ret[0].(*admin.ClusterSearchIndex) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateSearchIndexesDeprecated indicates an expected call of CreateSearchIndexesDeprecated. +func (mr *MockSearchIndexCreatorDeprecatedMockRecorder) CreateSearchIndexesDeprecated(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSearchIndexesDeprecated", reflect.TypeOf((*MockSearchIndexCreatorDeprecated)(nil).CreateSearchIndexesDeprecated), arg0, arg1, arg2) +} + +// MockSearchIndexDescriberDeprecated is a mock of SearchIndexDescriberDeprecated interface. +type MockSearchIndexDescriberDeprecated struct { + ctrl *gomock.Controller + recorder *MockSearchIndexDescriberDeprecatedMockRecorder +} + +// MockSearchIndexDescriberDeprecatedMockRecorder is the mock recorder for MockSearchIndexDescriberDeprecated. +type MockSearchIndexDescriberDeprecatedMockRecorder struct { + mock *MockSearchIndexDescriberDeprecated +} + +// NewMockSearchIndexDescriberDeprecated creates a new mock instance. +func NewMockSearchIndexDescriberDeprecated(ctrl *gomock.Controller) *MockSearchIndexDescriberDeprecated { + mock := &MockSearchIndexDescriberDeprecated{ctrl: ctrl} + mock.recorder = &MockSearchIndexDescriberDeprecatedMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockSearchIndexDescriberDeprecated) EXPECT() *MockSearchIndexDescriberDeprecatedMockRecorder { + return m.recorder +} + +// SearchIndexDeprecated mocks base method. +func (m *MockSearchIndexDescriberDeprecated) SearchIndexDeprecated(arg0, arg1, arg2 string) (*admin.ClusterSearchIndex, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchIndexDeprecated", arg0, arg1, arg2) + ret0, _ := ret[0].(*admin.ClusterSearchIndex) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SearchIndexDeprecated indicates an expected call of SearchIndexDeprecated. +func (mr *MockSearchIndexDescriberDeprecatedMockRecorder) SearchIndexDeprecated(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchIndexDeprecated", reflect.TypeOf((*MockSearchIndexDescriberDeprecated)(nil).SearchIndexDeprecated), arg0, arg1, arg2) +} + +// MockSearchIndexUpdaterDeprecated is a mock of SearchIndexUpdaterDeprecated interface. +type MockSearchIndexUpdaterDeprecated struct { + ctrl *gomock.Controller + recorder *MockSearchIndexUpdaterDeprecatedMockRecorder +} + +// MockSearchIndexUpdaterDeprecatedMockRecorder is the mock recorder for MockSearchIndexUpdaterDeprecated. +type MockSearchIndexUpdaterDeprecatedMockRecorder struct { + mock *MockSearchIndexUpdaterDeprecated +} + +// NewMockSearchIndexUpdaterDeprecated creates a new mock instance. +func NewMockSearchIndexUpdaterDeprecated(ctrl *gomock.Controller) *MockSearchIndexUpdaterDeprecated { + mock := &MockSearchIndexUpdaterDeprecated{ctrl: ctrl} + mock.recorder = &MockSearchIndexUpdaterDeprecatedMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockSearchIndexUpdaterDeprecated) EXPECT() *MockSearchIndexUpdaterDeprecatedMockRecorder { + return m.recorder +} + +// UpdateSearchIndexesDeprecated mocks base method. +func (m *MockSearchIndexUpdaterDeprecated) UpdateSearchIndexesDeprecated(arg0, arg1, arg2 string, arg3 *admin.ClusterSearchIndex) (*admin.ClusterSearchIndex, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateSearchIndexesDeprecated", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*admin.ClusterSearchIndex) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateSearchIndexesDeprecated indicates an expected call of UpdateSearchIndexesDeprecated. +func (mr *MockSearchIndexUpdaterDeprecatedMockRecorder) UpdateSearchIndexesDeprecated(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateSearchIndexesDeprecated", reflect.TypeOf((*MockSearchIndexUpdaterDeprecated)(nil).UpdateSearchIndexesDeprecated), arg0, arg1, arg2, arg3) +} + +// MockSearchIndexDeleterDeprecated is a mock of SearchIndexDeleterDeprecated interface. +type MockSearchIndexDeleterDeprecated struct { + ctrl *gomock.Controller + recorder *MockSearchIndexDeleterDeprecatedMockRecorder +} + +// MockSearchIndexDeleterDeprecatedMockRecorder is the mock recorder for MockSearchIndexDeleterDeprecated. +type MockSearchIndexDeleterDeprecatedMockRecorder struct { + mock *MockSearchIndexDeleterDeprecated +} + +// NewMockSearchIndexDeleterDeprecated creates a new mock instance. +func NewMockSearchIndexDeleterDeprecated(ctrl *gomock.Controller) *MockSearchIndexDeleterDeprecated { + mock := &MockSearchIndexDeleterDeprecated{ctrl: ctrl} + mock.recorder = &MockSearchIndexDeleterDeprecatedMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockSearchIndexDeleterDeprecated) EXPECT() *MockSearchIndexDeleterDeprecatedMockRecorder { + return m.recorder +} + +// DeleteSearchIndexDeprecated mocks base method. +func (m *MockSearchIndexDeleterDeprecated) DeleteSearchIndexDeprecated(arg0, arg1, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteSearchIndexDeprecated", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteSearchIndexDeprecated indicates an expected call of DeleteSearchIndexDeprecated. +func (mr *MockSearchIndexDeleterDeprecatedMockRecorder) DeleteSearchIndexDeprecated(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSearchIndexDeprecated", reflect.TypeOf((*MockSearchIndexDeleterDeprecated)(nil).DeleteSearchIndexDeprecated), arg0, arg1, arg2) +} + +// MockSearchIndexCreatorDescriberDeprecated is a mock of SearchIndexCreatorDescriberDeprecated interface. +type MockSearchIndexCreatorDescriberDeprecated struct { + ctrl *gomock.Controller + recorder *MockSearchIndexCreatorDescriberDeprecatedMockRecorder +} + +// MockSearchIndexCreatorDescriberDeprecatedMockRecorder is the mock recorder for MockSearchIndexCreatorDescriberDeprecated. +type MockSearchIndexCreatorDescriberDeprecatedMockRecorder struct { + mock *MockSearchIndexCreatorDescriberDeprecated +} + +// NewMockSearchIndexCreatorDescriberDeprecated creates a new mock instance. +func NewMockSearchIndexCreatorDescriberDeprecated(ctrl *gomock.Controller) *MockSearchIndexCreatorDescriberDeprecated { + mock := &MockSearchIndexCreatorDescriberDeprecated{ctrl: ctrl} + mock.recorder = &MockSearchIndexCreatorDescriberDeprecatedMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockSearchIndexCreatorDescriberDeprecated) EXPECT() *MockSearchIndexCreatorDescriberDeprecatedMockRecorder { + return m.recorder +} + +// CreateSearchIndexesDeprecated mocks base method. +func (m *MockSearchIndexCreatorDescriberDeprecated) CreateSearchIndexesDeprecated(arg0, arg1 string, arg2 *admin.ClusterSearchIndex) (*admin.ClusterSearchIndex, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateSearchIndexesDeprecated", arg0, arg1, arg2) + ret0, _ := ret[0].(*admin.ClusterSearchIndex) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateSearchIndexesDeprecated indicates an expected call of CreateSearchIndexesDeprecated. +func (mr *MockSearchIndexCreatorDescriberDeprecatedMockRecorder) CreateSearchIndexesDeprecated(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSearchIndexesDeprecated", reflect.TypeOf((*MockSearchIndexCreatorDescriberDeprecated)(nil).CreateSearchIndexesDeprecated), arg0, arg1, arg2) +} + +// SearchIndexDeprecated mocks base method. +func (m *MockSearchIndexCreatorDescriberDeprecated) SearchIndexDeprecated(arg0, arg1, arg2 string) (*admin.ClusterSearchIndex, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchIndexDeprecated", arg0, arg1, arg2) + ret0, _ := ret[0].(*admin.ClusterSearchIndex) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SearchIndexDeprecated indicates an expected call of SearchIndexDeprecated. +func (mr *MockSearchIndexCreatorDescriberDeprecatedMockRecorder) SearchIndexDeprecated(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchIndexDeprecated", reflect.TypeOf((*MockSearchIndexCreatorDescriberDeprecated)(nil).SearchIndexDeprecated), arg0, arg1, arg2) +} diff --git a/internal/store/search.go b/internal/store/search.go index ba35c1b45e..5b46c42e5a 100644 --- a/internal/store/search.go +++ b/internal/store/search.go @@ -18,55 +18,69 @@ import ( atlasv2 "go.mongodb.org/atlas-sdk/v20240805005/admin" ) -//go:generate mockgen -destination=../mocks/mock_search.go -package=mocks github.com/mongodb/mongodb-atlas-cli/atlascli/internal/store SearchIndexLister,SearchIndexCreator,SearchIndexDescriber,SearchIndexUpdater,SearchIndexDeleter +//go:generate mockgen -destination=../mocks/mock_search.go -package=mocks github.com/mongodb/mongodb-atlas-cli/atlascli/internal/store SearchIndexLister,SearchIndexCreator,SearchIndexDescriber,SearchIndexUpdater,SearchIndexDeleter,SearchIndexCreatorDescriber type SearchIndexLister interface { - SearchIndexes(string, string, string, string) ([]atlasv2.ClusterSearchIndex, error) + SearchIndexListerDeprecated + + SearchIndexes(string, string, string, string) ([]atlasv2.SearchIndexResponse, error) +} + +type SearchIndexCreatorDescriber interface { + SearchIndexDescriber + SearchIndexCreator } type SearchIndexCreator interface { - CreateSearchIndexes(string, string, *atlasv2.ClusterSearchIndex) (*atlasv2.ClusterSearchIndex, error) - SearchIndex(string, string, string) (*atlasv2.ClusterSearchIndex, error) + SearchIndexCreatorDeprecated + + CreateSearchIndexes(string, string, *atlasv2.SearchIndexCreateRequest) (*atlasv2.SearchIndexResponse, error) } type SearchIndexDescriber interface { - SearchIndex(string, string, string) (*atlasv2.ClusterSearchIndex, error) + SearchIndexDescriberDeprecated + + SearchIndex(string, string, string) (*atlasv2.SearchIndexResponse, error) } type SearchIndexUpdater interface { - UpdateSearchIndexes(string, string, string, *atlasv2.ClusterSearchIndex) (*atlasv2.ClusterSearchIndex, error) + SearchIndexUpdaterDeprecated + + UpdateSearchIndexes(string, string, string, *atlasv2.SearchIndexUpdateRequest) (*atlasv2.SearchIndexResponse, error) } type SearchIndexDeleter interface { + SearchIndexDeleterDeprecated + DeleteSearchIndex(string, string, string) error } // SearchIndexes encapsulate the logic to manage different cloud providers. -func (s *Store) SearchIndexes(projectID, clusterName, dbName, collName string) ([]atlasv2.ClusterSearchIndex, error) { - result, _, err := s.clientv2.AtlasSearchApi.ListAtlasSearchIndexesDeprecated(s.ctx, projectID, clusterName, collName, dbName).Execute() +func (s *Store) SearchIndexes(projectID, clusterName, dbName, collName string) ([]atlasv2.SearchIndexResponse, error) { + result, _, err := s.clientv2.AtlasSearchApi.ListAtlasSearchIndexes(s.ctx, projectID, clusterName, collName, dbName).Execute() return result, err } // CreateSearchIndexes encapsulate the logic to manage different cloud providers. -func (s *Store) CreateSearchIndexes(projectID, clusterName string, index *atlasv2.ClusterSearchIndex) (*atlasv2.ClusterSearchIndex, error) { - result, _, err := s.clientv2.AtlasSearchApi.CreateAtlasSearchIndexDeprecated(s.ctx, projectID, clusterName, index).Execute() +func (s *Store) CreateSearchIndexes(projectID, clusterName string, index *atlasv2.SearchIndexCreateRequest) (*atlasv2.SearchIndexResponse, error) { + result, _, err := s.clientv2.AtlasSearchApi.CreateAtlasSearchIndex(s.ctx, projectID, clusterName, index).Execute() return result, err } // SearchIndex encapsulate the logic to manage different cloud providers. -func (s *Store) SearchIndex(projectID, clusterName, indexID string) (*atlasv2.ClusterSearchIndex, error) { - index, _, err := s.clientv2.AtlasSearchApi.GetAtlasSearchIndexDeprecated(s.ctx, projectID, clusterName, indexID).Execute() +func (s *Store) SearchIndex(projectID, clusterName, indexID string) (*atlasv2.SearchIndexResponse, error) { + index, _, err := s.clientv2.AtlasSearchApi.GetAtlasSearchIndex(s.ctx, projectID, clusterName, indexID).Execute() return index, err } // UpdateSearchIndexes encapsulate the logic to manage different cloud providers. -func (s *Store) UpdateSearchIndexes(projectID, clusterName, indexID string, index *atlasv2.ClusterSearchIndex) (*atlasv2.ClusterSearchIndex, error) { - result, _, err := s.clientv2.AtlasSearchApi.UpdateAtlasSearchIndexDeprecated(s.ctx, projectID, clusterName, indexID, index).Execute() +func (s *Store) UpdateSearchIndexes(projectID, clusterName, indexID string, index *atlasv2.SearchIndexUpdateRequest) (*atlasv2.SearchIndexResponse, error) { + result, _, err := s.clientv2.AtlasSearchApi.UpdateAtlasSearchIndex(s.ctx, projectID, clusterName, indexID, index).Execute() return result, err } // DeleteSearchIndex encapsulate the logic to manage different cloud providers. func (s *Store) DeleteSearchIndex(projectID, clusterName, indexID string) error { - _, _, err := s.clientv2.AtlasSearchApi.DeleteAtlasSearchIndexDeprecated(s.ctx, projectID, clusterName, indexID).Execute() + _, _, err := s.clientv2.AtlasSearchApi.DeleteAtlasSearchIndex(s.ctx, projectID, clusterName, indexID).Execute() return err } diff --git a/internal/store/search_deprecated.go b/internal/store/search_deprecated.go new file mode 100644 index 0000000000..aac25a2de4 --- /dev/null +++ b/internal/store/search_deprecated.go @@ -0,0 +1,76 @@ +// Copyright 2020 MongoDB Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package store + +import ( + atlasv2 "go.mongodb.org/atlas-sdk/v20240805005/admin" +) + +//go:generate mockgen -destination=../mocks/mock_search_deprecated.go -package=mocks github.com/mongodb/mongodb-atlas-cli/atlascli/internal/store SearchIndexListerDeprecated,SearchIndexCreatorDeprecated,SearchIndexDescriberDeprecated,SearchIndexUpdaterDeprecated,SearchIndexDeleterDeprecated,SearchIndexCreatorDescriberDeprecated + +type SearchIndexListerDeprecated interface { + SearchIndexesDeprecated(string, string, string, string) ([]atlasv2.ClusterSearchIndex, error) +} + +type SearchIndexCreatorDescriberDeprecated interface { + SearchIndexDescriberDeprecated + SearchIndexCreatorDeprecated +} + +type SearchIndexCreatorDeprecated interface { + CreateSearchIndexesDeprecated(string, string, *atlasv2.ClusterSearchIndex) (*atlasv2.ClusterSearchIndex, error) +} + +type SearchIndexDescriberDeprecated interface { + SearchIndexDeprecated(string, string, string) (*atlasv2.ClusterSearchIndex, error) +} + +type SearchIndexUpdaterDeprecated interface { + UpdateSearchIndexesDeprecated(string, string, string, *atlasv2.ClusterSearchIndex) (*atlasv2.ClusterSearchIndex, error) +} + +type SearchIndexDeleterDeprecated interface { + DeleteSearchIndexDeprecated(string, string, string) error +} + +// SearchIndexesDeprecated encapsulate the logic to manage different cloud providers. +func (s *Store) SearchIndexesDeprecated(projectID, clusterName, dbName, collName string) ([]atlasv2.ClusterSearchIndex, error) { + result, _, err := s.clientv2.AtlasSearchApi.ListAtlasSearchIndexesDeprecated(s.ctx, projectID, clusterName, collName, dbName).Execute() + return result, err +} + +// CreateSearchIndexesDeprecated encapsulate the logic to manage different cloud providers. +func (s *Store) CreateSearchIndexesDeprecated(projectID, clusterName string, index *atlasv2.ClusterSearchIndex) (*atlasv2.ClusterSearchIndex, error) { + result, _, err := s.clientv2.AtlasSearchApi.CreateAtlasSearchIndexDeprecated(s.ctx, projectID, clusterName, index).Execute() + return result, err +} + +// SearchIndex encapsulate the logic to manage different cloud providers. +func (s *Store) SearchIndexDeprecated(projectID, clusterName, indexID string) (*atlasv2.ClusterSearchIndex, error) { + index, _, err := s.clientv2.AtlasSearchApi.GetAtlasSearchIndexDeprecated(s.ctx, projectID, clusterName, indexID).Execute() + return index, err +} + +// UpdateSearchIndexesDeprecated encapsulate the logic to manage different cloud providers. +func (s *Store) UpdateSearchIndexesDeprecated(projectID, clusterName, indexID string, index *atlasv2.ClusterSearchIndex) (*atlasv2.ClusterSearchIndex, error) { + result, _, err := s.clientv2.AtlasSearchApi.UpdateAtlasSearchIndexDeprecated(s.ctx, projectID, clusterName, indexID, index).Execute() + return result, err +} + +// DeleteSearchIndexDeprecated encapsulate the logic to manage different cloud providers. +func (s *Store) DeleteSearchIndexDeprecated(projectID, clusterName, indexID string) error { + _, _, err := s.clientv2.AtlasSearchApi.DeleteAtlasSearchIndexDeprecated(s.ctx, projectID, clusterName, indexID).Execute() + return err +} diff --git a/test/e2e/atlas/search_test.go b/test/e2e/atlas/search_test.go index 968924645e..66d0b3a568 100644 --- a/test/e2e/atlas/search_test.go +++ b/test/e2e/atlas/search_test.go @@ -30,6 +30,8 @@ import ( atlasv2 "go.mongodb.org/atlas-sdk/v20240805005/admin" ) +const analyzer = "lucene.simple" + func TestSearch(t *testing.T) { g := newAtlasE2ETestGenerator(t) g.generateProjectAndCluster("search") @@ -56,6 +58,411 @@ func TestSearch(t *testing.T) { require.NoError(t, cmd.Run()) }) + t.Run("Create via file", func(t *testing.T) { + fileName := fmt.Sprintf("create_index_search_test-%v.json", n) + + file, err := os.Create(fileName) + require.NoError(t, err) + t.Cleanup(func() { + require.NoError(t, os.Remove(fileName)) + }) + + tpl := template.Must(template.New("").Parse(` +{ + "collectionName": "{{ .collectionName }}", + "database": "test", + "name": "{{ .indexName }}", + "definition": { + "mappings": { + "dynamic": true + } + } +}`)) + require.NoError(t, tpl.Execute(file, map[string]string{ + "collectionName": collectionName, + "indexName": indexName, + })) + + cmd := exec.Command(cliPath, + clustersEntity, + searchEntity, + indexEntity, + "create", + "--clusterName", g.clusterName, + "--file", + fileName, + "--projectId", g.projectID, + "-o=json") + + cmd.Env = os.Environ() + resp, err := e2e.RunAndGetStdOut(cmd) + require.NoError(t, err, string(resp)) + var index atlasv2.ClusterSearchIndex + require.NoError(t, json.Unmarshal(resp, &index)) + assert.Equal(t, index.GetName(), indexName) + indexID = index.GetIndexID() + }) + + t.Run("Describe", func(t *testing.T) { + cmd := exec.Command(cliPath, + clustersEntity, + searchEntity, + indexEntity, + "describe", + indexID, + "--clusterName", g.clusterName, + "--projectId", g.projectID, + "-o=json") + cmd.Env = os.Environ() + resp, err := e2e.RunAndGetStdOut(cmd) + require.NoError(t, err, string(resp)) + var index atlasv2.ClusterSearchIndex + require.NoError(t, json.Unmarshal(resp, &index)) + assert.Equal(t, indexID, index.GetIndexID()) + }) + + t.Run("Update via file", func(t *testing.T) { + fileName := fmt.Sprintf("update_index_search_test-%v.json", n) + + file, err := os.Create(fileName) + require.NoError(t, err) + t.Cleanup(func() { + require.NoError(t, os.Remove(fileName)) + }) + + tpl := template.Must(template.New("").Parse(` +{ + "collectionName": "{{ .collectionName }}", + "database": "test", + "name": "{{ .indexName }}", + "definition": { + "analyzer": "{{ .analyzer }}", + "mappings": { + "dynamic": true + } + } +}`)) + require.NoError(t, tpl.Execute(file, map[string]string{ + "collectionName": collectionName, + "indexName": indexName, + "analyzer": analyzer, + })) + + cmd := exec.Command(cliPath, + clustersEntity, + searchEntity, + indexEntity, + "update", + indexID, + "--clusterName", g.clusterName, + "--projectId", g.projectID, + "--file", + fileName, + "-o=json") + + cmd.Env = os.Environ() + resp, err := e2e.RunAndGetStdOut(cmd) + require.NoError(t, err, string(resp)) + var index atlasv2.ClusterSearchIndex + require.NoError(t, json.Unmarshal(resp, &index)) + a := assert.New(t) + a.Equal(indexID, index.GetIndexID()) + a.Equal(analyzer, index.GetAnalyzer()) + }) + + t.Run("Delete", func(t *testing.T) { + cmd := exec.Command(cliPath, + clustersEntity, + searchEntity, + indexEntity, + "delete", + indexID, + "--clusterName", g.clusterName, + "--projectId", g.projectID, + "--force") + cmd.Env = os.Environ() + resp, err := e2e.RunAndGetStdOut(cmd) + require.NoError(t, err, string(resp)) + expected := fmt.Sprintf("Index '%s' deleted\n", indexID) + assert.Equal(t, expected, string(resp)) + }) + + t.Run("Create combinedMapping", func(t *testing.T) { + fileName := fmt.Sprintf("create_index_search_test-%v.json", n) + + file, err := os.Create(fileName) + r.NoError(err) + t.Cleanup(func() { + require.NoError(t, os.Remove(fileName)) + }) + + tpl := template.Must(template.New("").Parse(` +{ + "collectionName": "planets", + "database": "sample_guides", + "name": "{{ .indexName }}", + "definition": { + "analyzer": "lucene.standard", + "searchAnalyzer": "lucene.standard", + "mappings": { + "dynamic": false, + "fields": { + "name": { + "type": "string", + "analyzer": "lucene.whitespace", + "multi": { + "mySecondaryAnalyzer": { + "type": "string", + "analyzer": "lucene.french" + } + } + }, + "mainAtmosphere": { + "type": "string", + "analyzer": "lucene.standard" + }, + "surfaceTemperatureC": { + "type": "document", + "dynamic": true, + "analyzer": "lucene.standard" + } + } + } + } +}`)) + require.NoError(t, tpl.Execute(file, map[string]string{ + "indexName": indexName, + })) + + cmd := exec.Command(cliPath, + clustersEntity, + searchEntity, + indexEntity, + "create", + "--clusterName", g.clusterName, + "--file", + fileName, + "--projectId", g.projectID, + "-o=json") + + cmd.Env = os.Environ() + resp, err := e2e.RunAndGetStdOut(cmd) + require.NoError(t, err, string(resp)) + var index atlasv2.ClusterSearchIndex + require.NoError(t, json.Unmarshal(resp, &index)) + assert.Equal(t, indexName, index.Name) + }) + + t.Run("Create staticMapping", func(t *testing.T) { + fileName := fmt.Sprintf("create_index_search_test-array-%v.json", n) + + file, err := os.Create(fileName) + r.NoError(err) + t.Cleanup(func() { + require.NoError(t, os.Remove(fileName)) + }) + + tpl := template.Must(template.New("").Parse(` +{ + "collectionName": "posts", + "database": "sample_training", + "name": "{{ .indexName }}", + "analyzer": "lucene.standard", + "searchAnalyzer": "lucene.standard", + "mappings": { + "dynamic": false, + "fields": { + "comments": { + "type": "document", + "fields": { + "body": { + "type": "string", + "analyzer": "lucene.simple", + "ignoreAbove": 255 + }, + "author": { + "type": "string", + "analyzer": "keywordLowerCase" + } + } + }, + "body": { + "type": "string", + "analyzer": "lucene.whitespace", + "multi": { + "mySecondaryAnalyzer": { + "type": "string", + "analyzer": "keywordLowerCase" + } + } + }, + "tags": { + "type": "string", + "analyzer": "standardLowerCase" + } + } + }, +"analyzers":[ + { + "charFilters":[ + + ], + "name":"keywordLowerCase", + "tokenFilters":[ + { + "type":"lowercase" + } + ], + "tokenizer":{ + "type":"keyword" + } + }, + { + "charFilters":[ + + ], + "name":"standardLowerCase", + "tokenFilters":[ + { + "type":"lowercase" + } + ], + "tokenizer":{ + "type":"standard" + } + } + ] +}`)) + require.NoError(t, tpl.Execute(file, map[string]string{ + "indexName": indexName, + })) + + cmd := exec.Command(cliPath, + clustersEntity, + searchEntity, + indexEntity, + "create", + "--clusterName", g.clusterName, + "--file", + fileName, + "--projectId", g.projectID, + "-o=json") + + cmd.Env = os.Environ() + resp, err := e2e.RunAndGetStdOut(cmd) + require.NoError(t, err, string(resp)) + var index atlasv2.ClusterSearchIndex + require.NoError(t, json.Unmarshal(resp, &index)) + assert.Equal(t, indexName, index.Name) + }) + + t.Run("Create array mapping", func(t *testing.T) { + n, err := e2e.RandInt(1000) + r.NoError(err) + indexName := fmt.Sprintf("index-array-%v", n) + fileName := fmt.Sprintf("create_index_search_test-array-%v.json", n) + + file, err := os.Create(fileName) + r.NoError(err) + t.Cleanup(func() { + require.NoError(t, os.Remove(fileName)) + }) + + tpl := template.Must(template.New("").Parse(` +{ + "collectionName": "posts", + "database": "sample_training", + "name": "{{ .indexName }}", + "name": "{{ .indexName }}", + "definition": { + "searchAnalyzer": "lucene.standard", + "mappings": { + "dynamic": false, + "fields": { + "comments": [ + { + "dynamic": true, + "type": "document" + }, + { + "type": "string" + } + ] + } + } + } +}`)) + require.NoError(t, tpl.Execute(file, map[string]string{ + "indexName": indexName, + })) + + cmd := exec.Command(cliPath, + clustersEntity, + searchEntity, + indexEntity, + "create", + "--clusterName", g.clusterName, + "--file", + fileName, + "--projectId", g.projectID, + "-o=json") + + cmd.Env = os.Environ() + resp, err := e2e.RunAndGetStdOut(cmd) + require.NoError(t, err, string(resp)) + var index atlasv2.ClusterSearchIndex + require.NoError(t, json.Unmarshal(resp, &index)) + assert.Equal(t, indexName, index.Name) + }) + + t.Run("list", func(t *testing.T) { + cmd := exec.Command(cliPath, + clustersEntity, + searchEntity, + indexEntity, + "list", + "--clusterName", g.clusterName, + "--db=test", + "--collection", collectionName, + "--projectId", g.projectID, + "-o=json") + + cmd.Env = os.Environ() + resp, err := e2e.RunAndGetStdOut(cmd) + require.NoError(t, err, string(resp)) + + var indexes []atlasv2.ClusterSearchIndex + require.NoError(t, json.Unmarshal(resp, &indexes)) + assert.NotEmpty(t, indexes) + }) +} + +func TestSearchDeprecated(t *testing.T) { + g := newAtlasE2ETestGenerator(t) + g.generateProjectAndCluster("search") + r := require.New(t) + + cliPath, err := e2e.AtlasCLIBin() + r.NoError(err) + + n, err := e2e.RandInt(1000) + r.NoError(err) + indexName := fmt.Sprintf("index-%v", n) + collectionName := fmt.Sprintf("collection-%v", n) + var indexID string + + t.Run("Load Sample data", func(t *testing.T) { + cmd := exec.Command(cliPath, + clustersEntity, + "sampleData", + "load", + g.clusterName, + "--projectId", g.projectID, + "-o=json") + cmd.Env = os.Environ() + require.NoError(t, cmd.Run()) + }) + t.Run("Create via file", func(t *testing.T) { fileName := fmt.Sprintf("create_index_search_test-%v.json", n) @@ -118,7 +525,6 @@ func TestSearch(t *testing.T) { }) t.Run("Update via file", func(t *testing.T) { - analyzer := "lucene.simple" fileName := fmt.Sprintf("update_index_search_test-%v.json", n) file, err := os.Create(fileName) From 9ff3e96d6b952ecbebb4c0d0bd4f7fa5df6f785e Mon Sep 17 00:00:00 2001 From: Filipe C Menezes Date: Tue, 12 Nov 2024 11:59:04 +0000 Subject: [PATCH 02/10] fix lint --- internal/decryption/log_record.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/decryption/log_record.go b/internal/decryption/log_record.go index f80ae94d8b..aa536ba8c9 100644 --- a/internal/decryption/log_record.go +++ b/internal/decryption/log_record.go @@ -106,7 +106,7 @@ func (logLine *AuditLogLine) logAdditionalAuthData() []byte { const AADByteSize = 8 additionalAuthData := make([]byte, AADByteSize) - + //nolint:gosec binary.LittleEndian.PutUint64(additionalAuthData, uint64(logLine.TS.UnixMilli())) return additionalAuthData } From bbd388301a66bc357c07b7a70b71727819a033cb Mon Sep 17 00:00:00 2001 From: Filipe C Menezes Date: Tue, 12 Nov 2024 12:17:58 +0000 Subject: [PATCH 03/10] add index deprecated --- build/ci/evergreen.yml | 23 +- test/e2e/atlas/data/sample_vector_search.json | 34 +- .../data/sample_vector_search_deprecated.json | 22 + ...yments_local_auth_index_deprecated_test.go | 411 ++++++++++++++++++ test/e2e/atlas/deployments_local_auth_test.go | 2 +- 5 files changed, 473 insertions(+), 19 deletions(-) create mode 100644 test/e2e/atlas/data/sample_vector_search_deprecated.json create mode 100644 test/e2e/atlas/deployments_local_auth_index_deprecated_test.go diff --git a/build/ci/evergreen.yml b/build/ci/evergreen.yml index dae71bc5af..70961f37c6 100644 --- a/build/ci/evergreen.yml +++ b/build/ci/evergreen.yml @@ -1479,7 +1479,7 @@ tasks: E2E_TAGS: atlas,deployments,local,nocli E2E_TIMEOUT: 3h - name: atlas_deployments_local_auth_e2e - tags: ["e2e","deployments","local","auth"] + tags: ["e2e","deployments","local","auth","new"] must_have_test_results: true exec_timeout_secs: 11400 # 3 hours 10 minutes commands: @@ -1495,7 +1495,26 @@ tasks: MCLI_PUBLIC_API_KEY: ${atlas_public_api_key} MCLI_OPS_MANAGER_URL: ${mcli_ops_manager_url} MCLI_SERVICE: cloud - E2E_TAGS: atlas,deployments,local,auth + E2E_TAGS: atlas,deployments,local,auth,new + E2E_TIMEOUT: 3h + - name: atlas_deployments_local_auth_deprecated_e2e + tags: ["e2e","deployments","local","auth","deprecated"] + must_have_test_results: true + exec_timeout_secs: 11400 # 3 hours 10 minutes + commands: + - func: "install gotestsum" + - func: "install mongodb database tools" + - func: "increase inotify limits" + - func: "e2e test" + timeout_secs: 11400 # 3 hours 10 minutes + vars: + MCLI_ORG_ID: ${atlas_org_id} + MCLI_PROJECT_ID: ${atlas_project_id} + MCLI_PRIVATE_API_KEY: ${atlas_private_api_key} + MCLI_PUBLIC_API_KEY: ${atlas_public_api_key} + MCLI_OPS_MANAGER_URL: ${mcli_ops_manager_url} + MCLI_SERVICE: cloud + E2E_TAGS: atlas,deployments,local,auth,deprecated E2E_TIMEOUT: 3h - name: build_win11_image tags: ["packer", "windows", "win11"] diff --git a/test/e2e/atlas/data/sample_vector_search.json b/test/e2e/atlas/data/sample_vector_search.json index f4ba764fac..1e15cdd187 100644 --- a/test/e2e/atlas/data/sample_vector_search.json +++ b/test/e2e/atlas/data/sample_vector_search.json @@ -3,20 +3,22 @@ "name": "sampleVectorSearch", "database": "sample_mflix", "collectionName": "embedded_movies", - "fields": [ - { - "type": "vector", - "path": "plot_embedding", - "numDimensions": 1536, - "similarity": "euclidean" - }, - { - "type": "filter", - "path": "genres" - }, - { - "type": "filter", - "path": "year" - } - ] + "definition": { + "fields": [ + { + "type": "vector", + "path": "plot_embedding", + "numDimensions": 1536, + "similarity": "euclidean" + }, + { + "type": "filter", + "path": "genres" + }, + { + "type": "filter", + "path": "year" + } + ] + } } diff --git a/test/e2e/atlas/data/sample_vector_search_deprecated.json b/test/e2e/atlas/data/sample_vector_search_deprecated.json new file mode 100644 index 0000000000..f4ba764fac --- /dev/null +++ b/test/e2e/atlas/data/sample_vector_search_deprecated.json @@ -0,0 +1,22 @@ +{ + "type": "vectorSearch", + "name": "sampleVectorSearch", + "database": "sample_mflix", + "collectionName": "embedded_movies", + "fields": [ + { + "type": "vector", + "path": "plot_embedding", + "numDimensions": 1536, + "similarity": "euclidean" + }, + { + "type": "filter", + "path": "genres" + }, + { + "type": "filter", + "path": "year" + } + ] +} diff --git a/test/e2e/atlas/deployments_local_auth_index_deprecated_test.go b/test/e2e/atlas/deployments_local_auth_index_deprecated_test.go new file mode 100644 index 0000000000..65362934c7 --- /dev/null +++ b/test/e2e/atlas/deployments_local_auth_index_deprecated_test.go @@ -0,0 +1,411 @@ +// Copyright 2023 MongoDB Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//go:build e2e || (atlas && deployments && local && auth && deprecated) + +package atlas_test + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "os/exec" + "strings" + "testing" + + "github.com/mongodb/mongodb-atlas-cli/atlascli/test/e2e" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func TestDeploymentsLocalWithAuthIndexDeprecated(t *testing.T) { + const ( + deploymentName = "test-auth" + dbUsername = "admin" + dbUserPassword = "testpwd" + ) + + cliPath, err := e2e.AtlasCLIBin() + req := require.New(t) + req.NoError(err) + + t.Run("Setup", func(t *testing.T) { + t.Cleanup(func() { + cmd := exec.Command(cliPath, + deploymentEntity, + "diagnostics", + deploymentName, + ) + + cmd.Env = os.Environ() + + r, errDiag := e2e.RunAndGetStdOut(cmd) + t.Log("Diagnostics") + t.Log(errDiag, string(r)) + }) + + cmd := exec.Command(cliPath, + deploymentEntity, + "setup", + deploymentName, + "--type", + "local", + "--username", + dbUsername, + "--password", + dbUserPassword, + "--bindIpAll", + "--force", + ) + + cmd.Env = os.Environ() + + r, setupErr := e2e.RunAndGetStdOut(cmd) + require.NoError(t, setupErr, string(r)) + }) + + t.Cleanup(func() { + cmd := exec.Command(cliPath, + deploymentEntity, + "delete", + deploymentName, + "--type", + "local", + "--force", + ) + + cmd.Env = os.Environ() + + r, delErr := e2e.RunAndGetStdOut(cmd) + require.NoError(t, delErr, string(r)) + }) + + t.Run("List deployments", func(t *testing.T) { + cmd := exec.Command(cliPath, + deploymentEntity, + "list", + "--type", + "local", + ) + + cmd.Env = os.Environ() + + o, e, err := splitOutput(cmd) + require.NoError(t, err, e) + + outputLines := strings.Split(o, "\n") + assert.Regexp(t, `NAME\s+TYPE\s+MDB VER\s+STATE`, outputLines[0]) + + cols := strings.Fields(outputLines[1]) + assert.Equal(t, deploymentName, cols[0]) + assert.Equal(t, "LOCAL", cols[1]) + assert.Contains(t, cols[2], "8.0.") + assert.Equal(t, "IDLE", cols[3]) + }) + + ctx := context.Background() + const localFile = "sampledata.archive" + var connectionString string + + t.Run("Get connection string", func(t *testing.T) { + cmd := exec.Command(cliPath, + deploymentEntity, + "connect", + deploymentName, + "--type", + "local", + "--username", + dbUsername, + "--password", + dbUserPassword, + "--connectWith", + "connectionString", + ) + + cmd.Env = os.Environ() + + r, err := e2e.RunAndGetStdOut(cmd) + require.NoError(t, err, string(r)) + + connectionString = strings.TrimSpace(string(r)) + }) + + t.Run("Download sample dataset", func(t *testing.T) { + out, err := os.Create(localFile) + require.NoError(t, err) + defer out.Close() + req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://atlas-education.s3.amazonaws.com/sampledata.archive", nil) + require.NoError(t, err) + resp, err := http.DefaultClient.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + _, err = io.Copy(out, resp.Body) + require.NoError(t, err) + }) + + t.Cleanup(func() { + os.Remove(localFile) + }) + + t.Run("Seed database", func(t *testing.T) { + cmd := exec.Command("mongorestore", + "--uri", connectionString, + "--archive="+localFile, + ) + + cmd.Env = os.Environ() + + r, err := e2e.RunAndGetStdOut(cmd) + require.NoError(t, err, string(r)) + }) + + t.Run("Create Search Index", func(t *testing.T) { + cmd := exec.Command(cliPath, + deploymentEntity, + searchEntity, + indexEntity, + "create", + searchIndexName, + "--type", + "local", + "--deploymentName", + deploymentName, + "--db", + databaseName, + "--collection", + collectionName, + "--username", + dbUsername, + "--password", + dbUserPassword, + "--type", + "LOCAL", + "-w", + ) + + cmd.Env = os.Environ() + + r, err := e2e.RunAndGetStdOut(cmd) + out := string(r) + req.NoError(err, out) + assert.Contains(t, out, "Search index created with ID:") + }) + + t.Run("Create vectorSearch Index", func(t *testing.T) { + cmd := exec.Command(cliPath, + deploymentEntity, + searchEntity, + indexEntity, + "create", + "--deploymentName", + deploymentName, + "--username", + dbUsername, + "--password", + dbUserPassword, + "--type", + "local", + "--file", + "data/sample_vector_search_deprecated.json", + "-w", + ) + + cmd.Env = os.Environ() + + r, err := e2e.RunAndGetStdOut(cmd) + out := string(r) + require.NoError(t, err, out) + assert.Contains(t, out, "Search index created with ID:") + }) + + var indexID string + + t.Run("Index List", func(t *testing.T) { + cmd := exec.Command(cliPath, + deploymentEntity, + searchEntity, + indexEntity, + "ls", + "--deploymentName", + deploymentName, + "--db", + databaseName, + "--collection", + collectionName, + "--type", + "LOCAL", + "--username", + dbUsername, + "--password", + dbUserPassword, + ) + + cmd.Env = os.Environ() + o, e, err := splitOutput(cmd) + req.NoError(err, e) + assert.Contains(t, o, searchIndexName) + + lines := strings.Split(o, "\n") + cols := strings.Fields(lines[1]) + indexID = cols[0] + }) + + t.Run("Describe search index", func(t *testing.T) { + cmd := exec.Command(cliPath, + deploymentEntity, + searchEntity, + indexEntity, + "describe", + indexID, + "--deploymentName", + deploymentName, + "--type", + "LOCAL", + "--username", + dbUsername, + "--password", + dbUserPassword, + ) + + cmd.Env = os.Environ() + + r, err := e2e.RunAndGetStdOut(cmd) + require.NoError(t, err, string(r)) + }) + + t.Run("Test Search Index", func(t *testing.T) { + client, err := mongo.Connect(ctx, options.Client().ApplyURI(connectionString)) + req.NoError(err) + t.Cleanup(func() { + require.NoError(t, client.Disconnect(ctx)) + }) + c, err := client.Database(databaseName).Collection(collectionName).Aggregate(ctx, bson.A{ + bson.M{ + "$search": bson.M{ + "index": searchIndexName, + "text": bson.M{ + "query": "baseball", + "path": "plot", + }, + }, + }, + bson.M{ + "$limit": 5, + }, + bson.M{ + "$project": bson.M{ + "_id": 0, + "title": 1, + "plot": 1, + }, + }, + }) + require.NoError(t, err) + var results []bson.M + require.NoError(t, c.All(ctx, &results)) + assert.Len(t, results, 5) + }) + + t.Run("Test vectorSearch Index", func(t *testing.T) { + b, err := os.ReadFile("data/sample_vector_search_pipeline.json") + req.NoError(err) + + var pipeline []map[string]any + err = json.Unmarshal(b, &pipeline) + req.NoError(err) + + client, err := mongo.Connect(ctx, options.Client().ApplyURI(connectionString)) + req.NoError(err) + t.Cleanup(func() { + require.NoError(t, client.Disconnect(ctx)) + }) + c, err := client.Database(vectorSearchDB).Collection(vectorSearchCol).Aggregate(ctx, pipeline) + req.NoError(err) + var results []bson.M + req.NoError(c.All(ctx, &results)) + t.Log(results) + req.Len(results, 10) + for _, v := range results { + req.Greater(v["score"], float64(0)) + } + }) + + t.Run("Delete Index", func(t *testing.T) { + cmd := exec.Command(cliPath, + deploymentEntity, + searchEntity, + indexEntity, + "rm", + indexID, + "--deploymentName", + deploymentName, + "--force", + "--type", + "LOCAL", + "--username", + dbUsername, + "--password", + dbUserPassword, + "--debug", + ) + + cmd.Env = os.Environ() + + var o, e bytes.Buffer + cmd.Stdout = &o + cmd.Stderr = &e + require.NoError(t, cmd.Run(), e.String()) + assert.Contains(t, o.String(), fmt.Sprintf("Index '%s' deleted", indexID)) + }) + + t.Run("Pause Deployment", func(t *testing.T) { + cmd := exec.Command(cliPath, + deploymentEntity, + "pause", + deploymentName, + "--type", + "local", + "--debug", + ) + + cmd.Env = os.Environ() + + r, err := cmd.CombinedOutput() + out := string(r) + require.NoError(t, err, out) + assert.Contains(t, out, fmt.Sprintf("Pausing deployment '%s'", deploymentName)) + }) + + t.Run("Start Deployment", func(t *testing.T) { + cmd := exec.Command(cliPath, + deploymentEntity, + "start", + deploymentName, + "--type", + "local", + "--debug", + ) + cmd.Env = os.Environ() + r, err := cmd.CombinedOutput() + out := string(r) + require.NoError(t, err, out) + assert.Contains(t, out, fmt.Sprintf("Starting deployment '%s'", deploymentName)) + }) +} diff --git a/test/e2e/atlas/deployments_local_auth_test.go b/test/e2e/atlas/deployments_local_auth_test.go index 2920dbb78d..c6a2c629f6 100644 --- a/test/e2e/atlas/deployments_local_auth_test.go +++ b/test/e2e/atlas/deployments_local_auth_test.go @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -//go:build e2e || (atlas && deployments && local && auth) +//go:build e2e || (atlas && deployments && local && auth && new) package atlas_test From 16276ff64475a65df453174bd7ee40ee28c777d4 Mon Sep 17 00:00:00 2001 From: Filipe C Menezes Date: Tue, 12 Nov 2024 13:00:48 +0000 Subject: [PATCH 04/10] set db and col names --- internal/mongodbclient/collection.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/internal/mongodbclient/collection.go b/internal/mongodbclient/collection.go index 4efb3b9c92..6bb7dc0c73 100644 --- a/internal/mongodbclient/collection.go +++ b/internal/mongodbclient/collection.go @@ -90,6 +90,13 @@ func (c *collection) SearchIndexByName(ctx context.Context, name string) (*Searc return nil, ErrSearchIndexNotFound } + for _, result := range results { + db := c.collection.Database().Name() + result.Database = &db + coll := c.collection.Name() + result.CollectionName = &coll + } + return results[0], nil } @@ -104,6 +111,13 @@ func (c *collection) SearchIndexes(ctx context.Context) ([]*SearchIndexDefinitio return nil, err } + for _, result := range results { + db := c.collection.Database().Name() + result.Database = &db + coll := c.collection.Name() + result.CollectionName = &coll + } + return results, nil } From 25687f95fa1c1f342dc416fa8556f16b7298d2be Mon Sep 17 00:00:00 2001 From: Filipe C Menezes Date: Tue, 12 Nov 2024 13:37:25 +0000 Subject: [PATCH 05/10] fix --- internal/cli/deployments/search/indexes/create.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/cli/deployments/search/indexes/create.go b/internal/cli/deployments/search/indexes/create.go index 66763caa63..fcf51eb314 100644 --- a/internal/cli/deployments/search/indexes/create.go +++ b/internal/cli/deployments/search/indexes/create.go @@ -115,6 +115,7 @@ func (opts *CreateOpts) RunLocal(ctx context.Context) error { definition = index.Definition case *admin.ClusterSearchIndex: _, _ = log.Warningln("you're using an old search index definition") + idxType = index.Type opts.indexID.Database = index.Database opts.indexID.Collection = index.CollectionName From 901f819f27ee25643440b6f1004a39edb102a232 Mon Sep 17 00:00:00 2001 From: Filipe C Menezes Date: Tue, 12 Nov 2024 14:06:00 +0000 Subject: [PATCH 06/10] fix --- test/e2e/atlas/search_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/atlas/search_test.go b/test/e2e/atlas/search_test.go index 66d0b3a568..ca6a5dd402 100644 --- a/test/e2e/atlas/search_test.go +++ b/test/e2e/atlas/search_test.go @@ -163,11 +163,11 @@ func TestSearch(t *testing.T) { cmd.Env = os.Environ() resp, err := e2e.RunAndGetStdOut(cmd) require.NoError(t, err, string(resp)) - var index atlasv2.ClusterSearchIndex + var index *atlasv2.SearchIndexResponse require.NoError(t, json.Unmarshal(resp, &index)) a := assert.New(t) a.Equal(indexID, index.GetIndexID()) - a.Equal(analyzer, index.GetAnalyzer()) + a.Equal(analyzer, index.GetLatestDefinition().Analyzer) }) t.Run("Delete", func(t *testing.T) { From 501b73b334d321907ac6211556ecb9cf800a1abb Mon Sep 17 00:00:00 2001 From: Filipe C Menezes Date: Tue, 12 Nov 2024 17:06:09 +0000 Subject: [PATCH 07/10] avoid breaking change --- .../deployments/search/indexes/create_test.go | 10 +++---- internal/cli/search/create_test.go | 4 +-- internal/cli/search/index_opts.go | 28 ++++++++----------- internal/cli/search/update_test.go | 4 +-- 4 files changed, 21 insertions(+), 25 deletions(-) diff --git a/internal/cli/deployments/search/indexes/create_test.go b/internal/cli/deployments/search/indexes/create_test.go index c7e0136116..a7d4b29ca8 100644 --- a/internal/cli/deployments/search/indexes/create_test.go +++ b/internal/cli/deployments/search/indexes/create_test.go @@ -281,10 +281,10 @@ func TestCreate_RunAtlas(t *testing.T) { index, err := opts.CreateSearchIndex() require.NoError(t, err) - indexWithID := &atlasv2.SearchIndexResponse{ - CollectionName: &opts.Collection, - Database: &opts.DBName, - Name: &opts.Name, + indexWithID := &atlasv2.ClusterSearchIndex{ + CollectionName: opts.Collection, + Database: opts.DBName, + Name: opts.Name, IndexID: &indexID, } @@ -292,7 +292,7 @@ func TestCreate_RunAtlas(t *testing.T) { mockIndexStore. EXPECT(). - CreateSearchIndexes(opts.ProjectID, opts.DeploymentName, index). + CreateSearchIndexesDeprecated(opts.ProjectID, opts.DeploymentName, index). Times(1). Return(indexWithID, nil) diff --git a/internal/cli/search/create_test.go b/internal/cli/search/create_test.go index d6bd33139b..32ae58ecc4 100644 --- a/internal/cli/search/create_test.go +++ b/internal/cli/search/create_test.go @@ -45,10 +45,10 @@ func TestCreateOpts_Run(t *testing.T) { if err != nil { t.Fatalf("newSearchIndex() unexpected error: %v", err) } - expected := &atlasv2.SearchIndexResponse{} + expected := &atlasv2.ClusterSearchIndex{} mockStore. EXPECT(). - CreateSearchIndexes(opts.ProjectID, opts.clusterName, request). + CreateSearchIndexesDeprecated(opts.ProjectID, opts.clusterName, request). Return(expected, nil). Times(1) diff --git a/internal/cli/search/index_opts.go b/internal/cli/search/index_opts.go index 41c3c8675f..5a3068ec8e 100644 --- a/internal/cli/search/index_opts.go +++ b/internal/cli/search/index_opts.go @@ -123,18 +123,16 @@ func (opts *IndexOpts) CreateSearchIndex() (any, error) { opts.SearchAnalyzer = DefaultAnalyzer } - i := &atlasv2.SearchIndexCreateRequest{ + i := &atlasv2.ClusterSearchIndex{ CollectionName: opts.Collection, Database: opts.DBName, Name: opts.Name, Type: pointer.Get(SearchIndexType), - Definition: &atlasv2.BaseSearchIndexCreateRequestDefinition{ - Analyzer: &opts.Analyzer, - SearchAnalyzer: &opts.SearchAnalyzer, - Mappings: &atlasv2.SearchMappings{ - Dynamic: &opts.Dynamic, - Fields: f, - }, + Analyzer: &opts.Analyzer, + SearchAnalyzer: &opts.SearchAnalyzer, + Mappings: &atlasv2.ApiAtlasFTSMappings{ + Dynamic: &opts.Dynamic, + Fields: f, }, } return i, nil @@ -178,14 +176,12 @@ func (opts *IndexOpts) UpdateSearchIndex() (any, error) { opts.SearchAnalyzer = DefaultAnalyzer } - i := &atlasv2.SearchIndexUpdateRequest{ - Definition: atlasv2.SearchIndexUpdateRequestDefinition{ - Analyzer: &opts.Analyzer, - SearchAnalyzer: &opts.SearchAnalyzer, - Mappings: &atlasv2.SearchMappings{ - Dynamic: &opts.Dynamic, - Fields: f, - }, + i := &atlasv2.ClusterSearchIndex{ + Analyzer: &opts.Analyzer, + SearchAnalyzer: &opts.SearchAnalyzer, + Mappings: &atlasv2.ApiAtlasFTSMappings{ + Dynamic: &opts.Dynamic, + Fields: f, }, } return i, nil diff --git a/internal/cli/search/update_test.go b/internal/cli/search/update_test.go index 06bd21810d..5d1090bd0f 100644 --- a/internal/cli/search/update_test.go +++ b/internal/cli/search/update_test.go @@ -37,13 +37,13 @@ func TestUpdateOpts_Run(t *testing.T) { updateOpts.Name = testName updateOpts.id = "1" - expected := &atlasv2.SearchIndexResponse{} + expected := &atlasv2.ClusterSearchIndex{} request, err := updateOpts.UpdateSearchIndex() require.NoError(t, err) mockStore. EXPECT(). - UpdateSearchIndexes(updateOpts.ConfigProjectID(), updateOpts.clusterName, updateOpts.id, request). + UpdateSearchIndexesDeprecated(updateOpts.ConfigProjectID(), updateOpts.clusterName, updateOpts.id, request). Return(expected, nil). Times(1) From aabb70bc27667e661e392937e7f5ef7607f471e7 Mon Sep 17 00:00:00 2001 From: Filipe C Menezes Date: Tue, 12 Nov 2024 17:35:51 +0000 Subject: [PATCH 08/10] fix test --- test/e2e/atlas/search_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/e2e/atlas/search_test.go b/test/e2e/atlas/search_test.go index ca6a5dd402..03501a745b 100644 --- a/test/e2e/atlas/search_test.go +++ b/test/e2e/atlas/search_test.go @@ -167,7 +167,8 @@ func TestSearch(t *testing.T) { require.NoError(t, json.Unmarshal(resp, &index)) a := assert.New(t) a.Equal(indexID, index.GetIndexID()) - a.Equal(analyzer, index.GetLatestDefinition().Analyzer) + a.NotNil(index.GetLatestDefinition().Analyzer) + a.Equal(analyzer, *index.GetLatestDefinition().Analyzer) }) t.Run("Delete", func(t *testing.T) { From 60adfc848393b99fca552365981e98324ed90850 Mon Sep 17 00:00:00 2001 From: Filipe C Menezes Date: Tue, 12 Nov 2024 18:03:04 +0000 Subject: [PATCH 09/10] fix --- test/e2e/atlas/deployments_local_auth_index_deprecated_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/atlas/deployments_local_auth_index_deprecated_test.go b/test/e2e/atlas/deployments_local_auth_index_deprecated_test.go index 65362934c7..8832f8716f 100644 --- a/test/e2e/atlas/deployments_local_auth_index_deprecated_test.go +++ b/test/e2e/atlas/deployments_local_auth_index_deprecated_test.go @@ -37,7 +37,7 @@ import ( func TestDeploymentsLocalWithAuthIndexDeprecated(t *testing.T) { const ( - deploymentName = "test-auth" + deploymentName = "test-auth-deprecated" dbUsername = "admin" dbUserPassword = "testpwd" ) From 30bc41788dee7b08e44e1d90d39a496d0ea0c370 Mon Sep 17 00:00:00 2001 From: Filipe C Menezes Date: Wed, 13 Nov 2024 11:35:32 +0000 Subject: [PATCH 10/10] add docker login --- build/ci/evergreen.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/build/ci/evergreen.yml b/build/ci/evergreen.yml index 70961f37c6..dadb19c778 100644 --- a/build/ci/evergreen.yml +++ b/build/ci/evergreen.yml @@ -425,6 +425,12 @@ functions: args: - -f - expansions.yaml + "docker_login": + - command: shell.exec + params: + shell: bash + script: | + echo "${dockerhub_password}" | docker login -u ${dockerhub_username} --password-stdin tasks: - name: compile tags: ["code_health"] @@ -1448,6 +1454,7 @@ tasks: - func: "install gotestsum" - func: "install mongodb database tools" - func: "increase inotify limits" + - func: "docker_login" - func: "e2e test" timeout_secs: 11400 # 3 hours 10 minutes vars: @@ -1467,6 +1474,7 @@ tasks: - func: "install gotestsum" - func: "install mongodb database tools" - func: "increase inotify limits" + - func: "docker_login" - func: "e2e test" timeout_secs: 11400 # 3 hours 10 minutes vars: @@ -1486,6 +1494,7 @@ tasks: - func: "install gotestsum" - func: "install mongodb database tools" - func: "increase inotify limits" + - func: "docker_login" - func: "e2e test" timeout_secs: 11400 # 3 hours 10 minutes vars: @@ -1505,6 +1514,7 @@ tasks: - func: "install gotestsum" - func: "install mongodb database tools" - func: "increase inotify limits" + - func: "docker_login" - func: "e2e test" timeout_secs: 11400 # 3 hours 10 minutes vars: