Skip to content

Commit

Permalink
Merge branch 'main' into build-without-postgres-sqlite
Browse files Browse the repository at this point in the history
  • Loading branch information
henvic authored Dec 4, 2023
2 parents 82b76d1 + 126b59d commit f2a2104
Show file tree
Hide file tree
Showing 5 changed files with 263 additions and 110 deletions.
143 changes: 129 additions & 14 deletions integration/commands_administration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,25 +158,140 @@ func TestCommandsAdministrationListDatabases(t *testing.T) {

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")
})

actual, err := db.Client().ListDatabases(ctx, bson.D{{"name", name}})
require.NoError(t, err)
require.Len(t, actual.Databases, 1)
testCases := map[string]struct { //nolint:vet // for readability
filter any
opts []*options.ListDatabasesOptions

expected := mongo.ListDatabasesResult{
Databases: []mongo.DatabaseSpecification{{
Name: name,
SizeOnDisk: actual.Databases[0].SizeOnDisk,
Empty: actual.Databases[0].Empty,
}},
TotalSize: actual.TotalSize,
expectedNameOnly bool
expected mongo.ListDatabasesResult
}{
"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{},
},
},
"RegexNotFound": {
filter: bson.D{
{Key: "name", Value: name},
{Key: "name", Value: primitive.Regex{Pattern: "^xyz$", Options: "i"}},
},
expected: mongo.ListDatabasesResult{
Databases: []mongo.DatabaseSpecification{},
},
},
"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,
},
},
},
},
}

assert.Equal(t, expected, actual)
for name, tc := range testCases {
tc, name := tc, name
t.Run(name, func(t *testing.T) {
t.Parallel()

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")
}

assert.NotZero(t, actual.Databases[0].SizeOnDisk, "%s's SizeOnDisk should be non-zero", name)
assert.False(t, actual.Databases[0].Empty, "%s's Empty should be false", name)
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.Equal(t, tc.expected, actual)
})
}
}

