From 6f412de2c9522333749b3b18d75aff58be823828 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 4 Sep 2023 14:25:42 -0700 Subject: [PATCH] add CompareAndSwap (cas) tests Signed-off-by: Brad Fitzpatrick --- memcache/fakeserver_test.go | 9 ++++++--- memcache/memcache_test.go | 22 +++++++++++++++++++--- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/memcache/fakeserver_test.go b/memcache/fakeserver_test.go index 12c8ffea..6e644bc2 100644 --- a/memcache/fakeserver_test.go +++ b/memcache/fakeserver_test.go @@ -71,7 +71,7 @@ func (c *testConn) reply(msg string) bool { } var ( - writeRx = regexp.MustCompile(`^(set|add|replace|append|prepend|cas) (\S+) (\d+) (\d+) (\d+)( \S+)?( noreply)?\r\n`) + writeRx = regexp.MustCompile(`^(set|add|replace|append|prepend|cas) (\S+) (\d+) (\d+) (\d+)(?: (\S+))?( noreply)?\r\n`) deleteRx = regexp.MustCompile(`^delete (\S+)( noreply)?\r\n`) incrDecrRx = regexp.MustCompile(`^(incr|decr) (\S+) (\d+)( noreply)?\r\n`) touchRx = regexp.MustCompile(`^touch (\S+) (\d+)( noreply)?\r\n`) @@ -148,7 +148,6 @@ func (c *testConn) handleRequestLine(line string) bool { exptimeVal, _ := strconv.ParseInt(exptimeStr, 10, 64) itemLen, _ := strconv.ParseInt(lenStr, 10, 32) //log.Printf("got %q flags=%q exp=%d %d len=%d cas=%q noreply=%q", verb, key, flags, exptimeVal, itemLen, casUniq, noReply) - _ = casUniq // TODO if c.s.m == nil { c.s.m = make(map[string]serverItem) } @@ -200,7 +199,11 @@ func (c *testConn) handleRequestLine(line string) bool { if !ok { reply("NOT_FOUND") } - return false + if casUniq != fmt.Sprint(was.casUniq) { + return reply("EXISTS") + } + c.s.m[key] = newItem + return reply("STORED") case "append": if !ok { return reply("NOT_STORED") diff --git a/memcache/memcache_test.go b/memcache/memcache_test.go index 05f06087..e9e8ec32 100644 --- a/memcache/memcache_test.go +++ b/memcache/memcache_test.go @@ -99,20 +99,36 @@ func testWithClient(t *testing.T, c *Client) { mustSet := mustSetF(t, c) // Set - foo := &Item{Key: "foo", Value: []byte("fooval"), Flags: 123} + foo := &Item{Key: "foo", Value: []byte("fooval-fromset"), Flags: 123} err := c.Set(foo) checkErr(err, "first set(foo): %v", err) err = c.Set(foo) checkErr(err, "second set(foo): %v", err) - // Get + // CompareAndSwap it, err := c.Get("foo") checkErr(err, "get(foo): %v", err) + if string(it.Value) != "fooval-fromset" { + t.Errorf("get(foo) Value = %q, want fooval-romset", it.Value) + } + it0, err := c.Get("foo") // another get, to fail our CAS later + checkErr(err, "get(foo): %v", err) + it.Value = []byte("fooval") + err = c.CompareAndSwap(it) + checkErr(err, "cas(foo): %v", err) + it0.Value = []byte("should-fail") + if err := c.CompareAndSwap(it0); err != ErrCASConflict { + t.Fatalf("cas(foo) error = %v; want ErrCASConflict", err) + } + + // Get + it, err = c.Get("foo") + checkErr(err, "get(foo): %v", err) if it.Key != "foo" { t.Errorf("get(foo) Key = %q, want foo", it.Key) } if string(it.Value) != "fooval" { - t.Errorf("get(foo) Value = %q, want fooval", string(it.Value)) + t.Errorf("get(foo) Value = %q, want fooval", it.Value) } if it.Flags != 123 { t.Errorf("get(foo) Flags = %v, want 123", it.Flags)