Merge pull request #16044 from serathius/robusness-empty

tests/robustness: Assume starting from empty etcd instead of throwing out first failed request
dependabot/go_modules/github.com/prometheus/procfs-0.11.0
Marek Siarkowicz 2023-06-12 10:18:34 +02:00 committed by GitHub
commit a6ab774458
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 32 additions and 14 deletions

View File

@ -70,12 +70,8 @@ func (s etcdState) Step(request EtcdRequest, response EtcdResponse) (bool, etcdS
// initState tries to create etcd state based on the first request. // initState tries to create etcd state based on the first request.
func initState(request EtcdRequest, response EtcdResponse) etcdState { func initState(request EtcdRequest, response EtcdResponse) etcdState {
state := etcdState{ state := emptyState()
Revision: response.Revision, state.Revision = response.Revision
KeyValues: map[string]ValueRevision{},
KeyLeases: map[string]int64{},
Leases: map[int64]EtcdLease{},
}
switch request.Type { switch request.Type {
case Txn: case Txn:
if response.Txn.Failure { if response.Txn.Failure {
@ -118,6 +114,15 @@ func initState(request EtcdRequest, response EtcdResponse) etcdState {
return state return state
} }
func emptyState() etcdState {
return etcdState{
Revision: 1,
KeyValues: map[string]ValueRevision{},
KeyLeases: map[string]int64{},
Leases: map[int64]EtcdLease{},
}
}
// step handles a successful request, returning updated state and response it would generate. // step handles a successful request, returning updated state and response it would generate.
func (s etcdState) step(request EtcdRequest) (etcdState, EtcdResponse) { func (s etcdState) step(request EtcdRequest) (etcdState, EtcdResponse) {
newKVs := map[string]ValueRevision{} newKVs := map[string]ValueRevision{}

View File

@ -71,11 +71,10 @@ type EtcdNonDeterministicResponse struct {
func (states nonDeterministicState) Step(request EtcdRequest, response EtcdNonDeterministicResponse) (bool, nonDeterministicState) { func (states nonDeterministicState) Step(request EtcdRequest, response EtcdNonDeterministicResponse) (bool, nonDeterministicState) {
if len(states) == 0 { if len(states) == 0 {
// states were not initialized if response.Err == nil && !response.ResultUnknown {
if response.Err != nil || response.ResultUnknown || response.Revision == 0 { return true, nonDeterministicState{initState(request, response.EtcdResponse)}
return true, nil
} }
return true, initNonDeterministicState(request, response) states = nonDeterministicState{emptyState()}
} }
var newStates nonDeterministicState var newStates nonDeterministicState
if response.Err != nil { if response.Err != nil {
@ -86,10 +85,6 @@ func (states nonDeterministicState) Step(request EtcdRequest, response EtcdNonDe
return len(newStates) > 0, newStates return len(newStates) > 0, newStates
} }
func initNonDeterministicState(request EtcdRequest, response EtcdNonDeterministicResponse) nonDeterministicState {
return nonDeterministicState{initState(request, response.EtcdResponse)}
}
// stepFailedRequest duplicates number of states by considering request persisted and lost. // stepFailedRequest duplicates number of states by considering request persisted and lost.
func (states nonDeterministicState) stepFailedRequest(request EtcdRequest) nonDeterministicState { func (states nonDeterministicState) stepFailedRequest(request EtcdRequest) nonDeterministicState {
newStates := make(nonDeterministicState, 0, len(states)*2) newStates := make(nonDeterministicState, 0, len(states)*2)

View File

@ -21,6 +21,8 @@ import (
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.etcd.io/etcd/api/v3/mvccpb"
) )
func TestModelNonDeterministic(t *testing.T) { func TestModelNonDeterministic(t *testing.T) {
@ -30,6 +32,22 @@ func TestModelNonDeterministic(t *testing.T) {
} }
nonDeterministicTestScenarios = append(nonDeterministicTestScenarios, []nonDeterministicModelTest{ nonDeterministicTestScenarios = append(nonDeterministicTestScenarios, []nonDeterministicModelTest{
{
name: "First Put request fails, but is persisted",
operations: []nonDeterministicOperation{
{req: putRequest("key1", "1"), resp: failedResponse(errors.New("failed"))},
{req: putRequest("key2", "2"), resp: putResponse(3)},
{req: rangeRequest("key", true, 0), resp: rangeResponse([]*mvccpb.KeyValue{{Key: []byte("key1"), Value: []byte("1"), ModRevision: 2}, {Key: []byte("key2"), Value: []byte("2"), ModRevision: 3}}, 2, 3)},
},
},
{
name: "First Put request fails, and is lost",
operations: []nonDeterministicOperation{
{req: putRequest("key1", "1"), resp: failedResponse(errors.New("failed"))},
{req: putRequest("key2", "2"), resp: putResponse(2)},
{req: rangeRequest("key", true, 0), resp: rangeResponse([]*mvccpb.KeyValue{{Key: []byte("key2"), Value: []byte("2"), ModRevision: 2}}, 1, 2)},
},
},
{ {
name: "Put can fail and be lost before get", name: "Put can fail and be lost before get",
operations: []nonDeterministicOperation{ operations: []nonDeterministicOperation{