func TestCommandsAdministrationListCollections(t *testing.T) {
Expand Down
101 changes: 71 additions & 30 deletions integration/commands_diagnostic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,38 +271,79 @@ func TestCommandsDiagnosticListCommands(t *testing.T) {

func TestCommandsDiagnosticValidate(t *testing.T) {
t.Parallel()
ctx, collection := setup.Setup(t, shareddata.Doubles)

var doc bson.D
err := collection.Database().RunCommand(ctx, bson.D{{"validate", collection.Name()}}).Decode(&doc)
require.NoError(t, err)
t.Run("Basic", func(t *testing.T) {
t.Parallel()

ctx, collection := setup.Setup(t, shareddata.Doubles)

var doc bson.D
command := bson.D{{"validate", collection.Name()}}
err := collection.Database().RunCommand(ctx, command).Decode(&doc)
require.NoError(t, err)

actual := ConvertDocument(t, doc)
expected := must.NotFail(types.NewDocument(
"ns", "TestCommandsDiagnosticValidate-Basic.TestCommandsDiagnosticValidate-Basic",
"nInvalidDocuments", int32(0),
"nNonCompliantDocuments", int32(0),
"nrecords", int32(25),
"nIndexes", int32(1),
"valid", true,
"repaired", false,
"warnings", types.MakeArray(0),
"errors", types.MakeArray(0),
"extraIndexEntries", types.MakeArray(0),
"missingIndexEntries", types.MakeArray(0),
"corruptRecords", types.MakeArray(0),
"ok", float64(1),
))

actual.Remove("keysPerIndex")
actual.Remove("indexDetails")
actual.Remove("$clusterTime")
actual.Remove("operationTime")

testutil.AssertEqual(t, expected, actual)
})

t.Log(doc.Map())

actual := ConvertDocument(t, doc)
expected := must.NotFail(types.NewDocument(
"ns", "TestCommandsDiagnosticValidate.TestCommandsDiagnosticValidate",
"nInvalidDocuments", int32(0),
"nNonCompliantDocuments", int32(0),
"nrecords", int32(0), // replaced below
"nIndexes", int32(1),
"valid", true,
"repaired", false,
"warnings", types.MakeArray(0),
"errors", types.MakeArray(0),
"extraIndexEntries", types.MakeArray(0),
"missingIndexEntries", types.MakeArray(0),
"corruptRecords", types.MakeArray(0),
"ok", float64(1),
))

actual.Remove("keysPerIndex")
actual.Remove("indexDetails")
actual.Remove("$clusterTime")
actual.Remove("operationTime")

testutil.CompareAndSetByPathNum(t, expected, actual, 39, types.NewStaticPath("nrecords"))
testutil.AssertEqual(t, expected, actual)
t.Run("TwoIndexes", func(t *testing.T) {
t.Parallel()

ctx, collection := setup.Setup(t, shareddata.Doubles)

_, err := collection.Indexes().CreateOne(ctx, mongo.IndexModel{Keys: bson.D{{"a", 1}}})
require.NoError(t, err)

var doc bson.D
command := bson.D{{"validate", collection.Name()}}
err = collection.Database().RunCommand(ctx, command).Decode(&doc)
require.NoError(t, err)

actual := ConvertDocument(t, doc)
expected := must.NotFail(types.NewDocument(
"ns", "TestCommandsDiagnosticValidate-TwoIndexes.TestCommandsDiagnosticValidate-TwoIndexes",
"nInvalidDocuments", int32(0),
"nNonCompliantDocuments", int32(0),
"nrecords", int32(25),
"nIndexes", int32(2),
"valid", true,
"repaired", false,
"warnings", types.MakeArray(0),
"errors", types.MakeArray(0),
"extraIndexEntries", types.MakeArray(0),
"missingIndexEntries", types.MakeArray(0),
"corruptRecords", types.MakeArray(0),
"ok", float64(1),
))

actual.Remove("keysPerIndex")
actual.Remove("indexDetails")
actual.Remove("$clusterTime")
actual.Remove("operationTime")

testutil.AssertEqual(t, expected, actual)
})
}

func TestCommandsDiagnosticValidateError(t *testing.T) {
Expand Down
24 changes: 10 additions & 14 deletions internal/handler/msg_listdatabases.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,6 @@ func (h *Handler) MsgListDatabases(ctx context.Context, msg *wire.OpMsg) (*wire.
databases := types.MakeArray(len(res.Databases))

for _, dbInfo := range res.Databases {
if nameOnly {
databases.Append(must.NotFail(types.NewDocument(
"name", dbInfo.Name,
)))

continue
}

db, err := h.b.Database(dbInfo.Name)
if err != nil {
h.L.Warn("Failed to get database", zap.Error(err))
Expand All @@ -88,18 +80,22 @@ func (h *Handler) MsgListDatabases(ctx context.Context, msg *wire.OpMsg) (*wire.
"empty", stats.SizeTotal == 0,
))

totalSize += stats.SizeTotal

matches, err := common.FilterDocument(d, filter)
if err != nil {
return nil, lazyerrors.Error(err)
}

if !matches {
continue
}
if matches {
if nameOnly {
d = must.NotFail(types.NewDocument(
"name", dbInfo.Name,
))
} else {
totalSize += stats.SizeTotal
}

databases.Append(d)
databases.Append(d)
}
}

var reply wire.OpMsg
Expand Down
8 changes: 4 additions & 4 deletions internal/handler/msg_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (h *Handler) MsgValidate(ctx context.Context, msg *wire.OpMsg) (*wire.OpMsg
return nil, lazyerrors.Error(err)
}

common.Ignored(document, h.L, "full", "repair", "metadata")
common.Ignored(document, h.L, "full", "repair", "metadata", "checkBSONConformance")

command := document.Command()

Expand All @@ -58,7 +58,7 @@ func (h *Handler) MsgValidate(ctx context.Context, msg *wire.OpMsg) (*wire.OpMsg
return nil, lazyerrors.Error(err)
}

_, err = c.Stats(ctx, &backends.CollectionStatsParams{Refresh: true})
stats, err := c.Stats(ctx, &backends.CollectionStatsParams{Refresh: true})
if err != nil {
if backends.ErrorCodeIs(err, backends.ErrorCodeCollectionDoesNotExist) {
msg := fmt.Sprintf("Collection '%s.%s' does not exist to validate.", dbName, collection)
Expand All @@ -74,8 +74,8 @@ func (h *Handler) MsgValidate(ctx context.Context, msg *wire.OpMsg) (*wire.OpMsg
"ns", dbName+"."+collection,
"nInvalidDocuments", int32(0),
"nNonCompliantDocuments", int32(0),
"nrecords", int32(-1), // TODO https://github.com/FerretDB/FerretDB/issues/419
"nIndexes", int32(1), // TODO https://github.com/FerretDB/FerretDB/issues/419
"nrecords", int32(stats.CountDocuments),
"nIndexes", int32(len(stats.IndexSizes)),
"valid", true,
"repaired", false,
"warnings", types.MakeArray(0),
Expand Down
Loading

0 comments on commit f2a2104

Please sign in to comment.