def test_forall(): a = A() sc = timewinder.statetree.StateController(timewinder.statetree.MemoryCAS()) sc.mount("a", a) ok = timewinder.ForAll(A, lambda m: m.foo == "a") assert ok.check(sc) fail = timewinder.ForAll(A, lambda m: m.foo == "b") assert not fail.check(sc)
def test_check_and_withdraw_reinterp(benchmark): @timewinder.process def check_and_withdraw(sender, reciever, amt): if amt <= sender.acc: sender.acc = sender.acc - amt yield "deposit" reciever.acc = reciever.acc + amt no_overdrafts = timewinder.ForAll(Account, lambda a: a.acc >= 0) def reset_and_eval(): alice = Account("alice", 5) bob = Account("bob", 5) ev = timewinder.Evaluator( objects=[alice, bob], threads=[ check_and_withdraw(alice, bob, Set(range(1, 6))), check_and_withdraw(alice, bob, Set(range(1, 6))), ], specs=[no_overdrafts], ) ev.evaluate(steps=10) return ev.stats stats = benchmark(reset_and_eval) assert stats.states == 225
def test_overdraft_1(): @timewinder.object class Account: def __init__(self, name): self.name = name self.acc = 5 alice = Account("alice") bob = Account("bob") @timewinder.step def withdraw(state, sender, amount): sender.acc = sender.acc - amount @timewinder.step def deposit(state, reciever, amount): reciever.acc = reciever.acc + amount alg = timewinder.FuncProcess( withdraw(alice, 3), deposit(bob, 3), ) no_overdrafts = timewinder.ForAll(Account, lambda a: a.acc >= 0) ev = timewinder.Evaluator( objects=[alice, bob], threads=[alg], specs=[no_overdrafts], ) ev.evaluate() ev._print_state_space() assert ev.stats.states == 3
def test_overdraft_initial_conditions(): alice = Account("alice", 5) bob = Account("bob", 5) @timewinder.process def withdraw(sender, reciever, amount): sender.acc = sender.acc - amount yield "deposit" reciever.acc = reciever.acc + amount no_overdrafts = timewinder.ForAll(Account, lambda a: a.acc >= 0) ev = timewinder.Evaluator( objects=[alice, bob], threads=[withdraw(alice, bob, Set(range(1, 7)))], specs=[no_overdrafts], ) got_error = False try: ev.evaluate() except ConstraintError as e: got_error = True print(e.name) print(e.thunk) assert got_error assert ev.stats.states == 12
def test_multiple_processes_if(): @timewinder.object class Account: def __init__(self, name): self.name = name self.acc = 5 alice = Account("alice") bob = Account("bob") @timewinder.step def withdraw(state, sender): sender.acc = sender.acc - state["amt"] @timewinder.step def deposit(state, reciever): reciever.acc = reciever.acc + state["amt"] @timewinder.step def check_funds(state, sender): if state["amt"] > sender.acc: raise timewinder.StopProcess() def alg(): return timewinder.FuncProcess( check_funds(alice), withdraw(alice), deposit(bob), state={"amt": Set(range(1, 6))}, ) no_overdrafts = timewinder.ForAll(Account, lambda a: a.acc >= 0) ev = timewinder.Evaluator( objects=[alice, bob], threads=[alg(), alg()], specs=[no_overdrafts], ) got_error = False try: ev.evaluate(steps=10) except ConstraintError as e: got_error = True print(e.name, " failed") ev.replay_thunk(e.thunk) assert got_error assert ev.stats.states == 295
def test_overdraft_initial_conditions(): @timewinder.object class Account: def __init__(self, name): self.name = name self.acc = 5 alice = Account("alice") bob = Account("bob") @timewinder.step def withdraw(state, sender): sender.acc = sender.acc - state["amt"] @timewinder.step def deposit(state, reciever): reciever.acc = reciever.acc + state["amt"] alg = timewinder.FuncProcess( withdraw(alice), deposit(bob), state={ "amt": Set(range(1, 7)), }, ) no_overdrafts = timewinder.ForAll(Account, lambda a: a.acc >= 0) ev = timewinder.Evaluator( objects=[alice, bob], threads=[alg], specs=[no_overdrafts], ) got_error = False try: ev.evaluate() except ConstraintError as e: got_error = True print(e.name) print(e.thunk) assert got_error assert ev.stats.states == 12
def bounded_queue_example(n_producers, n_consumers, queue_size): n_threads = n_producers + n_consumers runnable = CondWait(n_producers, n_consumers) bqueue = BoundedQueue(queue_size) threads = [] for i in range(n_threads): if i < n_producers: threads.append(producer(bqueue, runnable, i)) else: threads.append(consumer(bqueue, runnable, i)) no_deadlocks = timewinder.ForAll(CondWait, lambda c: any(c.status)) return timewinder.Evaluator( objects=[runnable, bqueue], specs=[no_deadlocks], threads=threads, )
def test_liveness_reinterp(): @timewinder.process def check_and_withdraw(sender, reciever, amt): if amt <= sender.acc: sender.acc = sender.acc - amt yield "deposit" reciever.acc = reciever.acc + amt no_overdrafts = timewinder.ForAll(Account, lambda a: a.acc >= 0) @timewinder.predicate def consistent_total(a, b): total = a.acc + b.acc return total == 10 alice = Account("alice", 5) bob = Account("bob", 5) eventually_consistent = timewinder.Eventually( timewinder.Always(consistent_total(alice, bob))) ev = timewinder.Evaluator( objects=[alice, bob], threads=[ check_and_withdraw(alice, bob, Set(range(1, 6))), check_and_withdraw(alice, bob, Set(range(1, 6))), ], specs=[ no_overdrafts, eventually_consistent, ], ) got_error = False try: ev.evaluate(steps=10) except StutterConstraintError as s: got_error = True print("\n" + s.name + "\n") ev.replay_thunk(s.thunk) assert got_error
def test_check_and_withdraw(benchmark): @timewinder.object class Account: def __init__(self, name): self.name = name self.acc = 5 @timewinder.step def deposit(state, reciever): reciever.acc = reciever.acc + state["amt"] @timewinder.step def check_and_withdraw(state, sender): if state["amt"] > sender.acc: raise timewinder.StopProcess() else: sender.acc = sender.acc - state["amt"] no_overdrafts = timewinder.ForAll(Account, lambda a: a.acc >= 0) def reset_and_eval(): alice = Account("alice") bob = Account("bob") def alg(): return timewinder.FuncProcess( check_and_withdraw(alice), deposit(bob), state={"amt": Set(range(1, 6))}, ) ev = timewinder.Evaluator( objects=[alice, bob], threads=[alg(), alg()], specs=[no_overdrafts], ) ev.evaluate(steps=10) return ev.stats stats = benchmark(reset_and_eval) assert stats.states == 225
def test_overdraft_1(): alice = Account("alice", 5) bob = Account("bob", 5) @timewinder.process def withdraw(sender, reciever, amount): sender.acc = sender.acc - amount yield "deposit" reciever.acc = reciever.acc + amount no_overdrafts = timewinder.ForAll(Account, lambda a: a.acc >= 0) ev = timewinder.Evaluator( objects=[alice, bob], threads=[withdraw(alice, bob, 3)], specs=[no_overdrafts], ) ev.evaluate() ev._print_state_space() assert ev.stats.states == 3
@timewinder.process def check_and_withdraw(sender, reciever, amt): if amt <= sender.acc: sender.acc = sender.acc - amt yield "deposit" reciever.acc = reciever.acc + amt # Instantiate our example account objects alice = Account("alice", 5) bob = Account("bob", 5) # Create a predicate that says, at every stage, all Account # objects must carry positive balances. no_overdrafts = timewinder.ForAll(Account, lambda a: a.acc >= 0) # Run the evaluator. ev = timewinder.Evaluator( # Pass our two objects objects=[alice, bob], # Declare the predicates we want to check. specs=[no_overdrafts], # Only have one thread do a withdrawal of too much # money, and it should fail. # threads=[withdraw(alice, bob, 6)], # Alternately, run two threads, both withdrawing from Alice and depositing # to Bob's account. The `Set` function is a generator that will # try every transfer amount from 1 to 5, as per Python's `range`
THREADS = PRODUCERS + CONSUMERS runnable = CondWait(PRODUCERS, CONSUMERS) bqueue = BoundedQueue(QUEUE_SIZE) threads = [] for i in range(THREADS): if i < PRODUCERS: threads.append(producer(bqueue, runnable, i)) else: threads.append(consumer(bqueue, runnable, i)) no_deadlocks = timewinder.ForAll(CondWait, lambda c: any(c.status)) ev = timewinder.Evaluator( objects=[runnable, bqueue], specs=[no_deadlocks], threads=threads, ) err = None try: ev.evaluate(steps=None) except timewinder.ConstraintError as e: err = e