def test(self):
        with ExampleApplicationWithAlternativeSequencedItemType(self.datastore.session) as app:
            # Create entity.
            entity1 = create_new_example(a='a', b='b')
            self.assertIsInstance(entity1.id, UUID)
            self.assertEqual(entity1.a, 'a')
            self.assertEqual(entity1.b, 'b')

            # Check there is a stored event.
            all_records = list(app.event_store.active_record_strategy.all_records())
            assert len(all_records) == 1
            stored_event, _ = all_records[0]
            assert stored_event.originator_id == entity1.id
            assert stored_event.originator_version == 0

            # Read entity from repo.
            retrieved_obj = app.repository[entity1.id]
            self.assertEqual(retrieved_obj.id, entity1.id)
Ejemplo n.º 2
0
    def test(self):
        with ExampleApplicationWithAlternativeSequencedItemType() as app:
            # Create entity.
            entity1 = create_new_example(a='a', b='b')
            self.assertIsInstance(entity1.id, UUID)
            self.assertEqual(entity1.a, 'a')
            self.assertEqual(entity1.b, 'b')

            # Check there is a stored event.
            all_records = list(app.event_store.record_manager.all_records())
            assert len(all_records) == 1, len(all_records)
            stored_event = all_records[0]
            assert isinstance(stored_event, StoredEventRecord), stored_event
            assert stored_event.originator_id == entity1.id
            assert stored_event.originator_version == 0

            # Read entity from repo.
            retrieved_obj = app.repository[entity1.id]
            self.assertEqual(retrieved_obj.id, entity1.id)
    def _test(self):
        with ExampleApplicationWithAlternativeSequencedItemType(
                self.datastore.session) as app:
            # Create entity.
            entity1 = create_new_example(a='a', b='b')
            self.assertIsInstance(entity1.id, UUID)
            self.assertEqual(entity1.a, 'a')
            self.assertEqual(entity1.b, 'b')

            # Check there is a stored event.
            all_records = list(
                app.event_store.record_manager.get_notifications())
            self.assertEqual(1, len(all_records))
            stored_event = all_records[0]
            self.assertEqual(stored_event.originator_id, entity1.id)
            self.assertEqual(stored_event.originator_version, 0)

            # Read entity from repo.
            retrieved_obj = app.repository[entity1.id]
            self.assertEqual(retrieved_obj.id, entity1.id)
Ejemplo n.º 4
0
    def test(self):
        with ExampleApplicationWithExtendedSequencedItemType(
                self.datastore.session) as app:
            # Create entity.
            entity1 = create_new_example(a='a', b='b')
            self.assertIsInstance(entity1.id, UUID)
            self.assertEqual(entity1.a, 'a')
            self.assertEqual(entity1.b, 'b')

            # Check there is a stored event.
            all_records = list(app.event_store.record_manager.all_records())
            self.assertEqual(len(all_records), 1)
            record = all_records[0]
            self.assertEqual(record.sequence_id, entity1.id)
            self.assertEqual(record.position, 0)
            self.assertEqual(record.event_type, 'Example.Created',
                             record.event_type)
            self.assertEqual(record.timestamp, entity1.__created_on__)

            # Read entity from repo.
            retrieved_obj = app.repository[entity1.id]
            self.assertEqual(retrieved_obj.id, entity1.id)
