Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
350 changes: 350 additions & 0 deletions admin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -477,3 +477,353 @@ func TestCreateIndexWithBackgroundOption(t *testing.T) {
require.Contains(t, row, "name")
})
}

func TestCreateIndexes(t *testing.T) {
testutil.RunOnAllDBs(t, func(t *testing.T, db testutil.TestDB) {
dbName := fmt.Sprintf("testdb_create_idxs_%s", db.Name)
defer testutil.CleanupDatabase(t, db.Client, dbName)

ctx := context.Background()

_, err := db.Client.Database(dbName).Collection("users").InsertOne(ctx, bson.M{"name": "alice", "email": "[email protected]", "age": 30})
require.NoError(t, err)

gc := gomongo.NewClient(db.Client)

result, err := gc.Execute(ctx, dbName, `db.users.createIndexes([{ key: { name: 1 }, name: "name_idx" }, { key: { email: 1 }, name: "email_idx" }])`)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, 2, len(result.Value))

// Values should be index name strings
name0, ok := result.Value[0].(string)
require.True(t, ok)
require.Equal(t, "name_idx", name0)
name1, ok := result.Value[1].(string)
require.True(t, ok)
require.Equal(t, "email_idx", name1)

// Verify indexes exist
idxResult, err := gc.Execute(ctx, dbName, `db.users.getIndexes()`)
require.NoError(t, err)
require.Equal(t, 3, len(idxResult.Value)) // _id + name_idx + email_idx
})
}

func TestDbStats(t *testing.T) {
testutil.RunOnAllDBs(t, func(t *testing.T, db testutil.TestDB) {
dbName := fmt.Sprintf("testdb_db_stats_%s", db.Name)
defer testutil.CleanupDatabase(t, db.Client, dbName)

ctx := context.Background()

// Create some data
_, err := db.Client.Database(dbName).Collection("test").InsertOne(ctx, bson.M{"x": 1})
require.NoError(t, err)

gc := gomongo.NewClient(db.Client)

result, err := gc.Execute(ctx, dbName, `db.stats()`)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, 1, len(result.Value))

row := valueToJSON(result.Value[0])
require.Contains(t, row, `"db"`)
require.Contains(t, row, `"collections"`)
})
}

func TestCollectionStats(t *testing.T) {
testutil.RunOnAllDBs(t, func(t *testing.T, db testutil.TestDB) {
dbName := fmt.Sprintf("testdb_coll_stats_%s", db.Name)
defer testutil.CleanupDatabase(t, db.Client, dbName)

ctx := context.Background()

_, err := db.Client.Database(dbName).Collection("users").InsertOne(ctx, bson.M{"name": "alice"})
require.NoError(t, err)

gc := gomongo.NewClient(db.Client)

result, err := gc.Execute(ctx, dbName, `db.users.stats()`)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, 1, len(result.Value))

row := valueToJSON(result.Value[0])
require.Contains(t, row, `"ns"`)
require.Contains(t, row, `"count"`)
})
}

func TestServerStatus(t *testing.T) {
// serverStatus is not supported on DocumentDB
testutil.RunOnMongoDBOnly(t, func(t *testing.T, db testutil.TestDB) {
dbName := fmt.Sprintf("testdb_server_status_%s", db.Name)
defer testutil.CleanupDatabase(t, db.Client, dbName)

ctx := context.Background()
gc := gomongo.NewClient(db.Client)

result, err := gc.Execute(ctx, dbName, `db.serverStatus()`)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, 1, len(result.Value))

row := valueToJSON(result.Value[0])
require.Contains(t, row, `"ok"`)
})
}

func TestServerBuildInfo(t *testing.T) {
testutil.RunOnAllDBs(t, func(t *testing.T, db testutil.TestDB) {
dbName := fmt.Sprintf("testdb_build_info_%s", db.Name)
defer testutil.CleanupDatabase(t, db.Client, dbName)

ctx := context.Background()
gc := gomongo.NewClient(db.Client)

result, err := gc.Execute(ctx, dbName, `db.serverBuildInfo()`)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, 1, len(result.Value))

row := valueToJSON(result.Value[0])
require.Contains(t, row, `"version"`)
})
}

