def test(self):
        with self.get_application() as app:

            # Start with a new table.
            app.drop_table()
            app.drop_table()
            app.setup_table()
            app.setup_table()

            # Check the application's persistence policy,
            # repository, and event store, are working.
            aggregate = ExampleAggregateRoot.__create__()
            aggregate.__save__()
            self.assertTrue(aggregate.id in app.repository)

            # Check the notifications.
            reader = NotificationLogReader(app.notification_log)
            notifications = reader.read()
            self.assertEqual(1, len(notifications))
            topic = 'eventsourcing.tests.core_tests.test_aggregate_root#ExampleAggregateRoot.Created'
            self.assertEqual(topic, notifications[0]['topic'])

            app.drop_table()
Beispiel #2
0
    def __init__(self,
                 normal_speed,
                 scale_factor,
                 stop_event: Event,
                 is_verbose=False,
                 seen_prompt_events=None,
                 processes=None):
        super(ProcessRunningClockThread, self).__init__(daemon=True)
        self.normal_speed = normal_speed
        self.scale_factor = scale_factor
        self.stop_event = stop_event
        self.seen_prompt_events = seen_prompt_events
        self.processes = processes
        self.last_tick_time = None
        self.last_process_time = None
        self.all_tick_durations = deque()
        self.tick_adjustment = 0.0
        self.is_verbose = is_verbose
        if normal_speed and scale_factor:
            self.tick_interval = 1 / normal_speed / scale_factor
        else:
            self.tick_interval = None
        if self.tick_interval:

            self.tick_durations_window_size = max(
                100, int(round(1 / self.tick_interval, 0)))
        else:
            self.tick_durations_window_size = 1000
        # Construct lists of followers for each process.
        self.followers = {}
        for process_name, process in self.processes.items():
            self.followers[process_name] = []
        for process_name, process in self.processes.items():
            for upstream_process_name in process.readers:
                self.followers[upstream_process_name].append(process_name)

        # Construct a notification log reader for each process.
        self.readers = {}
        for process_name, process in self.processes.items():
            reader = NotificationLogReader(
                notification_log=process.notification_log,
                use_direct_query_if_available=True)
            self.readers[process_name] = reader
Beispiel #3
0
 def follow(self, upstream_application_name, notification_log):
     # Create a reader.
     reader = NotificationLogReader(notification_log, use_direct_query_if_available=True)
     self.readers[upstream_application_name] = reader
Beispiel #4
0
    def test_remote_notification_log(self):
        num_notifications = 42

        section_size = 5

        # Build a notification log (fixture).
        self.append_notifications(num_notifications)

        # Start a simple server.
        from wsgiref.util import setup_testing_defaults
        from wsgiref.simple_server import make_server

        port = 8080
        base_url = 'http://127.0.0.1:{}/notifications/'.format(port)

        def simple_app(environ, start_response):
            """Simple WSGI application."""
            setup_testing_defaults(environ)

            # Identify log and section from request.
            path_info = environ['PATH_INFO']
            try:
                section_id = path_info.strip('/').split('/')[-1]
            except ValueError:
                # Start response.
                status = '404 Not Found'
                headers = [('Content-type', 'text/plain; charset=utf-8')]
                start_response(status, headers)
                return []

            # Select the notification log.
            notification_log = self.create_notification_log(section_size)

            # Get serialized section.
            view = NotificationLogView(notification_log)
            section, is_archived = view.present_section(section_id)
            # Todo: Maybe redirect if the section ID is a mismatch, so
            # the URL is good for cacheing.

            # Start response.
            status = '200 OK'
            headers = [('Content-type', 'text/plain; charset=utf-8')]
            start_response(status, headers)

            # Return a list of lines.
            return [(line + '\n').encode('utf8')
                    for line in section.split('\n')]

        httpd = make_server('', port, simple_app)
        print("Serving on port {}...".format(port))
        thread = Thread(target=httpd.serve_forever)
        thread.setDaemon(True)
        thread.start()
        try:
            # Use reader with client to read all items in remote feed after item 5.
            notification_log = RemoteNotificationLog(base_url)

            # Get all the items.
            notification_log_reader = NotificationLogReader(
                notification_log=notification_log)
            items_from_start = notification_log_reader.read_list()

            # Check we got all the items.
            self.assertEqual(len(items_from_start), num_notifications)
            self.assertEqual(items_from_start[0]['id'], 1)
            self.assertEqual(items_from_start[0]['state'], 'item1')
            self.assertEqual(items_from_start[0]['topic'],
                             'eventsourcing.domain.model.events#DomainEvent')
            expected_section_count = ceil(num_notifications /
                                          float(section_size))
            self.assertEqual(notification_log_reader.section_count,
                             expected_section_count)

            # Get all the items from item 5.
            items_from_5 = list(notification_log_reader[section_size - 1:])

            # Check we got everything after item 5.
            self.assertEqual(len(items_from_5),
                             num_notifications - section_size + 1)
            self.assertEqual(items_from_5[0]['id'], section_size)
            self.assertEqual(items_from_5[0]['topic'],
                             'eventsourcing.domain.model.events#DomainEvent')
            self.assertEqual(items_from_5[0]['state'],
                             'item{}'.format(section_size))
            expected_section_count = ceil(num_notifications /
                                          float(section_size))
            self.assertEqual(notification_log_reader.section_count,
                             expected_section_count)

            # Check ValueError is raised for deserialization errors.
            with self.assertRaises(ValueError):
                notification_log.deserialize_section('invalid json')

        finally:
            httpd.shutdown()
            thread.join()
            httpd.server_close()
