// Copyright 2023 The etcd Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package model import ( "errors" "testing" "github.com/stretchr/testify/assert" "go.etcd.io/etcd/api/v3/mvccpb" ) func TestModelDescribe(t *testing.T) { tcs := []struct { req EtcdRequest resp EtcdNonDeterministicResponse expectDescribe string }{ { req: getRequest("key1"), resp: emptyGetResponse(1), expectDescribe: `get("key1") -> nil, rev: 1`, }, { req: getRequest("key2"), resp: getResponse("key", "2", 2, 2), expectDescribe: `get("key2") -> "2", rev: 2`, }, { req: getRequest("key2b"), resp: getResponse("key2b", "01234567890123456789", 2, 2), expectDescribe: `get("key2b") -> hash: 2945867837, rev: 2`, }, { req: putRequest("key3", "3"), resp: putResponse(3), expectDescribe: `put("key3", "3") -> ok, rev: 3`, }, { req: putWithLeaseRequest("key3b", "3b", 3), resp: putResponse(3), expectDescribe: `put("key3b", "3b", 3) -> ok, rev: 3`, }, { req: putRequest("key3c", "01234567890123456789"), resp: putResponse(3), expectDescribe: `put("key3c", hash: 2945867837) -> ok, rev: 3`, }, { req: putRequest("key4", "4"), resp: failedResponse(errors.New("failed")), expectDescribe: `put("key4", "4") -> err: "failed"`, }, { req: putRequest("key4b", "4b"), resp: unknownResponse(42), expectDescribe: `put("key4b", "4b") -> unknown, rev: 42`, }, { req: deleteRequest("key5"), resp: deleteResponse(1, 5), expectDescribe: `delete("key5") -> deleted: 1, rev: 5`, }, { req: deleteRequest("key6"), resp: failedResponse(errors.New("failed")), expectDescribe: `delete("key6") -> err: "failed"`, }, { req: compareAndSetRequest("key7", 7, "77"), resp: compareAndSetResponse(false, 7), expectDescribe: `if(mod_rev(key7)==7).then(put("key7", "77")) -> txn failed, rev: 7`, }, { req: compareAndSetRequest("key8", 8, "88"), resp: compareAndSetResponse(true, 8), expectDescribe: `if(mod_rev(key8)==8).then(put("key8", "88")) -> ok, rev: 8`, }, { req: compareAndSetRequest("key9", 9, "99"), resp: failedResponse(errors.New("failed")), expectDescribe: `if(mod_rev(key9)==9).then(put("key9", "99")) -> err: "failed"`, }, { req: txnRequest(nil, []EtcdOperation{{Type: Range, Key: "10"}, {Type: Put, Key: "11", Value: ValueOrHash{Value: "111"}}, {Type: Delete, Key: "12"}}), resp: txnResponse([]EtcdOperationResult{{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`, }, { req: defragmentRequest(), resp: defragmentResponse(10), expectDescribe: `defragment() -> ok, rev: 10`, }, { req: rangeRequest("key11", true), resp: rangeResponse(nil, 11), expectDescribe: `range("key11") -> [], rev: 11`, }, { req: rangeRequest("key12", true), resp: rangeResponse([]*mvccpb.KeyValue{{Value: []byte("12")}}, 12), expectDescribe: `range("key12") -> ["12"], rev: 12`, }, { req: rangeRequest("key13", true), resp: rangeResponse([]*mvccpb.KeyValue{{Value: []byte("01234567890123456789")}}, 13), expectDescribe: `range("key13") -> [hash: 2945867837], rev: 13`, }, } for _, tc := range tcs { assert.Equal(t, tc.expectDescribe, NonDeterministicModel.DescribeOperation(tc.req, tc.resp)) } }