diff --git a/tests/robustness/client/client.go b/tests/robustness/client/client.go index 531fbacba7c..fa13c791076 100644 --- a/tests/robustness/client/client.go +++ b/tests/robustness/client/client.go @@ -356,6 +356,7 @@ func toWatchEvent(event clientv3.Event) (watch model.WatchEvent) { watch.PrevValue = &model.ValueRevision{ Value: model.ToValueOrHash(string(event.PrevKv.Value)), ModRevision: event.PrevKv.ModRevision, + Version: event.PrevKv.Version, } } watch.IsCreate = event.IsCreate() diff --git a/tests/robustness/model/describe.go b/tests/robustness/model/describe.go index 71f2b15f26b..43eb58c06bd 100644 --- a/tests/robustness/model/describe.go +++ b/tests/robustness/model/describe.go @@ -91,6 +91,9 @@ func describeGuaranteedTxn(txn *TxnRequest) string { if txn.Conditions[0].Key != txn.OperationsOnSuccess[0].Put.Key || (len(txn.OperationsOnFailure) == 1 && txn.Conditions[0].Key != txn.OperationsOnFailure[0].Range.Start) { return "" } + if txn.Conditions[0].ExpectedVersion > 0 { + return "" + } if txn.Conditions[0].ExpectedRevision == 0 { return fmt.Sprintf("guaranteedCreate(%q, %s)", txn.Conditions[0].Key, describeValueOrHash(txn.OperationsOnSuccess[0].Put.Value)) } @@ -106,8 +109,12 @@ func describeGuaranteedTxn(txn *TxnRequest) string { func describeEtcdConditions(conds []EtcdCondition) string { opsDescription := make([]string, len(conds)) - for i := range conds { - opsDescription[i] = fmt.Sprintf("mod_rev(%s)==%d", conds[i].Key, conds[i].ExpectedRevision) + for i, cond := range conds { + if cond.ExpectedVersion > 0 { + opsDescription[i] = fmt.Sprintf("ver(%s)==%d", cond.Key, cond.ExpectedVersion) + } else { + opsDescription[i] = fmt.Sprintf("mod_rev(%s)==%d", cond.Key, cond.ExpectedRevision) + } } return strings.Join(opsDescription, " && ") } diff --git a/tests/robustness/model/deterministic.go b/tests/robustness/model/deterministic.go index 6f570ce0825..9b61d13afd0 100644 --- a/tests/robustness/model/deterministic.go +++ b/tests/robustness/model/deterministic.go @@ -127,7 +127,13 @@ func (s EtcdState) Step(request EtcdRequest) (EtcdState, MaybeEtcdResponse) { case Txn: failure := false for _, cond := range request.Txn.Conditions { - if val := newState.KeyValues[cond.Key]; val.ModRevision != cond.ExpectedRevision { + val := newState.KeyValues[cond.Key] + if cond.ExpectedVersion > 0 { + if val.Version != cond.ExpectedVersion { + failure = true + break + } + } else if val.ModRevision != cond.ExpectedRevision { failure = true break } @@ -149,9 +155,14 @@ func (s EtcdState) Step(request EtcdRequest) (EtcdState, MaybeEtcdResponse) { if op.Put.LeaseID != 0 && !leaseExists { break } + ver := int64(1) + if val, exists := newState.KeyValues[op.Put.Key]; exists && val.Version > 0 { + ver = val.Version + 1 + } newState.KeyValues[op.Put.Key] = ValueRevision{ Value: op.Put.Value, ModRevision: newState.Revision + 1, + Version: ver, } increaseRevision = true newState = detachFromOldLease(newState, op.Put.Key) @@ -326,6 +337,7 @@ type TxnRequest struct { type EtcdCondition struct { Key string ExpectedRevision int64 + ExpectedVersion int64 } type EtcdOperation struct { @@ -434,6 +446,7 @@ func (el EtcdLease) DeepCopy() EtcdLease { type ValueRevision struct { Value ValueOrHash ModRevision int64 + Version int64 } type ValueOrHash struct { diff --git a/tests/robustness/model/deterministic_test.go b/tests/robustness/model/deterministic_test.go index 5e7bc0f0585..6e75126239d 100644 --- a/tests/robustness/model/deterministic_test.go +++ b/tests/robustness/model/deterministic_test.go @@ -82,8 +82,8 @@ var commonTestScenarios = []modelTestCase{ operations: []testOperation{ {req: putRequest("key1", "1"), resp: putResponse(2)}, {req: putRequest("key2", "2"), resp: putResponse(3)}, - {req: listRequest("key", 0), resp: rangeResponse([]*mvccpb.KeyValue{{Key: []byte("key1"), Value: []byte("1"), ModRevision: 2}, {Key: []byte("key2"), Value: []byte("2"), ModRevision: 3}}, 2, 3)}, - {req: listRequest("key", 0), resp: rangeResponse([]*mvccpb.KeyValue{{Key: []byte("key1"), Value: []byte("1"), ModRevision: 2}, {Key: []byte("key2"), Value: []byte("2"), ModRevision: 3}}, 2, 3)}, + {req: listRequest("key", 0), resp: rangeResponse([]*mvccpb.KeyValue{{Key: []byte("key1"), Value: []byte("1"), ModRevision: 2, Version: 1}, {Key: []byte("key2"), Value: []byte("2"), ModRevision: 3, Version: 1}}, 2, 3)}, + {req: listRequest("key", 0), resp: rangeResponse([]*mvccpb.KeyValue{{Key: []byte("key1"), Value: []byte("1"), ModRevision: 2, Version: 1}, {Key: []byte("key2"), Value: []byte("2"), ModRevision: 3, Version: 1}}, 2, 3)}, }, }, { @@ -93,26 +93,26 @@ var commonTestScenarios = []modelTestCase{ {req: putRequest("key2", "2"), resp: putResponse(3)}, {req: putRequest("key3", "3"), resp: putResponse(4)}, {req: listRequest("key", 0), resp: rangeResponse([]*mvccpb.KeyValue{ - {Key: []byte("key1"), Value: []byte("1"), ModRevision: 2}, - {Key: []byte("key2"), Value: []byte("2"), ModRevision: 3}, - {Key: []byte("key3"), Value: []byte("3"), ModRevision: 4}, + {Key: []byte("key1"), Value: []byte("1"), ModRevision: 2, Version: 1}, + {Key: []byte("key2"), Value: []byte("2"), ModRevision: 3, Version: 1}, + {Key: []byte("key3"), Value: []byte("3"), ModRevision: 4, Version: 1}, }, 3, 4)}, {req: listRequest("key", 4), resp: rangeResponse([]*mvccpb.KeyValue{ - {Key: []byte("key1"), Value: []byte("1"), ModRevision: 2}, - {Key: []byte("key2"), Value: []byte("2"), ModRevision: 3}, - {Key: []byte("key3"), Value: []byte("3"), ModRevision: 4}, + {Key: []byte("key1"), Value: []byte("1"), ModRevision: 2, Version: 1}, + {Key: []byte("key2"), Value: []byte("2"), ModRevision: 3, Version: 1}, + {Key: []byte("key3"), Value: []byte("3"), ModRevision: 4, Version: 1}, }, 3, 4)}, {req: listRequest("key", 3), resp: rangeResponse([]*mvccpb.KeyValue{ - {Key: []byte("key1"), Value: []byte("1"), ModRevision: 2}, - {Key: []byte("key2"), Value: []byte("2"), ModRevision: 3}, - {Key: []byte("key3"), Value: []byte("3"), ModRevision: 4}, + {Key: []byte("key1"), Value: []byte("1"), ModRevision: 2, Version: 1}, + {Key: []byte("key2"), Value: []byte("2"), ModRevision: 3, Version: 1}, + {Key: []byte("key3"), Value: []byte("3"), ModRevision: 4, Version: 1}, }, 3, 4)}, {req: listRequest("key", 2), resp: rangeResponse([]*mvccpb.KeyValue{ - {Key: []byte("key1"), Value: []byte("1"), ModRevision: 2}, - {Key: []byte("key2"), Value: []byte("2"), ModRevision: 3}, + {Key: []byte("key1"), Value: []byte("1"), ModRevision: 2, Version: 1}, + {Key: []byte("key2"), Value: []byte("2"), ModRevision: 3, Version: 1}, }, 3, 4)}, {req: listRequest("key", 1), resp: rangeResponse([]*mvccpb.KeyValue{ - {Key: []byte("key1"), Value: []byte("1"), ModRevision: 2}, + {Key: []byte("key1"), Value: []byte("1"), ModRevision: 2, Version: 1}, }, 3, 4)}, }, }, @@ -123,19 +123,19 @@ var commonTestScenarios = []modelTestCase{ {req: putRequest("key2", "1"), resp: putResponse(3)}, {req: putRequest("key1", "2"), resp: putResponse(4)}, {req: listRequest("key", 0), resp: rangeResponse([]*mvccpb.KeyValue{ - {Key: []byte("key1"), Value: []byte("2"), ModRevision: 4}, - {Key: []byte("key2"), Value: []byte("1"), ModRevision: 3}, - {Key: []byte("key3"), Value: []byte("3"), ModRevision: 2}, + {Key: []byte("key1"), Value: []byte("2"), ModRevision: 4, Version: 1}, + {Key: []byte("key2"), Value: []byte("1"), ModRevision: 3, Version: 1}, + {Key: []byte("key3"), Value: []byte("3"), ModRevision: 2, Version: 1}, }, 3, 4)}, {req: listRequest("key", 0), resp: rangeResponse([]*mvccpb.KeyValue{ - {Key: []byte("key2"), Value: []byte("1"), ModRevision: 3}, - {Key: []byte("key1"), Value: []byte("2"), ModRevision: 4}, - {Key: []byte("key3"), Value: []byte("3"), ModRevision: 2}, + {Key: []byte("key2"), Value: []byte("1"), ModRevision: 3, Version: 1}, + {Key: []byte("key1"), Value: []byte("2"), ModRevision: 4, Version: 1}, + {Key: []byte("key3"), Value: []byte("3"), ModRevision: 2, Version: 1}, }, 3, 4), expectFailure: true}, {req: listRequest("key", 0), resp: rangeResponse([]*mvccpb.KeyValue{ - {Key: []byte("key3"), Value: []byte("3"), ModRevision: 2}, - {Key: []byte("key2"), Value: []byte("1"), ModRevision: 3}, - {Key: []byte("key1"), Value: []byte("2"), ModRevision: 4}, + {Key: []byte("key3"), Value: []byte("3"), ModRevision: 2, Version: 1}, + {Key: []byte("key2"), Value: []byte("1"), ModRevision: 3, Version: 1}, + {Key: []byte("key1"), Value: []byte("2"), ModRevision: 4, Version: 1}, }, 3, 4), expectFailure: true}, }, }, @@ -146,7 +146,7 @@ var commonTestScenarios = []modelTestCase{ {req: getRequest("key"), resp: getResponse("key", "123456789012345678901", 2, 2), expectFailure: true}, {req: getRequest("key"), resp: getResponse("key", "012345678901234567890", 2, 2)}, {req: putRequest("key", "123456789012345678901"), resp: putResponse(3)}, - {req: getRequest("key"), resp: getResponse("key", "123456789012345678901", 3, 3)}, + {req: getRequest("key"), resp: getResponseWithVer("key", "123456789012345678901", 3, 2, 3)}, {req: getRequest("key"), resp: getResponse("key", "012345678901234567890", 3, 3), expectFailure: true}, }, }, @@ -228,8 +228,8 @@ var commonTestScenarios = []modelTestCase{ {req: getRequest("key"), resp: getResponse("key", "1", 2, 2), expectFailure: true}, {req: getRequest("key"), resp: getResponse("key", "1", 2, 3), expectFailure: true}, {req: getRequest("key"), resp: getResponse("key", "1", 3, 3), expectFailure: true}, - {req: getRequest("key"), resp: getResponse("key", "2", 2, 2), expectFailure: true}, - {req: getRequest("key"), resp: getResponse("key", "2", 3, 3)}, + {req: getRequest("key"), resp: getResponseWithVer("key", "2", 2, 2, 2), expectFailure: true}, + {req: getRequest("key"), resp: getResponseWithVer("key", "2", 3, 2, 3)}, }, }, { @@ -239,7 +239,7 @@ var commonTestScenarios = []modelTestCase{ {req: compareRevisionAndPutRequest("key1", 0, "2"), resp: compareRevisionAndPutResponse(true, 2)}, {req: compareRevisionAndPutRequest("key1", 0, "3"), resp: compareRevisionAndPutResponse(true, 3), expectFailure: true}, {req: txnRequestSingleOperation(compareRevision("key1", 0), putOperation("key1", "4"), putOperation("key1", "5")), resp: txnPutResponse(false, 3)}, - {req: getRequest("key1"), resp: getResponse("key1", "5", 3, 3)}, + {req: getRequest("key1"), resp: getResponseWithVer("key1", "5", 3, 2, 3)}, {req: compareRevisionAndPutRequest("key2", 0, "6"), resp: compareRevisionAndPutResponse(true, 4)}, }, }, @@ -291,7 +291,7 @@ var commonTestScenarios = []modelTestCase{ {req: putWithLeaseRequest("key", "2", 1), resp: putResponse(2)}, {req: putRequest("key", "3"), resp: putResponse(3)}, {req: leaseRevokeRequest(1), resp: leaseRevokeResponse(3)}, - {req: getRequest("key"), resp: getResponse("key", "3", 3, 3)}, + {req: getRequest("key"), resp: getResponseWithVer("key", "3", 3, 2, 3)}, }, }, { @@ -302,7 +302,7 @@ var commonTestScenarios = []modelTestCase{ {req: putWithLeaseRequest("key", "2", 1), resp: putResponse(2)}, {req: putWithLeaseRequest("key", "3", 2), resp: putResponse(3)}, {req: leaseRevokeRequest(1), resp: leaseRevokeResponse(3)}, - {req: getRequest("key"), resp: getResponse("key", "3", 3, 3)}, + {req: getRequest("key"), resp: getResponseWithVer("key", "3", 3, 2, 3)}, {req: leaseRevokeRequest(2), resp: leaseRevokeResponse(4)}, {req: getRequest("key"), resp: emptyGetResponse(4)}, }, @@ -313,7 +313,7 @@ var commonTestScenarios = []modelTestCase{ {req: leaseGrantRequest(1), resp: leaseGrantResponse(1)}, {req: putWithLeaseRequest("key", "2", 1), resp: putResponse(2)}, {req: putWithLeaseRequest("key", "3", 1), resp: putResponse(3)}, - {req: getRequest("key"), resp: getResponse("key", "3", 3, 3)}, + {req: getRequest("key"), resp: getResponseWithVer("key", "3", 3, 2, 3)}, }, }, { diff --git a/tests/robustness/model/history.go b/tests/robustness/model/history.go index 20ebd1c7cff..fc224a8afff 100644 --- a/tests/robustness/model/history.go +++ b/tests/robustness/model/history.go @@ -183,12 +183,13 @@ func toEtcdCondition(cmp clientv3.Cmp) (cond EtcdCondition) { switch { case cmp.Result == etcdserverpb.Compare_EQUAL && cmp.Target == etcdserverpb.Compare_MOD: cond.Key = string(cmp.KeyBytes()) - case cmp.Result == etcdserverpb.Compare_EQUAL && cmp.Target == etcdserverpb.Compare_CREATE: + cond.ExpectedRevision = cmp.TargetUnion.(*etcdserverpb.Compare_ModRevision).ModRevision + case cmp.Result == etcdserverpb.Compare_EQUAL && cmp.Target == etcdserverpb.Compare_VERSION: + cond.ExpectedVersion = cmp.TargetUnion.(*etcdserverpb.Compare_Version).Version cond.Key = string(cmp.KeyBytes()) default: panic(fmt.Sprintf("Compare not supported, target: %q, result: %q", cmp.Target, cmp.Result)) } - cond.ExpectedRevision = cmp.TargetUnion.(*etcdserverpb.Compare_ModRevision).ModRevision return cond } @@ -228,6 +229,7 @@ func toEtcdOperationResult(resp *etcdserverpb.ResponseOp) EtcdOperationResult { ValueRevision: ValueRevision{ Value: ToValueOrHash(string(kv.Value)), ModRevision: kv.ModRevision, + Version: kv.Version, }, } } @@ -342,7 +344,11 @@ func emptyGetResponse(revision int64) MaybeEtcdResponse { } func getResponse(key, value string, modRevision, revision int64) MaybeEtcdResponse { - return rangeResponse([]*mvccpb.KeyValue{{Key: []byte(key), Value: []byte(value), ModRevision: modRevision}}, 1, revision) + return getResponseWithVer(key, value, modRevision, 1, revision) +} + +func getResponseWithVer(key, value string, modRevision, ver, revision int64) MaybeEtcdResponse { + return rangeResponse([]*mvccpb.KeyValue{{Key: []byte(key), Value: []byte(value), ModRevision: modRevision, Version: ver}}, 1, revision) } func rangeResponse(kvs []*mvccpb.KeyValue, count int64, revision int64) MaybeEtcdResponse { @@ -354,6 +360,7 @@ func rangeResponse(kvs []*mvccpb.KeyValue, count int64, revision int64) MaybeEtc ValueRevision: ValueRevision{ Value: ToValueOrHash(string(kv.Value)), ModRevision: kv.ModRevision, + Version: kv.Version, }, } } diff --git a/tests/robustness/model/non_deterministic_test.go b/tests/robustness/model/non_deterministic_test.go index d5c981973e5..b6622e6fa81 100644 --- a/tests/robustness/model/non_deterministic_test.go +++ b/tests/robustness/model/non_deterministic_test.go @@ -33,7 +33,7 @@ func TestModelNonDeterministic(t *testing.T) { operations: []testOperation{ {req: putRequest("key1", "1"), resp: failedResponse(errors.New("failed"))}, {req: putRequest("key2", "2"), resp: putResponse(3)}, - {req: listRequest("key", 0), resp: rangeResponse([]*mvccpb.KeyValue{{Key: []byte("key1"), Value: []byte("1"), ModRevision: 2}, {Key: []byte("key2"), Value: []byte("2"), ModRevision: 3}}, 2, 3)}, + {req: listRequest("key", 0), resp: rangeResponse([]*mvccpb.KeyValue{{Key: []byte("key1"), Value: []byte("1"), ModRevision: 2, Version: 1}, {Key: []byte("key2"), Value: []byte("2"), ModRevision: 3, Version: 1}}, 2, 3)}, }, }, { @@ -41,7 +41,7 @@ func TestModelNonDeterministic(t *testing.T) { operations: []testOperation{ {req: putRequest("key1", "1"), resp: failedResponse(errors.New("failed"))}, {req: putRequest("key2", "2"), resp: putResponse(2)}, - {req: listRequest("key", 0), resp: rangeResponse([]*mvccpb.KeyValue{{Key: []byte("key2"), Value: []byte("2"), ModRevision: 2}}, 1, 2)}, + {req: listRequest("key", 0), resp: rangeResponse([]*mvccpb.KeyValue{{Key: []byte("key2"), Value: []byte("2"), ModRevision: 2, Version: 1}}, 1, 2)}, }, }, { @@ -90,14 +90,14 @@ func TestModelNonDeterministic(t *testing.T) { // One failed request, one persisted. {req: putRequest("key", "1"), resp: putResponse(2)}, {req: putRequest("key", "2"), resp: failedResponse(errors.New("failed"))}, - {req: getRequest("key"), resp: getResponse("key", "3", 3, 3), expectFailure: true}, - {req: getRequest("key"), resp: getResponse("key", "3", 2, 3), expectFailure: true}, - {req: getRequest("key"), resp: getResponse("key", "2", 2, 2), expectFailure: true}, - {req: getRequest("key"), resp: getResponse("key", "2", 3, 3)}, + {req: getRequest("key"), resp: getResponseWithVer("key", "3", 3, 2, 3), expectFailure: true}, + {req: getRequest("key"), resp: getResponseWithVer("key", "3", 2, 2, 3), expectFailure: true}, + {req: getRequest("key"), resp: getResponseWithVer("key", "2", 2, 2, 2), expectFailure: true}, + {req: getRequest("key"), resp: getResponseWithVer("key", "2", 3, 2, 3)}, // Two failed request, two persisted. {req: putRequest("key", "3"), resp: failedResponse(errors.New("failed"))}, {req: putRequest("key", "4"), resp: failedResponse(errors.New("failed"))}, - {req: getRequest("key"), resp: getResponse("key", "4", 5, 5)}, + {req: getRequest("key"), resp: getResponseWithVer("key", "4", 5, 4, 5)}, }, }, { @@ -133,7 +133,7 @@ func TestModelNonDeterministic(t *testing.T) { {req: putRequest("key", "4"), resp: putResponse(4)}, {req: compareRevisionAndPutRequest("key", 5, ""), resp: compareRevisionAndPutResponse(false, 4)}, {req: putRequest("key", "5"), resp: failedResponse(errors.New("failed"))}, - {req: getRequest("key"), resp: getResponse("key", "5", 5, 5)}, + {req: getRequest("key"), resp: getResponseWithVer("key", "5", 5, 4, 5)}, }, }, { @@ -249,13 +249,13 @@ func TestModelNonDeterministic(t *testing.T) { // One failed request, one persisted. {req: putRequest("key", "1"), resp: putResponse(2)}, {req: compareRevisionAndPutRequest("key", 2, "2"), resp: failedResponse(errors.New("failed"))}, - {req: getRequest("key"), resp: getResponse("key", "2", 2, 2), expectFailure: true}, - {req: getRequest("key"), resp: getResponse("key", "2", 3, 3)}, + {req: getRequest("key"), resp: getResponseWithVer("key", "2", 2, 2, 2), expectFailure: true}, + {req: getRequest("key"), resp: getResponseWithVer("key", "2", 3, 2, 3)}, // Two failed request, two persisted. {req: putRequest("key", "3"), resp: putResponse(4)}, {req: compareRevisionAndPutRequest("key", 4, "4"), resp: failedResponse(errors.New("failed"))}, {req: compareRevisionAndPutRequest("key", 5, "5"), resp: failedResponse(errors.New("failed"))}, - {req: getRequest("key"), resp: getResponse("key", "5", 6, 6)}, + {req: getRequest("key"), resp: getResponseWithVer("key", "5", 6, 5, 6)}, }, }, { diff --git a/tests/robustness/report/wal.go b/tests/robustness/report/wal.go index 133ba9bb100..077ddc8896a 100644 --- a/tests/robustness/report/wal.go +++ b/tests/robustness/report/wal.go @@ -199,10 +199,20 @@ func parseEntryNormal(ent raftpb.Entry) (*model.EtcdRequest, error) { OperationsOnFailure: []model.EtcdOperation{}, } for _, cmp := range raftReq.Txn.Compare { - txn.Conditions = append(txn.Conditions, model.EtcdCondition{ - Key: string(cmp.Key), - ExpectedRevision: cmp.GetModRevision(), - }) + switch { + case cmp.Result == pb.Compare_EQUAL && cmp.Target == pb.Compare_VERSION: + txn.Conditions = append(txn.Conditions, model.EtcdCondition{ + Key: string(cmp.Key), + ExpectedVersion: cmp.GetVersion(), + }) + case cmp.Result == pb.Compare_EQUAL && cmp.Target == pb.Compare_MOD: + txn.Conditions = append(txn.Conditions, model.EtcdCondition{ + Key: string(cmp.Key), + ExpectedRevision: cmp.GetModRevision(), + }) + default: + panic(fmt.Sprintf("unsupported condition: %+v", cmp)) + } } for _, op := range raftReq.Txn.Success { txn.OperationsOnSuccess = append(txn.OperationsOnSuccess, toEtcdOperation(op)) diff --git a/tests/robustness/traffic/kubernetes.go b/tests/robustness/traffic/kubernetes.go index ad1d7de4209..1e6493454f0 100644 --- a/tests/robustness/traffic/kubernetes.go +++ b/tests/robustness/traffic/kubernetes.go @@ -235,9 +235,8 @@ const ( func compact(ctx context.Context, client *client.RecordingClient, t, rev int64) (int64, int64, error) { // Based on https://github.com/kubernetes/apiserver/blob/7dd4904f1896e11244ba3c5a59797697709de6b6/pkg/storage/etcd3/compact.go#L133-L162 - // TODO: Use Version and not ModRevision when model supports key versioning. resp, err := client.Txn(ctx). - If(clientv3.Compare(clientv3.ModRevision(compactRevKey), "=", t)). + If(clientv3.Compare(clientv3.Version(compactRevKey), "=", t)). Then(clientv3.OpPut(compactRevKey, strconv.FormatInt(rev, 10))). Else(clientv3.OpGet(compactRevKey)). Commit() @@ -248,8 +247,7 @@ func compact(ctx context.Context, client *client.RecordingClient, t, rev int64) curRev := resp.Header.Revision if !resp.Succeeded { - // TODO: Use Version and not ModRevision when model supports key versioning. - curTime := resp.Responses[0].GetResponseRange().Kvs[0].ModRevision + curTime := resp.Responses[0].GetResponseRange().Kvs[0].Version return curTime, curRev, nil } curTime := t + 1 diff --git a/tests/robustness/validate/operations_test.go b/tests/robustness/validate/operations_test.go index c6b7afab91f..a244d9f7533 100644 --- a/tests/robustness/validate/operations_test.go +++ b/tests/robustness/validate/operations_test.go @@ -290,6 +290,7 @@ func keyValueRevision(key, value string, rev int64) model.KeyValue { ValueRevision: model.ValueRevision{ Value: model.ToValueOrHash(value), ModRevision: rev, + Version: 1, }, } } diff --git a/tests/robustness/validate/validate_test.go b/tests/robustness/validate/validate_test.go index 14a3a3210ff..e847af672a9 100644 --- a/tests/robustness/validate/validate_test.go +++ b/tests/robustness/validate/validate_test.go @@ -1633,8 +1633,8 @@ func TestValidateWatch(t *testing.T) { { Events: []model.WatchEvent{ putWatchEvent("a", "1", 2, true), - putWatchEventWithPrevKV("a", "2", 3, false, "1", 2), - deleteWatchEventWithPrevKV("a", 4, "2", 3), + putWatchEventWithPrevKVV("a", "2", 3, false, "1", 2, 1), + deleteWatchEventWithPrevKVV("a", 4, "2", 3, 2), putWatchEvent("a", "4", 5, true), }, }, @@ -1864,21 +1864,31 @@ func deleteWatchEvent(key string, rev int64) model.WatchEvent { } func putWatchEventWithPrevKV(key, value string, rev int64, isCreate bool, prevValue string, modRev int64) model.WatchEvent { + return putWatchEventWithPrevKVV(key, value, rev, isCreate, prevValue, modRev, 0) +} + +func putWatchEventWithPrevKVV(key, value string, rev int64, isCreate bool, prevValue string, modRev, ver int64) model.WatchEvent { return model.WatchEvent{ PersistedEvent: putPersistedEvent(key, value, rev, isCreate), PrevValue: &model.ValueRevision{ Value: model.ToValueOrHash(prevValue), ModRevision: modRev, + Version: ver, }, } } func deleteWatchEventWithPrevKV(key string, rev int64, prevValue string, modRev int64) model.WatchEvent { + return deleteWatchEventWithPrevKVV(key, rev, prevValue, modRev, 0) +} + +func deleteWatchEventWithPrevKVV(key string, rev int64, prevValue string, modRev, ver int64) model.WatchEvent { return model.WatchEvent{ PersistedEvent: deletePersistedEvent(key, rev), PrevValue: &model.ValueRevision{ Value: model.ToValueOrHash(prevValue), ModRevision: modRev, + Version: ver, }, } }