Beispiel #1
0
// createTestTable tries to create a new table named based on the passed in id.
// It is designed to be synced with a number of concurrent calls to this
// function. Before starting, it first signals a done on the start waitgroup
// and then will block until the signal channel is closed. Once closed, it will
// proceed to try to create the table. Once the table creation is finished (be
// it successful or not) it signals a done on the end waitgroup.
func createTestTable(
	t *testing.T,
	tc *testcluster.TestCluster,
	id int,
	db *gosql.DB,
	wgStart *sync.WaitGroup,
	wgEnd *sync.WaitGroup,
	signal chan struct{},
	completed chan int,
) {
	defer wgEnd.Done()

	wgStart.Done()
	<-signal

	tableSQL := fmt.Sprintf(`
		CREATE TABLE IF NOT EXISTS "test"."table_%d" (
			id INT PRIMARY KEY,
			val INT
		)`, id)

	for {
		if _, err := db.Exec(tableSQL); err != nil {
			if testutils.IsSQLRetryableError(err) {
				continue
			}
			t.Errorf("table %d: could not be created: %v", id, err)
			return
		}
		completed <- id
		break
	}
}
Beispiel #2
0
// queryRowScan performs first a QueryRow and follows that up with a Scan using
// a preexisting or new connection.
func (dc *dynamicClient) queryRowScan(query string, queryArgs, destArgs []interface{}) error {
	for dc.isRunning() {
		client, err := dc.getClient()
		if err != nil {
			return err
		}
		if err := client.QueryRow(
			query, queryArgs...,
		).Scan(destArgs...); err == nil || !testutils.IsSQLRetryableError(err) {
			return err
		}
	}
	return errTestFinished
}
Beispiel #3
0
// exec calls exec on a client using a preexisting or new connection.
func (dc *dynamicClient) exec(query string, args ...interface{}) (gosql.Result, error) {
	for dc.isRunning() {
		client, err := dc.getClient()
		if err != nil {
			return nil, err
		}
		if result, err := client.Exec(
			query, args...,
		); err == nil || !testutils.IsSQLRetryableError(err) {
			return result, err
		}
	}
	return nil, errTestFinished
}
Beispiel #4
0
// Verify accounts.
func verifyAccounts(t *testing.T, client *testClient) {
	var sum int
	testutils.SucceedsSoon(t, func() error {
		// Hold the read lock on the client to prevent it being restarted by
		// chaos monkey.
		client.RLock()
		defer client.RUnlock()
		err := client.db.QueryRow("SELECT SUM(balance) FROM bank.accounts").Scan(&sum)
		if err != nil && !testutils.IsSQLRetryableError(err) {
			t.Fatal(err)
		}
		return err
	})
	if sum != 0 {
		t.Fatalf("The bank is not in good order. Total value: %d", sum)
	}

}
Beispiel #5
0
// Continuously transfers money until done().
func transferMoneyLoop(idx int, state *testState, numAccounts, maxTransfer int) {
	client := &state.clients[idx]
	for !state.done() {
		if err := transferMoney(client, numAccounts, maxTransfer); err != nil {
			// Ignore some errors.
			if !testutils.IsSQLRetryableError(err) {
				// Report the err and terminate.
				state.errChan <- err
				break
			}
		} else {
			// Only advance the counts on a successful update.
			atomic.AddUint64(&client.count, 1)
		}
	}
	log.Infof(context.Background(), "client %d shutting down", idx)
	state.errChan <- nil
}