// 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 }
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 }
// 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()) }
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) } }