Example #1
0
// TestEngineMerge tests that the passing through of engine merge operations
// to the goMerge function works as expected. The semantics are tested more
// exhaustively in the merge tests themselves.
func TestEngineMerge(t *testing.T) {
	runWithAllEngines(func(engine Engine, t *testing.T) {
		testKey := Key("haste not in life")
		merges := [][]byte{
			[]byte(encoding.MustGobEncode(Appender("x"))),
			[]byte(encoding.MustGobEncode(Appender("y"))),
			[]byte(encoding.MustGobEncode(Appender("z"))),
		}
		for i, update := range merges {
			if err := engine.Merge(testKey, update); err != nil {
				t.Fatalf("%d: %v", i, err)
			}
		}
		result, _ := engine.Get(testKey)
		if !bytes.Equal(encoding.MustGobDecode(result).(Appender), Appender("xyz")) {
			t.Errorf("unexpected append-merge result")
		}
	}, t)
}
Example #2
0
func TestEngineBatch(t *testing.T) {
	runWithAllEngines(func(engine Engine, t *testing.T) {
		numShuffles := 100
		key := Key("a")
		// Those are randomized below.
		batch := []interface{}{
			BatchPut{Key: key, Value: []byte("~ockroachDB")},
			BatchPut{Key: key, Value: []byte("C~ckroachDB")},
			BatchPut{Key: key, Value: []byte("Co~kroachDB")},
			BatchPut{Key: key, Value: []byte("Coc~roachDB")},
			BatchPut{Key: key, Value: []byte("C**k~oachDB")},
			BatchPut{Key: key, Value: []byte("Cockr~achDB")},
			BatchPut{Key: key, Value: []byte("Cockro~chDB")},
			BatchPut{Key: key, Value: []byte("Cockroa~hDB")},
			BatchPut{Key: key, Value: []byte("Cockroac~DB")},
			BatchPut{Key: key, Value: []byte("Cockroach~B")},
			BatchPut{Key: key, Value: []byte("CockroachD~")},
			BatchDelete(key),
			BatchMerge{Key: key, Value: encoding.MustGobEncode(Appender("C"))},
			BatchMerge{Key: key, Value: encoding.MustGobEncode(Appender(" o"))},
			BatchMerge{Key: key, Value: encoding.MustGobEncode(Appender("  c"))},
			BatchMerge{Key: key, Value: encoding.MustGobEncode(Appender(" k"))},
			BatchMerge{Key: key, Value: encoding.MustGobEncode(Appender("r"))},
			BatchMerge{Key: key, Value: encoding.MustGobEncode(Appender(" o"))},
			BatchMerge{Key: key, Value: encoding.MustGobEncode(Appender("  a"))},
			BatchMerge{Key: key, Value: encoding.MustGobEncode(Appender(" c"))},
			BatchMerge{Key: key, Value: encoding.MustGobEncode(Appender("h"))},
			BatchMerge{Key: key, Value: encoding.MustGobEncode(Appender(" D"))},
			BatchMerge{Key: key, Value: encoding.MustGobEncode(Appender("  B"))},
		}

		for i := 0; i < numShuffles; i++ {
			// In each run, create an array of shuffled operations.
			shuffledIndices := rand.Perm(len(batch))
			currentBatch := make([]interface{}, len(batch))
			for k := range currentBatch {
				currentBatch[k] = batch[shuffledIndices[k]]
			}
			// Reset the key
			engine.Clear(key)
			// Run it once with individual operations and remember the result.
			for _, op := range currentBatch {
				if err := engine.WriteBatch([]interface{}{op}); err != nil {
					t.Errorf("batch test: %d: op %v: %v", i, op, err)
					continue
				}
			}
			correctValue, _ := engine.Get(key)
			// Run the whole thing as a batch and compare.
			if err := engine.WriteBatch(currentBatch); err != nil {
				t.Errorf("batch test: %d: %v", i, err)
				continue
			}
			actualValue, _ := engine.Get(key)
			if !bytes.Equal(actualValue, correctValue) {
				t.Errorf("batch test: %d: result inconsistent", i)
			}
		}
	}, t)
}
Example #3
0
// TestGoMerge tests the function goMerge but not the integration with
// the storage engines. For that, see the engine tests.
func TestGoMerge(t *testing.T) {
	// Let's start with stuff that should go wrong.
	badCombinations := []struct {
		old, update interface{}
	}{
		{Counter(0), Appender("")},
		{[]byte("apple"), nil},
		{"", ""},
		{0, 0},
		{Appender(""), Counter(0)},
		{0, "asd"},
		{float64(1.3), Counter(0)},
		{Counter(0), nil},
	}
	for i, c := range badCombinations {
		_, err := goMerge(encoding.MustGobEncode(c.old), encoding.MustGobEncode(c.update))
		if err == nil {
			t.Errorf("goMerge: %d: expected error", i)
		}
	}

	testCasesCounter := []struct {
		old, update, expected Counter
		wantError             bool
	}{
		{0, 10, 10, false},
		{10, 20, 30, false},
		{595, -600, -5, false},
		// Close to overflow, but not quite there.
		{math.MinInt64 + 3, -3, math.MinInt64, false},
		{math.MaxInt64, 0, math.MaxInt64, false},
		// Overflows.
		{math.MaxInt64, 1, 0, true},
		{-1, math.MinInt64, 0, true},
	}

	gibber1, gibber2 := gibberishBytes(100), gibberishBytes(200)

	testCasesAppender := []struct {
		old, update, expected Appender
	}{
		{Appender(""), Appender(""), Appender("")},
		{nil, Appender(""), Appender("")},
		{nil, nil, nil},
		{Appender("\n "), Appender(" \t "), Appender("\n  \t ")},
		{Appender("ქართული"), Appender("\nKhartuli"), Appender("ქართული\nKhartuli")},
		{gibber1, gibber2, append(append([]byte(nil), gibber1...), gibber2...)},
	}

	for i, c := range testCasesCounter {
		oEncoded := encoding.MustGobEncode(c.old)
		uEncoded := encoding.MustGobEncode(c.update)

		result, err := goMerge(oEncoded, uEncoded)
		if c.wantError {
			if err == nil {
				t.Errorf("goMerge: %d: wanted error but got success", i)
			}
			continue
		}
		if err != nil {
			t.Errorf("goMerge error: %d: %v", i, err)
			continue
		}
		resultDecoded := encoding.MustGobDecode(result)
		if resultDecoded != c.expected {
			t.Errorf("goMerge error: %d: want %v, get %v", i, c.expected, result)
		}
	}
	for i, c := range testCasesAppender {
		oEncoded := encoding.MustGobEncode(c.old)
		uEncoded := encoding.MustGobEncode(c.update)

		result, err := goMerge(oEncoded, uEncoded)
		if err != nil {
			t.Errorf("goMerge error: %d: %v", i, err)
			continue
		}
		resultDecoded := encoding.MustGobDecode(result)
		if !bytes.Equal(resultDecoded.(Appender), c.expected) {
			t.Errorf("goMerge error: %d: want %v, get %v", i, c.expected, result)
		}
	}

}