Ejemplo n.º 5
0
    def test_entity_performance(self):
        """
        Reports on the performance of Example entity and repo.

        NB: This test doesn't actually assert anything, so it isn't really a test.
        """

        with self.construct_application() as app:

            # Initialise dict of entities.
            self.entities = {}

            report_name = type(self).__name__[4:]
            print("\n\n{} report:\n".format(report_name))

            repetitions = 10  # 10

            # NB: Use range(1, 5) to test whether we can get more than 10000 items
            # from Cassandra.
            # Setup a number of entities, with different lengths of event history.
            for i in range(0, 4):

                # Initialise table with other entities.
                num_other_entities = i
                filling = []
                for _ in range(num_other_entities):
                    filling.append(create_new_example(a=1, b=2))

                # b = str([uuid4().hex for _ in range(100000)])
                b = 2
                example = create_new_example(a=1, b=b)
                self.entities[i] = example

                # Beat a number of times.
                num_beats = int(floor(10**i))
                start_beating = time.time()
                for _ in range(num_beats):
                    # print("Beat example")
                    example.beat_heart()

                    for other in filling:
                        other.beat_heart()

                total_beats = num_beats * (1 + len(filling))
                time_beating = time.time() - start_beating
                try:
                    beats_per_second = total_beats / time_beating
                except ZeroDivisionError as e:
                    print("Warning: beats per second {} / {}: {}".format(
                        total_beats, time_beating, e))
                    beats_per_second = -999999999999.99999999
                try:
                    beat_period = time_beating / total_beats
                except ZeroDivisionError as e:
                    print("Warning: beat period {} / {}: {}".format(
                        time_beating, total_beats, e))
                    beat_period = -999999999999.9999999

                print(
                    "Time to beat {} times: {:.4f}s ({:.0f} beats/s, {:.6f}s each)"
                    "".format(
                        num_beats,
                        time_beating / (1 + num_other_entities),
                        beats_per_second,
                        beat_period,
                    ))

                # Get the last n events from the repo.
                def last_n(n):
                    n = min(n, num_beats + 1)
                    assert isinstance(app.example_repository.event_store,
                                      EventStore)
                    start_last_n = time.time()
                    events = app.example_repository.event_store.list_events(
                        originator_id=example.id,
                        gt=num_beats - n,
                    )
                    assert len(events) == n, "Asked for %s but got %s" % (
                        n,
                        len(events),
                    )
                    time_last_n = (time.time() - start_last_n) / repetitions

                    # num_retrieved_events = len(last_n_stored_events)
                    events_per_second = n / time_last_n
                    print(
                        ("Time to get last {:>" + str(i + 1) +
                         "} events after {} events: {:.6f}s ({:.0f} events/s)"
                         "").format(n, num_beats + 1, time_last_n,
                                    events_per_second))

                for j in range(0, i + 1):
                    last_n(10**j)

                # Get the entity by replaying all events (which it must since there
                # isn't a snapshot).
                start_replay = time.time()
                for _ in range(repetitions):
                    example = app.example_repository[example.id]
                    assert isinstance(example, Example)
                    heartbeats = example.count_heartbeats()
                    assert heartbeats == num_beats, (heartbeats, num_beats)

                time_replaying = (time.time() - start_replay) / repetitions
                print(
                    "Time to replay {} beats: {:.2f}s ({:.0f} beats/s, {:.6f}s each)"
                    "".format(
                        num_beats,
                        time_replaying,
                        num_beats / time_replaying,
                        time_replaying / num_beats,
                    ))

                # Take snapshot, and beat heart a few more times.
                app.example_repository.take_snapshot(example.id)

                extra_beats = 4
                for _ in range(extra_beats):
                    example.beat_heart()
                num_beats += extra_beats

                # Get the entity using snapshot and replaying events since the snapshot.
                start_replay = time.time()
                for _ in range(repetitions):
                    example = app.example_repository[example.id]
                time_replaying = (time.time() - start_replay) / repetitions

                events_per_second = (
                    extra_beats +
                    1) / time_replaying  # +1 for the snapshot event
                beats_per_second = num_beats / time_replaying
                print(
                    "Time to replay snapshot with {} extra beats: {:.6f}s ({:.0f} "
                    "events/s, {:.0f} beats/s)"
                    "".format(extra_beats, time_replaying, events_per_second,
                              beats_per_second))

                print("")