func TestDbVersion(t *testing.T) {
testutil.RunOnAllDBs(t, func(t *testing.T, db testutil.TestDB) {
dbName := fmt.Sprintf("testdb_db_version_%s", db.Name)
defer testutil.CleanupDatabase(t, db.Client, dbName)

ctx := context.Background()
gc := gomongo.NewClient(db.Client)

result, err := gc.Execute(ctx, dbName, `db.version()`)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, 1, len(result.Value))

version, ok := result.Value[0].(string)
require.True(t, ok)
require.NotEmpty(t, version)
// Version should look like a semver (e.g., "4.4.0", "8.0.0")
require.True(t, strings.Contains(version, "."), "version should contain dots: %s", version)
})
}

func TestHostInfo(t *testing.T) {
testutil.RunOnAllDBs(t, func(t *testing.T, db testutil.TestDB) {
dbName := fmt.Sprintf("testdb_host_info_%s", db.Name)
defer testutil.CleanupDatabase(t, db.Client, dbName)

ctx := context.Background()
gc := gomongo.NewClient(db.Client)

result, err := gc.Execute(ctx, dbName, `db.hostInfo()`)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, 1, len(result.Value))

row := valueToJSON(result.Value[0])
require.Contains(t, row, `"ok"`)
})
}

func TestListCommands(t *testing.T) {
testutil.RunOnAllDBs(t, func(t *testing.T, db testutil.TestDB) {
dbName := fmt.Sprintf("testdb_list_cmds_%s", db.Name)
defer testutil.CleanupDatabase(t, db.Client, dbName)

ctx := context.Background()
gc := gomongo.NewClient(db.Client)

result, err := gc.Execute(ctx, dbName, `db.listCommands()`)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, 1, len(result.Value))

row := valueToJSON(result.Value[0])
require.Contains(t, row, `"ok"`)
require.Contains(t, row, `"commands"`)
})
}

func TestDataSize(t *testing.T) {
testutil.RunOnAllDBs(t, func(t *testing.T, db testutil.TestDB) {
dbName := fmt.Sprintf("testdb_data_size_%s", db.Name)
defer testutil.CleanupDatabase(t, db.Client, dbName)

ctx := context.Background()

_, err := db.Client.Database(dbName).Collection("users").InsertOne(ctx, bson.M{"name": "alice"})
require.NoError(t, err)

gc := gomongo.NewClient(db.Client)

result, err := gc.Execute(ctx, dbName, `db.users.dataSize()`)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, 1, len(result.Value))
// dataSize returns a numeric value (int32 or int64)
require.NotNil(t, result.Value[0])
})
}

func TestStorageSize(t *testing.T) {
testutil.RunOnAllDBs(t, func(t *testing.T, db testutil.TestDB) {
dbName := fmt.Sprintf("testdb_storage_size_%s", db.Name)
defer testutil.CleanupDatabase(t, db.Client, dbName)

ctx := context.Background()

_, err := db.Client.Database(dbName).Collection("users").InsertOne(ctx, bson.M{"name": "alice"})
require.NoError(t, err)

gc := gomongo.NewClient(db.Client)

result, err := gc.Execute(ctx, dbName, `db.users.storageSize()`)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, 1, len(result.Value))
require.NotNil(t, result.Value[0])
})
}

func TestTotalIndexSize(t *testing.T) {
testutil.RunOnAllDBs(t, func(t *testing.T, db testutil.TestDB) {
dbName := fmt.Sprintf("testdb_total_idx_size_%s", db.Name)
defer testutil.CleanupDatabase(t, db.Client, dbName)

ctx := context.Background()

_, err := db.Client.Database(dbName).Collection("users").InsertOne(ctx, bson.M{"name": "alice"})
require.NoError(t, err)

gc := gomongo.NewClient(db.Client)

result, err := gc.Execute(ctx, dbName, `db.users.totalIndexSize()`)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, 1, len(result.Value))
require.NotNil(t, result.Value[0])
})
}

func TestTotalSize(t *testing.T) {
testutil.RunOnAllDBs(t, func(t *testing.T, db testutil.TestDB) {
dbName := fmt.Sprintf("testdb_total_size_%s", db.Name)
defer testutil.CleanupDatabase(t, db.Client, dbName)

ctx := context.Background()

_, err := db.Client.Database(dbName).Collection("users").InsertOne(ctx, bson.M{"name": "alice"})
require.NoError(t, err)

gc := gomongo.NewClient(db.Client)

result, err := gc.Execute(ctx, dbName, `db.users.totalSize()`)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, 1, len(result.Value))
// totalSize is int64 (storageSize + totalIndexSize)
_, ok := result.Value[0].(int64)
require.True(t, ok, "expected int64, got %T", result.Value[0])
})
}

