Skip to content

Commit

Permalink
Merge pull request #19255 from AwesomePatrol/add-version-to-robustnes…
Browse files Browse the repository at this point in the history
…s-model

Add Version field to the robustness model
  • Loading branch information
serathius authored Jan 27, 2025
2 parents f7a36a5 + 3dbe62f commit f98fa31
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 57 deletions.
1 change: 1 addition & 0 deletions tests/robustness/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
11 changes: 9 additions & 2 deletions tests/robustness/model/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
Expand All @@ -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, " && ")
}
Expand Down
15 changes: 14 additions & 1 deletion tests/robustness/model/deterministic.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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)
Expand Down Expand Up @@ -326,6 +337,7 @@ type TxnRequest struct {
type EtcdCondition struct {
Key string
ExpectedRevision int64
ExpectedVersion int64
}

type EtcdOperation struct {
Expand Down Expand Up @@ -434,6 +446,7 @@ func (el EtcdLease) DeepCopy() EtcdLease {
type ValueRevision struct {
Value ValueOrHash
ModRevision int64
Version int64
}

type ValueOrHash struct {
Expand Down
60 changes: 30 additions & 30 deletions tests/robustness/model/deterministic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)},
},
},
{
Expand All @@ -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)},
},
},
Expand All @@ -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},
},
},
Expand All @@ -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},
},
},
Expand Down Expand Up @@ -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)},
},
},
{
Expand All @@ -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)},
},
},
Expand Down Expand Up @@ -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)},
},
},
{
Expand All @@ -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)},
},
Expand All @@ -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)},
},
},
{
Expand Down
13 changes: 10 additions & 3 deletions tests/robustness/model/history.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -228,6 +229,7 @@ func toEtcdOperationResult(resp *etcdserverpb.ResponseOp) EtcdOperationResult {
ValueRevision: ValueRevision{
Value: ToValueOrHash(string(kv.Value)),
ModRevision: kv.ModRevision,
Version: kv.Version,
},
}
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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,
},
}
}
Expand Down
22 changes: 11 additions & 11 deletions tests/robustness/model/non_deterministic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ 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)},
},
},
{
name: "First Put request fails, and is lost",
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)},
},
},
{
Expand Down Expand Up @@ -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)},
},
},
{
Expand Down Expand Up @@ -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)},
},
},
{
Expand Down Expand Up @@ -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)},
},
},
{
Expand Down
18 changes: 14 additions & 4 deletions tests/robustness/report/wal.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
6 changes: 2 additions & 4 deletions tests/robustness/traffic/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions tests/robustness/validate/operations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ func keyValueRevision(key, value string, rev int64) model.KeyValue {
ValueRevision: model.ValueRevision{
Value: model.ToValueOrHash(value),
ModRevision: rev,
Version: 1,
},
}
}
Loading

0 comments on commit f98fa31

Please sign in to comment.