Files
docdb/integration/commands_administration_test.go
zeekayandHanzo Dev 06d5eca873 Declare operations on the group that serves them
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]>
2026-09-17 06:11:42 -07:00

2494 lines
70 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"
"math"
"math/rand/v2"
"runtime"
"strconv"
"sync"
"testing"
"time"
"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/build/version"
"github.com/hanzoai/docdb/internal/util/ctxutil"
"github.com/hanzoai/docdb/integration/setup"
"github.com/hanzoai/docdb/integration/shareddata"
)
func TestCreateCollectionDropListCollections(t *testing.T) {
ctx, collection := setup.Setup(t)
db := collection.Database()
name := collection.Name()
names, err := db.ListCollectionNames(ctx, bson.D{})
require.NoError(t, err)
require.Empty(t, names, "setup should not create collection if no providers are given")
// drop non-existing collection in non-existing database; error is consumed by the driver
err = collection.Drop(ctx)
require.NoError(t, err)
err = db.Collection(name).Drop(ctx)
require.NoError(t, err)
err = db.CreateCollection(ctx, name)
require.NoError(t, err)
// List collection names
names, err = db.ListCollectionNames(ctx, bson.D{})
require.NoError(t, err)
assert.Contains(t, names, name)
// drop existing collection
err = collection.Drop(ctx)
require.NoError(t, err)
// And try to drop existing collection again manually to check behavior.
var actual bson.D
err = db.RunCommand(ctx, bson.D{{"drop", name}}).Decode(&actual)
assert.NoError(t, err)
AssertEqualDocuments(t, bson.D{{"ok", float64(1)}}, actual)
}
func TestDropDatabaseListDatabases(t *testing.T) {
t.Parallel()
ctx, collection := setup.Setup(t) // no providers there
db := collection.Database()
name := db.Name()
filter := bson.D{{
"name", bson.D{{
"$in", bson.A{name}, // skip admin, other tests databases, etc
}},
}}
names, err := db.Client().ListDatabaseNames(ctx, filter)
require.NoError(t, err)
require.Empty(t, names, "setup should not create database if no providers are given")
// drop non-existing database; error is consumed by the driver
err = db.Drop(ctx)
require.NoError(t, err)
// drop manually to check error
var res bson.D
err = db.RunCommand(ctx, bson.D{{"dropDatabase", 1}}).Decode(&res)
require.NoError(t, err)
AssertEqualDocuments(t, bson.D{{"ok", float64(1)}}, res)
// there is no explicit command to create database, so create collection instead
err = db.Client().Database(name).CreateCollection(ctx, collection.Name())
require.NoError(t, err)
names, err = db.Client().ListDatabaseNames(ctx, filter)
require.NoError(t, err)
assert.Equal(t, []string{name}, names)
// drop existing database
err = db.Drop(ctx)
require.NoError(t, err)
// drop manually to check error
err = db.RunCommand(ctx, bson.D{{"dropDatabase", 1}}).Decode(&res)
require.NoError(t, err)
AssertEqualDocuments(t, bson.D{{"ok", float64(1)}}, res)
}
func TestListDatabases(t *testing.T) {
t.Parallel()
ctx, collection := setup.Setup(t, shareddata.DocumentsStrings)
db := collection.Database()
name := db.Name()
dbClient := collection.Database().Client()
// Add an extra DB to help verify if ListDatabases returns multiple databases as intended.
extraDB := dbClient.Database(name + "_extra")
_, err := extraDB.Collection(collection.Name()+"_extra").InsertOne(ctx, shareddata.DocumentsDoubles)
assert.NoError(t, err, "failed to insert document on extra collection")
t.Cleanup(func() {
assert.NoError(t, extraDB.Drop(ctx), "failed to drop extra DB")
})
testCases := map[string]struct { //nolint:vet // for readability
filter any
opts []*options.ListDatabasesOptions
expectedNameOnly bool
expected mongo.ListDatabasesResult
failsForDocDB string
}{
"Exists": {
filter: bson.D{{Key: "name", Value: name}},
expected: mongo.ListDatabasesResult{
Databases: []mongo.DatabaseSpecification{{
Name: name,
Empty: false,
}},
},
},
"ExistsNameOnly": {
filter: bson.D{{Key: "name", Value: name}},
opts: []*options.ListDatabasesOptions{
options.ListDatabases().SetNameOnly(true),
},
expectedNameOnly: true,
expected: mongo.ListDatabasesResult{
Databases: []mongo.DatabaseSpecification{{
Name: name,
}},
},
},
"Regex": {
filter: bson.D{
{Key: "name", Value: name},
{Key: "name", Value: primitive.Regex{Pattern: "^Test", Options: "i"}},
},
expected: mongo.ListDatabasesResult{
Databases: []mongo.DatabaseSpecification{{
Name: name,
}},
},
},
"RegexNameOnly": {
filter: bson.D{
{Key: "name", Value: name},
{Key: "name", Value: primitive.Regex{Pattern: "^Test", Options: "i"}},
},
opts: []*options.ListDatabasesOptions{
options.ListDatabases().SetNameOnly(true),
},
expectedNameOnly: true,
expected: mongo.ListDatabasesResult{
Databases: []mongo.DatabaseSpecification{{
Name: name,
}},
},
},
"NotFound": {
filter: bson.D{{Key: "name", Value: "unknown"}},
expected: mongo.ListDatabasesResult{
Databases: []mongo.DatabaseSpecification{},
},
failsForDocDB: "https://github.com/hanzoai/docdb/issues/4862",
},
"RegexNotFound": {
filter: bson.D{
{Key: "name", Value: name},
{Key: "name", Value: primitive.Regex{Pattern: "^xyz$", Options: "i"}},
},
expected: mongo.ListDatabasesResult{
Databases: []mongo.DatabaseSpecification{},
},
failsForDocDB: "https://github.com/hanzoai/docdb/issues/4862",
},
"RegexNotFoundNameOnly": {
filter: bson.D{
{Key: "name", Value: name},
{Key: "name", Value: primitive.Regex{Pattern: "^xyz$", Options: "i"}},
},
opts: []*options.ListDatabasesOptions{
options.ListDatabases().SetNameOnly(true),
},
expectedNameOnly: true,
expected: mongo.ListDatabasesResult{
Databases: []mongo.DatabaseSpecification{},
},
},
"Multiple": {
filter: bson.D{
{Key: "name", Value: primitive.Regex{Pattern: "^" + name, Options: "i"}},
},
expected: mongo.ListDatabasesResult{
Databases: []mongo.DatabaseSpecification{
{
Name: name,
Empty: false,
},
{
Name: name + "_extra",
Empty: false,
},
},
},
},
}
for name, tc := range testCases {
t.Run(name, func(tt *testing.T) {
tt.Parallel()
var t testing.TB = tt
if tc.failsForDocDB != "" {
t = setup.FailsForDocDB(tt, tc.failsForDocDB)
}
actual, err := db.Client().ListDatabases(ctx, tc.filter, tc.opts...)
assert.NoError(t, err)
assert.Len(t, actual.Databases, len(tc.expected.Databases))
if tc.expectedNameOnly || len(tc.expected.Databases) == 0 {
assert.Zero(t, actual.TotalSize, "TotalSize should be zero")
} else {
assert.NotZero(t, actual.TotalSize, "TotalSize should be non-zero")
}
// Reset values of dynamic data received by the server to zero for making comparison viable.
for index := range actual.Databases {
actual.Databases[index].SizeOnDisk = 0
}
actual.TotalSize = 0
assert.ElementsMatch(t, tc.expected.Databases, actual.Databases)
})
}
}
func TestListCollectionNames(t *testing.T) {
t.Parallel()
ctx, targetCollections, compatCollections := setup.SetupCompat(t)
filterNames := make(bson.A, len(targetCollections))
for i, n := range targetCollections {
filterNames[i] = n.Name()
}
// We should remove shuffle there once it is implemented in the setup.
// TODO https://github.com/hanzoai/docdb-DocumentDB/issues/825
rand.Shuffle(len(filterNames), func(i, j int) { filterNames[i], filterNames[j] = filterNames[j], filterNames[i] })
filterNames = filterNames[:len(filterNames)-1]
require.NotEmpty(t, filterNames)
filter := bson.D{{
"name", bson.D{{
"$in", filterNames,
}},
}}
compat, err := compatCollections[0].Database().ListCollectionNames(ctx, filter)
require.NoError(t, err)
target, err := targetCollections[0].Database().ListCollectionNames(ctx, filter)
require.NoError(t, err)
assert.Len(t, target, len(filterNames))
assert.ElementsMatch(t, compat, target)
}
func TestListCollectionsUUID(t *testing.T) {
t.Parallel()
ctx, collection := setup.Setup(t)
db := collection.Database()
collName := collection.Name()
err := db.CreateCollection(ctx, collName)
require.NoError(t, err)
cursor, err := db.ListCollections(ctx, bson.D{})
require.NoError(t, err)
var res []bson.D
err = cursor.All(ctx, &res)
require.NoError(t, err)
require.Len(t, res, 1)
var uuid primitive.Binary
for _, v := range res[0] {
if v.Key == "info" {
info := v.Value.(bson.D)
for _, vv := range info {
if vv.Key == "uuid" {
uuid = vv.Value.(primitive.Binary)
assert.Equal(t, bson.TypeBinaryUUID, uuid.Subtype)
assert.Len(t, uuid.Data, 16)
}
}
}
}
// collection rename should not change the initial UUID
newName := collName + "_new"
command := bson.D{
{"renameCollection", db.Name() + "." + collName},
{"to", db.Name() + "." + newName},
}
err = collection.Database().Client().Database("admin").RunCommand(ctx, command).Err()
require.NoError(t, err)
cursor, err = db.ListCollections(ctx, bson.D{})
require.NoError(t, err)
err = cursor.All(ctx, &res)
require.NoError(t, err)
require.Len(t, res, 1)
expected := bson.D{
{"name", newName},
{"type", "collection"},
{"options", bson.D{}},
{"info", bson.D{
{"readOnly", false},
{"uuid", uuid},
}},
{"idIndex", bson.D{
{"v", int32(2)},
{"key", bson.D{{"_id", int32(1)}}},
{"name", "_id_"},
}},
}
AssertEqualDocuments(t, expected, res[0])
}
func TestGetParameterCommand(t *testing.T) {
t.Parallel()
s := setup.SetupWithOpts(t, &setup.SetupOpts{
DatabaseName: "admin",
})
for name, tc := range map[string]struct {
command bson.D // required, command to run
expected map[string]any // optional, expected keys of response
unexpected []string // optional, unexpected keys of response
err *mongo.CommandError // optional, expected error from MongoDB
altMessage string // optional, alternative error message for DocDB, ignored if empty
}{
"GetParameter_Asterisk1": {
command: bson.D{{"getParameter", "*"}},
expected: map[string]any{
"authSchemaVersion": int32(5),
"quiet": false,
"ok": float64(1),
},
},
"GetParameter_Asterisk2": {
command: bson.D{{"getParameter", "*"}, {"quiet", 1}, {"comment", "getParameter test"}},
expected: map[string]any{
"authSchemaVersion": int32(5),
"quiet": false,
"ok": float64(1),
},
},
"GetParameter_Asterisk3": {
command: bson.D{{"getParameter", "*"}, {"quiet", 1}, {"quiet_other", 1}, {"comment", "getParameter test"}},
expected: map[string]any{
"authSchemaVersion": int32(5),
"quiet": false,
"ok": float64(1),
},
},
"GetParameter_Asterisk4": {
command: bson.D{{"getParameter", "*"}, {"quiet_other", 1}, {"comment", "getParameter test"}},
expected: map[string]any{
"authSchemaVersion": int32(5),
"quiet": false,
"ok": float64(1),
},
},
"GetParameter_Int": {
command: bson.D{{"getParameter", 1}, {"quiet", 1}, {"comment", "getParameter test"}},
expected: map[string]any{
"quiet": false,
"ok": float64(1),
},
},
"GetParameter_Zero": {
command: bson.D{{"getParameter", 0}, {"quiet", 1}, {"comment", "getParameter test"}},
expected: map[string]any{
"quiet": false,
"ok": float64(1),
},
},
"GetParameter_Nil": {
command: bson.D{{"getParameter", nil}, {"quiet", 1}, {"comment", "getParameter test"}},
expected: map[string]any{
"quiet": false,
"ok": float64(1),
},
},
"GetParameter_String": {
command: bson.D{{"getParameter", "1"}, {"quiet", 1}, {"comment", "getParameter test"}},
expected: map[string]any{
"quiet": false,
"ok": float64(1),
},
},
"NonexistentParameters": {
command: bson.D{{"getParameter", 1}, {"quiet", 1}, {"quiet_other", 1}, {"comment", "getParameter test"}},
expected: map[string]any{
"quiet": false,
"ok": float64(1),
},
unexpected: []string{"quiet_other"},
},
"EmptyParameters": {
command: bson.D{{"getParameter", 1}, {"comment", "getParameter test"}},
err: &mongo.CommandError{Code: 72, Message: `no option found to get`, Name: "InvalidOptions"},
},
"OnlyNonexistentParameters": {
command: bson.D{{"getParameter", 1}, {"quiet_other", 1}, {"comment", "getParameter test"}},
err: &mongo.CommandError{Code: 72, Message: `no option found to get`, Name: "InvalidOptions"},
},
"ShowDetailsTrue": {
command: bson.D{{"getParameter", bson.D{{"showDetails", true}}}, {"quiet", true}},
expected: map[string]any{
"quiet": bson.D{
{"value", false},
{"settableAtRuntime", true},
{"settableAtStartup", true},
},
"ok": float64(1),
},
unexpected: []string{"acceptApiVersion2"},
},
"ShowDetailsFalse": {
command: bson.D{{"getParameter", bson.D{{"showDetails", false}}}, {"quiet", true}},
expected: map[string]any{
"quiet": false,
"ok": float64(1),
},
unexpected: []string{"acceptApiVersion2"},
},
"ShowDetails_NoParameter_1": {
command: bson.D{{"getParameter", bson.D{{"showDetails", true}}}},
err: &mongo.CommandError{Code: 72, Message: `no option found to get`, Name: "InvalidOptions"},
},
"ShowDetails_NoParameter_2": {
command: bson.D{{"getParameter", bson.D{{"showDetails", false}}}},
err: &mongo.CommandError{Code: 72, Message: `no option found to get`, Name: "InvalidOptions"},
},
"AllParametersTrue": {
command: bson.D{{"getParameter", bson.D{{"showDetails", true}, {"allParameters", true}}}},
expected: map[string]any{
"quiet": bson.D{
{"value", false},
{"settableAtRuntime", true},
{"settableAtStartup", true},
},
"ok": float64(1),
},
},
"AllParametersFalse_MissingParameter": {
command: bson.D{{"getParameter", bson.D{{"showDetails", true}, {"allParameters", false}}}},
err: &mongo.CommandError{Code: 72, Message: `no option found to get`, Name: "InvalidOptions"},
},
"AllParametersFalse_PresentParameter": {
command: bson.D{{"getParameter", bson.D{{"showDetails", true}, {"allParameters", false}}}, {"quiet", true}},
expected: map[string]any{
"quiet": bson.D{
{"value", false},
{"settableAtRuntime", true},
{"settableAtStartup", true},
},
"ok": float64(1),
},
unexpected: []string{"acceptApiVersion2"},
},
"AllParametersFalse_NonexistentParameter": {
command: bson.D{{"getParameter", bson.D{{"showDetails", true}, {"allParameters", false}}}, {"quiet_other", true}},
err: &mongo.CommandError{Code: 72, Message: `no option found to get`, Name: "InvalidOptions"},
},
"ShowDetailsFalse_AllParametersTrue": {
command: bson.D{{"getParameter", bson.D{{"showDetails", false}, {"allParameters", true}}}},
expected: map[string]any{
"authSchemaVersion": int32(5),
"quiet": false,
"ok": float64(1),
},
},
"ShowDetailsFalse_AllParametersFalse_1": {
command: bson.D{{"getParameter", bson.D{{"showDetails", false}, {"allParameters", false}}}},
err: &mongo.CommandError{Code: 72, Message: `no option found to get`, Name: "InvalidOptions"},
},
"ShowDetailsFalse_AllParametersFalse_2": {
command: bson.D{{"getParameter", bson.D{{"showDetails", false}, {"allParameters", false}}}, {"quiet", true}},
expected: map[string]any{
"quiet": false,
"ok": float64(1),
},
unexpected: []string{"acceptApiVersion2"},
},
"ShowDetails_NegativeInt": {
command: bson.D{{"getParameter", bson.D{{"showDetails", int64(-1)}}}, {"quiet", true}},
expected: map[string]any{
"quiet": bson.D{
{"value", false},
{"settableAtRuntime", true},
{"settableAtStartup", true},
},
"ok": float64(1),
},
},
"ShowDetails_PositiveInt": {
command: bson.D{{"getParameter", bson.D{{"showDetails", int64(1)}}}, {"quiet", true}},
expected: map[string]any{
"quiet": bson.D{
{"value", false},
{"settableAtRuntime", true},
{"settableAtStartup", true},
},
"ok": float64(1),
},
},
"ShowDetails_ZeroInt": {
command: bson.D{{"getParameter", bson.D{{"showDetails", int64(0)}}}, {"quiet", true}},
expected: map[string]any{
"quiet": false,
"ok": float64(1),
},
unexpected: []string{"acceptApiVersion2"},
},
"ShowDetails_ZeroFloat": {
command: bson.D{{"getParameter", bson.D{{"showDetails", float64(0)}}}, {"quiet", true}},
expected: map[string]any{
"quiet": false,
"ok": float64(1),
},
unexpected: []string{"acceptApiVersion2"},
},
"ShowDetails_SmallestNonzeroFloat": {
command: bson.D{{"getParameter", bson.D{{"showDetails", math.SmallestNonzeroFloat64}}}, {"quiet", true}},
expected: map[string]any{
"quiet": bson.D{
{"value", false},
{"settableAtRuntime", true},
{"settableAtStartup", true},
},
"ok": float64(1),
},
},
"ShowDetails_Nil": {
command: bson.D{{"getParameter", bson.D{{"showDetails", nil}}}, {"quiet", true}},
expected: map[string]any{
"quiet": false,
"ok": float64(1),
},
},
"ShowDetails_String": {
command: bson.D{{"getParameter", bson.D{{"showDetails", "1"}}}, {"quiet", true}},
err: &mongo.CommandError{
Code: 14,
Name: "TypeMismatch",
Message: `BSON field 'getParameter.showDetails' is the wrong type 'string', expected types '[bool, long, int, decimal, double']`,
},
altMessage: `BSON field 'showDetails' is the wrong type 'string', expected types '[bool, long, int, decimal, double]'`,
},
"AllParameters_NegativeInt": {
command: bson.D{{"getParameter", bson.D{{"showDetails", true}, {"allParameters", int64(-1)}}}, {"quiet", true}},
expected: map[string]any{
"quiet": bson.D{
{"value", false},
{"settableAtRuntime", true},
{"settableAtStartup", true},
},
"ok": float64(1),
},
},
"AllParameters_PositiveInt": {
command: bson.D{{"getParameter", bson.D{{"showDetails", true}, {"allParameters", int64(1)}}}, {"quiet", true}},
expected: map[string]any{
"quiet": bson.D{
{"value", false},
{"settableAtRuntime", true},
{"settableAtStartup", true},
},
"ok": float64(1),
},
},
"AllParameters_ZeroInt": {
command: bson.D{{"getParameter", bson.D{{"showDetails", true}, {"allParameters", int64(0)}}}, {"quiet", true}},
expected: map[string]any{
"quiet": bson.D{
{"value", false},
{"settableAtRuntime", true},
{"settableAtStartup", true},
},
"ok": float64(1),
},
},
"AllParameters_ZeroFloat": {
command: bson.D{{"getParameter", bson.D{{"showDetails", true}, {"allParameters", float64(0)}}}, {"quiet", true}},
expected: map[string]any{
"quiet": bson.D{
{"value", false},
{"settableAtRuntime", true},
{"settableAtStartup", true},
},
"ok": float64(1),
},
},
"AllParameters_SmallestNonzeroFloat": {
command: bson.D{{"getParameter", bson.D{{"showDetails", true}, {"allParameters", math.SmallestNonzeroFloat64}}}, {"quiet", true}},
expected: map[string]any{
"quiet": bson.D{
{"value", false},
{"settableAtRuntime", true},
{"settableAtStartup", true},
},
"ok": float64(1),
},
},
"AllParameters_Nil": {
command: bson.D{{"getParameter", bson.D{{"showDetails", true}, {"allParameters", nil}}}, {"quiet", true}},
expected: map[string]any{
"quiet": bson.D{
{"value", false},
{"settableAtRuntime", true},
{"settableAtStartup", true},
},
"ok": float64(1),
},
unexpected: []string{"acceptApiVersion2"},
},
"AllParameters_String": {
command: bson.D{{"getParameter", bson.D{{"showDetails", true}, {"allParameters", "1"}}}, {"quiet", true}},
err: &mongo.CommandError{
Code: 14,
Name: "TypeMismatch",
Message: `BSON field 'getParameter.allParameters' is the wrong type 'string', expected types '[bool, long, int, decimal, double']`,
},
altMessage: `BSON field 'allParameters' is the wrong type 'string', expected types '[bool, long, int, decimal, double]'`,
},
"FeatureCompatibilityVersion": {
command: bson.D{
{"getParameter", bson.D{}},
{"featureCompatibilityVersion", 1},
},
expected: map[string]any{
"featureCompatibilityVersion": bson.D{{"version", "7.0"}},
"ok": float64(1),
},
},
"FeatureCompatibilityVersionShowDetails": {
command: bson.D{
{"getParameter", bson.D{{"showDetails", true}}},
{"featureCompatibilityVersion", 1},
},
expected: map[string]any{
"featureCompatibilityVersion": bson.D{
{"value", bson.D{{"version", "7.0"}}},
{"settableAtRuntime", false},
{"settableAtStartup", false},
},
"ok": float64(1),
},
},
} {
t.Run(name, func(t *testing.T) {
t.Parallel()
require.NotNil(t, tc.command, "command must not be nil")
var actual bson.D
err := s.Collection.Database().RunCommand(s.Ctx, tc.command).Decode(&actual)
if tc.err != nil {
AssertEqualAltCommandError(t, *tc.err, tc.altMessage, err)
return
}
require.NoError(t, err)
m := actual.Map()
keys := CollectKeys(t, actual)
for k, item := range tc.expected {
assert.Contains(t, keys, k)
assert.IsType(t, item, m[k])
if it, ok := item.(primitive.D); ok {
z := m[k].(primitive.D)
AssertEqualDocuments(t, it, z)
} else {
assert.Equal(t, m[k], item)
}
}
for _, k := range tc.unexpected {
assert.NotContains(t, keys, k)
}
})
}
}
func TestGetParameterCommandAuthenticationMechanisms(t *testing.T) {
t.Parallel()
s := setup.SetupWithOpts(t, &setup.SetupOpts{
DatabaseName: "admin",
})
t.Run("ShowDetails", func(t *testing.T) {
var actual bson.D
err := s.Collection.Database().RunCommand(s.Ctx, bson.D{
{"getParameter", bson.D{{"showDetails", true}}},
{"authenticationMechanisms", 1},
}).Decode(&actual)
require.NoError(t, err)
var actualComparable bson.D
for _, field := range actual {
switch field.Key {
case "authenticationMechanisms":
var mComparable bson.D
for _, m := range field.Value.(bson.D) {
switch m.Key {
case "value":
var values bson.A
for _, v := range m.Value.(bson.A) {
switch v.(string) {
case "MONGODB-X509":
// exclusive to MongoDB
default:
values = append(values, v)
}
}
mComparable = append(mComparable, bson.E{Key: m.Key, Value: values})
default:
mComparable = append(mComparable, m)
}
}
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: mComparable})
default:
actualComparable = append(actualComparable, field)
}
}
expected := bson.D{
{
"authenticationMechanisms",
bson.D{
{"value", bson.A{"SCRAM-SHA-1", "SCRAM-SHA-256"}},
{"settableAtRuntime", false},
{"settableAtStartup", true},
},
},
{"ok", float64(1)},
}
AssertEqualDocuments(t, expected, actualComparable)
})
t.Run("authenticationMechanisms", func(t *testing.T) {
var actual bson.D
err := s.Collection.Database().RunCommand(s.Ctx, bson.D{
{"getParameter", bson.D{}},
{"authenticationMechanisms", 1},
}).Decode(&actual)
require.NoError(t, err)
var actualComparable bson.D
for _, field := range actual {
switch field.Key {
case "authenticationMechanisms":
var values bson.A
for _, v := range field.Value.(bson.A) {
switch v.(string) {
case "MONGODB-X509":
// exclusive to MongoDB
default:
values = append(values, v)
}
}
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: values})
default:
actualComparable = append(actualComparable, field)
}
}
expected := bson.D{
{"authenticationMechanisms", bson.A{"SCRAM-SHA-1", "SCRAM-SHA-256"}},
{"ok", float64(1)},
}
AssertEqualDocuments(t, expected, actualComparable)
})
}
func TestBuildInfoCommand(t *testing.T) {
t.Parallel()
ctx, collection := setup.Setup(t)
info := version.Get()
var actual bson.D
command := bson.D{{"buildInfo", int32(1)}}
err := collection.Database().RunCommand(ctx, command).Decode(&actual)
require.NoError(t, err)
var actualComparable bson.D
for _, field := range actual {
switch field.Key {
case "docdb":
value, ok := field.Value.(bson.D)
require.True(t, ok)
AssertEqualDocuments(t, bson.D{{"package", info.Package}, {"version", info.Version}}, value)
case "version":
assert.IsType(t, "", field.Value)
assert.Regexp(t, `^7\.0\.`, field.Value)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: "7.0.0"})
case "debug":
assert.IsType(t, false, field.Value)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: false})
case "versionArray":
arr, ok := field.Value.(bson.A)
require.True(t, ok)
assert.Equal(t, int32(7), arr[0])
assert.Equal(t, int32(0), arr[1])
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: bson.A{}})
case "gitVersion":
assert.IsType(t, "", field.Value)
assert.NotEmpty(t, field.Value)
actualComparable = append(actualComparable, bson.E{"gitVersion", ""})
case "bits":
assert.Equal(t, int32(strconv.IntSize), field.Value)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: int32(0)})
case "buildEnvironment":
assert.IsType(t, bson.D{}, field.Value)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: bson.D{}})
case "openssl", "storageEngines", "allocator", "javascriptEngine":
// exclusive to MongoDB
default:
actualComparable = append(actualComparable, field)
}
}
expected := bson.D{
{"version", "7.0.0"},
{"gitVersion", ""},
{"modules", bson.A{}},
{"sysInfo", "deprecated"},
{"versionArray", bson.A{}},
{"buildEnvironment", bson.D{}},
{"bits", int32(0)},
{"debug", false},
{"maxBsonObjectSize", int32(16777216)},
{"ok", float64(1)},
}
AssertEqualDocuments(t, expected, actualComparable)
}
func TestCollStatsCommandEmpty(tt *testing.T) {
tt.Parallel()
t := setup.FailsForDocDB(tt, "https://github.com/hanzoai/docdb/issues/4792")
ctx, collection := setup.Setup(tt)
var actual bson.D
command := bson.D{{"collStats", collection.Name()}}
err := collection.Database().RunCommand(ctx, command).Decode(&actual)
require.NoError(t, err)
expected := bson.D{
{"ns", collection.Database().Name() + "." + collection.Name()},
{"size", int32(0)},
{"count", int32(0)},
{"numOrphanDocs", int32(0)},
{"storageSize", int32(0)},
{"totalSize", int32(0)},
{"nindexes", int32(0)},
{"totalIndexSize", int32(0)},
{"indexDetails", bson.D{}},
{"indexSizes", bson.D{}},
{"scaleFactor", int32(1)},
{"ok", float64(1)},
}
AssertEqualDocuments(t, expected, actual)
}
func TestCollStatsCommand(tt *testing.T) {
tt.Parallel()
t := setup.FailsForDocDB(tt, "https://github.com/hanzoai/docdb-DocumentDB/issues/555")
ctx, collection := setup.Setup(tt, shareddata.DocumentsStrings)
var actual bson.D
command := bson.D{{"collStats", collection.Name()}}
err := collection.Database().RunCommand(ctx, command).Decode(&actual)
require.NoError(t, err)
var actualComparable, actualFieldNames bson.D
for _, field := range actual {
switch field.Key {
case "size", "avgObjSize", "storageSize", "totalIndexSize", "totalSize":
assert.GreaterOrEqual(t, field.Value, int32(0))
case "wiredTiger":
// exclusive to MongoDB
continue
case "indexDetails", "indexSizes":
v, ok := field.Value.(bson.D)
require.True(t, ok)
var indexNames []string
for _, index := range v {
indexNames = append(indexNames, index.Key)
}
assert.Equal(t, []string{"_id_"}, indexNames)
default:
actualComparable = append(actualComparable, field)
}
actualFieldNames = append(actualFieldNames, bson.E{Key: field.Key})
}
expectedComparable := bson.D{
{"ns", collection.Database().Name() + "." + collection.Name()},
{"count", int32(6)},
{"numOrphanDocs", int32(0)},
{"freeStorageSize", int32(0)},
{"capped", false},
{"nindexes", int32(1)},
{"indexBuilds", bson.A{}},
{"scaleFactor", int32(1)},
{"ok", float64(1)},
}
AssertEqualDocuments(t, expectedComparable, actualComparable)
expectedFieldNames := bson.D{
{Key: "ns"},
{Key: "size"},
{Key: "count"},
{Key: "avgObjSize"},
{Key: "numOrphanDocs"},
{Key: "storageSize"},
{Key: "freeStorageSize"},
{Key: "capped"},
{Key: "nindexes"},
{Key: "indexDetails"},
{Key: "indexBuilds"},
{Key: "totalIndexSize"},
{Key: "indexSizes"},
{Key: "totalSize"},
{Key: "scaleFactor"},
{Key: "ok"},
}
AssertEqualDocuments(t, expectedFieldNames, actualFieldNames)
}
func TestCollStatsCommandScale(t *testing.T) {
t.Parallel()
s := setup.SetupWithOpts(t, &setup.SetupOpts{
Providers: []shareddata.Provider{shareddata.DocumentsStrings},
})
ctx, collection := s.Ctx, s.Collection
for name, tc := range map[string]struct { //nolint:vet // for readability
scale any
scaleFactor any
err *mongo.CommandError
altMessage string
failsForDocDB string
}{
"scaleOne": {
scale: int32(1),
scaleFactor: int32(1),
failsForDocDB: "https://github.com/hanzoai/docdb/issues/4792",
},
"scaleBig": {
scale: int64(1000),
scaleFactor: int32(1000),
failsForDocDB: "https://github.com/hanzoai/docdb/issues/4792",
},
"scaleMaxInt": {
scale: math.MaxInt64,
scaleFactor: int32(math.MaxInt32),
failsForDocDB: "https://github.com/hanzoai/docdb/issues/4792",
},
"scaleZero": {
scale: int32(0),
err: &mongo.CommandError{
Code: 51024,
Name: "Location51024",
Message: `BSON field 'scale' value must be >= 1, actual value '0'`,
},
},
"scaleNegative": {
scale: int32(-100),
err: &mongo.CommandError{
Code: 51024,
Name: "Location51024",
Message: `BSON field 'scale' value must be >= 1, actual value '-100'`,
},
},
"scaleFloat": {
scale: 2.8,
scaleFactor: int32(2),
failsForDocDB: "https://github.com/hanzoai/docdb/issues/4792",
},
"scaleFloatNegative": {
scale: -2.8,
err: &mongo.CommandError{
Code: 51024,
Name: "Location51024",
Message: `BSON field 'scale' value must be >= 1, actual value '-2'`,
},
},
"scaleMinFloat": {
scale: -math.MaxFloat64,
err: &mongo.CommandError{
Code: 51024,
Name: "Location51024",
Message: `BSON field 'scale' value must be >= 1, actual value '-2147483648'`,
},
},
"scaleMaxFloat": {
scale: math.MaxFloat64,
scaleFactor: int32(math.MaxInt32),
failsForDocDB: "https://github.com/hanzoai/docdb/issues/4792",
},
"scaleString": {
scale: "1",
err: &mongo.CommandError{
Code: 14,
Name: "TypeMismatch",
Message: `BSON field 'collStats.scale' is the wrong type 'string', expected types '[long, int, decimal, double']`,
},
altMessage: `BSON field 'collStats.scale' is the wrong type 'string', expected types '[long, int, decimal, double]'`,
},
"scaleObject": {
scale: bson.D{{"a", 1}},
err: &mongo.CommandError{
Code: 14,
Name: "TypeMismatch",
Message: `BSON field 'collStats.scale' is the wrong type 'object', expected types '[long, int, decimal, double']`,
},
altMessage: `BSON field 'collStats.scale' is the wrong type 'wirebson.RawDocument', expected types '[long, int, decimal, double]'`,
},
"scaleNull": {
scale: nil,
scaleFactor: int32(1),
failsForDocDB: "https://github.com/hanzoai/docdb/issues/4792",
},
} {
t.Run(name, func(tt *testing.T) {
tt.Parallel()
var t testing.TB = tt
if tc.failsForDocDB != "" {
t = setup.FailsForDocDB(tt, tc.failsForDocDB)
}
var res bson.D
command := bson.D{{"collStats", collection.Name()}, {"scale", tc.scale}}
err := collection.Database().RunCommand(ctx, command).Decode(&res)
if err != nil {
AssertEqualAltCommandError(t, *tc.err, tc.altMessage, err)
return
}
require.NoError(t, err)
var actualComparable bson.D
for _, field := range res {
switch field.Key {
case "size", "avgObjSize", "storageSize", "totalIndexSize", "totalSize", "freeStorageSize":
assert.GreaterOrEqual(t, field.Value, int32(0))
case "wiredTiger":
// exclusive to MongoDB
case "indexDetails", "indexSizes":
v, ok := field.Value.(bson.D)
require.True(t, ok)
var indexNames []string
for _, index := range v {
indexNames = append(indexNames, index.Key)
}
assert.Equal(t, []string{"_id_"}, indexNames)
default:
actualComparable = append(actualComparable, field)
}
}
expectedComparable := bson.D{
{"ns", collection.Database().Name() + "." + collection.Name()},
{"count", int32(6)},
{"numOrphanDocs", int32(0)},
{"capped", false},
{"nindexes", int32(1)},
{"indexBuilds", bson.A{}},
{"scaleFactor", tc.scaleFactor},
{"ok", float64(1)},
}
AssertEqualDocuments(t, expectedComparable, actualComparable)
})
}
}
// TestCollStatsCommandCount adds large number of documents and checks
// approximation used by backends returns the correct count of documents from collStats.
func TestCollStatsCommandCount(tt *testing.T) {
tt.Parallel()
t := setup.FailsForDocDB(tt, "https://github.com/hanzoai/docdb-DocumentDB/issues/555")
ctx, collection := setup.Setup(tt)
var n int32 = 1000
docs := GenerateDocuments(0, n)
_, err := collection.InsertMany(ctx, docs)
require.NoError(t, err)
var actual bson.D
command := bson.D{{"collStats", collection.Name()}}
err = collection.Database().RunCommand(ctx, command).Decode(&actual)
require.NoError(t, err)
var actualComparable bson.D
for _, field := range actual {
switch field.Key {
case "size", "avgObjSize", "storageSize", "totalIndexSize", "totalSize":
assert.GreaterOrEqual(t, field.Value, int32(0))
case "wiredTiger":
// exclusive to MongoDB
case "indexDetails", "indexSizes":
v, ok := field.Value.(bson.D)
require.True(t, ok)
var indexNames []string
for _, index := range v {
indexNames = append(indexNames, index.Key)
}
assert.Equal(t, []string{"_id_"}, indexNames)
default:
actualComparable = append(actualComparable, field)
}
}
expectedComparable := bson.D{
{"ns", collection.Database().Name() + "." + collection.Name()},
{"count", int32(1000)},
{"numOrphanDocs", int32(0)},
{"freeStorageSize", int32(0)},
{"capped", false},
{"nindexes", int32(1)},
{"indexBuilds", bson.A{}},
{"scaleFactor", int32(1)},
{"ok", float64(1)},
}
AssertEqualDocuments(t, expectedComparable, actualComparable)
}
func TestCollStatsCommandScaleSize(tt *testing.T) {
t := setup.FailsForDocDB(tt, "https://github.com/hanzoai/docdb/issues/4792")
tt.Parallel()
ctx, collection := setup.Setup(tt, shareddata.DocumentsStrings)
indexName := "custom-name"
resIndexName, err := collection.Indexes().CreateOne(ctx, mongo.IndexModel{
Keys: bson.D{{"foo", 1}, {"bar", -1}},
Options: options.Index().SetName(indexName),
})
require.NoError(t, err)
require.Equal(t, indexName, resIndexName)
var resComparable, resNoScaleComparable bson.D
var ready bool
scale := int32(10)
retries := 10
for range retries {
if ready {
break
}
resComparable, resNoScaleComparable = nil, nil
var resNoScale, res bson.D
err = collection.Database().RunCommand(ctx, bson.D{{"collStats", collection.Name()}}).Decode(&resNoScale)
require.NoError(t, err)
err = collection.Database().RunCommand(ctx, bson.D{{"collStats", collection.Name()}, {"scale", scale}}).Decode(&res)
require.NoError(t, err)
var resTotalIndexSize any
for _, field := range res {
switch field.Key {
case "indexDetails":
v, ok := field.Value.(bson.D)
require.True(t, ok)
var indexNames []string
for _, index := range v {
indexNames = append(indexNames, index.Key)
}
assert.Equal(t, []string{"_id_", indexName}, indexNames)
case "scaleFactor":
assert.Equal(t, int32(10), field.Value)
case "totalIndexSize":
resTotalIndexSize = field.Value
resComparable = append(resComparable, field)
default:
resComparable = append(resComparable, field)
}
}
for _, field := range resNoScale {
switch field.Key {
case "totalIndexSize":
size, ok := field.Value.(int32)
require.True(t, ok, "%[1]v %[1]T", field.Value)
scaledSize := size / scale
if scaledSize == resTotalIndexSize {
ready = true
}
resNoScaleComparable = append(resNoScaleComparable, bson.E{Key: field.Key, Value: scaledSize})
case "size", "storageSize", "totalSize":
size, ok := field.Value.(int32)
require.True(t, ok, "%[1]v %[1]T", field.Value)
scaledSize := size / scale
resNoScaleComparable = append(resNoScaleComparable, bson.E{Key: field.Key, Value: scaledSize})
case "indexDetails":
v, ok := field.Value.(bson.D)
require.True(t, ok)
var indexNames []string
for _, index := range v {
indexNames = append(indexNames, index.Key)
}
assert.Equal(t, []string{"_id_", indexName}, indexNames)
case "indexSizes":
v, ok := field.Value.(bson.D)
require.True(t, ok)
var indexSizes bson.D
for _, fieldName := range v {
var size int32
size, ok = fieldName.Value.(int32)
require.True(t, ok, "%[1]v %[1]T", fieldName.Value)
scaledSize := size / scale
indexSizes = append(indexSizes, bson.E{Key: fieldName.Key, Value: scaledSize})
}
resNoScaleComparable = append(resNoScaleComparable, bson.E{Key: field.Key, Value: indexSizes})
case "scaleFactor":
assert.Equal(t, int32(1), field.Value)
default:
resNoScaleComparable = append(resNoScaleComparable, field)
}
}
}
AssertEqualDocuments(t, resComparable, resNoScaleComparable)
}
func TestDataSizeCommand(t *testing.T) {
t.Parallel()
t.Run("Existing", func(tt *testing.T) {
tt.Parallel()
t := setup.FailsForDocDB(tt, "https://github.com/hanzoai/docdb-DocumentDB/issues/802")
ctx, collection := setup.Setup(tt, shareddata.DocumentsStrings)
// call validate to updated statistics
err := collection.Database().RunCommand(ctx, bson.D{{"validate", collection.Name()}}).Err()
require.NoError(t, err)
var actual bson.D
command := bson.D{{"dataSize", collection.Database().Name() + "." + collection.Name()}}
err = collection.Database().RunCommand(ctx, command).Decode(&actual)
require.NoError(t, err)
var actualComparable, actualFieldNames bson.D
for _, field := range actual {
switch field.Key {
case "size", "millis":
assert.GreaterOrEqual(t, field.Value, int64(0))
default:
actualComparable = append(actualComparable, field)
}
actualFieldNames = append(actualFieldNames, bson.E{Key: field.Key})
}
expectedComparable := bson.D{
{"numObjects", int64(len(shareddata.DocumentsStrings.Docs()))},
{"estimate", false},
{"ok", float64(1)},
}
AssertEqualDocuments(t, expectedComparable, actualComparable)
expectedFieldNames := bson.D{
{Key: "size"},
{Key: "numObjects"},
{Key: "millis"},
{Key: "estimate"},
{Key: "ok"},
}
AssertEqualDocuments(t, expectedFieldNames, actualFieldNames)
})
t.Run("NonExistent", func(tt *testing.T) {
tt.Parallel()
t := setup.FailsForDocDB(tt, "https://github.com/hanzoai/docdb-DocumentDB/issues/802")
ctx, collection := setup.Setup(tt)
var actual bson.D
command := bson.D{{"dataSize", collection.Database().Name() + "." + collection.Name()}}
err := collection.Database().RunCommand(ctx, command).Decode(&actual)
require.NoError(t, err)
var actualComparable, actualFieldNames bson.D
for _, field := range actual {
switch field.Key {
case "millis":
assert.GreaterOrEqual(t, field.Value, int64(0))
default:
actualComparable = append(actualComparable, field)
}
actualFieldNames = append(actualFieldNames, bson.E{Key: field.Key})
}
expectedComparable := bson.D{
{"size", int64(0)},
{"numObjects", int64(0)},
{"ok", float64(1)},
}
AssertEqualDocuments(t, expectedComparable, actualComparable)
expectedFieldNames := bson.D{
{Key: "size"},
{Key: "numObjects"},
{Key: "millis"},
{Key: "ok"},
}
AssertEqualDocuments(t, expectedFieldNames, actualFieldNames)
})
}
func TestDataSizeCommandErrors(t *testing.T) {
t.Parallel()
ctx, collection := setup.Setup(t, shareddata.DocumentsStrings)
for name, tc := range map[string]struct { //nolint:vet // for readability
command bson.D // required, command to run
err *mongo.CommandError // required, expected error from MongoDB
altMessage string // optional, alternative error message for DocDB, ignored if empty
}{
"InvalidNamespace": {
command: bson.D{{"dataSize", "invalid"}},
err: &mongo.CommandError{
Code: 73,
Name: "InvalidNamespace",
Message: "Namespace invalid is not a valid collection name",
},
altMessage: "Invalid namespace specified 'invalid'",
},
"InvalidNamespaceTypeDocument": {
command: bson.D{{"dataSize", bson.D{}}},
err: &mongo.CommandError{
Code: 14,
Name: "TypeMismatch",
Message: "BSON field 'dataSize.dataSize' is the wrong type 'object', expected type 'string'",
},
},
} {
t.Run(name, func(t *testing.T) {
t.Parallel()
require.NotNil(t, tc.command, "command must not be nil")
require.NotNil(t, tc.err, "err must not be nil")
var actual bson.D
err := collection.Database().RunCommand(ctx, tc.command).Decode(&actual)
assert.Nil(t, actual)
AssertEqualAltCommandError(t, *tc.err, tc.altMessage, err)
})
}
}
func TestDBStatsCommand(tt *testing.T) {
tt.Parallel()
t := setup.FailsForDocDB(tt, "https://github.com/hanzoai/docdb/issues/4821")
ctx, collection := setup.Setup(tt, shareddata.DocumentsStrings)
var actual bson.D
command := bson.D{{"dbStats", int32(1)}}
err := collection.Database().RunCommand(ctx, command).Decode(&actual)
require.NoError(t, err)
var actualComparable bson.D
for _, field := range actual {
switch field.Key {
case "avgObjSize", "dataSize", "storageSize", "indexSize", "totalSize":
val, ok := field.Value.(float64)
require.True(t, ok)
assert.InDelta(t, 37_500, val, 37_460, "field %s", field.Key)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: float64(0)})
case "fsUsedSize", "fsTotalSize":
val, ok := field.Value.(float64)
require.True(t, ok)
assert.Greater(t, val, float64(0))
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: float64(0)})
default:
actualComparable = append(actualComparable, field)
}
}
expected := bson.D{
{"db", collection.Database().Name()},
{"collections", int64(1)},
{"views", int64(0)},
{"objects", int64(len(shareddata.DocumentsStrings.Docs()))},
{"avgObjSize", float64(0)},
{"dataSize", float64(0)},
{"storageSize", float64(0)},
{"indexes", int64(1)},
{"indexSize", float64(0)},
{"totalSize", float64(0)},
{"scaleFactor", int64(1)},
{"fsUsedSize", float64(0)},
{"fsTotalSize", float64(0)},
{"ok", float64(1)},
}
AssertEqualDocuments(t, expected, actualComparable)
}
func TestDBStatsCommandEmpty(tt *testing.T) {
tt.Parallel()
t := setup.FailsForDocDB(tt, "https://github.com/hanzoai/docdb/issues/4821")
ctx, collection := setup.Setup(tt)
var actual bson.D
command := bson.D{{"dbStats", int32(1)}}
err := collection.Database().RunCommand(ctx, command).Decode(&actual)
require.NoError(t, err)
expected := bson.D{
{"db", collection.Database().Name()},
{"collections", int64(0)},
{"views", int64(0)},
{"objects", int64(0)},
{"avgObjSize", float64(0)},
{"dataSize", float64(0)},
{"storageSize", float64(0)},
{"indexes", int64(0)},
{"indexSize", float64(0)},
{"totalSize", float64(0)},
{"scaleFactor", int64(1)},
{"fsUsedSize", float64(0)},
{"fsTotalSize", float64(0)},
{"ok", float64(1)},
}
AssertEqualDocuments(t, expected, actual)
}
func TestDBStatsCommandScale(tt *testing.T) {
tt.Parallel()
ctx, collection := setup.Setup(tt, shareddata.DocumentsStrings)
for name, tc := range map[string]struct { //nolint:vet // for readability
scale any
expectedScaleFactor int64
}{
"scaleOne": {scale: int32(1), expectedScaleFactor: int64(1)},
"scaleBig": {scale: int64(1_000), expectedScaleFactor: int64(1_000)},
"scaleFloat": {scale: 2.8, expectedScaleFactor: int64(2)},
"scaleNull": {scale: nil, expectedScaleFactor: int64(1)},
} {
tt.Run(name, func(tt *testing.T) {
tt.Helper()
tt.Parallel()
t := setup.FailsForDocDB(tt, "https://github.com/hanzoai/docdb/issues/4821")
var actual bson.D
command := bson.D{{"dbStats", int32(1)}, {"scale", tc.scale}}
err := collection.Database().RunCommand(ctx, command).Decode(&actual)
require.NoError(t, err)
var actualComparable bson.D
for _, field := range actual {
switch field.Key {
case "avgObjSize", "dataSize", "storageSize", "indexSize", "totalSize":
val, ok := field.Value.(float64)
require.True(t, ok)
assert.InDelta(t, 35_500, val, 35_500)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: float64(0)})
case "fsUsedSize", "fsTotalSize":
val, ok := field.Value.(float64)
require.True(t, ok)
assert.Greater(t, val, float64(0))
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: float64(0)})
default:
actualComparable = append(actualComparable, field)
}
}
expected := bson.D{
{"db", collection.Database().Name()},
{"collections", int64(1)},
{"views", int64(0)},
{"objects", int64(len(shareddata.DocumentsStrings.Docs()))},
{"avgObjSize", float64(0)},
{"dataSize", float64(0)},
{"storageSize", float64(0)},
{"indexes", int64(1)},
{"indexSize", float64(0)},
{"totalSize", float64(0)},
{"scaleFactor", tc.expectedScaleFactor},
{"fsUsedSize", float64(0)},
{"fsTotalSize", float64(0)},
{"ok", float64(1)},
}
AssertEqualDocuments(t, expected, actualComparable)
})
}
}
func TestDBStatsCommandScaleEmptyDatabase(tt *testing.T) {
tt.Parallel()
t := setup.FailsForDocDB(tt, "https://github.com/hanzoai/docdb/issues/4821")
ctx, collection := setup.Setup(tt)
var actual bson.D
command := bson.D{{"dbStats", int32(1)}, {"scale", float64(1_000)}}
err := collection.Database().RunCommand(ctx, command).Decode(&actual)
require.NoError(t, err)
expected := bson.D{
{"db", collection.Database().Name()},
{"collections", int64(0)},
{"views", int64(0)},
{"objects", int64(0)},
{"avgObjSize", float64(0)},
{"dataSize", float64(0)},
{"storageSize", float64(0)},
{"indexes", int64(0)},
{"indexSize", float64(0)},
{"totalSize", float64(0)},
{"scaleFactor", int64(1000)},
{"fsUsedSize", float64(0)},
{"fsTotalSize", float64(0)},
{"ok", float64(1)},
}
AssertEqualDocuments(t, expected, actual)
}
func TestDBStatsCommandFreeStorage(tt *testing.T) {
tt.Parallel()
ctx, collection := setup.Setup(tt, shareddata.DocumentsStrings)
for name, tc := range map[string]struct { //nolint:vet // for readability
command bson.D // required, command to run
expected bson.D // required, expected result
}{
"Unset": {
command: bson.D{{"dbStats", int32(1)}},
expected: bson.D{
{"db", collection.Database().Name()},
{"collections", int64(1)},
{"views", int64(0)},
{"objects", int64(len(shareddata.DocumentsStrings.Docs()))},
{"avgObjSize", float64(0)},
{"dataSize", float64(0)},
{"storageSize", float64(0)},
{"indexes", int64(1)},
{"indexSize", float64(0)},
{"totalSize", float64(0)},
{"scaleFactor", int64(1)},
{"fsUsedSize", float64(0)},
{"fsTotalSize", float64(0)},
{"ok", float64(1)},
},
},
"Int32Zero": {
command: bson.D{{"dbStats", int32(1)}, {"freeStorage", int32(0)}},
expected: bson.D{
{"db", collection.Database().Name()},
{"collections", int64(1)},
{"views", int64(0)},
{"objects", int64(len(shareddata.DocumentsStrings.Docs()))},
{"avgObjSize", float64(0)},
{"dataSize", float64(0)},
{"storageSize", float64(0)},
{"indexes", int64(1)},
{"indexSize", float64(0)},
{"totalSize", float64(0)},
{"scaleFactor", int64(1)},
{"fsUsedSize", float64(0)},
{"fsTotalSize", float64(0)},
{"ok", float64(1)},
},
},
"Int32One": {
command: bson.D{{"dbStats", int32(1)}, {"freeStorage", int32(1)}},
expected: bson.D{
{"db", collection.Database().Name()},
{"collections", int64(1)},
{"views", int64(0)},
{"objects", int64(len(shareddata.DocumentsStrings.Docs()))},
{"avgObjSize", float64(0)},
{"dataSize", float64(0)},
{"storageSize", float64(0)},
{"indexes", int64(1)},
{"indexSize", float64(0)},
{"totalSize", float64(0)},
{"freeStorageSize", float64(0)},
{"indexFreeStorageSize", float64(0)},
{"totalFreeStorageSize", float64(0)},
{"scaleFactor", int64(1)},
{"fsUsedSize", float64(0)},
{"fsTotalSize", float64(0)},
{"ok", float64(1)},
},
},
"Int32Negative": {
command: bson.D{{"dbStats", int32(1)}, {"freeStorage", int32(-1)}},
expected: bson.D{
{"db", collection.Database().Name()},
{"collections", int64(1)},
{"views", int64(0)},
{"objects", int64(len(shareddata.DocumentsStrings.Docs()))},
{"avgObjSize", float64(0)},
{"dataSize", float64(0)},
{"storageSize", float64(0)},
{"indexes", int64(1)},
{"indexSize", float64(0)},
{"totalSize", float64(0)},
{"freeStorageSize", float64(0)},
{"indexFreeStorageSize", float64(0)},
{"totalFreeStorageSize", float64(0)},
{"scaleFactor", int64(1)},
{"fsUsedSize", float64(0)},
{"fsTotalSize", float64(0)},
{"ok", float64(1)},
},
},
"True": {
command: bson.D{{"dbStats", int32(1)}, {"freeStorage", true}},
expected: bson.D{
{"db", collection.Database().Name()},
{"collections", int64(1)},
{"views", int64(0)},
{"objects", int64(len(shareddata.DocumentsStrings.Docs()))},
{"avgObjSize", float64(0)},
{"dataSize", float64(0)},
{"storageSize", float64(0)},
{"indexes", int64(1)},
{"indexSize", float64(0)},
{"totalSize", float64(0)},
{"freeStorageSize", float64(0)},
{"indexFreeStorageSize", float64(0)},
{"totalFreeStorageSize", float64(0)},
{"scaleFactor", int64(1)},
{"fsUsedSize", float64(0)},
{"fsTotalSize", float64(0)},
{"ok", float64(1)},
},
},
"False": {
command: bson.D{{"dbStats", int32(1)}, {"freeStorage", false}},
expected: bson.D{
{"db", collection.Database().Name()},
{"collections", int64(1)},
{"views", int64(0)},
{"objects", int64(len(shareddata.DocumentsStrings.Docs()))},
{"avgObjSize", float64(0)},
{"dataSize", float64(0)},
{"storageSize", float64(0)},
{"indexes", int64(1)},
{"indexSize", float64(0)},
{"totalSize", float64(0)},
{"scaleFactor", int64(1)},
{"fsUsedSize", float64(0)},
{"fsTotalSize", float64(0)},
{"ok", float64(1)},
},
},
"Nil": {
command: bson.D{{"dbStats", int32(1)}, {"freeStorage", nil}},
expected: bson.D{
{"db", collection.Database().Name()},
{"collections", int64(1)},
{"views", int64(0)},
{"objects", int64(len(shareddata.DocumentsStrings.Docs()))},
{"avgObjSize", float64(0)},
{"dataSize", float64(0)},
{"storageSize", float64(0)},
{"indexes", int64(1)},
{"indexSize", float64(0)},
{"totalSize", float64(0)},
{"scaleFactor", int64(1)},
{"fsUsedSize", float64(0)},
{"fsTotalSize", float64(0)},
{"ok", float64(1)},
},
},
} {
tt.Run(name, func(tt *testing.T) {
tt.Parallel()
t := setup.FailsForDocDB(tt, "https://github.com/hanzoai/docdb/issues/4821")
var actual bson.D
err := collection.Database().RunCommand(ctx, tc.command).Decode(&actual)
require.NoError(t, err)
var actualComparable bson.D
for _, field := range actual {
switch field.Key {
case "avgObjSize", "dataSize", "storageSize", "indexSize", "totalSize",
"freeStorageSize", "indexFreeStorageSize", "totalFreeStorageSize":
val, ok := field.Value.(float64)
require.True(t, ok)
assert.InDelta(t, 35_500, val, 35_500)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: float64(0)})
case "fsUsedSize", "fsTotalSize":
val, ok := field.Value.(float64)
require.True(t, ok)
assert.Greater(t, val, float64(0))
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: float64(0)})
default:
actualComparable = append(actualComparable, field)
}
}
AssertEqualDocuments(t, tc.expected, actualComparable)
})
}
}
//nolint:paralleltest // we test a global server status
func TestServerStatusCommand(t *testing.T) {
ctx, collection := setup.Setup(t)
info := version.Get()
var actual bson.D
command := bson.D{{"serverStatus", int32(1)}}
err := collection.Database().RunCommand(ctx, command).Decode(&actual)
require.NoError(t, err)
var actualComparable bson.D
var freeMonitoringComparable bson.D // only for DocDB
for _, field := range actual {
switch field.Key {
case "docdb":
docdb, buildEnvironment := RemoveKey(t, field.Value.(bson.D), "buildEnvironment")
assert.IsType(t, bson.D{}, buildEnvironment)
expected := bson.D{
{"version", info.Version},
{"gitVersion", info.Commit},
{"debug", true},
{"package", info.Package},
{"postgresql", version.PostgreSQLTest},
{"documentdb", version.DocumentDB},
}
AssertEqualDocuments(t, expected, docdb)
case "freeMonitoring":
freeMonitoring, ok := field.Value.(bson.D)
require.True(t, ok)
freeMonitoringComparable = freeMonitoring
case "version":
assert.IsType(t, "", field.Value)
assert.Regexp(t, `^7\.0\.`, field.Value)
actualComparable = append(actualComparable, bson.E{"version", "7.0.0"})
case "catalogStats":
catalogStats, ok := field.Value.(bson.D)
require.True(t, ok)
var catalogStatsComparable bson.D
for _, subField := range catalogStats {
switch subField.Key {
case "capped", "csfle", "queryableEncryption":
// TODO https://github.com/hanzoai/docdb-DocumentDB/issues/629
// Fields are not set in DocDB
case "collections", "internalCollections", "internalViews":
assert.IsType(t, int32(0), subField.Value)
catalogStatsComparable = append(catalogStatsComparable, bson.E{subField.Key, int32(0)})
default:
catalogStatsComparable = append(catalogStatsComparable, subField)
}
}
actualComparable = append(actualComparable, bson.E{field.Key, catalogStatsComparable})
case "host", "process":
assert.IsType(t, "", field.Value)
assert.NotEmpty(t, field.Value)
actualComparable = append(actualComparable, bson.E{field.Key, ""})
case "localTime":
assert.IsType(t, primitive.DateTime(0), field.Value)
assert.WithinDuration(t, time.Now(), field.Value.(primitive.DateTime).Time(), 2*time.Second)
actualComparable = append(actualComparable, bson.E{field.Key, primitive.DateTime(0)})
case "pid", "uptimeMillis":
assert.IsType(t, int64(0), field.Value)
assert.Greater(t, field.Value, int64(0), field.Key)
actualComparable = append(actualComparable, bson.E{field.Key, int64(0)})
case "uptimeEstimate":
assert.IsType(t, int64(0), field.Value)
actualComparable = append(actualComparable, bson.E{field.Key, int64(0)})
case "uptime":
assert.IsType(t, float64(0), field.Value)
actualComparable = append(actualComparable, bson.E{field.Key, float64(0)})
case "wiredTiger", "query", "metrics", "asserts", "batchedDeletes", "connections", "defaultRWConcern",
"electionMetrics", "internalTransactions", "extra_info", "logicalSessionRecordCache",
"featureCompatibilityVersion", "flowControl", "globalLock", "indexBuilds", "indexBulkBuilder",
"indexStats", "locks", "network", "compression", "serviceExecutors", "opLatencies",
"opcounters", "opcountersRepl", "oplogTruncation", "queryAnalyzers",
"readConcernCounters", "readPreferenceCounters", "repl", "scramCache", "security", "shardSplits",
"storageEngine", "tcmalloc", "tenantMigrations", "trafficRecording", "transactions", "transportSecurity",
"twoPhaseCommitCoordinator", "mem", "collectionCatalog":
// TODO https://github.com/hanzoai/docdb-DocumentDB/issues/629
// Not implemented in DocDB, we might want to support some of these fields
default:
actualComparable = append(actualComparable, field)
}
}
t.Run("FreeMonitoring", func(t *testing.T) {
tt := setup.FailsForMongoDB(t, "MongoDB decommissioned free monitoring")
freeMonitoringExpected := bson.D{
{"state", "undecided"},
}
AssertEqualDocuments(tt, freeMonitoringExpected, freeMonitoringComparable)
})
expected := bson.D{
{"host", ""},
{"version", "7.0.0"},
{"process", ""},
{"pid", int64(0)},
{"uptime", float64(0)},
{"uptimeMillis", int64(0)},
{"uptimeEstimate", int64(0)},
{"localTime", primitive.DateTime(0)},
{"catalogStats", bson.D{
{"collections", int32(0)},
{"clustered", int32(0)},
{"timeseries", int32(0)},
{"views", int32(0)},
{"internalCollections", int32(0)},
{"internalViews", int32(0)},
}},
{"ok", float64(1)},
}
AssertEqualDocuments(t, expected, actualComparable)
}
func TestServerStatusCommandMetrics(t *testing.T) {
setup.SkipForMongoDB(t, "MongoDB decommissioned server status metrics")
t.Parallel()
info := version.Get()
for name, tc := range map[string]struct {
cmds []bson.D
expectedNonZero []string
}{
"BasicCmd": {
cmds: []bson.D{
{{"ping", int32(1)}},
},
expectedNonZero: []string{"total"},
},
"UpdateCmd": {
cmds: []bson.D{
{{"update", "values"}, {"updates", bson.A{bson.D{{"q", bson.D{{"v", "foo"}}}}}}},
},
expectedNonZero: []string{"total"},
},
"UpdateCmdFailed": {
cmds: []bson.D{
{{"update", int32(1)}},
},
expectedNonZero: []string{"failed", "total"},
},
} {
t.Run(name, func(t *testing.T) {
t.Parallel()
ctx, collection := setup.Setup(t)
for _, cmd := range tc.cmds {
collection.Database().RunCommand(ctx, cmd)
}
// ensure non-zero uptime
ctxutil.Sleep(ctx, time.Second)
command := bson.D{{"serverStatus", int32(1)}}
var actual bson.D
err := collection.Database().RunCommand(ctx, command).Decode(&actual)
require.NoError(t, err)
var actualComparable bson.D
for _, field := range actual {
switch field.Key {
case "docdb":
f, buildEnvironment := RemoveKey(t, field.Value.(bson.D), "buildEnvironment")
assert.IsType(t, bson.D{}, buildEnvironment)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: f})
case "host":
host, ok := field.Value.(string)
require.True(t, ok)
assert.NotEmpty(t, host)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: ""})
case "localTime":
localTime, ok := field.Value.(primitive.DateTime)
require.True(t, ok)
assert.NotEmpty(t, localTime)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: primitive.DateTime(0)})
case "pid", "uptimeMillis":
subField, ok := field.Value.(int64)
require.True(t, ok)
assert.Greater(t, subField, int64(0), field.Key)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: int64(0)})
case "uptimeEstimate":
require.IsType(t, int64(0), field.Value)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: int64(0)})
case "process":
process, ok := field.Value.(string)
require.True(t, ok)
assert.NotEmpty(t, process)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: ""})
case "uptime":
uptime, ok := field.Value.(float64)
require.True(t, ok)
assert.Greater(t, uptime, float64(0))
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: float64(0)})
case "version":
version, ok := field.Value.(string)
require.True(t, ok)
assert.Regexp(t, `^7\.0\.`, version)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: "7.0.0"})
case "metrics":
metrics, ok := field.Value.(bson.D)
require.True(t, ok)
var metricsComparable bson.D
for _, mField := range metrics {
switch mField.Key {
case "commands":
commands, cOk := mField.Value.(bson.D)
assert.True(t, cOk)
for _, command := range commands {
cmd, cmdOk := command.Value.(bson.D)
assert.True(t, cmdOk)
var cmdComparable bson.D
for _, cmdField := range cmd {
switch cmdField.Key {
case "total", "failed":
assert.IsType(t, int64(0), cmdField.Value)
cmdComparable = append(cmdComparable, bson.E{Key: cmdField.Key, Value: int64(0)})
default:
cmdComparable = append(cmdComparable, cmdField)
}
}
cmdExpected := bson.D{
{"failed", int64(0)},
{"total", int64(0)},
}
AssertEqualDocuments(t, cmdExpected, cmdComparable)
}
metricsComparable = append(metricsComparable, bson.E{Key: mField.Key, Value: bson.D{}})
default:
metricsComparable = append(metricsComparable, mField)
}
}
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: metricsComparable})
default:
actualComparable = append(actualComparable, field)
}
}
expected := bson.D{
{"catalogStats", bson.D{
{"clustered", int32(0)},
{"collections", int32(0)},
{"internalCollections", int32(0)},
{"internalViews", int32(0)},
{"timeseries", int32(0)},
{"views", int32(0)},
}},
{"docdb", bson.D{
{"version", info.Version},
{"gitVersion", info.Commit},
{"debug", true},
{"package", info.Package},
{"postgresql", version.PostgreSQLTest},
{"documentdb", version.DocumentDB},
}},
{"freeMonitoring", bson.D{{"state", "undecided"}}},
{"host", ""},
{"localTime", primitive.DateTime(0)},
{"metrics", bson.D{{"commands", bson.D{}}}},
{"ok", float64(1)},
{"pid", int64(0)},
{"process", ""},
{"uptime", float64(0)},
{"uptimeEstimate", int64(0)},
{"uptimeMillis", int64(0)},
{"version", "7.0.0"},
}
AssertEqualDocuments(t, expected, actualComparable)
})
}
}
func TestServerStatusCommandFreeMonitoring(t *testing.T) {
setup.SkipForMongoDB(t, "MongoDB decommissioned free monitoring")
// this test shouldn't be run in parallel, because it requires a specific state of the field which would be modified by the other tests.
s := setup.SetupWithOpts(t, &setup.SetupOpts{
DatabaseName: "admin",
})
info := version.Get()
for name, tc := range map[string]struct {
command bson.D
expectedStatus string
}{
"Enable": {
command: bson.D{{"setFreeMonitoring", 1}, {"action", "enable"}},
expectedStatus: "enabled",
},
"Disable": {
command: bson.D{{"setFreeMonitoring", 1}, {"action", "disable"}},
expectedStatus: "disabled",
},
} {
t.Run(name, func(t *testing.T) {
require.NotNil(t, tc.command, "command must not be nil")
res := s.Collection.Database().RunCommand(s.Ctx, tc.command)
require.NoError(t, res.Err())
var actual bson.D
err := s.Collection.Database().RunCommand(s.Ctx, bson.D{{"serverStatus", 1}}).Decode(&actual)
require.NoError(t, err)
var status any
var actualComparable bson.D
for _, field := range actual {
switch field.Key {
case "docdb":
f, buildEnvironment := RemoveKey(t, field.Value.(bson.D), "buildEnvironment")
assert.IsType(t, bson.D{}, buildEnvironment)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: f})
case "host":
host, ok := field.Value.(string)
require.True(t, ok)
assert.NotEmpty(t, host)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: ""})
case "localTime":
localTime, ok := field.Value.(primitive.DateTime)
require.True(t, ok)
assert.NotEmpty(t, localTime)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: primitive.DateTime(0)})
case "pid", "uptimeMillis":
subField, ok := field.Value.(int64)
require.True(t, ok)
assert.Greater(t, subField, int64(0), field.Key)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: int64(0)})
case "uptimeEstimate":
require.IsType(t, int64(0), field.Value)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: int64(0)})
case "process":
process, ok := field.Value.(string)
require.True(t, ok)
assert.NotEmpty(t, process)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: ""})
case "uptime":
uptime, ok := field.Value.(float64)
require.True(t, ok)
assert.Greater(t, uptime, float64(0))
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: float64(0)})
case "version":
version, ok := field.Value.(string)
require.True(t, ok)
assert.Regexp(t, `^7\.0\.`, version)
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: "7.0.0"})
case "freeMonitoring":
freeMonitoring, ok := field.Value.(bson.D)
require.True(t, ok)
for _, subField := range freeMonitoring {
switch subField.Key {
case "state":
status = subField.Value
}
}
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: freeMonitoring})
case "metrics":
metrics, ok := field.Value.(bson.D)
require.True(t, ok)
var metricsComparable bson.D
for _, mField := range metrics {
switch mField.Key {
case "commands":
commands, cOk := mField.Value.(bson.D)
assert.True(t, cOk)
for _, command := range commands {
cmd, cmdOk := command.Value.(bson.D)
assert.True(t, cmdOk)
var cmdComparable bson.D
for _, cmdField := range cmd {
switch cmdField.Key {
case "total", "failed":
assert.IsType(t, int64(0), cmdField.Value)
cmdComparable = append(cmdComparable, bson.E{Key: cmdField.Key, Value: int64(0)})
default:
cmdComparable = append(cmdComparable, cmdField)
}
}
cmdExpected := bson.D{
{"failed", int64(0)},
{"total", int64(0)},
}
AssertEqualDocuments(t, cmdExpected, cmdComparable)
}
metricsComparable = append(metricsComparable, bson.E{Key: mField.Key, Value: bson.D{}})
default:
metricsComparable = append(metricsComparable, mField)
}
}
actualComparable = append(actualComparable, bson.E{Key: field.Key, Value: metricsComparable})
default:
actualComparable = append(actualComparable, field)
}
}
expected := bson.D{
{"catalogStats", bson.D{
{"clustered", int32(0)},
{"collections", int32(0)},
{"internalCollections", int32(0)},
{"internalViews", int32(0)},
{"timeseries", int32(0)},
{"views", int32(0)},
}},
{"docdb", bson.D{
{"version", info.Version},
{"gitVersion", info.Commit},
{"debug", true},
{"package", info.Package},
{"postgresql", version.PostgreSQLTest},
{"documentdb", version.DocumentDB},
}},
{"freeMonitoring", bson.D{{"state", tc.expectedStatus}}},
{"host", ""},
{"localTime", primitive.DateTime(0)},
{"metrics", bson.D{{"commands", bson.D{}}}},
{"ok", float64(1)},
{"pid", int64(0)},
{"process", ""},
{"uptime", float64(0)},
{"uptimeEstimate", int64(0)},
{"uptimeMillis", int64(0)},
{"version", "7.0.0"},
}
AssertEqualDocuments(t, expected, actualComparable)
assert.Equal(t, tc.expectedStatus, status)
})
}
}
func TestServerStatusCommandStress(t *testing.T) {
// It should be rewritten to use teststress.Stress.
ctx, collection := setup.Setup(t) // no providers there, we will create collections concurrently
client := collection.Database().Client()
dbNum := runtime.GOMAXPROCS(-1) * 10
ready := make(chan struct{}, dbNum)
start := make(chan struct{})
var wg sync.WaitGroup
for i := 0; i < dbNum; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
ready <- struct{}{}
<-start
dbName := fmt.Sprintf("%s_stress_%d", collection.Database().Name(), i)
db := client.Database(dbName)
_ = db.Drop(ctx) // make sure DB doesn't exist (it will be created together with the collection)
collName := fmt.Sprintf("stress_%d", i)
err := db.CreateCollection(ctx, collName)
assert.NoError(t, err)
err = db.Drop(ctx)
assert.NoError(t, err)
command := bson.D{{"serverStatus", int32(1)}}
var actual bson.D
err = collection.Database().RunCommand(ctx, command).Decode(&actual)
assert.NoError(t, err)
}(i)
}
for i := 0; i < dbNum; i++ {
<-ready
}
close(start)
wg.Wait()
}
func TestCompactCommand(t *testing.T) {
// don't run in parallel as parallel `VACUUM FULL ANALYZE` may result in deadlock
s := setup.SetupWithOpts(t, &setup.SetupOpts{
DatabaseName: "admin",
Providers: []shareddata.Provider{shareddata.DocumentsStrings},
})
dr, err := s.Collection.DeleteMany(s.Ctx, bson.D{})
require.NoError(t, err)
assert.Positive(t, dr.DeletedCount)
command := bson.D{
{"compact", s.Collection.Name()},
{"force", true},
}
var res bson.D
err = s.Collection.Database().RunCommand(s.Ctx, command).Decode(&res)
require.NoError(t, err)
res, bf := RemoveKey(t, res, "bytesFreed")
assert.Zero(t, bf)
AssertEqualDocuments(t, bson.D{{"ok", float64(1)}}, res)
}
func TestCompactCommandNonExistent(t *testing.T) {
t.Parallel()
for name, tc := range map[string]struct {
dbName string
force any // optional, defaults to unset
err *mongo.CommandError // required
altMessage string // optional, alternative error message
}{
"NonExistentDB": {
force: true,
dbName: "non-existent",
err: &mongo.CommandError{
Code: 26,
Name: "NamespaceNotFound",
Message: "database does not exist",
},
altMessage: "ns does not exist: non-existent.non-existent",
},
"NonExistentCollection": {
force: true,
dbName: "admin",
err: &mongo.CommandError{
Code: 26,
Name: "NamespaceNotFound",
Message: "collection does not exist",
},
altMessage: "ns does not exist: admin.non-existent",
},
} {
t.Run(name, func(t *testing.T) {
t.Parallel()
require.Error(t, tc.err)
s := setup.SetupWithOpts(t, &setup.SetupOpts{
DatabaseName: tc.dbName,
})
command := bson.D{
{"compact", "non-existent"},
}
if tc.force != nil {
command = append(command, bson.E{Key: "force", Value: tc.force})
}
var res bson.D
err := s.Collection.Database().RunCommand(s.Ctx, command).Decode(&res)
AssertEqualAltCommandError(t, *tc.err, tc.altMessage, err)
})
}
}