// testRandomSyntax performs all of the RSG setup and teardown for common // random syntax testing operations. It takes a closure where the random // expression should be generated and executed. It returns an error indicating // if the statement executed successfully. This is used to verify that at // least 1 success occurs (otherwise it is likely a bad test). func testRandomSyntax( t *testing.T, setup func(*gosql.DB) error, fn func(*gosql.DB, *rsg.RSG) error, ) { if *flagRSGTime == 0 { t.Skip("enable with '-rsg <duration>'") } params, _ := createTestServerParams() params.UseDatabase = "ident" s, db, _ := serverutils.StartServer(t, params) defer s.Stopper().Stop() if setup != nil { err := setup(db) if err != nil { t.Fatal(err) } } yBytes, err := ioutil.ReadFile(filepath.Join("parser", "sql.y")) if err != nil { t.Fatal(err) } r, err := rsg.NewRSG(timeutil.Now().UnixNano(), string(yBytes)) if err != nil { t.Fatal(err) } // Broadcast channel for all workers. done := make(chan struct{}) time.AfterFunc(*flagRSGTime, func() { close(done) }) var wg sync.WaitGroup var countsMu struct { syncutil.Mutex total, success int } worker := func() { defer wg.Done() for { select { case <-done: return default: } err := fn(db, r) countsMu.Lock() countsMu.total++ if err == nil { countsMu.success++ } countsMu.Unlock() } } wg.Add(*flagRSGGoRoutines) for i := 0; i < *flagRSGGoRoutines; i++ { go worker() } wg.Wait() t.Logf("%d executions, %d successful", countsMu.total, countsMu.success) if countsMu.success == 0 { t.Fatal("0 successful executions") } }
// testRandomSyntax performs all of the RSG setup and teardown for common random syntax testing operations. It takes f, a closure where the random expression should be generated and executed. It returns a boolean indicating if the statement executed successfully. This is used to verify that at least 1 success occurs (otherwise it is likely a bad test). func testRandomSyntax( t *testing.T, setup func(db *gosql.DB) error, f func(db *gosql.DB, r *rsg.RSG) (success bool), ) { if *flagRSGTime == 0 { t.Skip("enable with '-rsg <duration>'") } params, _ := createTestServerParams() params.UseDatabase = "ident" s, db, _ := serverutils.StartServer(t, params) defer s.Stopper().Stop() if setup != nil { err := setup(db) if err != nil { t.Fatal(err) } } y, err := ioutil.ReadFile(filepath.Join("parser", "sql.y")) if err != nil { t.Fatal(err) } r, err := rsg.NewRSG(timeutil.Now().UnixNano(), string(y)) if err != nil { t.Fatal(err) } // Broadcast channel for all workers. done := make(chan bool) var wg sync.WaitGroup var lock syncutil.Mutex var total, success int worker := func() { defer wg.Done() for { select { case <-done: return default: } s := f(db, r) lock.Lock() total++ if s { success++ } lock.Unlock() } } for i := 0; i < *flagRSGGoRoutines; i++ { go worker() wg.Add(1) } time.Sleep(*flagRSGTime) close(done) wg.Wait() t.Logf("%d executions, %d successful", total, success) if success == 0 { t.Fatal("0 successful executions") } }