Ejemplo n.º 6
0
    def test_entity_lifecycle(self):
        # Check the factory creates an instance.
        example1 = create_new_example(a=1, b=2)
        self.assertIsInstance(example1, Example)

        # Check the instance is equal to itself.
        self.assertEqual(example1, example1)

        # Check the instance is equal to a clone of itself.
        clone = object.__new__(type(example1))
        clone.__dict__.update(example1.__dict__)
        self.assertEqual(example1, clone)

        # Check the properties of the Example class.
        self.assertEqual(1, example1.a)
        self.assertEqual(2, example1.b)

        # Check the properties of the TimestampedVersionedEntity class.
        self.assertTrue(example1.id)
        self.assertEqual(1, example1.version)
        self.assertTrue(example1.created_on)
        self.assertTrue(example1.last_modified_on)
        self.assertEqual(example1.created_on, example1.last_modified_on)

        # Check a different type with the same values is not "equal" to the first.
        class Subclass(Example): pass
        other = object.__new__(Subclass)
        other.__dict__.update(example1.__dict__)
        self.assertEqual(example1.__dict__, other.__dict__)
        self.assertNotEqual(example1, other)

        # Check a second instance with the same values is not "equal" to the first.
        example2 = create_new_example(a=1, b=2)
        self.assertEqual(type(example1), type(example2))
        self.assertNotEqual(example1, example2)

        # Setup the repo.
        repo = ExampleRepository(self.entity_event_store)

        # Check the example entities can be retrieved from the example repository.
        entity1 = repo[example1.id]
        self.assertIsInstance(entity1, Example)
        self.assertEqual(1, entity1.a)
        self.assertEqual(2, entity1.b)

        entity2 = repo[example2.id]
        self.assertIsInstance(entity2, Example)
        self.assertEqual(1, entity2.a)
        self.assertEqual(2, entity2.b)

        # Check the entity can be updated.
        entity1.a = 100
        self.assertEqual(100, repo[entity1.id].a)
        entity1.b = -200
        self.assertEqual(-200, repo[entity1.id].b)

        self.assertEqual(repo[entity1.id].created_on, entity1.created_on)
        self.assertEqual(repo[entity1.id].last_modified_on, entity1.last_modified_on)
        self.assertNotEqual(entity1.last_modified_on, entity1.created_on)

        self.assertEqual(0, entity1.count_heartbeats())
        entity1.beat_heart()
        entity1.beat_heart()
        entity1.beat_heart()
        self.assertEqual(3, entity1.count_heartbeats())
        self.assertEqual(3, repo[entity1.id].count_heartbeats())

        # Check the entity can publish multiple events simultaneously.
        entity1.beat_heart(number_of_beats=3)
        self.assertEqual(6, repo[entity1.id].count_heartbeats())

        # Check the entity can be discarded.
        entity1.discard()

        # Check the repo now raises a KeyError.
        self.assertRaises(RepositoryKeyError, repo.__getitem__, entity1.id)

        # Check the entity can't be discarded twice.
        self.assertRaises(AssertionError, entity1.discard)

        # Should fail to validate event with wrong entity ID.
        with self.assertRaises(MismatchedOriginatorIDError):
            entity2._validate_originator(
                VersionedEntity.Event(
                    originator_id=uuid4(),
                    originator_version=0
                )
            )
        # Should fail to validate event with wrong entity version.
        with self.assertRaises(MismatchedOriginatorVersionError):
            entity2._validate_originator(
                VersionedEntity.Event(
                    originator_id=entity2.id,
                    originator_version=0,
                )
            )

        # Should validate event with correct entity ID and version.
        entity2._validate_originator(
            VersionedEntity.Event(
                originator_id=entity2.id,
                originator_version=entity2.version,
            )
        )

        # Check an entity cannot be reregistered with the ID of a discarded entity.
        replacement_event = Example.Created(originator_id=entity1.id, a=11, b=12)
        with self.assertRaises(ConcurrencyError):
            publish(event=replacement_event)
    def test_take_snapshot(self):
        self.entity_persistence_policy = PersistencePolicy(
            event_store=self.entity_event_store,
            event_type=VersionedEntity.Event,
        )
        self.snapshot_persistence_policy = PersistencePolicy(
            event_store=self.snapshot_store,
            event_type=Snapshot,
        )
        snapshot_strategy = EventSourcedSnapshotStrategy(
            event_store=self.snapshot_store
        )
        event_player = EventPlayer(
            event_store=self.entity_event_store,
            mutator=Example._mutate,
            snapshot_strategy=snapshot_strategy
        )

        # Take a snapshot with a non-existent ID.
        unregistered_id = uuid4()
        # Check no snapshot is taken.
        self.assertIsNone(event_player.take_snapshot(unregistered_id))
        # Check no snapshot is available.
        self.assertIsNone(event_player.get_snapshot(unregistered_id))

        # Create a new entity.
        registered_example = create_new_example(a=123, b=234)

        # Take a snapshot of the new entity (no previous snapshots).
        snapshot1 = event_player.take_snapshot(registered_example.id, lt=registered_example.version)

        # Check the snapshot is pegged to the last applied version.
        self.assertEqual(snapshot1.originator_version, 0)

        # Replay from this snapshot.
        entity_from_snapshot1 = entity_from_snapshot(snapshot1)
        retrieved_example = event_player.replay_entity(registered_example.id,
                                                       initial_state=entity_from_snapshot1,
                                                       gte=entity_from_snapshot1._version)

        # Check the attributes are correct.
        self.assertEqual(retrieved_example.a, 123)

        # Remember the version now.
        version1 = retrieved_example._version
        self.assertEqual(version1, 1)

        # Change attribute value.
        retrieved_example.a = 999

        # Remember the version now.
        version2 = retrieved_example._version
        self.assertEqual(version2, 2)

        # Change attribute value.
        retrieved_example.a = 9999

        # Remember the version now.
        version3 = retrieved_example._version
        self.assertEqual(version3, 3)

        # Check the event sourced entities are correct.
        retrieved_example = event_player.replay_entity(registered_example.id)
        self.assertEqual(retrieved_example.a, 9999)

        # Take another snapshot.
        snapshot2 = event_player.take_snapshot(retrieved_example.id, lt=retrieved_example.version)

        # Replay from this snapshot.
        initial_state = entity_from_snapshot(snapshot2)
        retrieved_example = event_player.replay_entity(
            registered_example.id,
            initial_state=initial_state,
            gte=initial_state._version,
        )
        # Check the attributes are correct.
        self.assertEqual(retrieved_example.a, 9999)

        # Check we can get historical state at version1.
        retrieved_example = event_player.replay_entity(registered_example.id, lt=version1)
        self.assertEqual(retrieved_example.a, 123)

        # Check we can get historical state at version2.
        retrieved_example = event_player.replay_entity(registered_example.id, lt=version2)
        self.assertEqual(retrieved_example.a, 999)

        # Check we can get historical state at version3.
        retrieved_example = event_player.replay_entity(registered_example.id, lt=version3)
        self.assertEqual(retrieved_example.a, 9999)

        # Similarly, check we can get historical state using a snapshot
        initial_state = entity_from_snapshot(snapshot1)
        retrieved_example = event_player.replay_entity(
            registered_example.id,
            initial_state=initial_state,
            gte=initial_state._version,
            lt=version2,
        )
        self.assertEqual(retrieved_example.a, 999)

        # Discard the entity.
        registered_example = event_player.replay_entity(registered_example.id)
        registered_example.discard()

        # Take snapshot of discarded entity.
        snapshot3 = event_player.take_snapshot(registered_example.id)
        self.assertIsNone(snapshot3.state)
        self.assertIsNone(entity_from_snapshot(snapshot3))
