package memcache import ( "bytes" "strconv" "strings" "testing" ) func TestASCIIConnAdd(t *testing.T) { tests := []struct { name string a *Item e error }{ { "Add", &Item{ Key: "test_add", Value: []byte("0"), Flags: 0, Expiration: 60, }, nil, }, { "Add_Large", &Item{ Key: "test_add_large", Value: bytes.Repeat(space, _largeValue+1), Flags: 0, Expiration: 60, }, nil, }, { "Add_Exist", &Item{ Key: "test_add", Value: []byte("0"), Flags: 0, Expiration: 60, }, ErrNotStored, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { if err := testConnASCII.Add(test.a); err != test.e { t.Fatal(err) } if b, err := testConnASCII.Get(test.a.Key); err != nil { t.Fatal(err) } else { compareItem(t, test.a, b) } }) } } func TestASCIIConnGet(t *testing.T) { tests := []struct { name string a *Item k string e error }{ { "Get", &Item{ Key: "test_get", Value: []byte("0"), Flags: 0, Expiration: 60, }, "test_get", nil, }, { "Get_NotExist", &Item{ Key: "test_get_not_exist", Value: []byte("0"), Flags: 0, Expiration: 60, }, "test_get_not_exist!", ErrNotFound, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { if err := testConnASCII.Add(test.a); err != nil { t.Fatal(err) } if b, err := testConnASCII.Get(test.a.Key); err != nil { t.Fatal(err) } else { compareItem(t, test.a, b) } }) } } //func TestGetHasErr(t *testing.T) { // prepareEnv(t) // // st := &TestItem{Name: "json", Age: 10} // itemx := &Item{Key: "test", Object: st, Flags: FlagJSON} // c.Set(itemx) // // expected := errors.New("some error") // monkey.Patch(scanGetReply, func(line []byte, item *Item) (size int, err error) { // return 0, expected // }) // // if _, err := c.Get("test"); err.Error() != expected.Error() { // t.Errorf("conn.Get() unexpected error(%v)", err) // } // if err := c.(*asciiConn).err; err.Error() != expected.Error() { // t.Errorf("unexpected error(%v)", err) // } //} func TestASCIIConnGetMulti(t *testing.T) { tests := []struct { name string a []*Item k []string e error }{ {"getMulti_Add", []*Item{ { Key: "get_multi_1", Value: []byte("test"), Flags: FlagRAW, Expiration: 60, cas: 0, }, { Key: "get_multi_2", Value: []byte("test2"), Flags: FlagRAW, Expiration: 60, cas: 0, }, }, []string{"get_multi_1", "get_multi_2"}, nil, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { for _, i := range test.a { if err := testConnASCII.Set(i); err != nil { t.Fatal(err) } } if r, err := testConnASCII.GetMulti(test.k); err != nil { t.Fatal(err) } else { reply := r["get_multi_1"] compareItem(t, reply, test.a[0]) reply = r["get_multi_2"] compareItem(t, reply, test.a[1]) } }) } } func TestASCIIConnSet(t *testing.T) { tests := []struct { name string a *Item e error }{ { "SetLowerBound", &Item{ Key: strings.Repeat("a", 1), Value: []byte("4"), Flags: 0, Expiration: 60, }, nil, }, { "SetUpperBound", &Item{ Key: strings.Repeat("a", 250), Value: []byte("3"), Flags: 0, Expiration: 60, }, nil, }, { "SetIllegalKeyZeroLength", &Item{ Key: "", Value: []byte("2"), Flags: 0, Expiration: 60, }, ErrMalformedKey, }, { "SetIllegalKeyLengthExceededLimit", &Item{ Key: " ", Value: []byte("1"), Flags: 0, Expiration: 60, }, ErrMalformedKey, }, { "SeJsonItem", &Item{ Key: "set_obj", Object: &struct { Name string Age int }{"json", 10}, Expiration: 60, Flags: FlagJSON, }, nil, }, { "SeErrItemJSONGzip", &Item{ Key: "set_err_item", Expiration: 60, Flags: FlagJSON | FlagGzip, }, ErrItem, }, { "SeErrItemBytesValueWrongFlag", &Item{ Key: "set_err_item", Value: []byte("2"), Expiration: 60, Flags: FlagJSON, }, ErrItem, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { if err := testConnASCII.Set(test.a); err != test.e { t.Fatal(err) } }) } } func TestASCIIConnCompareAndSwap(t *testing.T) { tests := []struct { name string a *Item b *Item c *Item k string e error }{ { "CompareAndSwap", &Item{ Key: "test_cas", Value: []byte("2"), Flags: 0, Expiration: 60, }, nil, &Item{ Key: "test_cas", Value: []byte("3"), Flags: 0, Expiration: 60, }, "test_cas", nil, }, { "CompareAndSwapErrCASConflict", &Item{ Key: "test_cas_conflict", Value: []byte("2"), Flags: 0, Expiration: 60, }, &Item{ Key: "test_cas_conflict", Value: []byte("1"), Flags: 0, Expiration: 60, }, &Item{ Key: "test_cas_conflict", Value: []byte("3"), Flags: 0, Expiration: 60, }, "test_cas_conflict", ErrCASConflict, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { if err := testConnASCII.Set(test.a); err != nil { t.Fatal(err) } r, err := testConnASCII.Get(test.k) if err != nil { t.Fatal(err) } if test.b != nil { if err := testConnASCII.Set(test.b); err != nil { t.Fatal(err) } } r.Value = test.c.Value if err := testConnASCII.CompareAndSwap(r); err != nil { if err != test.e { t.Fatal(err) } } else { if fr, err := testConnASCII.Get(test.k); err != nil { t.Fatal(err) } else { compareItem(t, fr, test.c) } } }) } t.Run("TestCompareAndSwapErrNotFound", func(t *testing.T) { ti := &Item{ Key: "test_cas_notfound", Value: []byte("2"), Flags: 0, Expiration: 60, } if err := testConnASCII.Set(ti); err != nil { t.Fatal(err) } r, err := testConnASCII.Get(ti.Key) if err != nil { t.Fatal(err) } r.Key = "test_cas_notfound_boom" r.Value = []byte("3") if err := testConnASCII.CompareAndSwap(r); err != nil { if err != ErrNotFound { t.Fatal(err) } } }) } func TestASCIIConnReplace(t *testing.T) { tests := []struct { name string a *Item b *Item e error }{ { "TestReplace", &Item{ Key: "test_replace", Value: []byte("2"), Flags: 0, Expiration: 60, }, &Item{ Key: "test_replace", Value: []byte("3"), Flags: 0, Expiration: 60, }, nil, }, { "TestReplaceErrNotStored", &Item{ Key: "test_replace_not_stored", Value: []byte("2"), Flags: 0, Expiration: 60, }, &Item{ Key: "test_replace_not_stored_boom", Value: []byte("3"), Flags: 0, Expiration: 60, }, ErrNotStored, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { if err := testConnASCII.Set(test.a); err != nil { t.Fatal(err) } if err := testConnASCII.Replace(test.b); err != nil { if err == test.e { return } t.Fatal(err) } if r, err := testConnASCII.Get(test.b.Key); err != nil { t.Fatal(err) } else { compareItem(t, r, test.b) } }) } } func TestASCIIConnIncrDecr(t *testing.T) { tests := []struct { fn func(key string, delta uint64) (uint64, error) name string k string v uint64 w uint64 }{ { testConnASCII.Increment, "Incr_10", "test_incr", 10, 10, }, { testConnASCII.Increment, "Incr_10(2)", "test_incr", 10, 20, }, { testConnASCII.Decrement, "Decr_10", "test_incr", 10, 10, }, } if err := testConnASCII.Add(&Item{ Key: "test_incr", Value: []byte("0"), }); err != nil { t.Fatal(err) } for _, test := range tests { t.Run(test.name, func(t *testing.T) { if a, err := test.fn(test.k, test.v); err != nil { t.Fatal(err) } else { if a != test.w { t.Fatalf("want %d, got %d", test.w, a) } } if b, err := testConnASCII.Get(test.k); err != nil { t.Fatal(err) } else { if string(b.Value) != strconv.FormatUint(test.w, 10) { t.Fatalf("want %s, got %d", b.Value, test.w) } } }) } } func TestASCIIConnTouch(t *testing.T) { tests := []struct { name string k string a *Item e error }{ { "Touch", "test_touch", &Item{ Key: "test_touch", Value: []byte("0"), Expiration: 60, }, nil, }, { "Touch_NotExist", "test_touch_not_exist", nil, ErrNotFound, }, } for _, test := range tests { if test.a != nil { if err := testConnASCII.Add(test.a); err != nil { t.Fatal(err) } if err := testConnASCII.Touch(test.k, 1); err != test.e { t.Fatal(err) } } } } func TestASCIIConnDelete(t *testing.T) { tests := []struct { name string k string a *Item e error }{ { "Delete", "test_delete", &Item{ Key: "test_delete", Value: []byte("0"), Expiration: 60, }, nil, }, { "Delete_NotExist", "test_delete_not_exist", nil, ErrNotFound, }, } for _, test := range tests { if test.a != nil { if err := testConnASCII.Add(test.a); err != nil { t.Fatal(err) } if err := testConnASCII.Delete(test.k); err != test.e { t.Fatal(err) } if _, err := testConnASCII.Get(test.k); err != ErrNotFound { t.Fatal(err) } } } } func compareItem(t *testing.T, a, b *Item) { if a.Key != b.Key || !bytes.Equal(a.Value, b.Value) || a.Flags != b.Flags { t.Fatalf("compareItem: a(%s, %d, %d) : b(%s, %d, %d)", a.Key, len(a.Value), a.Flags, b.Key, len(b.Value), b.Flags) } }