Beispiel #1
0
// TestCommandsAgainstAuthedDBWhenAuthed tests some basic commands against a
// database that requires authenticaiton when the driver has proper
// authentication credentials
func TestCommandsAgainstAuthedDBWhenAuthed(t *testing.T) {
	if !authTestServerMode {
		t.Skipf("Skipping auth test with non-auth DB")
	}
	if err := teardownDB(); err != nil {
		t.Error(err)
	}
	numInserts := 20
	generator := newRecordedOpGenerator()
	docName := "Authed Insert Test"

	go func() {
		defer close(generator.opChan)
		t.Logf("Generating %d inserts\n", numInserts)
		err := generator.generateInsertHelper(docName, 0, numInserts)
		if err != nil {
			t.Error(err)
		}
	}()
	statCollector, _ := newStatCollector(testCollectorOpts, true, true)
	context := NewExecutionContext(statCollector)
	t.Logf("Beginning mongoreplay playback of generated traffic against host: %v\n", urlAuth)
	err := Play(context, generator.opChan, testSpeed, urlAuth, 1, 10)
	if err != nil {
		t.Error(err)
	}
	t.Log("Completed mongoreplay playback of generated traffic")

	session, err := mgo.Dial(urlAuth)
	coll := session.DB(testDB).C(testCollection)

	iter := coll.Find(bson.D{}).Sort("docNum").Iter()
	ind := 0
	result := testDoc{}

	t.Log("Querying database to ensure insert occured successfully")
	for iter.Next(&result) {
		t.Logf("Query result: %#v\n", result)
		if err := iter.Err(); err != nil {
			t.Errorf("Iterator returned an error: %v\n", err)
		}
		if result.DocumentNumber != ind {
			t.Errorf("Inserted document number did not match expected document number. Found: %v -- Expected: %v", result.DocumentNumber, ind)
		}
		if result.Name != "Authed Insert Test" {
			t.Errorf("Inserted document name did not match expected name. Found %v -- Expected: %v", result.Name, docName)
		}
		if !result.Success {
			t.Errorf("Inserted document field 'Success' was expected to be true, but was false")
		}
		ind++
	}
	if err := iter.Close(); err != nil {
		t.Error(err)
	}
	if err := teardownDB(); err != nil {
		t.Error(err)
	}

}
func setConnectionURL() error {
	var url string
	if os.Getenv("AUTH") == "1" {
		url = authTestServerURL
	} else {
		url = nonAuthTestServerURL
	}
	dialURL := fmt.Sprintf("%s:%v", url, defaultTestPort)
	if os.Getenv("AUTH") == "1" {
		dialURL += "/admin"
	}
	session, err := mgo.Dial(dialURL)
	if err != nil {
		return err
	}

	port, err := getTestDBPort(session)
	if err != nil {
		return err
	}
	urlNonAuth = fmt.Sprintf("%s:%s", nonAuthTestServerURL, port)
	urlAuth = fmt.Sprintf("%s:%v/admin", authTestServerURL, port)
	currentTestURL = urlNonAuth
	if os.Getenv("AUTH") == "1" {
		currentTestURL = urlAuth
	}
	return nil
}
Beispiel #3
0
func (context *ExecutionContext) newExecutionSession(url string, start time.Time, connectionNum int64) chan<- *RecordedOp {

	ch := make(chan *RecordedOp, 10000)

	context.SessionChansWaitGroup.Add(1)
	go func() {
		now := time.Now()
		var connected bool
		time.Sleep(start.Add(-5 * time.Second).Sub(now)) // Sleep until five seconds before the start time
		session, err := mgo.Dial(url)
		defer session.Close()
		if err == nil {
			userInfoLogger.Logvf(Info, "(Connection %v) New connection CREATED.", connectionNum)
			connected = true
		} else {
			userInfoLogger.Logvf(Info, "(Connection %v) New Connection FAILED: %v", connectionNum, err)
		}
		for recordedOp := range ch {
			var parsedOp Op
			var reply Replyable
			var err error
			msg := ""
			if connected {
				// Populate the op with the connection num it's being played on.
				// This allows it to be used for downstream reporting of stats.
				recordedOp.PlayedConnectionNum = connectionNum
				t := time.Now()
				if recordedOp.RawOp.Header.OpCode != OpCodeReply {
					if t.Before(recordedOp.PlayAt.Time) {
						time.Sleep(recordedOp.PlayAt.Sub(t))
					}
				}
				userInfoLogger.Logvf(DebugHigh, "(Connection %v) op %v", connectionNum, recordedOp.String())
				session.SetSocketTimeout(0)
				parsedOp, reply, err = context.Execute(recordedOp, session)
				if err != nil {
					toolDebugLogger.Logvf(Always, "context.Execute error: %v", err)
				}
			} else {
				parsedOp, err = recordedOp.Parse()
				if err != nil {
					toolDebugLogger.Logvf(Always, "Execution Session error: %v", err)
				}

				msg = fmt.Sprintf("Skipped on non-connected session (Connection %v)", connectionNum)
				toolDebugLogger.Logv(Always, msg)
			}
			if shouldCollectOp(parsedOp) {
				context.Collect(recordedOp, parsedOp, reply, msg)
			}
		}
		userInfoLogger.Logvf(Info, "(Connection %v) Connection ENDED.", connectionNum)
		context.SessionChansWaitGroup.Done()
	}()
	return ch
}
func teardownDB() error {
	session, err := mgo.Dial(currentTestURL)
	if err != nil {
		return err
	}

	session.DB(testDB).C(testCollection).DropCollection()
	session.Close()
	return nil
}
Beispiel #5
0
// TestCommandsAgainstAuthedDBWhenNotAuthed tests some basic commands against a
// database that requires authentication when the driver does not have proper
// authenticaiton. It generates a series of inserts and ensures that the docs
// they are attempting to insert are not later found in the database
func TestCommandsAgainstAuthedDBWhenNotAuthed(t *testing.T) {
	if !authTestServerMode {
		t.Skipf("Skipping auth test with non-auth DB")
	}
	if err := teardownDB(); err != nil {
		t.Error(err)
	}
	numInserts := 3
	generator := newRecordedOpGenerator()

	go func() {
		defer close(generator.opChan)

		t.Logf("Generating %d inserts\n", numInserts)
		err := generator.generateInsertHelper("Non-Authed Insert Test", 0, numInserts)
		if err != nil {
			t.Error(err)
		}
	}()
	statCollector, _ := newStatCollector(testCollectorOpts, true, true)
	context := NewExecutionContext(statCollector)
	err := Play(context, generator.opChan, testSpeed, urlNonAuth, 1, 10)
	if err != nil {
		t.Error(err)
	}
	t.Log("Completed mongoreplay playback of generated traffic")

	session, err := mgo.Dial(urlAuth)
	coll := session.DB(testDB).C(testCollection)

	t.Log("Performing query to ensure collection received no documents")

	num, err := coll.Find(bson.D{}).Count()
	if err != nil {
		t.Error(err)
	}
	if num != 0 {
		t.Errorf("Collection contained documents, expected it to be empty. Num: %d\n", num)
	}
	if err := teardownDB(); err != nil {
		t.Error(err)
	}

}
func TestMain(m *testing.M) {
	err := setConnectionURL()
	if err != nil {
		panic(err)
	}
	if os.Getenv("AUTH") == "1" {
		authTestServerMode = true
	} else {
		authTestServerMode = false
	}

	session, err := mgo.Dial(currentTestURL)
	if err != nil {
		panic(err)
	}
	res := &struct {
		Msg string
	}{}
	session.Run("ismaster", res)
	isMongosTestServer = (res.Msg == "isdbgrid")
	session.Close()

	os.Exit(m.Run())
}
Beispiel #7
0
func pcapTestHelper(t *testing.T, pcapFname string, preprocess bool, verifier verifyFunc) {

	pcapFile := "mongoreplay/testPcap/" + pcapFname
	if _, err := os.Stat(pcapFile); err != nil {
		t.Skipf("pcap file %v not present, skipping test", pcapFile)
	}

	if err := teardownDB(); err != nil {
		t.Error(err)
	}

	playbackFname := "pcap_test_run.tape"
	streamSettings := OpStreamSettings{
		PcapFile:      pcapFile,
		PacketBufSize: 9000,
	}
	t.Log("Opening op stream")
	ctx, err := getOpstream(streamSettings)
	if err != nil {
		t.Errorf("error opening opstream: %v\n", err)
	}

	playbackWriter, err := NewPlaybackWriter(playbackFname, false)
	defer os.Remove(playbackFname)
	if err != nil {
		t.Errorf("error opening playback file to write: %v\n", err)
	}

	t.Log("Recording playbackfile from pcap file")
	err = Record(ctx, playbackWriter, false)
	if err != nil {
		t.Errorf("error makign tape file: %v\n", err)
	}

	playbackReader, err := NewPlaybackFileReader(playbackFname, false)
	if err != nil {
		t.Errorf("error opening playback file to write: %v\n", err)
	}

	statCollector, _ := newStatCollector(testCollectorOpts, true, true)
	statRec := statCollector.StatRecorder.(*BufferedStatRecorder)
	context := NewExecutionContext(statCollector)

	var preprocessMap preprocessCursorManager
	if preprocess {
		opChan, errChan := NewOpChanFromFile(playbackReader, 1)
		preprocessMap, err := newPreprocessCursorManager(opChan)

		if err != nil {
			t.Errorf("error creating preprocess map: %v", err)
		}

		err = <-errChan
		if err != io.EOF {
			t.Errorf("error creating preprocess map: %v", err)
		}

		_, err = playbackReader.Seek(0, 0)
		if err != nil {
			t.Errorf("error seeking playbackfile: %v", err)
		}
		context.CursorIDMap = preprocessMap
	}

	opChan, errChan := NewOpChanFromFile(playbackReader, 1)

	t.Log("Reading ops from playback file")
	err = Play(context, opChan, testSpeed, currentTestURL, 1, 30)
	if err != nil {
		t.Errorf("error playing back recorded file: %v\n", err)
	}
	err = <-errChan
	if err != io.EOF {
		t.Errorf("error reading ops from file: %v\n", err)
	}
	//prepare a query for the database
	session, err := mgo.Dial(currentTestURL)
	if err != nil {
		t.Errorf("Error connecting to test server: %v", err)
	}
	verifier(t, session, statRec, &preprocessMap)

	if err := teardownDB(); err != nil {
		t.Error(err)
	}
}
func TestCommandOpInsertLiveDB(t *testing.T) {
	if err := teardownDB(); err != nil {
		t.Error(err)
	}
	if isMongosTestServer {
		t.Skipf("Skipping OpCommand test against mongos")
	}

	numInserts := 20
	insertName := "LiveDB CommandOp insert test"
	generator := newRecordedOpGenerator()
	go func() {
		defer close(generator.opChan)
		// generate numInserts RecordedOps
		t.Logf("Generating %d commandOp inserts\n", numInserts)
		err := generator.generateCommandOpInsertHelper(insertName, 0, numInserts)
		if err != nil {
			t.Error(err)
		}
	}()

	statCollector, _ := newStatCollector(testCollectorOpts, true, true)
	statRec := statCollector.StatRecorder.(*BufferedStatRecorder)
	context := NewExecutionContext(statCollector)

	// run mongoreplay's Play loop with the stubbed objects
	t.Logf("Beginning mongoreplay playback of generated traffic against host: %v\n", currentTestURL)
	err := Play(context, generator.opChan, testSpeed, currentTestURL, 1, 10)
	if err != nil {
		t.Errorf("Error Playing traffic: %v\n", err)
	}
	t.Log("Completed mongoreplay playback of generated traffic")

	// prepare a query for the database
	session, err := mgo.Dial(currentTestURL)
	if err != nil {
		t.Errorf("Error connecting to test server: %v", err)
	}

	coll := session.DB(testDB).C(testCollection)

	iter := coll.Find(bson.D{}).Sort("docNum").Iter()
	ind := 0
	result := testDoc{}

	// iterate over the results of the query and ensure they match expected documents
	t.Log("Querying database to ensure insert occured successfully")
	for iter.Next(&result) {
		t.Logf("Query result: %#v\n", result)
		if result.DocumentNumber != ind {
			t.Errorf("Inserted document number did not match expected document number. Found: %v -- Expected: %v", result.DocumentNumber, ind)
		}
		if result.Name != insertName {
			t.Errorf("Inserted document name did not match expected name. Found %v -- Expected: %v", result.Name, "LiveDB Insert Test")
		}
		if !result.Success {
			t.Errorf("Inserted document field 'Success' was expected to be true, but was false")
		}
		ind++
	}
	if err := iter.Close(); err != nil {
		t.Error(err)
	}

	// iterate over the operations found by the BufferedStatCollector
	t.Log("Examining collected stats to ensure they match expected")
	for i := 0; i < numInserts; i++ {
		stat := statRec.Buffer[i]
		t.Logf("Stat result: %#v\n", stat)
		// all commands should be inserts into mongoreplay.test
		if stat.OpType != "op_command" ||
			stat.Command != "insert" ||
			stat.Ns != "mongoreplay" {
			t.Errorf("Expected to see an insert into mongoreplay, but instead saw %v, %v into %v\n", stat.OpType, stat.Command, stat.Ns)
		}
	}

	if err := teardownDB(); err != nil {
		t.Error(err)
	}
}
// TestUpdateOpLiveDB tests the functionality of mongoreplay replaying an update
// against a live database Generates 20 recorded inserts and an update and
// passes them to the main execution of mongoreplay and queries the database to
// verify they were completed. It then checks its BufferedStatCollector to
// ensure the update matches what we expected.
func TestUpdateOpLiveDB(t *testing.T) {
	if err := teardownDB(); err != nil {
		t.Error(err)
	}

	numInserts := 20
	insertName := "LiveDB update test"
	generator := newRecordedOpGenerator()
	nameSpace := fmt.Sprintf("%s.%s", testDB, testCollection)
	flags := uint32(1<<1 | 1)

	docNum := bson.D{{"$lte", 9.0}}
	selector := bson.D{{"docNum", docNum}}
	change := bson.D{{"updated", true}}
	update := bson.D{{"$set", change}}
	updateOp := mgo.UpdateOp{
		Collection: nameSpace,
		Selector:   selector,
		Update:     update,
		Flags:      flags,
		Multi:      true,
		Upsert:     true,
	}

	go func() {
		defer close(generator.opChan)
		// generate numInserts RecordedOps
		t.Logf("Generating %d inserts\n", numInserts)
		err := generator.generateInsertHelper(insertName, 0, numInserts)
		if err != nil {
			t.Error(err)
		}
		recordedUpdate, err := generator.fetchRecordedOpsFromConn(&updateOp)
		if err != nil {
			t.Error(err)
		}
		generator.pushDriverRequestOps(recordedUpdate)

		t.Log("Generating getLastError")
		err = generator.generateGetLastError()
		if err != nil {
			t.Error(err)
		}
	}()

	statCollector, _ := newStatCollector(testCollectorOpts, true, true)
	statRec := statCollector.StatRecorder.(*BufferedStatRecorder)
	context := NewExecutionContext(statCollector)

	// run mongoreplay's Play loop with the stubbed objects
	t.Logf("Beginning mongoreplay playback of generated traffic against host: %v\n", currentTestURL)
	err := Play(context, generator.opChan, testSpeed, currentTestURL, 1, 10)
	if err != nil {
		t.Errorf("Error Playing traffic: %v\n", err)
	}
	t.Log("Completed mongoreplay playback of generated traffic")

	// prepare a query for the database
	session, err := mgo.Dial(currentTestURL)
	if err != nil {
		t.Errorf("Error connecting to test server: %v", err)
	}

	coll := session.DB(testDB).C(testCollection)

	iter := coll.Find(bson.D{}).Sort("docNum").Iter()
	ind := 0
	result := struct {
		DocumentNumber int    `bson:"docNum"`
		Name           string `bson:"name"`
		Updated        bool   `bson:"updated"`
	}{}

	// iterate over the results of the query and ensure they match expected documents
	t.Log("Querying database to ensure insert occured successfully")
	for iter.Next(&result) {
		t.Logf("Query result: %#v\n", result)
		if result.DocumentNumber != ind {
			t.Errorf("Inserted document number did not match expected document number. Found: %v -- Expected: %v", result.DocumentNumber, ind)
		}
		if result.Name != insertName {
			t.Errorf("Inserted document name did not match expected name. Found %v -- Expected: %v", result.Name, "LiveDB update test")
		}
		if result.DocumentNumber <= 9 {
			if result.Updated != true {
				t.Errorf("Document with number %v was supposed to be updated but wasn't", result.DocumentNumber)
			}
		}
		ind++
	}
	if err := iter.Close(); err != nil {
		t.Error(err)
	}

	// iterate over the operations found by the BufferedStatCollector
	t.Log("Examining collected stats to ensure they match expected")

	stat := statRec.Buffer[numInserts]
	t.Logf("Stat result: %#v\n", stat)
	// All commands should be inserts into mongoreplay.test
	if stat.OpType != "update" ||
		stat.Ns != "mongoreplay.test" {
		t.Errorf("Expected to see an update to mongoreplay.test, but instead saw %v, %v\n", stat.OpType, stat.Ns)
	}
	if err := teardownDB(); err != nil {
		t.Error(err)
	}
}