mirror of
https://github.com/hanzoai/docdb.git
synced 2026-10-30 18:39:39 +00:00
zip's registration is a verb method on the group, so an operation reads as the group answering it rather than a function taking the group, and a route that is not a typed operation says which method it answers with. The package-level form and the Router interface it existed to accept any target through are both gone. The toolchain and the pin move together, deliberately. Below zip v1.36.50 the JSON encoder was selected on a build tag, so a repo whose go directive rises first writes a wire that is neither the old release's nor the new one's until the pin catches up. Co-authored-by: Hanzo Dev <[email protected]>
1043 lines
38 KiB
Go
1043 lines
38 KiB
Go
// Copyright 2021 DocDB 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 integration
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/AlekSi/pointer"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
"go.mongodb.org/mongo-driver/mongo"
|
|
"go.mongodb.org/mongo-driver/mongo/options"
|
|
|
|
"github.com/hanzoai/docdb/integration/setup"
|
|
"github.com/hanzoai/docdb/integration/shareddata"
|
|
)
|
|
|
|
// updateCompatTestCase describes update compatibility test case.
|
|
type updateCompatTestCase struct {
|
|
update bson.D // required if replace is nil
|
|
replace bson.D // required if update is nil
|
|
filter bson.D // defaults to bson.D{{"_id", id}}
|
|
updateOpts *options.UpdateOptions // defaults to nil
|
|
replaceOpts *options.ReplaceOptions // defaults to nil
|
|
resultType CompatTestCaseResultType // defaults to NonEmptyResult
|
|
providers []shareddata.Provider // defaults to shareddata.AllProviders()
|
|
|
|
skip string // TODO https://github.com/hanzoai/docdb-DocumentDB/issues/1086
|
|
failsForDocDB string
|
|
failsIDs []struct {
|
|
provider shareddata.Provider
|
|
ids []string // defaults to all IDs of the provider
|
|
} // defaults to all providers
|
|
}
|
|
|
|
// testUpdateCompat tests update compatibility test cases.
|
|
func testUpdateCompat(t *testing.T, testCases map[string]updateCompatTestCase) {
|
|
t.Helper()
|
|
|
|
for name, tc := range testCases {
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Helper()
|
|
|
|
if tc.skip != "" {
|
|
t.Skip(tc.skip)
|
|
}
|
|
|
|
t.Parallel()
|
|
|
|
providers := shareddata.AllProviders()
|
|
if tc.providers != nil {
|
|
providers = tc.providers
|
|
}
|
|
|
|
s := setup.SetupCompatWithOpts(t, &setup.SetupCompatOpts{
|
|
Providers: providers,
|
|
AddNonExistentCollection: true,
|
|
})
|
|
ctx, targetCollections, compatCollections := s.Ctx, s.TargetCollections, s.CompatCollections
|
|
|
|
update, replace := tc.update, tc.replace
|
|
if update != nil {
|
|
require.Nil(t, replace, "`replace` must be nil if `update` is set")
|
|
} else {
|
|
require.NotNil(t, replace, "`replace` must be set if `update` is nil")
|
|
}
|
|
|
|
failsProviders := make(map[string][]string)
|
|
for _, p := range tc.failsIDs {
|
|
failsProviders[p.provider.Name()] = p.ids
|
|
}
|
|
|
|
allProvidersFail := len(failsProviders) == 0
|
|
|
|
var nonEmptyResults bool
|
|
for i := range targetCollections {
|
|
targetCollection := targetCollections[i]
|
|
compatCollection := compatCollections[i]
|
|
|
|
// a workaround to get provider name by using the part after last `_`,
|
|
// e.g. `Binaries` from `TestUpdateFieldCompatBit-Bool_Binaries`
|
|
str := strings.Split(targetCollection.Name(), "_")
|
|
providerName := str[len(str)-1]
|
|
|
|
failsIDs, providerFails := failsProviders[providerName]
|
|
allIDsFail := providerFails && len(failsIDs) == 0
|
|
|
|
t.Run(targetCollection.Name(), func(t *testing.T) {
|
|
t.Helper()
|
|
|
|
allDocs := FindAll(t, ctx, targetCollection)
|
|
|
|
for _, doc := range allDocs {
|
|
id := GetKey(t, doc, "_id")
|
|
|
|
t.Run(fmt.Sprint(id), func(tt *testing.T) {
|
|
tt.Helper()
|
|
|
|
idFails := slices.Contains(failsIDs, fmt.Sprint(id))
|
|
|
|
var t testing.TB = tt
|
|
|
|
if tc.failsForDocDB != "" && (allProvidersFail || allIDsFail || idFails) {
|
|
t = setup.FailsForDocDB(tt, tc.failsForDocDB)
|
|
}
|
|
|
|
filter := tc.filter
|
|
if tc.filter == nil {
|
|
filter = bson.D{{"_id", id}}
|
|
}
|
|
|
|
var targetUpdateRes, compatUpdateRes *mongo.UpdateResult
|
|
var targetErr, compatErr error
|
|
|
|
// Replace with UpdateMany/ReplaceMany.
|
|
// TODO https://github.com/hanzoai/docdb/issues/1507
|
|
if update != nil {
|
|
targetUpdateRes, targetErr = targetCollection.UpdateOne(ctx, filter, update, tc.updateOpts)
|
|
compatUpdateRes, compatErr = compatCollection.UpdateOne(ctx, filter, update, tc.updateOpts)
|
|
} else {
|
|
targetUpdateRes, targetErr = targetCollection.ReplaceOne(ctx, filter, replace, tc.replaceOpts)
|
|
compatUpdateRes, compatErr = compatCollection.ReplaceOne(ctx, filter, replace, tc.replaceOpts)
|
|
}
|
|
|
|
if targetErr != nil {
|
|
t.Logf("Target error: %v", targetErr)
|
|
|
|
if targetErr.Error() == "update document must have at least one element" {
|
|
// mongo go driver sent error that the update document is empty.
|
|
require.Equal(t, compatErr, targetErr)
|
|
|
|
return
|
|
}
|
|
|
|
// AssertMatchesWriteError compares error types and codes, it does not compare messages.
|
|
AssertMatchesWriteError(t, compatErr, targetErr)
|
|
} else {
|
|
require.NoError(t, compatErr, "compat error; target returned no error")
|
|
}
|
|
|
|
assert.Equal(t, compatUpdateRes, targetUpdateRes)
|
|
|
|
if pointer.Get(targetUpdateRes).ModifiedCount > 0 || pointer.Get(targetUpdateRes).UpsertedCount > 0 {
|
|
nonEmptyResults = true
|
|
}
|
|
|
|
var targetFindRes, compatFindRes bson.D
|
|
require.NoError(t, targetCollection.FindOne(ctx, bson.D{{"_id", id}}).Decode(&targetFindRes))
|
|
require.NoError(t, compatCollection.FindOne(ctx, bson.D{{"_id", id}}).Decode(&compatFindRes))
|
|
AssertEqualDocuments(t, compatFindRes, targetFindRes)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
switch tc.resultType {
|
|
case NonEmptyResult:
|
|
if tc.failsForDocDB != "" {
|
|
return
|
|
}
|
|
|
|
assert.True(t, nonEmptyResults, "expected non-empty results (some documents should be modified)")
|
|
case EmptyResult:
|
|
if tc.failsForDocDB != "" {
|
|
return
|
|
}
|
|
|
|
assert.False(t, nonEmptyResults, "expected empty results (no documents should be modified)")
|
|
default:
|
|
t.Fatalf("unknown result type %v", tc.resultType)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// testUpdateManyCompatTestCase describes update compatibility test case.
|
|
type testUpdateManyCompatTestCase struct { //nolint:vet // used for testing only
|
|
update bson.D // required if replace is nil
|
|
filter bson.D // defaults to bson.D{}
|
|
updateOpts *options.UpdateOptions // defaults to nil
|
|
resultType CompatTestCaseResultType // defaults to NonEmptyResult
|
|
providers []shareddata.Provider // defaults to shareddata.AllProviders()
|
|
|
|
skip string // TODO https://github.com/hanzoai/docdb-DocumentDB/issues/1086
|
|
}
|
|
|
|
// testUpdateManyCompat tests update compatibility test cases.
|
|
func testUpdateManyCompat(t *testing.T, testCases map[string]testUpdateManyCompatTestCase) {
|
|
t.Helper()
|
|
|
|
for name, tc := range testCases {
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Helper()
|
|
|
|
if tc.skip != "" {
|
|
t.Skip(tc.skip)
|
|
}
|
|
|
|
t.Parallel()
|
|
|
|
setupOpts := &setup.SetupCompatOpts{
|
|
Providers: tc.providers,
|
|
}
|
|
|
|
if tc.providers == nil {
|
|
setupOpts.Providers = shareddata.AllProviders()
|
|
setupOpts.AddNonExistentCollection = true
|
|
}
|
|
|
|
s := setup.SetupCompatWithOpts(t, setupOpts)
|
|
|
|
ctx, targetCollections, compatCollections := s.Ctx, s.TargetCollections, s.CompatCollections
|
|
|
|
update := tc.update
|
|
require.NotNil(t, update, "`update` must be set")
|
|
|
|
filter := tc.filter
|
|
if filter == nil {
|
|
filter = bson.D{}
|
|
}
|
|
|
|
var nonEmptyResults bool
|
|
for i := range targetCollections {
|
|
targetCollection := targetCollections[i]
|
|
compatCollection := compatCollections[i]
|
|
t.Run(targetCollection.Name(), func(t *testing.T) {
|
|
t.Helper()
|
|
|
|
var targetUpdateRes, compatUpdateRes *mongo.UpdateResult
|
|
var targetErr, compatErr error
|
|
|
|
targetUpdateRes, targetErr = targetCollection.UpdateMany(ctx, filter, update, tc.updateOpts)
|
|
compatUpdateRes, compatErr = compatCollection.UpdateMany(ctx, filter, update, tc.updateOpts)
|
|
|
|
if targetErr != nil {
|
|
t.Logf("Target error: %v", targetErr)
|
|
t.Logf("Compat error: %v", compatErr)
|
|
|
|
// error messages are intentionally not compared
|
|
AssertMatchesWriteError(t, compatErr, targetErr)
|
|
|
|
return
|
|
}
|
|
require.NoError(t, compatErr, "compat error; target returned no error")
|
|
|
|
assert.Equal(t, compatUpdateRes, targetUpdateRes)
|
|
|
|
if pointer.Get(targetUpdateRes).ModifiedCount > 0 || pointer.Get(targetUpdateRes).UpsertedCount > 0 {
|
|
nonEmptyResults = true
|
|
}
|
|
|
|
opts := options.Find().SetSort(bson.D{{"_id", 1}})
|
|
targetCursor, targetErr := targetCollection.Find(ctx, bson.D{}, opts)
|
|
compatCursor, compatErr := compatCollection.Find(ctx, bson.D{}, opts)
|
|
|
|
if targetCursor != nil {
|
|
defer targetCursor.Close(ctx)
|
|
}
|
|
if compatCursor != nil {
|
|
defer compatCursor.Close(ctx)
|
|
}
|
|
|
|
require.NoError(t, targetErr)
|
|
require.NoError(t, compatErr)
|
|
|
|
targetRes := FetchAll(t, ctx, targetCursor)
|
|
compatRes := FetchAll(t, ctx, compatCursor)
|
|
|
|
AssertEqualDocumentsSlice(t, compatRes, targetRes)
|
|
})
|
|
}
|
|
|
|
switch tc.resultType {
|
|
case NonEmptyResult:
|
|
assert.True(t, nonEmptyResults, "expected non-empty results (some documents should be modified)")
|
|
case EmptyResult:
|
|
assert.False(t, nonEmptyResults, "expected empty results (no documents should be modified)")
|
|
default:
|
|
t.Fatalf("unknown result type %v", tc.resultType)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// updateCommandCompatTestCase describes update command compatibility test case.
|
|
type updateCommandCompatTestCase struct {
|
|
multi any // defaults to false, if true updates multiple documents
|
|
upsert bool // defaults to false
|
|
update bson.D // required
|
|
filter bson.D // defaults to bson.D{{"_id", id}}
|
|
resultType CompatTestCaseResultType // defaults to NonEmptyResult
|
|
|
|
failsForDocDB string
|
|
failsIDs []struct {
|
|
provider shareddata.Provider
|
|
ids []string // defaults to all IDs of the provider
|
|
} // defaults to all providers
|
|
}
|
|
|
|
// testUpdateCommandCompat tests command compatibility test cases used for update.
|
|
// This is used for updating multiple documents and testing multi flag values.
|
|
func testUpdateCommandCompat(tt *testing.T, testCases map[string]updateCommandCompatTestCase) {
|
|
tt.Helper()
|
|
|
|
for name, tc := range testCases {
|
|
tt.Run(name, func(tt *testing.T) {
|
|
tt.Helper()
|
|
|
|
tt.Parallel()
|
|
|
|
// Use per-test setup because updates modify data set.
|
|
ctx, targetCollections, compatCollections := setup.SetupCompat(tt)
|
|
|
|
update := tc.update
|
|
require.NotNil(tt, update, "`update` must be set")
|
|
|
|
multi := tc.multi
|
|
if multi == nil {
|
|
multi = false
|
|
}
|
|
|
|
failsProviders := make(map[string][]string)
|
|
for _, p := range tc.failsIDs {
|
|
failsProviders[p.provider.Name()] = p.ids
|
|
}
|
|
|
|
allProvidersFail := len(failsProviders) == 0
|
|
|
|
var nonEmptyResults bool
|
|
for i := range targetCollections {
|
|
targetCollection := targetCollections[i]
|
|
compatCollection := compatCollections[i]
|
|
|
|
// a workaround to get provider name by using the part after last `_`,
|
|
// e.g. `Binaries` from `TestUpdateFieldCompatBit-Bool_Binaries`
|
|
str := strings.Split(targetCollection.Name(), "_")
|
|
providerName := str[len(str)-1]
|
|
|
|
failsIDs, providerFails := failsProviders[providerName]
|
|
allIDsFail := providerFails && len(failsIDs) == 0
|
|
|
|
tt.Run(targetCollection.Name(), func(tt *testing.T) {
|
|
tt.Helper()
|
|
|
|
allDocs := FindAll(tt, ctx, targetCollection)
|
|
|
|
for _, doc := range allDocs {
|
|
id, ok := doc.Map()["_id"]
|
|
require.True(tt, ok)
|
|
|
|
tt.Run(fmt.Sprint(id), func(tt *testing.T) {
|
|
idFails := slices.Contains(failsIDs, fmt.Sprint(id))
|
|
|
|
var t testing.TB = tt
|
|
|
|
if tc.failsForDocDB != "" && (allProvidersFail || allIDsFail || idFails) {
|
|
t = setup.FailsForDocDB(tt, tc.failsForDocDB)
|
|
}
|
|
|
|
t.Helper()
|
|
|
|
filter := tc.filter
|
|
if tc.filter == nil {
|
|
filter = bson.D{{"_id", id}}
|
|
}
|
|
|
|
targetCommand := bson.D{
|
|
{"update", targetCollection.Name()},
|
|
{"updates", bson.A{bson.D{
|
|
{"q", filter},
|
|
{"u", update},
|
|
{"multi", multi},
|
|
{"upsert", tc.upsert},
|
|
}}},
|
|
}
|
|
|
|
compatCommand := bson.D{
|
|
{"update", compatCollection.Name()},
|
|
{"updates", bson.A{bson.D{
|
|
{"q", filter},
|
|
{"u", update},
|
|
{"multi", multi},
|
|
{"upsert", tc.upsert},
|
|
}}},
|
|
}
|
|
|
|
var targetUpdateRes, compatUpdateRes bson.D
|
|
var targetErr, compatErr error
|
|
|
|
targetErr = targetCollection.Database().RunCommand(ctx, targetCommand).Decode(&targetUpdateRes)
|
|
compatErr = compatCollection.Database().RunCommand(ctx, compatCommand).Decode(&compatUpdateRes)
|
|
|
|
if targetErr != nil {
|
|
t.Logf("Target error: %v", targetErr)
|
|
t.Logf("Compat error: %v", compatErr)
|
|
|
|
// compare error type and error code
|
|
AssertMatchesError(t, compatErr, targetErr)
|
|
} else {
|
|
require.NoError(t, compatErr, "compat error; target returned no error")
|
|
}
|
|
|
|
if targetUpdateRes != nil || compatUpdateRes != nil {
|
|
nonEmptyResults = true
|
|
}
|
|
|
|
AssertEqualDocuments(t, compatUpdateRes, targetUpdateRes)
|
|
|
|
if isMulti, ok := multi.(bool); ok && isMulti {
|
|
// if multi == false, an item updated by compat and target are different.
|
|
|
|
opts := options.Find().SetSort(bson.D{{"_id", 1}})
|
|
targetCursor, targetErr := targetCollection.Find(ctx, filter, opts)
|
|
compatCursor, compatErr := compatCollection.Find(ctx, filter, opts)
|
|
|
|
if targetCursor != nil {
|
|
defer targetCursor.Close(ctx)
|
|
}
|
|
if compatCursor != nil {
|
|
defer compatCursor.Close(ctx)
|
|
}
|
|
|
|
if targetErr != nil {
|
|
t.Logf("Target error: %v", targetErr)
|
|
t.Logf("Compat error: %v", compatErr)
|
|
|
|
// error messages are intentionally not compared
|
|
AssertMatchesCommandError(t, compatErr, targetErr)
|
|
|
|
return
|
|
}
|
|
require.NoError(t, compatErr, "compat error; target returned no error")
|
|
|
|
targetRes := FetchAll(t, ctx, targetCursor)
|
|
compatRes := FetchAll(t, ctx, compatCursor)
|
|
|
|
t.Logf("Compat (expected) IDs: %v", CollectIDs(t, compatRes))
|
|
t.Logf("Target (actual) IDs: %v", CollectIDs(t, targetRes))
|
|
AssertEqualDocumentsSlice(t, compatRes, targetRes)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
switch tc.resultType {
|
|
case NonEmptyResult:
|
|
if tc.failsForDocDB != "" {
|
|
return
|
|
}
|
|
|
|
assert.True(tt, nonEmptyResults, "expected non-empty results (some documents should be modified)")
|
|
case EmptyResult:
|
|
assert.False(tt, nonEmptyResults, "expected empty results (no documents should be modified)")
|
|
default:
|
|
tt.Fatalf("unknown result type %v", tc.resultType)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// updateCurrentDateCompatTestCase describes update current date compatibility test case.
|
|
type updateCurrentDateCompatTestCase struct {
|
|
keys []string // keys to check after the update that we expect being updated by the operation
|
|
update bson.D // required
|
|
filter bson.D // defaults to bson.D{{"_id", id}}
|
|
resultType CompatTestCaseResultType // defaults to NonEmptyResult
|
|
|
|
failsForDocDB string
|
|
failsProvidersDocs []struct {
|
|
provider shareddata.Provider
|
|
ids []string
|
|
} // use only if failsForDocDB is set, defaults to all providers and all documents
|
|
}
|
|
|
|
// testUpdateCurrentDateCompat tests update compatibility test cases for current date.
|
|
// It checks current date in compat and target are within acceptable difference.
|
|
func testUpdateCurrentDateCompat(tt *testing.T, testCases map[string]updateCurrentDateCompatTestCase) {
|
|
tt.Helper()
|
|
|
|
maxDifference := 2 * time.Minute
|
|
|
|
for name, tc := range testCases {
|
|
tt.Run(name, func(tt *testing.T) {
|
|
tt.Helper()
|
|
|
|
tt.Parallel()
|
|
|
|
// Use per-test setup because updates modify data set.
|
|
ctx, targetCollections, compatCollections := setup.SetupCompat(tt)
|
|
|
|
update := tc.update
|
|
require.NotNil(tt, update, "`update` must be set")
|
|
|
|
keys := tc.keys
|
|
|
|
failsProviders := make(map[string][]string)
|
|
for _, p := range tc.failsProvidersDocs {
|
|
failsProviders[p.provider.Name()] = p.ids
|
|
}
|
|
|
|
var nonEmptyResults bool
|
|
for i := range targetCollections {
|
|
targetCollection := targetCollections[i]
|
|
compatCollection := compatCollections[i]
|
|
|
|
tt.Run(targetCollection.Name(), func(tt *testing.T) {
|
|
tt.Helper()
|
|
|
|
allDocs := FindAll(tt, ctx, targetCollection)
|
|
|
|
for _, doc := range allDocs {
|
|
id, ok := doc.Map()["_id"]
|
|
require.True(tt, ok)
|
|
|
|
idstr := fmt.Sprint(id)
|
|
|
|
tt.Run(idstr, func(tt *testing.T) {
|
|
// a workaround to get provider name by using the part after last `_`,
|
|
// e.g. `Doubles` from `TestQueryArrayCompatElemMatch_Doubles`
|
|
str := strings.Split(targetCollection.Name(), "_")
|
|
providerName := str[len(str)-1]
|
|
|
|
failsForDoc := len(tc.failsProvidersDocs) == 0 || slices.Contains(failsProviders[providerName], idstr)
|
|
|
|
var t testing.TB = tt
|
|
|
|
if tc.failsForDocDB != "" && failsForDoc {
|
|
t = setup.FailsForDocDB(tt, tc.failsForDocDB)
|
|
}
|
|
|
|
t.Helper()
|
|
|
|
filter := tc.filter
|
|
if tc.filter == nil {
|
|
filter = bson.D{{"_id", id}}
|
|
}
|
|
|
|
var targetUpdateRes, compatUpdateRes *mongo.UpdateResult
|
|
var targetErr, compatErr error
|
|
|
|
targetUpdateRes, targetErr = targetCollection.UpdateOne(ctx, filter, update)
|
|
compatUpdateRes, compatErr = compatCollection.UpdateOne(ctx, filter, update)
|
|
|
|
if targetErr != nil {
|
|
t.Logf("Target error: %v", targetErr)
|
|
// AssertMatchesWriteError compares error types and codes, it does not compare messages.
|
|
AssertMatchesWriteError(t, compatErr, targetErr)
|
|
} else {
|
|
require.NoError(t, compatErr, "compat error; target returned no error")
|
|
}
|
|
|
|
if pointer.Get(targetUpdateRes).ModifiedCount > 0 || pointer.Get(compatUpdateRes).ModifiedCount > 0 {
|
|
nonEmptyResults = true
|
|
}
|
|
|
|
assert.Equal(t, compatUpdateRes, targetUpdateRes)
|
|
|
|
var targetFindRes, compatFindRes bson.D
|
|
require.NoError(t, targetCollection.FindOne(ctx, bson.D{{"_id", id}}).Decode(&targetFindRes))
|
|
require.NoError(t, compatCollection.FindOne(ctx, bson.D{{"_id", id}}).Decode(&compatFindRes))
|
|
|
|
for _, k := range keys {
|
|
var expectedV, actualV any
|
|
|
|
for _, el := range compatFindRes {
|
|
if el.Key == k {
|
|
expectedV = el.Value
|
|
}
|
|
}
|
|
|
|
for i, el := range targetFindRes {
|
|
if el.Key == k {
|
|
actualV = el.Value
|
|
|
|
el.Value = expectedV
|
|
targetFindRes[i] = el
|
|
}
|
|
}
|
|
|
|
require.NotNil(t, expectedV)
|
|
require.NotNil(t, actualV)
|
|
require.IsType(t, expectedV, actualV)
|
|
|
|
switch actualV := actualV.(type) {
|
|
case primitive.DateTime:
|
|
assert.WithinDuration(t, expectedV.(primitive.DateTime).Time(), actualV.Time(), maxDifference)
|
|
|
|
case primitive.Timestamp:
|
|
expectedT := expectedV.(primitive.Timestamp)
|
|
assert.WithinDuration(t, time.Unix(int64(expectedT.T), 0), time.Unix(int64(actualV.T), 0), maxDifference)
|
|
|
|
default:
|
|
assert.Fail(t, fmt.Sprintf("expected primitive.DateTime or primitive.Timestamp, got %T %T", expectedV, actualV))
|
|
}
|
|
}
|
|
|
|
AssertEqualDocuments(t, compatFindRes, targetFindRes)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
switch tc.resultType {
|
|
case NonEmptyResult:
|
|
if tc.failsForDocDB != "" {
|
|
return
|
|
}
|
|
|
|
assert.True(tt, nonEmptyResults, "expected non-empty results (some documents should be modified)")
|
|
case EmptyResult:
|
|
assert.False(tt, nonEmptyResults, "expected empty results (no documents should be modified)")
|
|
default:
|
|
tt.Fatalf("unknown result type %v", tc.resultType)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUpdateCommandCompat(t *testing.T) {
|
|
_, collection := setup.Setup(t)
|
|
nonExistentDB := collection.Database().Client().Database("non-existent")
|
|
|
|
for name, tc := range map[string]struct {
|
|
db *mongo.Database // defaults to targetCollection.Database() and compatCollection.Database()
|
|
cName string
|
|
}{
|
|
"NonExistentDB": {
|
|
db: nonExistentDB,
|
|
cName: "nonExistentCollection",
|
|
},
|
|
"NonExistentCollection": {
|
|
cName: "nonExistentCollection",
|
|
},
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Helper()
|
|
|
|
t.Parallel()
|
|
|
|
s := setup.SetupCompatWithOpts(t, &setup.SetupCompatOpts{
|
|
Providers: []shareddata.Provider{shareddata.Composites},
|
|
AddNonExistentCollection: true,
|
|
})
|
|
ctx, targetCollection, compatCollection := s.Ctx, s.TargetCollections[0], s.CompatCollections[0]
|
|
|
|
targetDB := targetCollection.Database()
|
|
compatDB := compatCollection.Database()
|
|
if tc.db != nil {
|
|
targetDB = tc.db
|
|
compatDB = tc.db
|
|
}
|
|
|
|
q := bson.D{{"_id", "array"}}
|
|
command := bson.D{
|
|
{"update", tc.cName},
|
|
{"updates", bson.A{bson.D{
|
|
{"q", q},
|
|
{"u", bson.D{{"$set", bson.D{{"v", float64(1)}}}}},
|
|
}}},
|
|
}
|
|
|
|
var targetRes, compatRes bson.D
|
|
err := targetDB.RunCommand(ctx, command).Decode(&targetRes)
|
|
require.NoError(t, err)
|
|
|
|
err = compatDB.RunCommand(ctx, command).Decode(&compatRes)
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, targetCollection.FindOne(ctx, q).Decode(&targetRes))
|
|
require.NoError(t, compatCollection.FindOne(ctx, q).Decode(&compatRes))
|
|
|
|
assert.Equal(t, compatRes, targetRes)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUpdateCompat(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
testCases := map[string]updateCompatTestCase{
|
|
"UpdateEmptyDocument": {
|
|
update: bson.D{},
|
|
resultType: EmptyResult,
|
|
},
|
|
"ReplaceSimple": {
|
|
replace: bson.D{{"v", "foo"}},
|
|
failsForDocDB: "https://github.com/hanzoai/docdb-DocumentDB/issues/489",
|
|
failsIDs: []struct {
|
|
provider shareddata.Provider
|
|
ids []string
|
|
}{
|
|
{provider: shareddata.Strings, ids: []string{"string", "string-duplicate"}},
|
|
{provider: shareddata.Scalars, ids: []string{"string"}},
|
|
},
|
|
},
|
|
"ReplaceEmpty": {
|
|
replace: bson.D{{"v", ""}},
|
|
failsForDocDB: "https://github.com/hanzoai/docdb-DocumentDB/issues/489",
|
|
failsIDs: []struct {
|
|
provider shareddata.Provider
|
|
ids []string
|
|
}{
|
|
{provider: shareddata.Strings, ids: []string{"string-empty"}},
|
|
{provider: shareddata.Scalars, ids: []string{"string-empty"}},
|
|
},
|
|
},
|
|
"ReplaceNull": {
|
|
replace: bson.D{{"v", nil}},
|
|
failsForDocDB: "https://github.com/hanzoai/docdb-DocumentDB/issues/489",
|
|
failsIDs: []struct {
|
|
provider shareddata.Provider
|
|
ids []string
|
|
}{
|
|
{provider: shareddata.Strings, ids: []string{"string-null"}},
|
|
{provider: shareddata.Scalars, ids: []string{"null", "string-null"}},
|
|
{provider: shareddata.Nulls, ids: []string{"null"}},
|
|
{provider: shareddata.Bools, ids: []string{"bool-null"}},
|
|
{provider: shareddata.Mixed, ids: []string{"null"}},
|
|
{provider: shareddata.Timestamps, ids: []string{"timestamp-null"}},
|
|
{provider: shareddata.DateTimes, ids: []string{"datetime-null"}},
|
|
{provider: shareddata.DocumentsDoubles, ids: []string{"document-double-null"}},
|
|
{provider: shareddata.Regexes, ids: []string{"regex-null"}},
|
|
{provider: shareddata.Binaries, ids: []string{"binary-null"}},
|
|
{provider: shareddata.DocumentsStrings, ids: []string{"document-string-nil"}},
|
|
{provider: shareddata.Doubles, ids: []string{"double-null"}},
|
|
{provider: shareddata.ObjectIDs, ids: []string{"objectid-null"}},
|
|
},
|
|
},
|
|
"ReplaceEmptyDocument": {
|
|
replace: bson.D{},
|
|
},
|
|
"ReplaceNonExistentUpsert": {
|
|
filter: bson.D{{"non-existent", "no-match"}},
|
|
replace: bson.D{{"_id", "new"}},
|
|
replaceOpts: options.Replace().SetUpsert(true),
|
|
failsIDs: []struct {
|
|
provider shareddata.Provider
|
|
ids []string
|
|
}{
|
|
{provider: shareddata.Scalars, ids: []string{
|
|
"decimal128", "decimal128-int", "decimal128-int-zero", "decimal128-zero", "decimal128-double", "decimal128-whole",
|
|
"unset", "binary-empty", "bool-false", "bool-true", "datetime", "datetime-epoch", "datetime-year-max", "datetime-year-min", "double",
|
|
"double-1", "double-2", "double-3", "double-4", "double-5", "double-big", "double-max", "double-max-overflow", "double-min-overflow",
|
|
"double-smallest", "double-whole", "double-zero", "int32", "int32-1", "int32-2", "int32-3", "int32-max", "int32-min", "int32-zero",
|
|
"int64", "int64-1", "int64-2", "int64-3", "int64-big", "int64-double-big", "int64-max", "int64-min", "int64-zero", "null", "objectid",
|
|
"objectid-empty", "regex", "regex-empty", "string", "string-double", "string-empty", "string-whole", "timestamp", "timestamp-i",
|
|
}},
|
|
{provider: shareddata.Doubles, ids: []string{
|
|
"double-whole", "double-zero", "double-smallest", "double-big", "double-big-plus", "double-big-minus", "double-prec-max",
|
|
"double-prec-max-plus", "double-prec-max-plus-two", "double-prec-max-minus", "double-neg-big", "double-neg-big-plus",
|
|
"double-neg-big-minus", "double-prec-min", "double-prec-min-plus", "double-prec-min-minus", "double-prec-min-minus-two",
|
|
"double-null", "double-1", "double-2", "double-3", "double-4", "double-max-overflow", "double-min-overflow",
|
|
}},
|
|
{provider: shareddata.Decimal128s, ids: []string{
|
|
"decimal128-int", "decimal128-int-zero", "decimal128-max-exp", "decimal128-max-exp-sig",
|
|
"decimal128-max-sig", "decimal128-min-exp", "decimal128-min-exp-sig", "decimal128-whole", "decimal128-zero",
|
|
}},
|
|
{provider: shareddata.OverflowVergeDoubles, ids: []string{"double-max"}},
|
|
{provider: shareddata.SmallDoubles, ids: []string{"double-whole", "double-1", "double-2", "double-3"}},
|
|
{provider: shareddata.Strings, ids: []string{"string-double", "string-whole", "string-empty", "string-duplicate", "string-null"}},
|
|
{provider: shareddata.Binaries, ids: []string{"binary-empty", "binary-null"}},
|
|
{provider: shareddata.Bools, ids: []string{"bool-true", "bool-null"}},
|
|
{provider: shareddata.DateTimes, ids: []string{"datetime-epoch", "datetime-year-min", "datetime-year-max", "datetime-null"}},
|
|
{provider: shareddata.Regexes, ids: []string{"regex-empty", "regex-null"}},
|
|
{provider: shareddata.Int32s, ids: []string{"int32-zero", "int32-max", "int32-min", "int32-1", "int32-2", "int32-3"}},
|
|
{provider: shareddata.Timestamps, ids: []string{"timestamp-i", "timestamp-null"}},
|
|
{provider: shareddata.Int64s, ids: []string{
|
|
"int64-zero", "int64-max", "int64-min", "int64-1", "int64-2", "int64-3", "int64-big", "int64-big-plus", "int64-big-minus",
|
|
"int64-prec-max", "int64-prec-max-plus", "int64-prec-max-plus-two", "int64-prec-max-minus", "int64-neg-big", "int64-neg-big-plus",
|
|
"int64-neg-big-minus", "int64-prec-min", "int64-prec-min-plus", "int64-prec-min-minus", "int64-prec-min-minus-two",
|
|
}},
|
|
{provider: shareddata.ObjectIDs, ids: []string{"objectid-empty", "objectid-null"}},
|
|
{provider: shareddata.ObjectIDKeys, ids: []string{fmt.Sprint(
|
|
primitive.ObjectID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11},
|
|
)}},
|
|
{provider: shareddata.Composites, ids: []string{
|
|
"array-documents", "array-empty", "document", "document-composite", "document-composite-numerical-field-name",
|
|
"document-composite-reverse", "document-empty", "document-null", "array-composite", "array-null",
|
|
"array-numbers-asc", "array-strings-desc", "array-three", "array-three-reverse", "array-two",
|
|
}},
|
|
{provider: shareddata.DocumentsDoubles, ids: []string{
|
|
"document-double-whole", "document-double-zero", "document-double-max", "document-double-smallest",
|
|
"document-double-big", "document-double-empty", "document-double-null",
|
|
}},
|
|
{provider: shareddata.DocumentsStrings, ids: []string{
|
|
"document-string-double", "document-string-whole", "document-string-empty-str", "document-string-empty", "document-string-nil",
|
|
}},
|
|
{provider: shareddata.DocumentsDeeplyNested, ids: []string{"four", "three", "two"}},
|
|
{provider: shareddata.DocumentsDocuments, ids: []string{
|
|
fmt.Sprint(primitive.ObjectID{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
|
|
fmt.Sprint(primitive.ObjectID{0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}),
|
|
fmt.Sprint(primitive.ObjectID{0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03}),
|
|
fmt.Sprint(primitive.ObjectID{0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04}),
|
|
}},
|
|
{provider: shareddata.ArrayStrings, ids: []string{
|
|
"array-string-duplicate", "array-string-numbers", "array-string-with-nil", "array-string-empty",
|
|
}},
|
|
{provider: shareddata.ArrayDoubles, ids: []string{
|
|
"array-double-desc", "array-double-duplicate", "array-double-empty",
|
|
"array-double-big-plus", "array-double-prec-max", "array-double-prec-max-plus",
|
|
}},
|
|
{provider: shareddata.ArrayInt32s, ids: []string{
|
|
"array-int32-one", "array-int32-two", "array-int32-three",
|
|
"array-int32-six",
|
|
}},
|
|
{provider: shareddata.Mixed, ids: []string{"array-null", "null", "unset"}},
|
|
{provider: shareddata.ArrayDocuments, ids: []string{
|
|
"array-documents-nested-duplicate", "array-three-documents", "array-two-documents",
|
|
}},
|
|
{provider: shareddata.ArrayAndDocuments, ids: []string{"array-documents-two-fields", "document"}},
|
|
},
|
|
},
|
|
"UpdateNonExistentUpsert": {
|
|
filter: bson.D{{"_id", "non-existent"}},
|
|
update: bson.D{{"$set", bson.D{{"v", int32(42)}}}},
|
|
updateOpts: options.Update().SetUpsert(true),
|
|
},
|
|
}
|
|
|
|
testUpdateCompat(t, testCases)
|
|
}
|
|
|
|
func TestUpdateCompatArray(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
testCases := map[string]updateCompatTestCase{
|
|
"ReplaceDocumentFilter": {
|
|
filter: bson.D{{"v", bson.D{{"$eq", true}}}},
|
|
replace: bson.D{{"foo", int32(1)}},
|
|
},
|
|
"ReplaceDotNotationFilter": {
|
|
filter: bson.D{{"v.array.0", bson.D{{"$eq", int32(42)}}}, {"_id", "document-composite"}},
|
|
replace: bson.D{{"replacement-value", int32(1)}},
|
|
},
|
|
}
|
|
|
|
testUpdateCompat(t, testCases)
|
|
}
|
|
|
|
func TestUpdateCompatMultiFlagCommand(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
testCases := map[string]updateCommandCompatTestCase{
|
|
"False": {
|
|
filter: bson.D{{"v", int32(42)}},
|
|
update: bson.D{{"$set", bson.D{{"v", int32(43)}}}},
|
|
multi: false,
|
|
},
|
|
"True": {
|
|
filter: bson.D{{"v", int32(42)}},
|
|
update: bson.D{{"$set", bson.D{{"v", int32(43)}}}},
|
|
multi: true,
|
|
},
|
|
"String": {
|
|
filter: bson.D{{"v", int32(42)}},
|
|
update: bson.D{{"$set", bson.D{{"v", int32(43)}}}},
|
|
multi: "false",
|
|
resultType: EmptyResult,
|
|
},
|
|
"Int": {
|
|
filter: bson.D{{"v", int32(42)}},
|
|
update: bson.D{{"$set", bson.D{{"v", int32(43)}}}},
|
|
multi: int32(0),
|
|
resultType: EmptyResult,
|
|
},
|
|
"TrueEmptyDocument": {
|
|
update: bson.D{},
|
|
multi: true,
|
|
resultType: EmptyResult,
|
|
},
|
|
"FalseEmptyDocument": {
|
|
update: bson.D{},
|
|
multi: false,
|
|
},
|
|
}
|
|
|
|
testUpdateCommandCompat(t, testCases)
|
|
}
|
|
|
|
func TestReplaceKeepOrderCompat(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
s := setup.SetupCompatWithOpts(t, &setup.SetupCompatOpts{
|
|
Providers: shareddata.Providers{shareddata.Int32s},
|
|
})
|
|
|
|
ctx := s.Ctx
|
|
targetCollection := s.TargetCollections[0]
|
|
compatCollection := s.CompatCollections[0]
|
|
|
|
replace := bson.D{{"_id", "arr"}, {"c", int32(1)}, {"b", int32(2)}, {"a", int32(3)}}
|
|
filter := bson.D{{"_id", "arr"}}
|
|
|
|
_, err := targetCollection.InsertOne(ctx, filter)
|
|
require.NoError(t, err)
|
|
_, err = compatCollection.InsertOne(ctx, filter)
|
|
require.NoError(t, err)
|
|
|
|
_, err = targetCollection.ReplaceOne(ctx, filter, replace)
|
|
require.NoError(t, err)
|
|
_, err = compatCollection.ReplaceOne(ctx, filter, replace)
|
|
require.NoError(t, err)
|
|
|
|
targetResult := targetCollection.FindOne(ctx, filter)
|
|
require.NoError(t, targetResult.Err())
|
|
compatResult := compatCollection.FindOne(ctx, filter)
|
|
require.NoError(t, compatResult.Err())
|
|
|
|
var targetDoc, compatDoc bson.D
|
|
require.NoError(t, targetResult.Decode(&targetDoc))
|
|
require.NoError(t, compatResult.Decode(&compatDoc))
|
|
|
|
assert.Equal(t, compatDoc, targetDoc)
|
|
}
|
|
|
|
func TestUpdateCompatReplacementDoc(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
testCases := map[string]updateCommandCompatTestCase{
|
|
"Basic": {
|
|
update: bson.D{{"v", int32(43)}},
|
|
},
|
|
"EmptyDoc": {
|
|
update: bson.D{},
|
|
},
|
|
"FilterAndUpsertTrue": {
|
|
filter: bson.D{{"_id", "non-existent"}},
|
|
update: bson.D{{"v", int32(43)}},
|
|
upsert: true,
|
|
failsForDocDB: "https://github.com/hanzoai/docdb-DocumentDB/issues/359",
|
|
failsIDs: []struct {
|
|
provider shareddata.Provider
|
|
ids []string
|
|
}{
|
|
{provider: shareddata.Scalars, ids: []string{
|
|
"decimal128", "decimal128-int", "decimal128-int-zero", "decimal128-zero", "decimal128-double", "decimal128-whole",
|
|
"unset", "binary-empty", "bool-false", "bool-true", "datetime", "datetime-epoch", "datetime-year-max", "datetime-year-min", "double",
|
|
"double-1", "double-2", "double-3", "double-4", "double-5", "double-big", "double-max", "double-max-overflow", "double-min-overflow",
|
|
"double-smallest", "double-whole", "double-zero", "int32", "int32-1", "int32-2", "int32-3", "int32-max", "int32-min", "int32-zero",
|
|
"int64", "int64-1", "int64-2", "int64-3", "int64-big", "int64-double-big", "int64-max", "int64-min", "int64-zero", "null", "objectid",
|
|
"objectid-empty", "regex", "regex-empty", "string", "string-double", "string-empty", "string-whole", "timestamp", "timestamp-i",
|
|
}},
|
|
{provider: shareddata.Decimal128s, ids: []string{
|
|
"decimal128-int", "decimal128-int-zero", "decimal128-max-exp", "decimal128-max-exp-sig",
|
|
"decimal128-max-sig", "decimal128-min-exp", "decimal128-min-exp-sig", "decimal128-whole", "decimal128-zero",
|
|
}},
|
|
{provider: shareddata.Doubles, ids: []string{
|
|
"double-whole", "double-zero", "double-smallest", "double-big", "double-big-plus", "double-big-minus", "double-prec-max",
|
|
"double-prec-max-plus", "double-prec-max-plus-two", "double-prec-max-minus", "double-neg-big", "double-neg-big-plus",
|
|
"double-neg-big-minus", "double-prec-min", "double-prec-min-plus", "double-prec-min-minus", "double-prec-min-minus-two",
|
|
"double-null", "double-1", "double-2", "double-3", "double-4", "double-max-overflow", "double-min-overflow",
|
|
}},
|
|
{provider: shareddata.OverflowVergeDoubles, ids: []string{"double-max"}},
|
|
{provider: shareddata.SmallDoubles, ids: []string{"double-whole", "double-1", "double-2", "double-3"}},
|
|
{provider: shareddata.Strings, ids: []string{"string-double", "string-whole", "string-empty", "string-duplicate", "string-null"}},
|
|
{provider: shareddata.Binaries, ids: []string{"binary-empty", "binary-null"}},
|
|
{provider: shareddata.Bools, ids: []string{"bool-true", "bool-null"}},
|
|
{provider: shareddata.DateTimes, ids: []string{"datetime-epoch", "datetime-year-min", "datetime-year-max", "datetime-null"}},
|
|
{provider: shareddata.Regexes, ids: []string{"regex-empty", "regex-null"}},
|
|
{provider: shareddata.Int32s, ids: []string{"int32-zero", "int32-max", "int32-min", "int32-1", "int32-2", "int32-3"}},
|
|
{provider: shareddata.Timestamps, ids: []string{"timestamp-i", "timestamp-null"}},
|
|
{provider: shareddata.Int64s, ids: []string{
|
|
"int64-zero", "int64-max", "int64-min", "int64-1", "int64-2", "int64-3", "int64-big", "int64-big-plus", "int64-big-minus",
|
|
"int64-prec-max", "int64-prec-max-plus", "int64-prec-max-plus-two", "int64-prec-max-minus", "int64-neg-big", "int64-neg-big-plus",
|
|
"int64-neg-big-minus", "int64-prec-min", "int64-prec-min-plus", "int64-prec-min-minus", "int64-prec-min-minus-two",
|
|
}},
|
|
{provider: shareddata.ObjectIDs, ids: []string{"objectid-empty", "objectid-null"}},
|
|
{provider: shareddata.ObjectIDKeys, ids: []string{fmt.Sprint(primitive.ObjectID{
|
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11,
|
|
})}},
|
|
{provider: shareddata.Composites, ids: []string{
|
|
"array-documents", "array-empty", "document", "document-composite", "document-composite-numerical-field-name",
|
|
"document-composite-reverse", "document-empty", "document-null", "array-composite", "array-null",
|
|
"array-numbers-asc", "array-strings-desc", "array-three", "array-three-reverse", "array-two",
|
|
}},
|
|
{provider: shareddata.DocumentsDoubles, ids: []string{
|
|
"document-double-whole", "document-double-zero", "document-double-max", "document-double-smallest",
|
|
"document-double-big", "document-double-empty", "document-double-null",
|
|
}},
|
|
{provider: shareddata.DocumentsStrings, ids: []string{
|
|
"document-string-double", "document-string-whole", "document-string-empty-str", "document-string-empty", "document-string-nil",
|
|
}},
|
|
{provider: shareddata.DocumentsDeeplyNested, ids: []string{"four", "three", "two"}},
|
|
{provider: shareddata.DocumentsDocuments, ids: []string{
|
|
fmt.Sprint(primitive.ObjectID{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}),
|
|
fmt.Sprint(primitive.ObjectID{0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}),
|
|
fmt.Sprint(primitive.ObjectID{0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03}),
|
|
fmt.Sprint(primitive.ObjectID{0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04}),
|
|
}},
|
|
{provider: shareddata.ArrayStrings, ids: []string{
|
|
"array-string-duplicate", "array-string-numbers", "array-string-with-nil", "array-string-empty",
|
|
}},
|
|
{provider: shareddata.ArrayDoubles, ids: []string{
|
|
"array-double-desc", "array-double-duplicate", "array-double-empty",
|
|
"array-double-big-plus", "array-double-prec-max", "array-double-prec-max-plus",
|
|
}},
|
|
{provider: shareddata.ArrayInt32s, ids: []string{
|
|
"array-int32-one", "array-int32-two", "array-int32-three",
|
|
"array-int32-six",
|
|
}},
|
|
{provider: shareddata.Mixed, ids: []string{"array-null", "null", "unset"}},
|
|
{provider: shareddata.ArrayDocuments, ids: []string{
|
|
"array-documents-nested-duplicate", "array-three-documents", "array-two-documents",
|
|
}},
|
|
{provider: shareddata.ArrayAndDocuments, ids: []string{"array-documents-two-fields", "document"}},
|
|
},
|
|
},
|
|
"WithUpdateOp": {
|
|
update: bson.D{{"v", int32(43)}, {"$set", bson.D{{"test", int32(0)}}}},
|
|
resultType: EmptyResult,
|
|
},
|
|
"SameId": {
|
|
filter: bson.D{{"_id", "int32"}},
|
|
update: bson.D{{"_id", "int32"}, {"v", int32(43)}},
|
|
},
|
|
"DifferentId": {
|
|
filter: bson.D{{"_id", "int32"}},
|
|
update: bson.D{{"_id", "non-existent"}, {"v", int32(43)}},
|
|
},
|
|
}
|
|
|
|
testUpdateCommandCompat(t, testCases)
|
|
}
|