diff --git a/cmd/rawkv/main.go b/cmd/rawkv/main.go index 6dbb3a4..e5f0b64 100644 --- a/cmd/rawkv/main.go +++ b/cmd/rawkv/main.go @@ -17,7 +17,7 @@ var ( clientCase = flag.String("case", "register", "client test case, like bank,multi_bank") historyFile = flag.String("history", "./history.log", "history file") nemesises = flag.String("nemesis", "", "nemesis, seperated by name, like random_kill,all_kill") - verifyNames = flag.String("verifiers", "", "verifier names, seperate by comma, rawkv_register") + verifyNames = flag.String("verifiers", "", "verifier names, seperate by comma, register") ) func main() { diff --git a/cmd/verifier/verify/util.go b/cmd/verifier/verify/util.go index b753712..6df879e 100644 --- a/cmd/verifier/verify/util.go +++ b/cmd/verifier/verify/util.go @@ -5,9 +5,9 @@ import ( "log" "strings" - "github.com/siddontang/chaos/db/rawkv" "github.com/siddontang/chaos/db/tidb" "github.com/siddontang/chaos/pkg/history" + "github.com/siddontang/chaos/pkg/model" ) // Verify creates the verifier from verifer_names and verfies the history file. @@ -21,8 +21,8 @@ func Verify(ctx context.Context, historyFile string, verfier_names string) { verifier = tidb.BankVerifier{} case "tidb_bank_tso": verifier = tidb.BankTsoVerifier{} - case "rawkv_register": - verifier = rawkv.RegisterVerifier{} + case "register": + verifier = model.RegisterVerifier{} case "": continue default: diff --git a/db/rawkv/register.go b/db/rawkv/register.go index ee2d449..88043da 100644 --- a/db/rawkv/register.go +++ b/db/rawkv/register.go @@ -2,7 +2,6 @@ package rawkv import ( "context" - "encoding/json" "fmt" "log" "math/rand" @@ -16,7 +15,6 @@ import ( // use mysql _ "github.com/go-sql-driver/mysql" "github.com/siddontang/chaos/pkg/core" - "github.com/siddontang/chaos/pkg/history" "github.com/siddontang/chaos/pkg/model" ) @@ -58,7 +56,7 @@ func (c *registerClient) TearDown(ctx context.Context, nodes []string, node stri func (c *registerClient) invokeRead(ctx context.Context, r model.RegisterRequest) model.RegisterResponse { val, err := c.db.Get(register) if err != nil { - return model.RegisterResponse{Err: err} + return model.RegisterResponse{Unknown: true} } v, err := strconv.ParseInt(string(val), 10, 64) if err != nil { @@ -76,7 +74,7 @@ func (c *registerClient) Invoke(ctx context.Context, node string, r interface{}) val := fmt.Sprintf("%d", arg.Value) err := c.db.Put(register, []byte(val)) if err != nil { - return model.RegisterResponse{Err: err} + return model.RegisterResponse{Unknown: true} } return model.RegisterResponse{} } @@ -101,29 +99,6 @@ func newRegisterEvent(v interface{}, id uint) porcupine.Event { return porcupine.Event{Kind: porcupine.ReturnEvent, Value: v, Id: id} } -// TODO: maybe we can put the paser under the package `pkg/model`. -type registerParser struct { -} - -func (p registerParser) OnRequest(data json.RawMessage) (interface{}, error) { - r := model.RegisterRequest{} - err := json.Unmarshal(data, &r) - return r, err -} - -func (p registerParser) OnResponse(data json.RawMessage) (interface{}, error) { - r := model.RegisterResponse{} - err := json.Unmarshal(data, &r) - if r.Err != nil { - return nil, err - } - return r, err -} - -func (p registerParser) OnNoopResponse() interface{} { - return model.RegisterResponse{Err: fmt.Errorf("dummy error")} -} - // RegisterClientCreator creates a register test client for rawkv. type RegisterClientCreator struct { } @@ -132,17 +107,3 @@ type RegisterClientCreator struct { func (RegisterClientCreator) Create(node string) core.Client { return ®isterClient{} } - -// RegisterVerifier verifies the register history. -type RegisterVerifier struct { -} - -// Verify verifies the register history. -func (RegisterVerifier) Verify(historyFile string) (bool, error) { - return history.VerifyHistory(historyFile, model.RegisterModel(), registerParser{}) -} - -// Name returns the name of the verifier. -func (RegisterVerifier) Name() string { - return "register_verifier" -} diff --git a/pkg/model/register.go b/pkg/model/register.go index d95b86d..c0e4ec4 100644 --- a/pkg/model/register.go +++ b/pkg/model/register.go @@ -1,7 +1,10 @@ package model import ( + "encoding/json" + "github.com/anishathalye/porcupine" + "github.com/siddontang/chaos/pkg/history" ) // Op is an operation. @@ -22,8 +25,8 @@ type RegisterRequest struct { // RegisterResponse is the response returned by a register. type RegisterResponse struct { - Err error - Value int + Unknown bool + Value int } // RegisterModel returns a read/write register model @@ -40,7 +43,7 @@ func RegisterModel() porcupine.Model { // read if inp.Op == RegisterRead { - ok := out.Value == st || out.Err != nil + ok := out.Value == st || out.Unknown return ok, st } @@ -55,3 +58,39 @@ func RegisterModel() porcupine.Model { }, } } + +type registerParser struct { +} + +func (p registerParser) OnRequest(data json.RawMessage) (interface{}, error) { + r := RegisterRequest{} + err := json.Unmarshal(data, &r) + return r, err +} + +func (p registerParser) OnResponse(data json.RawMessage) (interface{}, error) { + r := RegisterResponse{} + err := json.Unmarshal(data, &r) + if r.Unknown { + return nil, err + } + return r, nil +} + +func (p registerParser) OnNoopResponse() interface{} { + return RegisterResponse{Unknown: true} +} + +// RegisterVerifier can verify a register history. +type RegisterVerifier struct { +} + +// Verify verifies a register history. +func (RegisterVerifier) Verify(historyFile string) (bool, error) { + return history.VerifyHistory(historyFile, RegisterModel(), registerParser{}) +} + +// Name returns the name of the verifier. +func (RegisterVerifier) Name() string { + return "register_verifier" +} diff --git a/pkg/model/register_test.go b/pkg/model/register_test.go index bd32e60..5c6e8f5 100644 --- a/pkg/model/register_test.go +++ b/pkg/model/register_test.go @@ -1,6 +1,7 @@ package model import ( + "encoding/json" "testing" "github.com/anishathalye/porcupine" @@ -12,9 +13,9 @@ func TestRegisterModel(t *testing.T) { // section VII ops := []porcupine.Operation{ - {RegisterRequest{RegisterWrite, 100}, 0, RegisterResponse{nil, 0}, 100}, - {RegisterRequest{RegisterRead, 0}, 25, RegisterResponse{nil, 100}, 75}, - {RegisterRequest{RegisterRead, 0}, 30, RegisterResponse{nil, 0}, 60}, + {RegisterRequest{RegisterWrite, 100}, 0, RegisterResponse{false, 0}, 100}, + {RegisterRequest{RegisterRead, 0}, 25, RegisterResponse{false, 100}, 75}, + {RegisterRequest{RegisterRead, 0}, 30, RegisterResponse{false, 0}, 60}, } res := porcupine.CheckOperations(RegisterModel(), ops) if res != true { @@ -26,9 +27,9 @@ func TestRegisterModel(t *testing.T) { {porcupine.CallEvent, RegisterRequest{RegisterWrite, 100}, 0}, {porcupine.CallEvent, RegisterRequest{RegisterRead, 0}, 1}, {porcupine.CallEvent, RegisterRequest{RegisterRead, 0}, 2}, - {porcupine.ReturnEvent, RegisterResponse{nil, 0}, 2}, - {porcupine.ReturnEvent, RegisterResponse{nil, 100}, 1}, - {porcupine.ReturnEvent, RegisterResponse{nil, 0}, 0}, + {porcupine.ReturnEvent, RegisterResponse{false, 0}, 2}, + {porcupine.ReturnEvent, RegisterResponse{false, 100}, 1}, + {porcupine.ReturnEvent, RegisterResponse{false, 0}, 0}, } res = porcupine.CheckEvents(RegisterModel(), events) if res != true { @@ -36,9 +37,9 @@ func TestRegisterModel(t *testing.T) { } ops = []porcupine.Operation{ - {RegisterRequest{RegisterWrite, 200}, 0, RegisterResponse{nil, 0}, 100}, - {RegisterRequest{RegisterRead, 0}, 10, RegisterResponse{nil, 200}, 30}, - {RegisterRequest{RegisterRead, 0}, 40, RegisterResponse{nil, 0}, 90}, + {RegisterRequest{RegisterWrite, 200}, 0, RegisterResponse{false, 0}, 100}, + {RegisterRequest{RegisterRead, 0}, 10, RegisterResponse{false, 200}, 30}, + {RegisterRequest{RegisterRead, 0}, 40, RegisterResponse{false, 0}, 90}, } res = porcupine.CheckOperations(RegisterModel(), ops) if res != false { @@ -49,13 +50,67 @@ func TestRegisterModel(t *testing.T) { events = []porcupine.Event{ {porcupine.CallEvent, RegisterRequest{RegisterWrite, 200}, 0}, {porcupine.CallEvent, RegisterRequest{RegisterRead, 0}, 1}, - {porcupine.ReturnEvent, RegisterResponse{nil, 200}, 1}, + {porcupine.ReturnEvent, RegisterResponse{false, 200}, 1}, {porcupine.CallEvent, RegisterRequest{RegisterRead, 0}, 2}, - {porcupine.ReturnEvent, RegisterResponse{nil, 0}, 2}, - {porcupine.ReturnEvent, RegisterResponse{nil, 0}, 0}, + {porcupine.ReturnEvent, RegisterResponse{false, 0}, 2}, + {porcupine.ReturnEvent, RegisterResponse{false, 0}, 0}, } res = porcupine.CheckEvents(RegisterModel(), events) if res != false { t.Fatal("expected operations to not be linearizable") } } + +func TestRegisterParser(t *testing.T) { + parser := registerParser{} + + for _, c := range []struct { + data []byte + req RegisterRequest + }{ + {[]byte(`{"Op":false,"Value":0}`), + RegisterRequest{RegisterRead, 0}}, + {[]byte(`{"Op":true,"Value":5135627519135374257}`), + RegisterRequest{RegisterWrite, 5135627519135374257}}, + } { + raw := json.RawMessage{} + if err := json.Unmarshal(c.data, &raw); err != nil { + t.Fatalf("unexpected err: %v, req: %v", err, c.req) + } + r, err := parser.OnRequest(raw) + if err != nil { + t.Fatalf("unexpected err: %v, req: %v", err, c.req) + } + req := r.(RegisterRequest) + if req.Op != c.req.Op || req.Value != c.req.Value { + t.Fatalf("expected equal: %v, req: %v", req, c.req) + } + } + + for _, c := range []struct { + data []byte + resp RegisterResponse + }{ + {[]byte(`{"Unknown":false,"Value":0}`), + RegisterResponse{false, 0}}, + {[]byte(`{"Unknown":false,"Value":5135627519135374257}`), + RegisterResponse{false, 5135627519135374257}}, + {[]byte(`{"Unknown":true,"Value":7}`), + RegisterResponse{true, 7}}, + } { + raw := json.RawMessage{} + if err := json.Unmarshal(c.data, &raw); err != nil { + t.Fatalf("unexpected err: %v, resp: %v", err, c.resp) + } + r, err := parser.OnResponse(raw) + if err != nil { + t.Fatalf("unexpected err: %v, resp: %v", err, c.resp) + } + if r != nil { + resp := r.(RegisterResponse) + if resp.Value != c.resp.Value || resp.Unknown != c.resp.Unknown { + t.Fatalf("expected equal: %v != %v", resp, c.resp) + } + } + } +}