mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-06 16:45:55 +00:00
This commit moves dependency management to use godep and the new experimental vendoring support in Go 1.5. NOTE: You must set `GO15VENDOREXPERIMENT` in your bash environment for vendoring to work properly! See the updated `README` for details.
447 lines
8.5 KiB
Go
447 lines
8.5 KiB
Go
// Copyright (C) 2012 Numerotron Inc.
|
|
// Use of this source code is governed by an MIT-style license
|
|
// that can be found in the LICENSE file.
|
|
|
|
package consistent
|
|
|
|
import (
|
|
"runtime"
|
|
"sort"
|
|
"strconv"
|
|
"testing"
|
|
"testing/quick"
|
|
)
|
|
|
|
func checkNum(num, expected int, t *testing.T) {
|
|
if num != expected {
|
|
t.Errorf("expected %d, got %d", expected, num)
|
|
}
|
|
}
|
|
|
|
func TestNew(t *testing.T) {
|
|
x := New()
|
|
if x == nil {
|
|
t.Errorf("expected obj")
|
|
}
|
|
checkNum(x.NumberOfReplicas, 20, t)
|
|
}
|
|
|
|
func TestAdd(t *testing.T) {
|
|
x := New()
|
|
x.Add("abcdefg")
|
|
checkNum(len(x.circle), 20, t)
|
|
checkNum(len(x.sortedHashes), 20, t)
|
|
if sort.IsSorted(x.sortedHashes) == false {
|
|
t.Errorf("expected sorted hashes to be sorted")
|
|
}
|
|
x.Add("qwer")
|
|
checkNum(len(x.circle), 40, t)
|
|
checkNum(len(x.sortedHashes), 40, t)
|
|
if sort.IsSorted(x.sortedHashes) == false {
|
|
t.Errorf("expected sorted hashes to be sorted")
|
|
}
|
|
}
|
|
|
|
func TestRemove(t *testing.T) {
|
|
x := New()
|
|
x.Add("abcdefg")
|
|
x.Remove("abcdefg")
|
|
checkNum(len(x.circle), 0, t)
|
|
checkNum(len(x.sortedHashes), 0, t)
|
|
}
|
|
|
|
func TestRemoveNonExisting(t *testing.T) {
|
|
x := New()
|
|
x.Add("abcdefg")
|
|
x.Remove("abcdefghijk")
|
|
checkNum(len(x.circle), 20, t)
|
|
}
|
|
|
|
func TestGetEmpty(t *testing.T) {
|
|
x := New()
|
|
_, err := x.Get("asdfsadfsadf")
|
|
if err == nil {
|
|
t.Errorf("expected error")
|
|
}
|
|
if err != ErrEmptyCircle {
|
|
t.Errorf("expected empty circle error")
|
|
}
|
|
}
|
|
|
|
func TestGetSingle(t *testing.T) {
|
|
x := New()
|
|
x.Add("abcdefg")
|
|
f := func(s string) bool {
|
|
y, err := x.Get(s)
|
|
if err != nil {
|
|
t.Logf("error: %q", err)
|
|
return false
|
|
}
|
|
t.Logf("s = %q, y = %q", s, y)
|
|
return y == "abcdefg"
|
|
}
|
|
if err := quick.Check(f, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestGetMultiple(t *testing.T) {
|
|
x := New()
|
|
x.Add("abcdefg")
|
|
x.Add("hijklmn")
|
|
x.Add("opqrstu")
|
|
result, err := x.Get("ggg")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if result != "opqrstu" {
|
|
t.Errorf("expected 'opqrstu', got %q", result)
|
|
}
|
|
result, err = x.Get("hhh")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if result != "abcdefg" {
|
|
t.Errorf("expected 'abcdefg', got %q", result)
|
|
}
|
|
result, err = x.Get("iiiiii")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if result != "hijklmn" {
|
|
t.Errorf("expected 'hijklmn', got %q", result)
|
|
}
|
|
}
|
|
|
|
func TestGetMultipleQuick(t *testing.T) {
|
|
x := New()
|
|
x.Add("abcdefg")
|
|
x.Add("hijklmn")
|
|
x.Add("opqrstu")
|
|
f := func(s string) bool {
|
|
y, err := x.Get(s)
|
|
if err != nil {
|
|
t.Logf("error: %q", err)
|
|
return false
|
|
}
|
|
t.Logf("s = %q, y = %q", s, y)
|
|
return y == "abcdefg" || y == "hijklmn" || y == "opqrstu"
|
|
}
|
|
if err := quick.Check(f, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestGetMultipleRemove(t *testing.T) {
|
|
x := New()
|
|
x.Add("abcdefg")
|
|
x.Add("hijklmn")
|
|
x.Add("opqrstu")
|
|
result, err := x.Get("ggg")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if result != "opqrstu" {
|
|
t.Errorf("expected 'opqrstu', got %q", result)
|
|
}
|
|
result, err = x.Get("hhh")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if result != "abcdefg" {
|
|
t.Errorf("expected 'abcdefg', got %q", result)
|
|
}
|
|
result, err = x.Get("iiiiii")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if result != "hijklmn" {
|
|
t.Errorf("expected 'hijklmn', got %q", result)
|
|
}
|
|
x.Remove("hijklmn")
|
|
result, err = x.Get("ggg")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if result != "opqrstu" {
|
|
t.Errorf("expected 'opqrstu', got %q", result)
|
|
}
|
|
result, err = x.Get("hhh")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if result != "abcdefg" {
|
|
t.Errorf("expected 'abcdefg', got %q", result)
|
|
}
|
|
result, err = x.Get("iiiiii")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if result != "opqrstu" {
|
|
t.Errorf("expected 'opqrstu', got %q", result)
|
|
}
|
|
}
|
|
|
|
func TestGetMultipleRemoveQuick(t *testing.T) {
|
|
x := New()
|
|
x.Add("abcdefg")
|
|
x.Add("hijklmn")
|
|
x.Add("opqrstu")
|
|
x.Remove("opqrstu")
|
|
f := func(s string) bool {
|
|
y, err := x.Get(s)
|
|
if err != nil {
|
|
t.Logf("error: %q", err)
|
|
return false
|
|
}
|
|
t.Logf("s = %q, y = %q", s, y)
|
|
return y == "abcdefg" || y == "hijklmn"
|
|
}
|
|
if err := quick.Check(f, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestGetTwo(t *testing.T) {
|
|
x := New()
|
|
x.Add("abcdefg")
|
|
x.Add("hijklmn")
|
|
x.Add("opqrstu")
|
|
a, b, err := x.GetTwo("99999999")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if a == b {
|
|
t.Errorf("a shouldn't equal b")
|
|
}
|
|
if a != "abcdefg" {
|
|
t.Errorf("wrong a: %q", a)
|
|
}
|
|
if b != "opqrstu" {
|
|
t.Errorf("wrong b: %q", b)
|
|
}
|
|
}
|
|
|
|
func TestGetTwoQuick(t *testing.T) {
|
|
x := New()
|
|
x.Add("abcdefg")
|
|
x.Add("hijklmn")
|
|
x.Add("opqrstu")
|
|
f := func(s string) bool {
|
|
a, b, err := x.GetTwo(s)
|
|
if err != nil {
|
|
t.Logf("error: %q", err)
|
|
return false
|
|
}
|
|
if a == b {
|
|
t.Logf("a == b")
|
|
return false
|
|
}
|
|
if a != "abcdefg" && a != "hijklmn" && a != "opqrstu" {
|
|
t.Logf("invalid a: %q", a)
|
|
return false
|
|
}
|
|
|
|
if b != "abcdefg" && b != "hijklmn" && b != "opqrstu" {
|
|
t.Logf("invalid b: %q", b)
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
if err := quick.Check(f, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestGetTwoOnlyTwoQuick(t *testing.T) {
|
|
x := New()
|
|
x.Add("abcdefg")
|
|
x.Add("hijklmn")
|
|
f := func(s string) bool {
|
|
a, b, err := x.GetTwo(s)
|
|
if err != nil {
|
|
t.Logf("error: %q", err)
|
|
return false
|
|
}
|
|
if a == b {
|
|
t.Logf("a == b")
|
|
return false
|
|
}
|
|
if a != "abcdefg" && a != "hijklmn" {
|
|
t.Logf("invalid a: %q", a)
|
|
return false
|
|
}
|
|
|
|
if b != "abcdefg" && b != "hijklmn" {
|
|
t.Logf("invalid b: %q", b)
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
if err := quick.Check(f, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestGetTwoOnlyOneInCircle(t *testing.T) {
|
|
x := New()
|
|
x.Add("abcdefg")
|
|
a, b, err := x.GetTwo("99999999")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if a == b {
|
|
t.Errorf("a shouldn't equal b")
|
|
}
|
|
if a != "abcdefg" {
|
|
t.Errorf("wrong a: %q", a)
|
|
}
|
|
if b != "" {
|
|
t.Errorf("wrong b: %q", b)
|
|
}
|
|
}
|
|
|
|
func TestSet(t *testing.T) {
|
|
x := New()
|
|
x.Add("abc")
|
|
x.Add("def")
|
|
x.Add("ghi")
|
|
x.Set([]string{"jkl", "mno"})
|
|
if x.count != 2 {
|
|
t.Errorf("expected 2 elts, got %d", x.count)
|
|
}
|
|
a, b, err := x.GetTwo("qwerqwerwqer")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if a != "jkl" && a != "mno" {
|
|
t.Errorf("expected jkl or mno, got %s", a)
|
|
}
|
|
if b != "jkl" && b != "mno" {
|
|
t.Errorf("expected jkl or mno, got %s", b)
|
|
}
|
|
if a == b {
|
|
t.Errorf("expected a != b, they were both %s", a)
|
|
}
|
|
x.Set([]string{"pqr", "mno"})
|
|
if x.count != 2 {
|
|
t.Errorf("expected 2 elts, got %d", x.count)
|
|
}
|
|
a, b, err = x.GetTwo("qwerqwerwqer")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if a != "pqr" && a != "mno" {
|
|
t.Errorf("expected jkl or mno, got %s", a)
|
|
}
|
|
if b != "pqr" && b != "mno" {
|
|
t.Errorf("expected jkl or mno, got %s", b)
|
|
}
|
|
if a == b {
|
|
t.Errorf("expected a != b, they were both %s", a)
|
|
}
|
|
x.Set([]string{"pqr", "mno"})
|
|
if x.count != 2 {
|
|
t.Errorf("expected 2 elts, got %d", x.count)
|
|
}
|
|
a, b, err = x.GetTwo("qwerqwerwqer")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if a != "pqr" && a != "mno" {
|
|
t.Errorf("expected jkl or mno, got %s", a)
|
|
}
|
|
if b != "pqr" && b != "mno" {
|
|
t.Errorf("expected jkl or mno, got %s", b)
|
|
}
|
|
if a == b {
|
|
t.Errorf("expected a != b, they were both %s", a)
|
|
}
|
|
}
|
|
|
|
// allocBytes returns the number of bytes allocated by invoking f.
|
|
func allocBytes(f func()) uint64 {
|
|
var stats runtime.MemStats
|
|
runtime.ReadMemStats(&stats)
|
|
t := stats.TotalAlloc
|
|
f()
|
|
runtime.ReadMemStats(&stats)
|
|
return stats.TotalAlloc - t
|
|
}
|
|
|
|
func mallocNum(f func()) uint64 {
|
|
var stats runtime.MemStats
|
|
runtime.ReadMemStats(&stats)
|
|
t := stats.Mallocs
|
|
f()
|
|
runtime.ReadMemStats(&stats)
|
|
return stats.Mallocs - t
|
|
}
|
|
|
|
func BenchmarkAllocations(b *testing.B) {
|
|
x := New()
|
|
x.Add("stays")
|
|
b.ResetTimer()
|
|
allocSize := allocBytes(func() {
|
|
for i := 0; i < b.N; i++ {
|
|
x.Add("Foo")
|
|
x.Remove("Foo")
|
|
}
|
|
})
|
|
b.Logf("%d: Allocated %d bytes (%.2fx)", b.N, allocSize, float64(allocSize)/float64(b.N))
|
|
}
|
|
|
|
func BenchmarkMalloc(b *testing.B) {
|
|
x := New()
|
|
x.Add("stays")
|
|
b.ResetTimer()
|
|
mallocs := mallocNum(func() {
|
|
for i := 0; i < b.N; i++ {
|
|
x.Add("Foo")
|
|
x.Remove("Foo")
|
|
}
|
|
})
|
|
b.Logf("%d: Mallocd %d times (%.2fx)", b.N, mallocs, float64(mallocs)/float64(b.N))
|
|
}
|
|
|
|
func BenchmarkCycle(b *testing.B) {
|
|
x := New()
|
|
x.Add("nothing")
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
x.Add("foo" + strconv.Itoa(i))
|
|
x.Remove("foo" + strconv.Itoa(i))
|
|
}
|
|
}
|
|
|
|
func BenchmarkCycleLarge(b *testing.B) {
|
|
x := New()
|
|
for i := 0; i < 10; i++ {
|
|
x.Add("start" + strconv.Itoa(i))
|
|
}
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
x.Add("foo" + strconv.Itoa(i))
|
|
x.Remove("foo" + strconv.Itoa(i))
|
|
}
|
|
}
|
|
|
|
func BenchmarkGet(b *testing.B) {
|
|
x := New()
|
|
x.Add("nothing")
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
x.Get("nothing")
|
|
}
|
|
}
|
|
|
|
func BenchmarkGetLarge(b *testing.B) {
|
|
x := New()
|
|
for i := 0; i < 10; i++ {
|
|
x.Add("start" + strconv.Itoa(i))
|
|
}
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
x.Get("nothing")
|
|
}
|
|
}
|