Repository: etcd-io/etcd
File: tests/robustness/model/non_deterministic.go (Go)

Code before:
	"github.com/anishathalye/porcupine"
)

// NonDeterministicModel extends DeterministicModel to allow for clients with imperfect knowledge of request destiny.
// Unknown/error response doesn't inform whether request was persisted or not, so model
// considers both cases. This is represented as multiple equally possible deterministic states.
// Failed requests fork the possible states, while successful requests merge and filter them.
var NonDeterministicModel = porcupine.Model{
	Init: func() any {
		return nonDeterministicState{freshEtcdState()}
	},
	Step: func(st any, in any, out any) (bool, any) {
		return st.(nonDeterministicState).apply(in.(EtcdRequest), out.(MaybeEtcdResponse))
	},
	Equal: func(st1, st2 any) bool {
		return st1.(nonDeterministicState).Equal(st2.(nonDeterministicState))
	},
	DescribeOperation: func(in, out any) string {
		return fmt.Sprintf("%s -> %s", describeEtcdRequest(in.(EtcdRequest)), describeEtcdResponse(in.(EtcdRequest), out.(MaybeEtcdResponse)))
	},
	DescribeState: func(st any) string {
		etcdStates := st.(nonDeterministicState)
		desc := ""

		for _, s := range etcdStates {
			desc += fmt.Sprintf("%s\n", describeEtcdState(s))
		}

		return desc
	},
}

type nonDeterministicState []EtcdState

func (states nonDeterministicState) Equal(other nonDeterministicState) bool {
	if len(states) != len(other) {
		return false
	}

	otherMatched := make([]bool, len(other))
	for _, sItem := range states {
		foundMatchInOther := false
		for j, otherItem := range other {
			if !otherMatched[j] && sItem.Equal(otherItem) {
				otherMatched[j] = true
				foundMatchInOther = true
				break
			}
		}
		if !foundMatchInOther {
			return false

Review comment (performance):
Strings are immutable in Go, meaning it's not recommended to append a string in for loop as it reallocates resulting in O(n^2) complexity. 

Better is to append to `[]string` and then use `strings.Join`

Code after:

	"github.com/anishathalye/porcupine"
)

// NonDeterministicModel extends DeterministicModel to allow for clients with imperfect knowledge of request destiny.
// Unknown/error response doesn't inform whether request was persisted or not, so model
// considers both cases. This is represented as multiple equally possible deterministic states.
// Failed requests fork the possible states, while successful requests merge and filter them.
var NonDeterministicModel = porcupine.Model{
	Init: func() any {
		return nonDeterministicState{freshEtcdState()}
	},
	Step: func(st any, in any, out any) (bool, any) {
		return st.(nonDeterministicState).apply(in.(EtcdRequest), out.(MaybeEtcdResponse))
	},
	Equal: func(st1, st2 any) bool {
		return st1.(nonDeterministicState).Equal(st2.(nonDeterministicState))
	},
	DescribeOperation: func(in, out any) string {
		return fmt.Sprintf("%s -> %s", describeEtcdRequest(in.(EtcdRequest)), describeEtcdResponse(in.(EtcdRequest), out.(MaybeEtcdResponse)))
	},
	DescribeState: func(st any) string {
		etcdStates := st.(nonDeterministicState)
		desc := make([]string, len(etcdStates))

		for _, s := range etcdStates {
			desc = append(desc, describeEtcdState(s))
		}

		return strings.Join(desc, "\n")
	},
}

type nonDeterministicState []EtcdState

func (states nonDeterministicState) Equal(other nonDeterministicState) bool {
	if len(states) != len(other) {
		return false
	}

	otherMatched := make([]bool, len(other))
	for _, sItem := range states {
		foundMatchInOther := false
		for j, otherItem := range other {
			if !otherMatched[j] && sItem.Equal(otherItem) {
				otherMatched[j] = true
				foundMatchInOther = true
				break
			}
		}
		if !foundMatchInOther {