PT-1741 Migrated Go pt-mongo-tools to new driver

This commit is contained in:
Carlos Salguero
2019-08-02 11:53:39 -03:00
parent e3409c720f
commit c388bbc01c
34 changed files with 1791 additions and 1304 deletions

View File

@@ -1,411 +1,106 @@
package main
import (
"context"
"fmt"
"io/ioutil"
"os"
"reflect"
"testing"
"time"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"gopkg.in/mgo.v2/dbtest"
"github.com/golang/mock/gomock"
"github.com/pborman/getopt"
"github.com/percona/percona-toolkit/src/go/lib/tutil"
tu "github.com/percona/percona-toolkit/src/go/internal/testutils"
"github.com/percona/percona-toolkit/src/go/mongolib/proto"
"github.com/percona/pmgo"
"github.com/percona/pmgo/pmgomock"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func TestGetOpCounterStats(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
session := pmgomock.NewMockSessionManager(ctrl)
database := pmgomock.NewMockDatabaseManager(ctrl)
ss := proto.ServerStatus{}
if err := tutil.LoadJson("test/sample/serverstatus.json", &ss); err != nil {
t.Fatalf("Cannot load sample file: %s", err)
}
session.EXPECT().DB("admin").Return(database)
database.EXPECT().Run(bson.D{
{Name: "serverStatus", Value: 1},
{Name: "recordStats", Value: 1},
}, gomock.Any()).SetArg(1, ss)
session.EXPECT().DB("admin").Return(database)
database.EXPECT().Run(bson.D{
{Name: "serverStatus", Value: 1},
{Name: "recordStats", Value: 1},
}, gomock.Any()).SetArg(1, ss)
session.EXPECT().DB("admin").Return(database)
database.EXPECT().Run(bson.D{
{Name: "serverStatus", Value: 1},
{Name: "recordStats", Value: 1},
}, gomock.Any()).SetArg(1, ss)
session.EXPECT().DB("admin").Return(database)
database.EXPECT().Run(bson.D{
{Name: "serverStatus", Value: 1},
{Name: "recordStats", Value: 1},
}, gomock.Any()).SetArg(1, ss)
session.EXPECT().DB("admin").Return(database)
database.EXPECT().Run(bson.D{
{Name: "serverStatus", Value: 1},
{Name: "recordStats", Value: 1},
}, gomock.Any()).SetArg(1, ss)
ss = addToCounters(ss, 1)
session.EXPECT().DB("admin").Return(database)
database.EXPECT().Run(bson.D{
{Name: "serverStatus", Value: 1}, {Name: "recordStats", Value: 1},
}, gomock.Any()).SetArg(1, ss)
sampleCount := 5
sampleRate := 10 * time.Millisecond // in seconds
expect := TimedStats{Min: 0, Max: 0, Total: 0, Avg: 0}
os, err := getOpCountersStats(session, sampleCount, sampleRate)
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(expect, os.Command) {
t.Errorf("getOpCountersStats. got: %+v\nexpect: %+v\n", os.Command, expect)
}
}
func TestSecurityOpts(t *testing.T) {
cmdopts := []proto.CommandLineOptions{
// 1
{
Parsed: proto.Parsed{
Net: proto.Net{
SSL: proto.SSL{
Mode: "",
},
},
},
Security: proto.Security{
KeyFile: "",
Authorization: "",
},
},
// 2
{
Parsed: proto.Parsed{
Net: proto.Net{
SSL: proto.SSL{
Mode: "",
},
},
},
Security: proto.Security{
KeyFile: "a file",
Authorization: "",
},
},
// 3
{
Parsed: proto.Parsed{
Net: proto.Net{
SSL: proto.SSL{
Mode: "",
},
},
},
Security: proto.Security{
KeyFile: "",
Authorization: "something here",
},
},
// 4
{
Parsed: proto.Parsed{
Net: proto.Net{
SSL: proto.SSL{
Mode: "super secure",
},
},
},
Security: proto.Security{
KeyFile: "",
Authorization: "",
},
},
// 5
{
Parsed: proto.Parsed{
Net: proto.Net{
SSL: proto.SSL{
Mode: "",
},
},
Security: proto.Security{
KeyFile: "/home/plavi/psmdb/percona-server-mongodb-3.4.0-1.0-beta-6320ac4/data/keyfile",
},
},
Security: proto.Security{
KeyFile: "",
Authorization: "",
},
},
}
expect := []*security{
// 1
{
Users: 1,
Roles: 2,
Auth: "disabled",
SSL: "disabled",
BindIP: "",
Port: 0,
WarningMsgs: nil,
},
// 2
{
Users: 1,
Roles: 2,
Auth: "enabled",
SSL: "disabled",
BindIP: "", Port: 0,
WarningMsgs: nil,
},
// 3
{
Users: 1,
Roles: 2,
Auth: "enabled",
SSL: "disabled",
BindIP: "",
Port: 0,
WarningMsgs: nil,
},
// 4
{
Users: 1,
Roles: 2,
Auth: "disabled",
SSL: "super secure",
BindIP: "",
Port: 0,
WarningMsgs: nil,
},
// 5
{
Users: 1,
Roles: 2,
Auth: "enabled",
SSL: "disabled",
BindIP: "",
Port: 0,
WarningMsgs: nil,
},
}
ctrl := gomock.NewController(t)
defer ctrl.Finish()
session := pmgomock.NewMockSessionManager(ctrl)
database := pmgomock.NewMockDatabaseManager(ctrl)
usersCol := pmgomock.NewMockCollectionManager(ctrl)
rolesCol := pmgomock.NewMockCollectionManager(ctrl)
for i, cmd := range cmdopts {
session.EXPECT().DB("admin").Return(database)
database.EXPECT().Run(bson.D{
{Name: "getCmdLineOpts", Value: 1}, {Name: "recordStats", Value: 1},
}, gomock.Any()).SetArg(1, cmd)
session.EXPECT().Clone().Return(session)
session.EXPECT().SetMode(mgo.Strong, true)
session.EXPECT().DB("admin").Return(database)
database.EXPECT().C("system.users").Return(usersCol)
usersCol.EXPECT().Count().Return(1, nil)
session.EXPECT().DB("admin").Return(database)
database.EXPECT().C("system.roles").Return(rolesCol)
rolesCol.EXPECT().Count().Return(2, nil)
session.EXPECT().Close().Return()
got, err := getSecuritySettings(session, "3.2")
if err != nil {
t.Errorf("cannot get sec settings: %v", err)
}
if !reflect.DeepEqual(got, expect[i]) {
t.Errorf("Test # %d,\ngot: %#v\nwant: %#v\n", i+1, got, expect[i])
}
}
}
func TestGetNodeType(t *testing.T) {
md := []struct {
in proto.MasterDoc
out string
func TestGetHostInfo(t *testing.T) {
testCases := []struct {
name string
uri string
want []string
}{
{proto.MasterDoc{SetName: "name"}, "replset"},
{proto.MasterDoc{Msg: "isdbgrid"}, "mongos"},
{proto.MasterDoc{Msg: "a msg"}, "mongod"},
}
ctrl := gomock.NewController(t)
defer ctrl.Finish()
session := pmgomock.NewMockSessionManager(ctrl)
for _, m := range md {
session.EXPECT().Run("isMaster", gomock.Any()).SetArg(1, m.in)
nodeType, err := getNodeType(session)
if err != nil {
t.Errorf("cannot get node type: %+v, error: %s\n", m.in, err)
}
if nodeType != m.out {
t.Errorf("invalid node type. got %s, expect: %s\n", nodeType, m.out)
}
}
session.EXPECT().Run("isMaster", gomock.Any()).Return(fmt.Errorf("some fake error"))
nodeType, err := getNodeType(session)
if err == nil {
t.Errorf("error expected, got nil")
}
if nodeType != "" {
t.Errorf("expected blank node type, got %s", nodeType)
}
}
func TestIsPrivateNetwork(t *testing.T) {
//privateCIDRs := []string{"10.0.0.0/24", "172.16.0.0/20", "192.168.0.0/16"}
testdata :=
[]struct {
ip string
want bool
err error
}{
{
ip: "127.0.0.1",
want: true,
err: nil,
},
{
ip: "10.0.0.1",
want: true,
err: nil,
},
{
ip: "10.0.1.1",
want: false,
err: nil,
},
{
ip: "172.16.1.2",
want: true,
err: nil,
},
{
ip: "192.168.1.2",
want: true,
err: nil,
},
{
ip: "8.8.8.8",
want: false,
err: nil,
},
}
for _, in := range testdata {
got, err := isPrivateNetwork(in.ip)
if err != in.err {
t.Errorf("ip %s. got err: %s, want err: %v", in.ip, err, in.err)
}
if got != in.want {
t.Errorf("ip %s. got: %v, want : %v", in.ip, got, in.want)
}
}
}
func TestGetChunks(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
session := pmgomock.NewMockSessionManager(ctrl)
database := pmgomock.NewMockDatabaseManager(ctrl)
pipe := pmgomock.NewMockPipeManager(ctrl)
col := pmgomock.NewMockCollectionManager(ctrl)
var res []proto.ChunksByCollection
if err := tutil.LoadJson("test/sample/chunks.json", &res); err != nil {
t.Errorf("Cannot load samples file: %s", err)
}
pipe.EXPECT().All(gomock.Any()).SetArg(0, res)
col.EXPECT().Pipe(gomock.Any()).Return(pipe)
database.EXPECT().C("chunks").Return(col)
session.EXPECT().DB("config").Return(database)
want := []proto.ChunksByCollection{
{ID: "samples.col2", Count: 5},
}
got, err := getChunksCount(session)
if err != nil {
t.Errorf("Cannot get chunks: %s", err.Error())
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Invalid getChunksCount response.\ngot: %+v\nwant: %+v\n", got, want)
}
}
func TestIntegrationGetChunks(t *testing.T) {
var server dbtest.DBServer
os.Setenv("CHECK_SESSIONS", "0")
tempDir, _ := ioutil.TempDir("", "testing")
server.SetPath(tempDir)
session := pmgo.NewSessionManager(server.Session())
if err := session.DB("config").C("chunks").Insert(bson.M{"ns": "samples.col1", "count": 2}); err != nil {
t.Errorf("Cannot insert sample data: %s", err)
}
want := []proto.ChunksByCollection{
{
ID: "samples.col1",
Count: 1,
name: "from_mongos",
uri: fmt.Sprintf("mongodb://%s:%s@%s:%s", tu.MongoDBUser, tu.MongoDBPassword, tu.MongoDBHost, tu.MongoDBMongosPort),
want: []string{"127.0.0.1:17001", "127.0.0.1:17002", "127.0.0.1:17004", "127.0.0.1:17005", "127.0.0.1:17007"},
},
{
name: "from_mongod",
uri: fmt.Sprintf("mongodb://%s:%s@%s:%s", tu.MongoDBUser, tu.MongoDBPassword, tu.MongoDBHost, tu.MongoDBShard1PrimaryPort),
want: []string{"127.0.0.1:17001", "127.0.0.1:17002", "127.0.0.1:17003"},
},
{
name: "from_non_sharded",
uri: fmt.Sprintf("mongodb://%s:%s@%s:%s", tu.MongoDBUser, tu.MongoDBPassword, tu.MongoDBHost, tu.MongoDBShard3PrimaryPort),
want: []string{"127.0.0.1:17021", "127.0.0.1:17022", "127.0.0.1:17023"},
},
}
got, err := getChunksCount(session)
if err != nil {
t.Errorf("Error in integration chunks count: %s", err.Error())
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
client, err := mongo.NewClient(options.Client().ApplyURI(test.uri))
if err != nil {
t.Fatalf("cannot get a new MongoDB client: %s", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
err = client.Connect(ctx)
if err != nil {
t.Fatalf("Cannot connect to MongoDB: %s", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Invalid integration chunks count.\ngot: %+v\nwant: %+v", got, want)
_, err = getHostInfo(ctx, client)
if err != nil {
t.Errorf("getHostnames: %v", err)
}
})
}
if err := server.Session().DB("config").DropDatabase(); err != nil {
t.Logf("Cannot drop config database (cleanup): %s", err)
}
server.Session().Close()
server.Stop()
}
func TestClusterWideInfo(t *testing.T) {
testCases := []struct {
name string
uri string
want []string
}{
{
name: "from_mongos",
uri: fmt.Sprintf("mongodb://%s:%s@%s:%s", tu.MongoDBUser, tu.MongoDBPassword, tu.MongoDBHost, tu.MongoDBMongosPort),
want: []string{"127.0.0.1:17001", "127.0.0.1:17002", "127.0.0.1:17004", "127.0.0.1:17005", "127.0.0.1:17007"},
},
{
name: "from_mongod",
uri: fmt.Sprintf("mongodb://%s:%s@%s:%s", tu.MongoDBUser, tu.MongoDBPassword, tu.MongoDBHost, tu.MongoDBShard1PrimaryPort),
want: []string{"127.0.0.1:17001", "127.0.0.1:17002", "127.0.0.1:17003"},
},
{
name: "from_non_sharded",
uri: fmt.Sprintf("mongodb://%s:%s@%s:%s", tu.MongoDBUser, tu.MongoDBPassword, tu.MongoDBHost, tu.MongoDBShard3PrimaryPort),
want: []string{"127.0.0.1:17021", "127.0.0.1:17022", "127.0.0.1:17023"},
},
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
client, err := mongo.NewClient(options.Client().ApplyURI(test.uri))
if err != nil {
t.Fatalf("cannot get a new MongoDB client: %s", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
err = client.Connect(ctx)
if err != nil {
t.Fatalf("Cannot connect to MongoDB: %s", err)
}
_, err = getClusterwideInfo(ctx, client)
if err != nil {
t.Errorf("getClisterWideInfo error: %v", err)
}
})
}
}
func addToCounters(ss proto.ServerStatus, increment int64) proto.ServerStatus {
ss.Opcounters.Command += increment
ss.Opcounters.Delete += increment
@@ -419,11 +114,11 @@ func addToCounters(ss proto.ServerStatus, increment int64) proto.ServerStatus {
func TestParseArgs(t *testing.T) {
tests := []struct {
args []string
want *options
want *cliOptions
}{
{
args: []string{TOOLNAME}, // arg[0] is the command itself
want: &options{
want: &cliOptions{
Host: DefaultHost,
LogLevel: DefaultLogLevel,
AuthDB: DefaultAuthDB,
@@ -456,5 +151,4 @@ func TestParseArgs(t *testing.T) {
}
os.Stdout = old
}