func TestIsCapped(t *testing.T) {
testutil.RunOnAllDBs(t, func(t *testing.T, db testutil.TestDB) {
dbName := fmt.Sprintf("testdb_is_capped_%s", db.Name)
defer testutil.CleanupDatabase(t, db.Client, dbName)

ctx := context.Background()

// Regular collection should not be capped
_, err := db.Client.Database(dbName).Collection("users").InsertOne(ctx, bson.M{"name": "alice"})
require.NoError(t, err)

gc := gomongo.NewClient(db.Client)

result, err := gc.Execute(ctx, dbName, `db.users.isCapped()`)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, 1, len(result.Value))

capped, ok := result.Value[0].(bool)
require.True(t, ok)
require.False(t, capped)
})
}

func TestIsCappedTrue(t *testing.T) {
testutil.RunOnMongoDBOnly(t, func(t *testing.T, db testutil.TestDB) {
dbName := fmt.Sprintf("testdb_is_capped_true_%s", db.Name)
defer testutil.CleanupDatabase(t, db.Client, dbName)

ctx := context.Background()
gc := gomongo.NewClient(db.Client)

// Create a capped collection
_, err := gc.Execute(ctx, dbName, `db.createCollection("capped_coll", { capped: true, size: 1048576 })`)
require.NoError(t, err)

result, err := gc.Execute(ctx, dbName, `db.capped_coll.isCapped()`)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, 1, len(result.Value))

capped, ok := result.Value[0].(bool)
require.True(t, ok)
require.True(t, capped)
})
}

func TestValidate(t *testing.T) {
testutil.RunOnAllDBs(t, func(t *testing.T, db testutil.TestDB) {
dbName := fmt.Sprintf("testdb_validate_%s", db.Name)
defer testutil.CleanupDatabase(t, db.Client, dbName)

ctx := context.Background()

_, err := db.Client.Database(dbName).Collection("users").InsertOne(ctx, bson.M{"name": "alice"})
require.NoError(t, err)

gc := gomongo.NewClient(db.Client)

result, err := gc.Execute(ctx, dbName, `db.users.validate()`)
require.NoError(t, err)
require.NotNil(t, result)
require.Equal(t, 1, len(result.Value))

row := valueToJSON(result.Value[0])
require.Contains(t, row, `"ok"`)
require.Contains(t, row, `"ns"`)
})
}

func TestLatencyStats(t *testing.T) {
// latencyStats uses $collStats aggregation which may not be available on all platforms
testutil.RunOnMongoDBOnly(t, func(t *testing.T, db testutil.TestDB) {
dbName := fmt.Sprintf("testdb_latency_%s", db.Name)
defer testutil.CleanupDatabase(t, db.Client, dbName)

ctx := context.Background()

_, err := db.Client.Database(dbName).Collection("users").InsertOne(ctx, bson.M{"name": "alice"})
require.NoError(t, err)

gc := gomongo.NewClient(db.Client)

result, err := gc.Execute(ctx, dbName, `db.users.latencyStats()`)
require.NoError(t, err)
require.NotNil(t, result)
require.GreaterOrEqual(t, len(result.Value), 1)

row := valueToJSON(result.Value[0])
require.Contains(t, row, `"latencyStats"`)
})
}
7 changes: 7 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,15 @@ func NewClient(client *mongo.Client) *Client {
// - OpShowDatabases, OpShowCollections, OpGetCollectionNames: each element is string
// - OpInsertOne, OpInsertMany, OpUpdateOne, OpUpdateMany, OpReplaceOne, OpDeleteOne, OpDeleteMany: single bson.D with operation result
// - OpCreateIndex: single element of string (index name)
// - OpCreateIndexes: each element is string (index name)
// - OpDropIndex, OpDropIndexes, OpCreateCollection, OpDropDatabase, OpRenameCollection: single bson.D with {ok: 1}
// - OpDrop: single element of bool (true)
// - OpDbStats, OpCollectionStats, OpServerStatus, OpServerBuildInfo, OpHostInfo, OpListCommands, OpValidate: single bson.D (command result)
// - OpDbVersion: single element of string (version)
// - OpDataSize, OpStorageSize, OpTotalIndexSize: single numeric value from collStats
// - OpTotalSize: single int64 (storageSize + totalIndexSize)
// - OpIsCapped: single element of bool
// - OpLatencyStats: each element is bson.D (aggregation result)
type Result struct {
Operation types.OperationType
Value []any
Expand Down
Loading