Beispiel #5
0
    def test(self):
        # Build notification log.
        section_size = 5
        notification_log = self.create_notification_log(
            section_size=section_size)

        # Append 13 notifications.
        self.append_notifications(13)

        # Construct notification log reader.
        reader = NotificationLogReader(notification_log)

        # Check position.
        self.assertEqual(reader.position, 0)

        # Read all notifications.
        all_notifications = list(reader)
        self.assertEqual(13, len(all_notifications))

        # Check position.
        self.assertEqual(reader.position, 13)

        # Add some more items to the log.
        self.append_notifications(13, 21)

        # Read subsequent notifications.
        subsequent_notifications_notifications = list(reader)
        self.assertEqual(len(subsequent_notifications_notifications), 8)

        # Check position.
        self.assertEqual(reader.position, 21)

        subsequent_notifications_notifications = list(reader)
        self.assertEqual(len(subsequent_notifications_notifications), 0)

        # Set position.
        reader.seek(13)
        subsequent_notifications_notifications = list(reader)
        self.assertEqual(len(subsequent_notifications_notifications), 8)

        # # Read items after a particular position.
        self.assertEqual(len(list(reader[0:])), 21)
        self.assertEqual(len(list(reader[1:])), 20)
        self.assertEqual(len(list(reader[2:])), 19)
        self.assertEqual(len(list(reader[3:])), 18)
        self.assertEqual(len(list(reader[13:])), 8)
        self.assertEqual(len(list(reader[18:])), 3)
        self.assertEqual(len(list(reader[19:])), 2)
        self.assertEqual(len(list(reader[20:])), 1)
        self.assertEqual(len(list(reader[21:])), 0)

        # Check last item numbers less than 1 cause a value errors.
        with self.assertRaises(ValueError):
            reader.position = -1
            list(reader)

        with self.assertRaises(ValueError):
            list(reader.seek(-1))

        # Resume from a saved position.
        saved_position = 5
        advance_by = 3
        reader.seek(saved_position)
        self.assertEqual(reader.position, saved_position)
        reader.read_list(advance_by=advance_by)
        self.assertEqual(reader.position, saved_position + advance_by)

        # Read items between particular positions.
        # - check stops at end of slice, and position tracks ok
        self.assertEqual(reader[0]['id'], 1)
        self.assertEqual(reader.position, 1)

        self.assertEqual(next(reader)['id'], 2)
        self.assertEqual(reader.position, 2)

        reader.seek(5)
        self.assertEqual(next(reader)['id'], 6)
        self.assertEqual(reader.position, 6)

        reader.seek(0)
        list(reader)
        self.assertEqual(reader.position, 21)

        self.assertEqual(len(list(reader[0:1])), 1)
        self.assertEqual(reader.position, 1)

        self.assertEqual(len(list(reader[1:3])), 2)
        self.assertEqual(reader.position, 3)

        self.assertEqual(len(list(reader[2:5])), 3)
        self.assertEqual(reader.position, 5)

        self.assertEqual(len(list(reader[3:7])), 4)
        self.assertEqual(reader.position, 7)

        self.assertEqual(len(list(reader[13:20])), 7)
        self.assertEqual(reader.position, 20)

        self.assertEqual(len(list(reader[18:20])), 2)
        self.assertEqual(reader.position, 20)

        self.assertEqual(len(list(reader[19:20])), 1)
        self.assertEqual(reader.position, 20)

        self.assertEqual(len(list(reader[20:20])), 0)
        self.assertEqual(reader.position, 20)

        self.assertEqual(len(list(reader[21:20])), 0)
        self.assertEqual(reader.position, 21)

        with self.assertRaises(StopIteration):
            next(reader)