Ejemplo n.º 8
0
    def test_entity_lifecycle(self):
        # Check the factory creates an instance.
        example1 = Example.__create__(a=1, b=2)

        self.assertIsInstance(example1, Example)

        # Check the instance is equal to itself.
        self.assertEqual(example1, example1)

        # Check the instance is equal to a clone of itself.
        clone = object.__new__(type(example1))
        clone.__dict__.update(example1.__dict__)
        self.assertEqual(example1, clone)

        # Check the properties of the Example class.
        self.assertEqual(1, example1.a)
        self.assertEqual(2, example1.b)

        # Check the properties of the TimestampedVersionedEntity class.
        self.assertTrue(example1.id)
        self.assertEqual(example1.__version__, 0)
        self.assertTrue(example1.__created_on__)
        self.assertLess(example1.__created_on__, time.time())
        self.assertGreater(example1.__created_on__, time.time() - 1)
        self.assertTrue(example1.__last_modified__)
        self.assertEqual(example1.__created_on__, example1.__last_modified__)

        # Test the datetime_from_timestamp() converts ok.
        tt = time.time()
        dt = datetime.datetime.utcnow()
        self.assertEqual(datetime_from_timestamp(tt).hour, dt.hour)

        # Check can get datetime from timestamps, and it corresponds to UTC.
        dt = datetime_from_timestamp(example1.__created_on__)
        self.assertLess(dt, datetime.datetime.utcnow())
        self.assertGreater(dt,
                           datetime.datetime.utcnow() - datetime.timedelta(1))

        # Check a different type with the same values is not "equal" to the first.
        class Subclass(Example):
            pass

        other = object.__new__(Subclass)
        other.__dict__.update(example1.__dict__)
        self.assertEqual(example1.__dict__, other.__dict__)
        self.assertNotEqual(example1, other)

        # Check a second instance with the same values is not "equal" to the first.
        example2 = create_new_example(a=1, b=2)
        self.assertEqual(type(example1), type(example2))
        self.assertNotEqual(example1, example2)

        # Check entity not hashable.
        with self.assertRaises(TypeError):
            hash(example1)

        # Setup the repo.
        repo = ExampleRepository(self.entity_event_store)

        # Check the example entities can be retrieved from the example repository.
        entity1 = repo[example1.id]
        self.assertIsInstance(entity1, Example)
        self.assertEqual(1, entity1.a)
        self.assertEqual(2, entity1.b)

        entity2 = repo[example2.id]
        self.assertIsInstance(entity2, Example)
        self.assertEqual(1, entity2.a)
        self.assertEqual(2, entity2.b)

        # Check the entity can be updated.
        entity1.a = 100
        self.assertEqual(100, repo[entity1.id].a)
        entity1.b = -200
        self.assertEqual(-200, repo[entity1.id].b)

        self.assertEqual(repo[entity1.id].__created_on__,
                         entity1.__created_on__)
        self.assertEqual(repo[entity1.id].__last_modified__,
                         entity1.__last_modified__)
        self.assertNotEqual(entity1.__last_modified__, entity1.__created_on__)

        self.assertEqual(0, entity1.count_heartbeats())
        entity1.beat_heart()
        entity1.beat_heart()
        entity1.beat_heart()
        self.assertEqual(3, entity1.count_heartbeats())
        self.assertEqual(3, repo[entity1.id].count_heartbeats())

        # Check the entity can publish multiple events simultaneously.
        entity1.beat_heart(number_of_beats=3)
        self.assertEqual(6, repo[entity1.id].count_heartbeats())

        # Check the entity can be discarded.
        entity1.__discard__()

        # Check the repo now raises a KeyError.
        self.assertRaises(RepositoryKeyError, repo.__getitem__, entity1.id)

        # Check the entity can't be discarded twice.
        self.assertRaises(AssertionError, entity1.__discard__)

        # Should fail to validate event with wrong entity ID.
        with self.assertRaises(OriginatorIDError):
            VersionedEntity.Event(
                originator_id=uuid4(),
                originator_version=0,
            ).__check_obj__(entity2)
        # Should fail to validate event with wrong entity version.
        with self.assertRaises(OriginatorVersionError):
            VersionedEntity.Event(
                originator_id=entity2.id,
                originator_version=0,
                __previous_hash__=entity2.__head__,
            ).__check_obj__(entity2)

        # Should validate event with correct entity ID and version.
        VersionedEntity.Event(
            originator_id=entity2.id,
            originator_version=entity2.__version__ + 1,
            __previous_hash__=entity2.__head__,
        ).__check_obj__(entity2)

        # Check an entity cannot be reregistered with the ID of a discarded entity.
        replacement_event = Example.Created(
            originator_id=entity1.id,
            a=11,
            b=12,
            originator_topic=get_topic(Example),
        )
        with self.assertRaises(ConcurrencyError):
            publish(event=replacement_event)
