func testHandler(req *http.Request, t *testing.T) { response := httptest.NewRecorder() TxLogger.Send("test msg") txlogzHandler(response, req) if !strings.Contains(response.Body.String(), "error") { t.Fatalf("should show an error page since transaction log format is invalid.") } txConn := &TxConnection{ TransactionID: 123456, StartTime: time.Now(), Queries: []string{"select * from test"}, Conclusion: "unknown", LogToFile: sync2.AtomicInt32{}, EffectiveCallerID: callerid.NewEffectiveCallerID("effective-caller", "component", "subcomponent"), ImmediateCallerID: callerid.NewImmediateCallerID("immediate-caller"), } txConn.EndTime = txConn.StartTime response = httptest.NewRecorder() TxLogger.Send(txConn) txlogzHandler(response, req) txConn.EndTime = txConn.StartTime.Add(time.Duration(2) * time.Second) response = httptest.NewRecorder() TxLogger.Send(txConn) txlogzHandler(response, req) txConn.EndTime = txConn.StartTime.Add(time.Duration(500) * time.Millisecond) response = httptest.NewRecorder() TxLogger.Send(txConn) txlogzHandler(response, req) }
// testCallerID adds a caller ID to a context, and makes sure the server // gets it. func testCallerID(t *testing.T, conn *vtgateconn.VTGateConn) { t.Log("testCallerID") ctx := context.Background() callerID := callerid.NewEffectiveCallerID("test_principal", "test_component", "test_subcomponent") ctx = callerid.NewContext(ctx, callerID, nil) data, err := json.Marshal(callerID) if err != nil { t.Errorf("failed to marshal callerid: %v", err) return } query := services.CallerIDPrefix + string(data) // test Execute forwards the callerID if _, err := conn.Execute(ctx, query, nil, pb.TabletType_MASTER); err != nil { t.Errorf("failed to pass callerid: %v", err) } // FIXME(alainjobart) add all function calls }
func TestQuerylogzHandler(t *testing.T) { req, _ := http.NewRequest("GET", "/querylogz?timeout=10&limit=1", nil) logStats := newLogStats("Execute", context.Background()) logStats.PlanType = planbuilder.PlanPassSelect.String() logStats.OriginalSQL = "select name from test_table limit 1000" logStats.RowsAffected = 1000 logStats.NumberOfQueries = 1 logStats.StartTime, _ = time.Parse("Jan 2 15:04:05", "Nov 29 13:33:09") logStats.MysqlResponseTime = 1 * time.Millisecond logStats.WaitingForConnection = 10 * time.Nanosecond logStats.TransactionID = 131 logStats.ctx = callerid.NewContext( context.Background(), callerid.NewEffectiveCallerID("effective-caller", "component", "subcomponent"), callerid.NewImmediateCallerID("immediate-caller"), ) // fast query fastQueryPattern := []string{ `<td>Execute</td>`, `<td></td>`, `<td>effective-caller</td>`, `<td>immediate-caller</td>`, `<td>Nov 29 13:33:09.000000</td>`, `<td>Nov 29 13:33:09.001000</td>`, `<td>0.001</td>`, `<td>0.001</td>`, `<td>1e-08</td>`, `<td>PASS_SELECT</td>`, `<td>select name from test_table limit 1000</td>`, `<td>1</td>`, `<td>none</td>`, `<td>1000</td>`, `<td>0</td>`, `<td>131</td>`, `<td></td>`, } logStats.EndTime = logStats.StartTime.Add(1 * time.Millisecond) response := httptest.NewRecorder() ch := make(chan interface{}, 1) ch <- logStats querylogzHandler(ch, response, req) close(ch) body, _ := ioutil.ReadAll(response.Body) checkQuerylogzHasStats(t, fastQueryPattern, logStats, body) // medium query mediumQueryPattern := []string{ `<td>Execute</td>`, `<td></td>`, `<td>effective-caller</td>`, `<td>immediate-caller</td>`, `<td>Nov 29 13:33:09.000000</td>`, `<td>Nov 29 13:33:09.020000</td>`, `<td>0.02</td>`, `<td>0.001</td>`, `<td>1e-08</td>`, `<td>PASS_SELECT</td>`, `<td>select name from test_table limit 1000</td>`, `<td>1</td>`, `<td>none</td>`, `<td>1000</td>`, `<td>0</td>`, `<td>131</td>`, `<td></td>`, } logStats.EndTime = logStats.StartTime.Add(20 * time.Millisecond) response = httptest.NewRecorder() ch = make(chan interface{}, 1) ch <- logStats querylogzHandler(ch, response, req) close(ch) body, _ = ioutil.ReadAll(response.Body) checkQuerylogzHasStats(t, mediumQueryPattern, logStats, body) // slow query slowQueryPattern := []string{ `<td>Execute</td>`, `<td></td>`, `<td>effective-caller</td>`, `<td>immediate-caller</td>`, `<td>Nov 29 13:33:09.000000</td>`, `<td>Nov 29 13:33:09.500000</td>`, `<td>0.5</td>`, `<td>0.001</td>`, `<td>1e-08</td>`, `<td>PASS_SELECT</td>`, `<td>select name from test_table limit 1000</td>`, `<td>1</td>`, `<td>none</td>`, `<td>1000</td>`, `<td>0</td>`, `<td>131</td>`, `<td></td>`, } logStats.EndTime = logStats.StartTime.Add(500 * time.Millisecond) ch = make(chan interface{}, 1) ch <- logStats querylogzHandler(ch, response, req) close(ch) body, _ = ioutil.ReadAll(response.Body) checkQuerylogzHasStats(t, slowQueryPattern, logStats, body) }
} entityKeyspaceIDsEcho = "[xid_type:INT64 xid_value:\"123\" keyspace_id:\"\\001\\002\\003\" xid_type:FLOAT64 xid_value:\"2\" keyspace_id:\"\\004\\005\\006\" xid_type:VARBINARY xid_value:\"\\001\\002\\003\" keyspace_id:\"\\007\\010\\t\" ]" tabletType = pbt.TabletType_REPLICA tabletTypeEcho = pbt.TabletType_name[int32(tabletType)] bindVars = map[string]interface{}{ "int": 123, "float": 2.0, "bytes": []byte{1, 2, 3}, } bindVarsEcho = "map[bytes:[1 2 3] float:2 int:123]" sessionEcho = "in_transaction:true " callerID = callerid.NewEffectiveCallerID("test_principal", "test_component", "test_subcomponent") callerIDEcho = "principal:\"test_principal\" component:\"test_component\" subcomponent:\"test_subcomponent\" " ) // testEcho exercises the test cases provided by the "echo" service. func testEcho(t *testing.T, conn *vtgateconn.VTGateConn) { testEchoExecute(t, conn) testEchoStreamExecute(t, conn) testEchoTransactionExecute(t, conn) testEchoSplitQuery(t, conn) } func testEchoExecute(t *testing.T, conn *vtgateconn.VTGateConn) { var qr *mproto.QueryResult var err error
// GoRPCEffectiveCallerID creates new EffectiveCallerID(vtrpcpb.CallerID) // from GoRPC's CallerID func GoRPCEffectiveCallerID(c *CallerID) *vtrpcpb.CallerID { if c == nil { return nil } return callerid.NewEffectiveCallerID(c.Principal, c.Component, c.Subcomponent) }
// testCallerID adds a caller ID to a context, and makes sure the server // gets it. func testCallerID(t *testing.T, conn *vtgateconn.VTGateConn) { t.Log("testCallerID") ctx := context.Background() callerID := callerid.NewEffectiveCallerID("test_principal", "test_component", "test_subcomponent") ctx = callerid.NewContext(ctx, callerID, nil) data, err := json.Marshal(callerID) if err != nil { t.Errorf("failed to marshal callerid: %v", err) return } query := services.CallerIDPrefix + string(data) // test Execute calls forward the callerID _, err = conn.Execute(ctx, query, nil, topodatapb.TabletType_MASTER, nil) checkCallerIDError(t, "Execute", err) _, err = conn.ExecuteShards(ctx, query, "", nil, nil, topodatapb.TabletType_MASTER, nil) checkCallerIDError(t, "ExecuteShards", err) _, err = conn.ExecuteKeyspaceIds(ctx, query, "", nil, nil, topodatapb.TabletType_MASTER, nil) checkCallerIDError(t, "ExecuteKeyspaceIds", err) _, err = conn.ExecuteKeyRanges(ctx, query, "", nil, nil, topodatapb.TabletType_MASTER, nil) checkCallerIDError(t, "ExecuteKeyRanges", err) _, err = conn.ExecuteEntityIds(ctx, query, "", "", nil, nil, topodatapb.TabletType_MASTER, nil) checkCallerIDError(t, "ExecuteEntityIds", err) // test ExecuteBatch calls forward the callerID _, err = conn.ExecuteBatchShards(ctx, []*vtgatepb.BoundShardQuery{ { Query: &querypb.BoundQuery{ Sql: query, }, }, }, topodatapb.TabletType_MASTER, false, nil) checkCallerIDError(t, "ExecuteBatchShards", err) _, err = conn.ExecuteBatchKeyspaceIds(ctx, []*vtgatepb.BoundKeyspaceIdQuery{ { Query: &querypb.BoundQuery{ Sql: query, }, }, }, topodatapb.TabletType_MASTER, false, nil) checkCallerIDError(t, "ExecuteBatchKeyspaceIds", err) // test StreamExecute calls forward the callerID err = getStreamError(conn.StreamExecute(ctx, query, nil, topodatapb.TabletType_MASTER, nil)) checkCallerIDError(t, "StreamExecute", err) err = getStreamError(conn.StreamExecuteShards(ctx, query, "", nil, nil, topodatapb.TabletType_MASTER, nil)) checkCallerIDError(t, "StreamExecuteShards", err) err = getStreamError(conn.StreamExecuteKeyspaceIds(ctx, query, "", nil, nil, topodatapb.TabletType_MASTER, nil)) checkCallerIDError(t, "StreamExecuteKeyspaceIds", err) err = getStreamError(conn.StreamExecuteKeyRanges(ctx, query, "", nil, nil, topodatapb.TabletType_MASTER, nil)) checkCallerIDError(t, "StreamExecuteKeyRanges", err) // test UpdateStream forwards the callerID err = getUpdateStreamError(conn.UpdateStream(ctx, query, nil, topodatapb.TabletType_MASTER, 0, nil)) checkCallerIDError(t, "UpdateStream", err) }