def test_stop_raises_if_notification_pulling_is_broken(self): system = System(pipes=[ [ BankAccounts, TestNewMultiThreadedRunner.BrokenPulling, ], ]) # Create runner. self.runner = self.runner_class(system) # Create some notifications. accounts = self.runner.get(BankAccounts) accounts.open_account( full_name="Alice", email_address="*****@*****.**", ) # Start runner. self.runner.start() # Trigger pulling of notifications. accounts = self.runner.get(BankAccounts) accounts.open_account( full_name="Alice", email_address="*****@*****.**", ) # Wait for runner to error. self.assertTrue(self.runner.has_errored.wait(timeout=1)) # Check stop() raises exception. with self.assertRaises(NotificationPullingError) as cm: self.runner.stop() self.assertIn( "Just testing error handling when pulling is broken", cm.exception.args[0], ) self.runner = None
def test_stops_if_app_processing_is_broken(self): system = System(pipes=[ [ BankAccounts, TestMultiThreadedRunner.BrokenProcessing, ], ]) self.start_runner(system) accounts = self.runner.get(BankAccounts) accounts.open_account( full_name="Alice", email_address="*****@*****.**", ) # Check watch_for_errors() raises exception. with self.assertRaises(EventProcessingError) as cm: self.runner.watch_for_errors(timeout=1) self.assertIn( "Just testing error handling when processing is broken", cm.exception.args[0], ) self.runner = None
def test_prompts_received_doesnt_accumulate_names(self): system = System( pipes=[ [ BankAccounts, EmailNotifications, ], ] ) runner = self.runner_class(system) runner.start() with self.assertRaises(RunnerAlreadyStarted): runner.start() # Check prompts_received list doesn't accumulate. runner.is_prompting = True self.assertEqual(runner.prompts_received, []) runner.receive_prompt("BankAccounts") self.assertEqual(runner.prompts_received, ["BankAccounts"]) runner.receive_prompt("BankAccounts") self.assertEqual(runner.prompts_received, ["BankAccounts"]) runner.is_prompting = False
def test_calling_start_twice_raises_error(self): self.start_runner(System(pipes=[[BankAccounts]])) with self.assertRaises(RunnerAlreadyStarted): self.runner.start()
def test_starts_with_single_app(self): self.start_runner(System(pipes=[[BankAccounts]])) app = self.runner.get(BankAccounts) self.assertIsInstance(app, BankAccounts)
def test_system_with_processing_loop(self): class Command(Aggregate): def __init__(self, text: str): self.text = text self.output: Optional[str] = None self.error: Optional[str] = None @event def done(self, output: str, error: str): self.output = output self.error = error class Result(Aggregate): def __init__(self, command_id: UUID, output: str, error: str): self.command_id = command_id self.output = output self.error = error class Commands(ProcessApplication): def create_command(self, text: str) -> UUID: command = Command(text=text) self.save(command) return command.id def policy( self, domain_event: AggregateEvent[Aggregate], processing_event: ProcessingEvent, ) -> None: if isinstance(domain_event, Result.Created): command = self.repository.get(domain_event.command_id) command.done( output=domain_event.output, error=domain_event.error, ) processing_event.collect_events(command) def get_result(self, command_id: UUID) -> Tuple[str, str]: command = self.repository.get(command_id) return command.output, command.error class Results(ProcessApplication): def policy( self, domain_event: AggregateEvent[Aggregate], processing_event: ProcessingEvent, ) -> None: if isinstance(domain_event, Command.Created): try: output = subprocess.check_output( shlex.split(domain_event.text)) error = "" except Exception as e: error = str(e) output = b"" result = Result( command_id=domain_event.originator_id, output=output.decode("utf8"), error=error, ) processing_event.collect_events(result) self.start_runner(System([[Commands, Results, Commands]])) commands = self.runner.get(Commands) command_id1 = commands.create_command("echo 'Hello World'") command_id2 = commands.create_command("notacommand") self.wait_for_runner() self.wait_for_runner() for _ in range(10): output, error = commands.get_result(command_id1) if output is None: sleep(0.1) else: break else: self.fail("No results from command") self.assertEqual(output, "Hello World\n") self.assertEqual(error, "") for _ in range(10): output, error = commands.get_result(command_id2) if output is None: sleep(0.1) else: break else: self.fail("No results from command") self.assertEqual(output, "") self.assertIn("No such file or directory: 'notacommand'", error)
from eventsourcing.system import System, SingleThreadedRunner from stocky.command.account.application import AccountApplication, AccountApplicationProducer # init system = System(pipes=[[AccountApplication, AccountApplicationProducer]]) runner = SingleThreadedRunner(system) runner.start() accounts = runner.get(AccountApplication) producer = AccountApplicationProducer() accounts.lead(producer) producer.follow(accounts.__class__.__name__, accounts.log)