Beispiel #6
0
 def follow(self, upstream_application_name, notification_log):
     # Create a reader.
     reader = NotificationLogReader(notification_log)
     self.readers[upstream_application_name] = reader
Beispiel #7
0
    # Optimistic concurrency control (no branches).

    old.rename('future')
    try:
        old.__save__()
    except ConcurrencyError:
        pass
    else:
        raise Exception("Shouldn't get here")

    # Check domain event data integrity (happens also during replay).
    events = app.event_store.get_domain_events(play.id)
    last_hash = ''

    for event in events:
        event.__check_hash__()
        assert event.__previous_hash__ == last_hash
        last_hash = event.__event_hash__

    # Verify stored sequence of events against known value.
    assert last_hash == play.__head__


    #play.delete()
    # Project application event notifications.
    from eventsourcing.interface.notificationlog import NotificationLogReader
    reader = NotificationLogReader(app.notification_log)

    #TODO: summfin cool?
Beispiel #8
0
    # Verify stored sequence of events against known value.
    assert last_hash == wallet.__head__

    # Check records are encrypted (values not visible in database).
    record_manager = app.event_store.record_manager
    items = record_manager.get_items(wallet.id)
    for item in items:
        for transaction_type in [
                TransactionType.deposit, TransactionType.bet,
                TransactionType.cashin
        ]:
            assert transaction_type not in item.state
        assert wallet.id == item.originator_id

    # Project application event notifications.
    from eventsourcing.interface.notificationlog import NotificationLogReader
    reader = NotificationLogReader(app.notification_log)
    notification_ids = [n['id'] for n in reader.read()]
    assert notification_ids == [1, 2, 3, 4, 5, 6]

    # - create two more aggregates
    wallet = Wallet.__create__(player_id=2, wallet_type=WalletType.real)
    wallet.__save__()

    wallet = Wallet.__create__(player_id=3, wallet_type=WalletType.real)
    wallet.__save__()

    # - get the new event notifications from the reader
    notification_ids = [n['id'] for n in reader.read()]
    assert notification_ids == [7, 8]
    def test_notification_log_reader(self):
        # Build notification log.
        big_array = self.create_big_array()
        section_size = 5
        notification_log = NotificationLog(big_array, section_size=section_size)

        # Append 13 notifications.
        self.append_notifications(big_array, 13)

        # Construct notification log reader.
        reader = NotificationLogReader(notification_log)

        # Read all notifications.
        all_notifications = list(reader)
        self.assertEqual(len(all_notifications), 13, all_notifications)

        # Check position.
        self.assertEqual(reader.position, 13)

        # Add some more items to the log.
        self.append_notifications(big_array, 13, 21)

        # Read subsequent notifications.
        subsequent_notifications_notifications = list(reader)
        self.assertEqual(len(subsequent_notifications_notifications), 8, subsequent_notifications_notifications)

        # Check position.
        self.assertEqual(reader.position, 21)

        subsequent_notifications_notifications = list(reader)
        self.assertEqual(len(subsequent_notifications_notifications), 0, subsequent_notifications_notifications)

        # Set position.
        reader.seek(13)
        subsequent_notifications_notifications = list(reader)
        self.assertEqual(len(subsequent_notifications_notifications), 8, subsequent_notifications_notifications)

        # # Read items after a particular position.
        self.assertEqual(len(list(reader[0:])), 21)
        self.assertEqual(len(list(reader[1:])), 20)
        self.assertEqual(len(list(reader[2:])), 19)
        self.assertEqual(len(list(reader[3:])), 18)
        self.assertEqual(len(list(reader[13:])), 8)
        self.assertEqual(len(list(reader[18:])), 3)
        self.assertEqual(len(list(reader[19:])), 2)
        self.assertEqual(len(list(reader[20:])), 1)
        self.assertEqual(len(list(reader[21:])), 0)

        # Check last item numbers less than 1 cause a value errors.
        with self.assertRaises(ValueError):
            reader.position = -1
            list(reader)

        with self.assertRaises(ValueError):
            list(reader.seek(-1))

        # Check resuming from a saved position.
        saved_position = 5
        advance_by = 3
        reader.seek(saved_position)
        count = 0
        self.assertEqual(reader.position, saved_position)
        for _ in reader:
            count += 1
            if count > advance_by:
                break
        else:
            self.fail("for loop didn't break")
        self.assertEqual(reader.position, saved_position + advance_by)

        # Read items between particular positions.
        # - check stops at end of slice, and position tracks ok
        self.assertEqual(len(list(reader[0:1])), 1)
        self.assertEqual(reader.position, 1)

        self.assertEqual(len(list(reader[1:3])), 2)
        self.assertEqual(reader.position, 3)

        self.assertEqual(len(list(reader[2:5])), 3)
        self.assertEqual(reader.position, 5)

        self.assertEqual(len(list(reader[3:7])), 4)
        self.assertEqual(reader.position, 7)

        self.assertEqual(len(list(reader[13:20])), 7)
        self.assertEqual(reader.position, 20)

        self.assertEqual(len(list(reader[18:20])), 2)
        self.assertEqual(reader.position, 20)

        self.assertEqual(len(list(reader[19:20])), 1)
        self.assertEqual(reader.position, 20)

        self.assertEqual(len(list(reader[20:20])), 0)
        self.assertEqual(reader.position, 20)

        self.assertEqual(len(list(reader[21:20])), 0)
        self.assertEqual(reader.position, 21)
    def test_remote_notification_log(self):
        log_name = str(uuid4())
        num_notifications = 42
        big_array = self.create_big_array()
        section_size = 5

        # Build a notification log (fixture).
        self.append_notifications(big_array, num_notifications)

        # Start a simple server.
        from wsgiref.util import setup_testing_defaults
        from wsgiref.simple_server import make_server

        port = 8080
        base_url = 'http://127.0.0.1:{}/notifications/'.format(port)

        def simple_app(environ, start_response):
            """Simple WSGI application, for testing purposes only."""
            setup_testing_defaults(environ)
            status = '200 OK'
            headers = [('Content-type', 'text/plain; charset=utf-8')]
            start_response(status, headers)

            # Extract log name and doc ID from path info.
            path_info = environ['PATH_INFO']
            try:
                notification_log_id, section_id = path_info.strip('/').split('/')[-2:]
            except ValueError as e:
                msg = "Couldn't extract log name and doc ID from path info {}: {}".format(path_info, e)
                raise ValueError(msg)

            # Get serialized section.
            section = present_section(big_array, section_id, section_size)

            # Return a list of lines.
            return [(line + '\n').encode('utf8') for line in section.split('\n')]

        httpd = make_server('', port, simple_app)
        print("Serving on port {}...".format(port))
        thread = Thread(target=httpd.serve_forever)
        thread.setDaemon(True)
        thread.start()
        try:
            # Use reader with client to read all items in remote feed after item 5.
            notification_log = RemoteNotificationLog(base_url, log_name)

            # Get all the items.
            notification_log_reader = NotificationLogReader(notification_log=notification_log)
            items_from_start = list(notification_log_reader.get_items())

            # Check we got all the items.
            self.assertEqual(len(items_from_start), num_notifications)
            self.assertEqual(items_from_start[0], 'item1')
            expected_section_count = ceil(num_notifications / float(section_size))
            self.assertEqual(notification_log_reader.section_count, expected_section_count)

            # Get all the items from item 5.
            items_from_5 = list(notification_log_reader[section_size - 1:])

            # Check we got everything after item 5.
            self.assertEqual(len(items_from_5), num_notifications - section_size + 1)
            self.assertEqual(items_from_5[0], 'item{}'.format(section_size))
            expected_section_count = ceil(num_notifications / float(section_size))
            self.assertEqual(notification_log_reader.section_count, expected_section_count)

        finally:
            httpd.shutdown()
            thread.join()
            httpd.server_close()
Beispiel #11
0
    except ConcurrencyError:
        pass
    else:
        raise Exception("Shouldn't get here")

    # Check domain event data integrity (happens also during replay).
    events = app.event_store.get_domain_events(world.id)
    last_hash = ''
    for event in events:
        event.__check_hash__()
        assert event.__previous_hash__ == last_hash
        last_hash = event.__event_hash__

    # Verify sequence of events (cryptographically).
    assert last_hash == world.__head__

    # Project application event notifications.
    from eventsourcing.interface.notificationlog import NotificationLogReader
    reader = NotificationLogReader(app.notification_log)
    notifications = reader.read()
    notification_ids = [n['id'] for n in notifications]
    assert notification_ids == [1, 2, 3, 4, 5, 6]

    # Check records are encrypted (values not visible in database).
    record_manager = app.event_store.record_manager
    items = record_manager.get_items(world.id)
    for item in items:
        assert item.originator_id == world.id
        assert 'dinosaurs' not in item.state
        assert 'trucks' not in item.state
        assert 'internet' not in item.state