mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
tests/robustness: Make watch event independent from etcd operation
Signed-off-by: Marek Siarkowicz <siarkowicz@google.com>
This commit is contained in:
parent
04d24c2128
commit
3f09a51c60
@ -95,17 +95,17 @@ func TestModelDescribe(t *testing.T) {
|
||||
expectDescribe: `if(mod_rev(key9)==9).then(put("key9", "99")) -> err: "failed"`,
|
||||
},
|
||||
{
|
||||
req: txnRequest([]EtcdCondition{{Key: "key9b", ExpectedRevision: 9}}, []EtcdOperation{{Type: PutOperation, Key: "key9b", PutOptions: PutOptions{Value: ValueOrHash{Value: "991"}}}}, []EtcdOperation{{Type: RangeOperation, Key: "key9b"}}),
|
||||
req: txnRequest([]EtcdCondition{{Key: "key9b", ExpectedRevision: 9}}, []EtcdOperation{{Type: PutOperation, Key: "key9b", Value: ValueOrHash{Value: "991"}}}, []EtcdOperation{{Type: RangeOperation, Key: "key9b"}}),
|
||||
resp: txnResponse([]EtcdOperationResult{{}}, true, 10),
|
||||
expectDescribe: `if(mod_rev(key9b)==9).then(put("key9b", "991")).else(get("key9b")) -> success(ok), rev: 10`,
|
||||
},
|
||||
{
|
||||
req: txnRequest([]EtcdCondition{{Key: "key9c", ExpectedRevision: 9}}, []EtcdOperation{{Type: PutOperation, Key: "key9c", PutOptions: PutOptions{Value: ValueOrHash{Value: "992"}}}}, []EtcdOperation{{Type: RangeOperation, Key: "key9c"}}),
|
||||
req: txnRequest([]EtcdCondition{{Key: "key9c", ExpectedRevision: 9}}, []EtcdOperation{{Type: PutOperation, Key: "key9c", Value: ValueOrHash{Value: "992"}}}, []EtcdOperation{{Type: RangeOperation, Key: "key9c"}}),
|
||||
resp: txnResponse([]EtcdOperationResult{{RangeResponse: RangeResponse{KVs: []KeyValue{{Key: "key9c", ValueRevision: ValueRevision{Value: ValueOrHash{Value: "993"}, ModRevision: 10}}}}}}, false, 10),
|
||||
expectDescribe: `if(mod_rev(key9c)==9).then(put("key9c", "992")).else(get("key9c")) -> failure("993"), rev: 10`,
|
||||
},
|
||||
{
|
||||
req: txnRequest(nil, []EtcdOperation{{Type: RangeOperation, Key: "10"}, {Type: PutOperation, Key: "11", PutOptions: PutOptions{Value: ValueOrHash{Value: "111"}}}, {Type: DeleteOperation, Key: "12"}}, nil),
|
||||
req: txnRequest(nil, []EtcdOperation{{Type: RangeOperation, Key: "10"}, {Type: PutOperation, Key: "11", Value: ValueOrHash{Value: "111"}}, {Type: DeleteOperation, Key: "12"}}, nil),
|
||||
resp: txnResponse([]EtcdOperationResult{{RangeResponse: RangeResponse{KVs: []KeyValue{{ValueRevision: ValueRevision{Value: ValueOrHash{Value: "110"}}}}}}, {}, {Deleted: 1}}, true, 10),
|
||||
expectDescribe: `get("10"), put("11", "111"), delete("12") -> "110", ok, deleted: 1, rev: 10`,
|
||||
},
|
||||
|
@ -261,11 +261,6 @@ type RangeOptions struct {
|
||||
Limit int64
|
||||
}
|
||||
|
||||
type PutOptions struct {
|
||||
Value ValueOrHash
|
||||
LeaseID int64
|
||||
}
|
||||
|
||||
type TxnRequest struct {
|
||||
Conditions []EtcdCondition
|
||||
OperationsOnSuccess []EtcdOperation
|
||||
@ -281,7 +276,8 @@ type EtcdOperation struct {
|
||||
Type OperationType
|
||||
Key string
|
||||
RangeOptions
|
||||
PutOptions
|
||||
Value ValueOrHash
|
||||
LeaseID int64
|
||||
}
|
||||
|
||||
type OperationType string
|
||||
|
@ -239,23 +239,20 @@ func toEtcdCondition(cmp clientv3.Cmp) (cond EtcdCondition) {
|
||||
return cond
|
||||
}
|
||||
|
||||
func toEtcdOperation(op clientv3.Op) EtcdOperation {
|
||||
var opType OperationType
|
||||
func toEtcdOperation(option clientv3.Op) (op EtcdOperation) {
|
||||
op.Key = string(option.KeyBytes())
|
||||
switch {
|
||||
case op.IsGet():
|
||||
opType = RangeOperation
|
||||
case op.IsPut():
|
||||
opType = PutOperation
|
||||
case op.IsDelete():
|
||||
opType = DeleteOperation
|
||||
case option.IsGet():
|
||||
op.Type = RangeOperation
|
||||
case option.IsPut():
|
||||
op.Type = PutOperation
|
||||
op.Value = ValueOrHash{Value: string(option.ValueBytes())}
|
||||
case option.IsDelete():
|
||||
op.Type = DeleteOperation
|
||||
default:
|
||||
panic("Unsupported operation")
|
||||
}
|
||||
return EtcdOperation{
|
||||
Type: opType,
|
||||
Key: string(op.KeyBytes()),
|
||||
PutOptions: PutOptions{Value: ValueOrHash{Value: string(op.ValueBytes())}},
|
||||
}
|
||||
return op
|
||||
}
|
||||
|
||||
func toEtcdOperationResult(resp *etcdserverpb.ResponseOp) EtcdOperationResult {
|
||||
@ -384,7 +381,7 @@ func partialResponse(revision int64) MaybeEtcdResponse {
|
||||
}
|
||||
|
||||
func putRequest(key, value string) EtcdRequest {
|
||||
return EtcdRequest{Type: Txn, Txn: &TxnRequest{OperationsOnSuccess: []EtcdOperation{{Type: PutOperation, Key: key, PutOptions: PutOptions{Value: ToValueOrHash(value)}}}}}
|
||||
return EtcdRequest{Type: Txn, Txn: &TxnRequest{OperationsOnSuccess: []EtcdOperation{{Type: PutOperation, Key: key, Value: ToValueOrHash(value)}}}}
|
||||
}
|
||||
|
||||
func putResponse(revision int64) MaybeEtcdResponse {
|
||||
@ -415,7 +412,7 @@ func compareRevision(key string, expectedRevision int64) *EtcdCondition {
|
||||
}
|
||||
|
||||
func putOperation(key, value string) *EtcdOperation {
|
||||
return &EtcdOperation{Type: PutOperation, Key: key, PutOptions: PutOptions{Value: ToValueOrHash(value)}}
|
||||
return &EtcdOperation{Type: PutOperation, Key: key, Value: ToValueOrHash(value)}
|
||||
}
|
||||
|
||||
func txnRequestSingleOperation(cond *EtcdCondition, onSuccess, onFailure *EtcdOperation) EtcdRequest {
|
||||
@ -451,7 +448,7 @@ func txnResponse(result []EtcdOperationResult, succeeded bool, revision int64) M
|
||||
}
|
||||
|
||||
func putWithLeaseRequest(key, value string, leaseID int64) EtcdRequest {
|
||||
return EtcdRequest{Type: Txn, Txn: &TxnRequest{OperationsOnSuccess: []EtcdOperation{{Type: PutOperation, Key: key, PutOptions: PutOptions{Value: ToValueOrHash(value), LeaseID: leaseID}}}}}
|
||||
return EtcdRequest{Type: Txn, Txn: &TxnRequest{OperationsOnSuccess: []EtcdOperation{{Type: PutOperation, Key: key, Value: ToValueOrHash(value), LeaseID: leaseID}}}}
|
||||
}
|
||||
|
||||
func leaseGrantRequest(leaseID int64) EtcdRequest {
|
||||
|
@ -73,7 +73,12 @@ func (r *EtcdReplay) next() (request EtcdRequest, revision int64, index int) {
|
||||
index = r.eventHistoryIndex
|
||||
operations := []EtcdOperation{}
|
||||
for r.eventHistory[index].Revision == revision {
|
||||
operations = append(operations, r.eventHistory[index].Op)
|
||||
event := r.eventHistory[index]
|
||||
operations = append(operations, EtcdOperation{
|
||||
Type: event.Type,
|
||||
Key: event.Key,
|
||||
Value: event.Value,
|
||||
})
|
||||
index++
|
||||
}
|
||||
return EtcdRequest{
|
||||
@ -84,16 +89,13 @@ func (r *EtcdReplay) next() (request EtcdRequest, revision int64, index int) {
|
||||
}, revision, index
|
||||
}
|
||||
|
||||
func operationToRequest(op EtcdOperation) EtcdRequest {
|
||||
return EtcdRequest{
|
||||
Type: Txn,
|
||||
Txn: &TxnRequest{
|
||||
OperationsOnSuccess: []EtcdOperation{op},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type WatchEvent struct {
|
||||
Op EtcdOperation
|
||||
Event
|
||||
Revision int64
|
||||
}
|
||||
|
||||
type Event struct {
|
||||
Type OperationType
|
||||
Key string
|
||||
Value ValueOrHash
|
||||
}
|
||||
|
@ -266,10 +266,10 @@ func toWatchEvent(event clientv3.Event) model.WatchEvent {
|
||||
}
|
||||
return model.WatchEvent{
|
||||
Revision: event.Kv.ModRevision,
|
||||
Op: model.EtcdOperation{
|
||||
Type: op,
|
||||
Key: string(event.Kv.Key),
|
||||
PutOptions: model.PutOptions{Value: model.ToValueOrHash(string(event.Kv.Value))},
|
||||
Event: model.Event{
|
||||
Type: op,
|
||||
Key: string(event.Kv.Key),
|
||||
Value: model.ToValueOrHash(string(event.Kv.Value)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
"go.etcd.io/etcd/tests/v3/robustness/traffic"
|
||||
)
|
||||
|
||||
func patchOperationsWithWatchEvents(operations []porcupine.Operation, watchEvents map[model.EtcdOperation]traffic.TimedWatchEvent) []porcupine.Operation {
|
||||
func patchOperationsWithWatchEvents(operations []porcupine.Operation, watchEvents map[model.Event]traffic.TimedWatchEvent) []porcupine.Operation {
|
||||
newOperations := make([]porcupine.Operation, 0, len(operations))
|
||||
lastObservedOperation := lastOperationObservedInWatch(operations, watchEvents)
|
||||
|
||||
@ -51,7 +51,7 @@ func patchOperationsWithWatchEvents(operations []porcupine.Operation, watchEvent
|
||||
return newOperations
|
||||
}
|
||||
|
||||
func lastOperationObservedInWatch(operations []porcupine.Operation, watchEvents map[model.EtcdOperation]traffic.TimedWatchEvent) porcupine.Operation {
|
||||
func lastOperationObservedInWatch(operations []porcupine.Operation, watchEvents map[model.Event]traffic.TimedWatchEvent) porcupine.Operation {
|
||||
var maxCallTime int64
|
||||
var lastOperation porcupine.Operation
|
||||
for _, op := range operations {
|
||||
@ -68,16 +68,13 @@ func lastOperationObservedInWatch(operations []porcupine.Operation, watchEvents
|
||||
return lastOperation
|
||||
}
|
||||
|
||||
func matchWatchEvent(request *model.TxnRequest, watchEvents map[model.EtcdOperation]traffic.TimedWatchEvent) *traffic.TimedWatchEvent {
|
||||
func matchWatchEvent(request *model.TxnRequest, watchEvents map[model.Event]traffic.TimedWatchEvent) *traffic.TimedWatchEvent {
|
||||
for _, etcdOp := range append(request.OperationsOnSuccess, request.OperationsOnFailure...) {
|
||||
if etcdOp.Type == model.PutOperation {
|
||||
// Remove LeaseID which is not exposed in watch.
|
||||
event, ok := watchEvents[model.EtcdOperation{
|
||||
Type: etcdOp.Type,
|
||||
Key: etcdOp.Key,
|
||||
PutOptions: model.PutOptions{
|
||||
Value: etcdOp.Value,
|
||||
},
|
||||
event, ok := watchEvents[model.Event{
|
||||
Type: etcdOp.Type,
|
||||
Key: etcdOp.Key,
|
||||
Value: etcdOp.Value,
|
||||
}]
|
||||
if ok {
|
||||
return &event
|
||||
|
@ -41,12 +41,12 @@ func operations(reports []traffic.ClientReport) []porcupine.Operation {
|
||||
return ops
|
||||
}
|
||||
|
||||
func uniqueWatchEvents(reports []traffic.ClientReport) map[model.EtcdOperation]traffic.TimedWatchEvent {
|
||||
persisted := map[model.EtcdOperation]traffic.TimedWatchEvent{}
|
||||
func uniqueWatchEvents(reports []traffic.ClientReport) map[model.Event]traffic.TimedWatchEvent {
|
||||
persisted := map[model.Event]traffic.TimedWatchEvent{}
|
||||
for _, r := range reports {
|
||||
for _, resp := range r.Watch {
|
||||
for _, event := range resp.Events {
|
||||
persisted[event.Op] = traffic.TimedWatchEvent{Time: resp.Time, WatchEvent: event}
|
||||
persisted[event.Event] = traffic.TimedWatchEvent{Time: resp.Time, WatchEvent: event}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,11 +79,12 @@ func validateUnique(t *testing.T, expectUniqueRevision bool, report traffic.Clie
|
||||
key = struct {
|
||||
revision int64
|
||||
key string
|
||||
}{event.Revision, event.Op.Key}
|
||||
}{event.Revision, event.Key}
|
||||
}
|
||||
|
||||
if _, found := uniqueOperations[key]; found {
|
||||
t.Errorf("Broke watch guarantee: Unique - an event will never appear on a watch twice, key: %q, revision: %d, client: %d", event.Op.Key, event.Revision, report.ClientId)
|
||||
|
||||
t.Errorf("Broke watch guarantee: Unique - an event will never appear on a watch twice, key: %q, revision: %d, client: %d", event.Key, event.Revision, report.ClientId)
|
||||
}
|
||||
uniqueOperations[key] = struct{}{}
|
||||
}
|
||||
@ -137,7 +138,8 @@ func validateEventsMatch(t *testing.T, reports []traffic.ClientReport) {
|
||||
for _, r := range reports {
|
||||
for _, resp := range r.Watch {
|
||||
for _, event := range resp.Events {
|
||||
rk := revisionKey{key: event.Op.Key, revision: event.Revision}
|
||||
|
||||
rk := revisionKey{key: event.Key, revision: event.Revision}
|
||||
if prev, found := revisionKeyToEvent[rk]; found {
|
||||
if prev.WatchEvent != event {
|
||||
t.Errorf("Events between clients %d and %d don't match, key: %q, revision: %d, diff: %s", prev.ClientId, r.ClientId, rk.key, rk.revision, cmp.Diff(prev, event))
|
||||
|
Loading…
x
Reference in New Issue
Block a user