Ejemplo n.º 9
0
    def test_entity_lifecycle(self):
        # Check the factory creates an instance.
        example1 = create_new_example(a=1, b=2)
        self.assertIsInstance(example1, Example)

        # Check the instance is equal to itself.
        self.assertEqual(example1, example1)

        # Check the instance is equal to a clone of itself.
        clone = object.__new__(type(example1))
        clone.__dict__.update(example1.__dict__)
        self.assertEqual(example1, clone)

        # Check the properties of the Example class.
        self.assertEqual(1, example1.a)
        self.assertEqual(2, example1.b)

        # Check the properties of the TimestampedVersionedEntity class.
        self.assertTrue(example1.id)
        self.assertEqual(1, example1.version)
        self.assertTrue(example1.created_on)
        self.assertTrue(example1.last_modified)
        self.assertEqual(example1.created_on, example1.last_modified)

        # Check a different type with the same values is not "equal" to the first.
        class Subclass(Example):
            pass

        other = object.__new__(Subclass)
        other.__dict__.update(example1.__dict__)
        self.assertEqual(example1.__dict__, other.__dict__)
        self.assertNotEqual(example1, other)

        # Check a second instance with the same values is not "equal" to the first.
        example2 = create_new_example(a=1, b=2)
        self.assertEqual(type(example1), type(example2))
        self.assertNotEqual(example1, example2)

        # Setup the repo.
        repo = ExampleRepository(self.entity_event_store)

        # Check the example entities can be retrieved from the example repository.
        entity1 = repo[example1.id]
        self.assertIsInstance(entity1, Example)
        self.assertEqual(1, entity1.a)
        self.assertEqual(2, entity1.b)

        entity2 = repo[example2.id]
        self.assertIsInstance(entity2, Example)
        self.assertEqual(1, entity2.a)
        self.assertEqual(2, entity2.b)

        # Check the entity can be updated.
        entity1.a = 100
        self.assertEqual(100, repo[entity1.id].a)
        entity1.b = -200
        self.assertEqual(-200, repo[entity1.id].b)

        self.assertEqual(repo[entity1.id].created_on, entity1.created_on)
        self.assertEqual(repo[entity1.id].last_modified, entity1.last_modified)
        self.assertNotEqual(entity1.last_modified, entity1.created_on)

        self.assertEqual(0, entity1.count_heartbeats())
        entity1.beat_heart()
        entity1.beat_heart()
        entity1.beat_heart()
        self.assertEqual(3, entity1.count_heartbeats())
        self.assertEqual(3, repo[entity1.id].count_heartbeats())

        # Check the entity can publish multiple events simultaneously.
        entity1.beat_heart(number_of_beats=3)
        self.assertEqual(6, repo[entity1.id].count_heartbeats())

        # Check the entity can be discarded.
        entity1.discard()

        # Check the repo now raises a KeyError.
        self.assertRaises(RepositoryKeyError, repo.__getitem__, entity1.id)

        # Check the entity can't be discarded twice.
        self.assertRaises(AssertionError, entity1.discard)

        # Should fail to validate event with wrong entity ID.
        with self.assertRaises(MismatchedOriginatorIDError):
            entity2._validate_originator(
                VersionedEntity.Event(originator_id=uuid4(),
                                      originator_version=0))
        # Should fail to validate event with wrong entity version.
        with self.assertRaises(MismatchedOriginatorVersionError):
            entity2._validate_originator(
                VersionedEntity.Event(
                    originator_id=entity2.id,
                    originator_version=0,
                ))

        # Should validate event with correct entity ID and version.
        entity2._validate_originator(
            VersionedEntity.Event(
                originator_id=entity2.id,
                originator_version=entity2.version,
            ))

        # Check an entity cannot be reregistered with the ID of a discarded entity.
        replacement_event = Example.Created(originator_id=entity1.id,
                                            a=11,
                                            b=12)
        with self.assertRaises(ConcurrencyError):
            publish(event=replacement_event)
