-
Notifications
You must be signed in to change notification settings - Fork 915
GODRIVER-2859 Add search index management helpers #1311
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
a09e00c
GODRIVER-2859 WIP
qingyang-hu a154b3a
GODRIVER-2859 Add search index management helpers.
qingyang-hu 30a895d
Merge branch 'master' into godriver2859
qingyang-hu a8fa83a
GODRIVER-2875 Add e2e testing.
qingyang-hu 064428a
fix typo
qingyang-hu 4585537
update prose test
qingyang-hu d0895df
Merge branch 'master' into godriver2859
qingyang-hu 73d6633
Update prose tests.
qingyang-hu b0d6b4f
Embed an entire AggregateOptions struct into the ListSearchIndexOptio…
qingyang-hu 9801d49
Merge branch 'master' into godriver2859
qingyang-hu 05250ef
Update prose test.
qingyang-hu ceebe17
Add options.SearchIndexesOptions.
qingyang-hu 0a4389c
update unified test suite.
qingyang-hu 4b7ab37
Merge branch 'master' into godriver2859
qingyang-hu 0c53f6f
Format code
qingyang-hu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,253 @@ | ||
// Copyright (C) MongoDB, Inc. 2023-present. | ||
// | ||
// 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 | ||
|
||
package integration | ||
|
||
import ( | ||
"context" | ||
"os" | ||
"sync" | ||
"testing" | ||
"time" | ||
|
||
"go.mongodb.org/mongo-driver/bson" | ||
"go.mongodb.org/mongo-driver/internal/assert" | ||
"go.mongodb.org/mongo-driver/internal/require" | ||
"go.mongodb.org/mongo-driver/internal/uuid" | ||
"go.mongodb.org/mongo-driver/mongo" | ||
"go.mongodb.org/mongo-driver/mongo/integration/mtest" | ||
"go.mongodb.org/mongo-driver/mongo/options" | ||
) | ||
|
||
func TestSearchIndexProse(t *testing.T) { | ||
t.Parallel() | ||
|
||
const timeout = 5 * time.Minute | ||
|
||
uri := os.Getenv("TEST_INDEX_URI") | ||
if uri == "" { | ||
t.Skip("skipping") | ||
} | ||
|
||
opts := options.Client().ApplyURI(uri).SetTimeout(timeout) | ||
mt := mtest.New(t, mtest.NewOptions().ClientOptions(opts).MinServerVersion("7.0").Topologies(mtest.ReplicaSet)) | ||
|
||
mt.Run("case 1: Driver can successfully create and list search indexes", func(mt *mtest.T) { | ||
ctx := context.Background() | ||
|
||
_, err := mt.Coll.InsertOne(ctx, bson.D{}) | ||
require.NoError(mt, err, "failed to insert") | ||
|
||
view := mt.Coll.SearchIndexes() | ||
|
||
definition := bson.D{{"mappings", bson.D{{"dynamic", false}}}} | ||
searchName := "test-search-index" | ||
opts := options.SearchIndexes().SetName(searchName) | ||
index, err := view.CreateOne(ctx, mongo.SearchIndexModel{ | ||
Definition: definition, | ||
Options: opts, | ||
}) | ||
require.NoError(mt, err, "failed to create index") | ||
require.Equal(mt, searchName, index, "unmatched name") | ||
|
||
var doc bson.Raw | ||
for doc == nil { | ||
cursor, err := view.List(ctx, opts) | ||
require.NoError(mt, err, "failed to list") | ||
|
||
if !cursor.Next(ctx) { | ||
break | ||
} | ||
if cursor.Current.Lookup("queryable").Boolean() { | ||
doc = cursor.Current | ||
} else { | ||
t.Logf("cursor: %s, sleep 5 seconds...", cursor.Current.String()) | ||
time.Sleep(5 * time.Second) | ||
} | ||
} | ||
require.NotNil(mt, doc, "got empty document") | ||
assert.Equal(mt, searchName, doc.Lookup("name").StringValue(), "unmatched name") | ||
expected, err := bson.Marshal(definition) | ||
require.NoError(mt, err, "failed to marshal definition") | ||
actual := doc.Lookup("latestDefinition").Value | ||
assert.Equal(mt, expected, actual, "unmatched definition") | ||
}) | ||
|
||
mt.Run("case 2: Driver can successfully create multiple indexes in batch", func(mt *mtest.T) { | ||
ctx := context.Background() | ||
|
||
_, err := mt.Coll.InsertOne(ctx, bson.D{}) | ||
require.NoError(mt, err, "failed to insert") | ||
|
||
view := mt.Coll.SearchIndexes() | ||
|
||
definition := bson.D{{"mappings", bson.D{{"dynamic", false}}}} | ||
models := []mongo.SearchIndexModel{ | ||
{ | ||
Definition: definition, | ||
Options: options.SearchIndexes().SetName("test-search-index-1"), | ||
}, | ||
{ | ||
Definition: definition, | ||
Options: options.SearchIndexes().SetName("test-search-index-2"), | ||
}, | ||
} | ||
indexes, err := view.CreateMany(ctx, models) | ||
require.NoError(mt, err, "failed to create index") | ||
require.Equal(mt, len(indexes), 2, "expected 2 indexes") | ||
for _, model := range models { | ||
require.Contains(mt, indexes, *model.Options.Name) | ||
} | ||
|
||
getDocument := func(opts *options.SearchIndexesOptions) bson.Raw { | ||
for { | ||
cursor, err := view.List(ctx, opts) | ||
require.NoError(mt, err, "failed to list") | ||
|
||
if !cursor.Next(ctx) { | ||
return nil | ||
} | ||
if cursor.Current.Lookup("queryable").Boolean() { | ||
return cursor.Current | ||
} | ||
t.Logf("cursor: %s, sleep 5 seconds...", cursor.Current.String()) | ||
time.Sleep(5 * time.Second) | ||
} | ||
} | ||
|
||
var wg sync.WaitGroup | ||
wg.Add(len(models)) | ||
for i := range models { | ||
go func(opts *options.SearchIndexesOptions) { | ||
defer wg.Done() | ||
|
||
doc := getDocument(opts) | ||
require.NotNil(mt, doc, "got empty document") | ||
assert.Equal(mt, *opts.Name, doc.Lookup("name").StringValue(), "unmatched name") | ||
expected, err := bson.Marshal(definition) | ||
require.NoError(mt, err, "failed to marshal definition") | ||
actual := doc.Lookup("latestDefinition").Value | ||
assert.Equal(mt, expected, actual, "unmatched definition") | ||
}(models[i].Options) | ||
} | ||
wg.Wait() | ||
}) | ||
|
||
mt.Run("case 3: Driver can successfully drop search indexes", func(mt *mtest.T) { | ||
ctx := context.Background() | ||
|
||
_, err := mt.Coll.InsertOne(ctx, bson.D{}) | ||
require.NoError(mt, err, "failed to insert") | ||
|
||
view := mt.Coll.SearchIndexes() | ||
|
||
definition := bson.D{{"mappings", bson.D{{"dynamic", false}}}} | ||
searchName := "test-search-index" | ||
opts := options.SearchIndexes().SetName(searchName) | ||
index, err := view.CreateOne(ctx, mongo.SearchIndexModel{ | ||
Definition: definition, | ||
Options: opts, | ||
}) | ||
require.NoError(mt, err, "failed to create index") | ||
require.Equal(mt, searchName, index, "unmatched name") | ||
|
||
var doc bson.Raw | ||
for doc == nil { | ||
cursor, err := view.List(ctx, opts) | ||
require.NoError(mt, err, "failed to list") | ||
|
||
if !cursor.Next(ctx) { | ||
break | ||
} | ||
if cursor.Current.Lookup("queryable").Boolean() { | ||
doc = cursor.Current | ||
} else { | ||
t.Logf("cursor: %s, sleep 5 seconds...", cursor.Current.String()) | ||
time.Sleep(5 * time.Second) | ||
} | ||
} | ||
require.NotNil(mt, doc, "got empty document") | ||
require.Equal(mt, searchName, doc.Lookup("name").StringValue(), "unmatched name") | ||
|
||
err = view.DropOne(ctx, searchName) | ||
require.NoError(mt, err, "failed to drop index") | ||
for { | ||
cursor, err := view.List(ctx, opts) | ||
require.NoError(mt, err, "failed to list") | ||
|
||
if !cursor.Next(ctx) { | ||
break | ||
} | ||
t.Logf("cursor: %s, sleep 5 seconds...", cursor.Current.String()) | ||
time.Sleep(5 * time.Second) | ||
} | ||
}) | ||
|
||
mt.Run("case 4: Driver can update a search index", func(mt *mtest.T) { | ||
ctx := context.Background() | ||
|
||
_, err := mt.Coll.InsertOne(ctx, bson.D{}) | ||
require.NoError(mt, err, "failed to insert") | ||
|
||
view := mt.Coll.SearchIndexes() | ||
|
||
definition := bson.D{{"mappings", bson.D{{"dynamic", false}}}} | ||
searchName := "test-search-index" | ||
opts := options.SearchIndexes().SetName(searchName) | ||
index, err := view.CreateOne(ctx, mongo.SearchIndexModel{ | ||
Definition: definition, | ||
Options: opts, | ||
}) | ||
require.NoError(mt, err, "failed to create index") | ||
require.Equal(mt, searchName, index, "unmatched name") | ||
|
||
getDocument := func() bson.Raw { | ||
for { | ||
cursor, err := view.List(ctx, opts) | ||
require.NoError(mt, err, "failed to list") | ||
|
||
if !cursor.Next(ctx) { | ||
return nil | ||
} | ||
if cursor.Current.Lookup("queryable").Boolean() { | ||
return cursor.Current | ||
} | ||
t.Logf("cursor: %s, sleep 5 seconds...", cursor.Current.String()) | ||
time.Sleep(5 * time.Second) | ||
} | ||
} | ||
|
||
doc := getDocument() | ||
require.NotNil(mt, doc, "got empty document") | ||
require.Equal(mt, searchName, doc.Lookup("name").StringValue(), "unmatched name") | ||
|
||
definition = bson.D{{"mappings", bson.D{{"dynamic", true}}}} | ||
err = view.UpdateOne(ctx, searchName, definition) | ||
require.NoError(mt, err, "failed to drop index") | ||
doc = getDocument() | ||
require.NotNil(mt, doc, "got empty document") | ||
assert.Equal(mt, searchName, doc.Lookup("name").StringValue(), "unmatched name") | ||
assert.Equal(mt, "READY", doc.Lookup("status").StringValue(), "unexpected status") | ||
expected, err := bson.Marshal(definition) | ||
require.NoError(mt, err, "failed to marshal definition") | ||
actual := doc.Lookup("latestDefinition").Value | ||
assert.Equal(mt, expected, actual, "unmatched definition") | ||
}) | ||
|
||
mt.Run("case 5: dropSearchIndex suppresses namespace not found errors", func(mt *mtest.T) { | ||
ctx := context.Background() | ||
|
||
id, err := uuid.New() | ||
require.NoError(mt, err) | ||
|
||
collection := mt.CreateCollection(mtest.Collection{ | ||
Name: id.String(), | ||
}, false) | ||
|
||
err = collection.SearchIndexes().DropOne(ctx, "foo") | ||
require.NoError(mt, err) | ||
}) | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.