Skip to content

Commit

Permalink
Implement dropUser command (#3866)
Browse files Browse the repository at this point in the history
Closes #1493.
  • Loading branch information
henvic authored Dec 20, 2023
1 parent 6a29fa9 commit eefeb0d
Show file tree
Hide file tree
Showing 5 changed files with 271 additions and 103 deletions.
14 changes: 6 additions & 8 deletions integration/users/create_user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func TestCreateUser(t *testing.T) {
} else {
// Erase any previously saved user in the database.
_, err := users.DeleteMany(ctx, bson.D{{"db", db.Name()}})
assert.NoError(t, err)
require.NoError(t, err)
}

testCases := map[string]struct { //nolint:vet // for readability
Expand Down Expand Up @@ -97,9 +97,7 @@ func TestCreateUser(t *testing.T) {
{"pwd", "password"},
},
expected: bson.D{
{
"ok", float64(1),
},
{"ok", float64(1)},
},
},
"WithComment": {
Expand All @@ -110,9 +108,7 @@ func TestCreateUser(t *testing.T) {
{"comment", "test string comment"},
},
expected: bson.D{
{
"ok", float64(1),
},
{"ok", float64(1)},
},
},
"MissingRoles": {
Expand All @@ -128,12 +124,14 @@ func TestCreateUser(t *testing.T) {
},
}

// The subtest "AlreadyExists" tries to create the following user, which should fail with an error that the user already exists.
// Here, we create the user for the very first time to populate the database.
err := db.RunCommand(ctx, bson.D{
{"createUser", "should_already_exist"},
{"roles", bson.A{}},
{"pwd", "password"},
}).Err()
assert.NoError(t, err)
require.NoError(t, err)

for name, tc := range testCases {
name, tc := name, tc
Expand Down
115 changes: 115 additions & 0 deletions integration/users/drop_user_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Copyright 2021 FerretDB 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 users

import (
"context"
"testing"

"github.com/stretchr/testify/require"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"

"github.com/FerretDB/FerretDB/integration"
"github.com/FerretDB/FerretDB/integration/setup"
"github.com/FerretDB/FerretDB/internal/util/must"
"github.com/FerretDB/FerretDB/internal/util/testutil"
)

func TestDropUser(t *testing.T) {
t.Parallel()

ctx, collection := setup.Setup(t)
db := collection.Database()
client := db.Client()
users := client.Database("admin").Collection("system.users")

// TODO https://github.com/FerretDB/FerretDB/issues/1492
if setup.IsMongoDB(t) {
require.NoError(t, collection.Database().RunCommand(ctx, bson.D{
{"dropAllUsersFromDatabase", 1},
}).Err())
} else {
// Erase any previously saved user in the database.
_, err := users.DeleteMany(ctx, bson.D{{"db", db.Name()}})
require.NoError(t, err)
}

err := db.RunCommand(ctx, bson.D{
{"createUser", "a_user"},
{"roles", bson.A{}},
{"pwd", "password"},
}).Err()
require.NoError(t, err)

testCases := map[string]struct { //nolint:vet // for readability
payload bson.D
err *mongo.CommandError
altMessage string
expected bson.D
}{
"NotFound": {
payload: bson.D{
{"dropUser", "not_found_user"},
},
err: &mongo.CommandError{
Code: 11,
Name: "UserNotFound",
Message: "User 'not_found_user@TestDropUser' not found",
},
},
"Success": {
payload: bson.D{
{"dropUser", "a_user"},
},
expected: bson.D{
{"ok", float64(1)},
},
},
}

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

var res bson.D
err := db.RunCommand(ctx, tc.payload).Decode(&res)
if tc.err != nil {
integration.AssertEqualAltCommandError(t, *tc.err, tc.altMessage, err)
return
}

require.NoError(t, err)

actual := integration.ConvertDocument(t, res)
actual.Remove("$clusterTime")
actual.Remove("operationTime")

expected := integration.ConvertDocument(t, tc.expected)
testutil.AssertEqual(t, expected, actual)

payload := integration.ConvertDocument(t, tc.payload)
assertUserNotFound(ctx, t, users, db.Name(), must.NotFail(payload.Get("dropUser")).(string))
})
}
}

// assertUserNotFound checks it the user doesn't exist in the admin.system.users collection.
func assertUserNotFound(ctx context.Context, t testing.TB, users *mongo.Collection, dbName, username string) {
t.Helper()
err := users.FindOne(ctx, bson.D{{"user", username}, {"db", dbName}}).Err()
require.Equal(t, mongo.ErrNoDocuments, err, `should return "no documents" error`)
}
3 changes: 3 additions & 0 deletions internal/handler/handlererrors/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ const (
// ErrFailedToParse indicates user input parsing failure.
ErrFailedToParse = ErrorCode(9) // FailedToParse

// ErrUserNotFound indicates an user was not found for the accessed database.
ErrUserNotFound = ErrorCode(11) // UserNotFound

// ErrUnauthorized indicates that cursor is not authorized to access another namespace.
ErrUnauthorized = ErrorCode(13) // Unauthorized

Expand Down
188 changes: 95 additions & 93 deletions internal/handler/handlererrors/errorcode_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit eefeb0d

Please sign in to comment.