Ejemplo n.º 10
0
    def test_take_snapshot(self):
        self.entity_persistence_policy = PersistencePolicy(
            event_store=self.entity_event_store,
            event_type=VersionedEntity.Event,
        )
        self.snapshot_persistence_policy = PersistencePolicy(
            event_store=self.snapshot_store,
            event_type=Snapshot,
        )
        snapshot_strategy = EventSourcedSnapshotStrategy(
            event_store=self.snapshot_store)
        event_player = EventPlayer(event_store=self.entity_event_store,
                                   mutator=Example._mutate,
                                   snapshot_strategy=snapshot_strategy)

        # Take a snapshot with a non-existent ID.
        unregistered_id = uuid4()
        # Check no snapshot is taken.
        self.assertIsNone(event_player.take_snapshot(unregistered_id))
        # Check no snapshot is available.
        self.assertIsNone(event_player.get_snapshot(unregistered_id))

        # Create a new entity.
        registered_example = create_new_example(a=123, b=234)

        # Take a snapshot of the new entity (no previous snapshots).
        snapshot1 = event_player.take_snapshot(registered_example.id,
                                               lt=registered_example.version)

        # Check the snapshot is pegged to the last applied version.
        self.assertEqual(snapshot1.originator_version, 0)

        # Replay from this snapshot.
        entity_from_snapshot1 = entity_from_snapshot(snapshot1)
        retrieved_example = event_player.replay_entity(
            registered_example.id,
            initial_state=entity_from_snapshot1,
            gte=entity_from_snapshot1._version)

        # Check the attributes are correct.
        self.assertEqual(retrieved_example.a, 123)

        # Remember the version now.
        version1 = retrieved_example._version
        self.assertEqual(version1, 1)

        # Change attribute value.
        retrieved_example.a = 999

        # Remember the version now.
        version2 = retrieved_example._version
        self.assertEqual(version2, 2)

        # Change attribute value.
        retrieved_example.a = 9999

        # Remember the version now.
        version3 = retrieved_example._version
        self.assertEqual(version3, 3)

        # Check the event sourced entities are correct.
        retrieved_example = event_player.replay_entity(registered_example.id)
        self.assertEqual(retrieved_example.a, 9999)

        # Take another snapshot.
        snapshot2 = event_player.take_snapshot(retrieved_example.id,
                                               lt=retrieved_example.version)

        # Replay from this snapshot.
        initial_state = entity_from_snapshot(snapshot2)
        retrieved_example = event_player.replay_entity(
            registered_example.id,
            initial_state=initial_state,
            gte=initial_state._version,
        )
        # Check the attributes are correct.
        self.assertEqual(retrieved_example.a, 9999)

        # Check we can get historical state at version1.
        retrieved_example = event_player.replay_entity(registered_example.id,
                                                       lt=version1)
        self.assertEqual(retrieved_example.a, 123)

        # Check we can get historical state at version2.
        retrieved_example = event_player.replay_entity(registered_example.id,
                                                       lt=version2)
        self.assertEqual(retrieved_example.a, 999)

        # Check we can get historical state at version3.
        retrieved_example = event_player.replay_entity(registered_example.id,
                                                       lt=version3)
        self.assertEqual(retrieved_example.a, 9999)

        # Similarly, check we can get historical state using a snapshot
        initial_state = entity_from_snapshot(snapshot1)
        retrieved_example = event_player.replay_entity(
            registered_example.id,
            initial_state=initial_state,
            gte=initial_state._version,
            lt=version2,
        )
        self.assertEqual(retrieved_example.a, 999)

        # Discard the entity.
        registered_example = event_player.replay_entity(registered_example.id)
        registered_example.discard()

        # Take snapshot of discarded entity.
        snapshot3 = event_player.take_snapshot(registered_example.id)
        self.assertIsNone(snapshot3.state)
        self.assertIsNone(entity_from_snapshot(snapshot3))
