def test_application_with_infrastructure(self): with self.construct_concrete_application() as app: # Start with a new table. app.drop_table() app.drop_table() app.setup_table() app.setup_table() # Check the notifications. reader = NotificationLogReader(app.notification_log) old_notifications = reader.list_notifications() len_old = len(old_notifications) # 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.list_notifications() self.assertEqual(1 + len_old, len(notifications)) topic = "eventsourcing.tests.core_tests.test_aggregate_root#ExampleAggregateRoot.Created" self.assertEqual(topic, notifications[len_old]["topic"]) app.drop_table()
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. json_encoder = ObjectJSONEncoder(separators=JSON_SEPARATORS) view = NotificationLogView(notification_log, json_encoder) resource = view.present_resource(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 resource.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) # Just before we start, test the deserialise_section_size exceptions. notification_log.deserialize_section_size('1') with self.assertRaises(ValueError): notification_log.deserialize_section_size('"1') with self.assertRaises(TypeError): notification_log.deserialize_section_size('"1"') # Get all the items. notification_log_reader = NotificationLogReader( notification_log=notification_log) items_from_start = notification_log_reader.list_notifications() # 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"], b"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).encode("utf8")) 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()
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.list_notifications(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)