Ejemplo n.º 11
0
 def create_new_example(self, foo="", a="", b=""):
     """Entity object factory."""
     return create_new_example(foo=foo, a=a, b=b)
Ejemplo n.º 12
0
 def create_new_example(self, foo='', a='', b=''):
     """Entity object factory."""
     return create_new_example(foo=foo, a=a, b=b)
    def test_entity_performance(self):
        """
        Reports on the performance of Example entity and repo.

        NB: This test doesn't actually assert anything, so it isn't really a test.
        """

        with self.construct_application() as app:

            # Initialise dict of entities.
            self.entities = {}

            report_name = type(self).__name__[4:]
            print("\n\n{} report:\n".format(report_name))

            repetitions = 10  # 10

            # NB: Use range(1, 5) to test whether we can get more than 10000 items from Cassandra.
            # Setup a number of entities, with different lengths of event history.
            for i in six.moves.range(0, 4):

                # Initialise table with other entities.
                num_other_entities = i
                filling = []
                for _ in six.moves.range(num_other_entities):
                    filling.append(create_new_example(a=1, b=2))

                # b = str([uuid4().hex for _ in six.moves.range(100000)])
                b = 2
                example = create_new_example(a=1, b=b)
                self.entities[i] = example

                # Beat a number of times.
                num_beats = int(floor(10 ** i))
                start_beating = time.time()
                for _ in six.moves.range(num_beats):
                    # print("Beat example")
                    example.beat_heart()

                    for other in filling:
                        other.beat_heart()

                total_beats = num_beats * (1 + len(filling))
                time_beating = time.time() - start_beating
                try:
                    beats_per_second = total_beats / time_beating
                except ZeroDivisionError as e:
                    print("Warning: beats per second {} / {}: {}".format(total_beats, time_beating, e))
                    beats_per_second = -999999999999.99999999
                try:
                    beat_period = time_beating / total_beats
                except ZeroDivisionError as e:
                    print("Warning: beat period {} / {}: {}".format(time_beating, total_beats, e))
                    beat_period = -999999999999.9999999

                print("Time to beat {} times: {:.4f}s ({:.0f} beats/s, {:.6f}s each)"
                      "".format(num_beats, time_beating / (1 + num_other_entities), beats_per_second, beat_period))

                # Get the last n events from the repo.
                def last_n(n):
                    n = min(n, num_beats + 1)
                    assert isinstance(app.example_repository.event_player.event_store, EventStore)
                    ars = app.example_repository.event_player.event_store.active_record_strategy
                    assert isinstance(ars, AbstractActiveRecordStrategy)

                    start_last_n = time.time()
                    last_n_stored_events = []
                    for _ in six.moves.range(repetitions):
                        iterator = SequencedItemIterator(
                            active_record_strategy=ars,
                            sequence_id=example.id,
                            limit=n,
                            is_ascending=False,
                        )
                        last_n_stored_events = list(iterator)
                    time_last_n = (time.time() - start_last_n) / repetitions

                    num_retrieved_events = len(last_n_stored_events)
                    events_per_second = num_retrieved_events / time_last_n
                    print(("Time to get last {:>" + str(i + 1) + "} events after {} events: {:.6f}s ({:.0f} events/s)"
                                                                 "").format(n, num_beats + 1, time_last_n,
                                                                            events_per_second))

                for j in range(0, i + 1):
                    last_n(10 ** j)

                # Get the entity by replaying all events (which it must since there isn't a snapshot).
                start_replay = time.time()
                for _ in six.moves.range(repetitions):
                    example = app.example_repository[example.id]
                    assert isinstance(example, Example)
                    heartbeats = example.count_heartbeats()
                    assert heartbeats == num_beats, (heartbeats, num_beats)

                time_replaying = (time.time() - start_replay) / repetitions
                print("Time to replay {} beats: {:.2f}s ({:.0f} beats/s, {:.6f}s each)"
                      "".format(num_beats, time_replaying, num_beats / time_replaying, time_replaying / num_beats))

                # Take snapshot, and beat heart a few more times.
                app.example_repository.take_snapshot(example.id, lt=example.version)

                extra_beats = 4
                for _ in six.moves.range(extra_beats):
                    example.beat_heart()
                num_beats += extra_beats

                # Get the entity using snapshot and replaying events since the snapshot.
                start_replay = time.time()
                for _ in six.moves.range(repetitions):
                    example = app.example_repository[example.id]
                time_replaying = (time.time() - start_replay) / repetitions

                events_per_second = (extra_beats + 1) / time_replaying  # +1 for the snapshot event
                beats_per_second = num_beats / time_replaying
                print("Time to replay snapshot with {} extra beats: {:.6f}s ({:.0f} events/s, {:.0f} beats/s)"
                      "".format(extra_beats, time_replaying, events_per_second, beats_per_second))

                print("")