def testBroadcastChannel(self): broadcast_channel = channel.BroadcastChannel('some-unique-channel-id') # This shouldn't error without any clients connected, but it shouldn't # queue up the message either. broadcast_channel.send_message('Hello world!') tokens = [] self.assertFalse(broadcast_channel.exists) tokens.append(channel.create_channel('foo')) tokens.append(channel.create_channel('bar')) tokens.append(channel.create_channel('*****@*****.**')) self.assertTrue(all(tokens), 'Bad tokens: %r' % tokens) broadcast_channel.subscribe('foo') broadcast_channel.subscribe('bar') broadcast_channel.subscribe('*****@*****.**') self.assertTrue(broadcast_channel.exists) # Must connect each client to the channel before broadcast. # This happens automatically by the client scripts in the real world. for token in tokens: self.channel_stub.connect_channel(token) broadcast_channel.send_message('Hello world!') for token in tokens: message = self.channel_stub.pop_first_message(token) message_data = { 'message': 'Hello world!', 'broadcast_channel_key': 'some-unique-channel-id' } self.assertEqual(json.dumps(message_data), message)
def testTaskManagerSubscribeHandlerTest(self): url = "/_titan/tasks/taskmanager/subscribe" response = self.app.post(url, expect_errors=True) self.assertEqual(400, response.status_int) url = "/_titan/tasks/taskmanager/subscribe?key=fake&client_id=foo" response = self.app.post(url, expect_errors=True) self.assertEqual(404, response.status_int) client_id = "unique-client-id" token = channel.create_channel(client_id) task_manager = tasks.TaskManager.new(broadcast_channel_key="broadcast") url = "/_titan/tasks/taskmanager/subscribe?key=%s&client_id=%s" % (task_manager.key, client_id) response = self.app.post(url) self.assertEqual(200, response.status_int) # Must connect each client to the channel before broadcast. # This happens automatically by the client scripts in the real world. self.channel_stub.connect_channel(token) task_manager.defer_task("task-key0", GoodCallback) task_manager.defer_task("task-key1", BadCallback) task_manager.finalize() # Weakly assert that messages were sent to the broadcast channel. self.assertTrue(self.channel_stub.pop_first_message(token))
def testTaskManagerSubscribeHandlerTest(self): url = '/_titan/tasks/taskmanager/subscribe' response = self.app.post(url, expect_errors=True) self.assertEqual(400, response.status_int) url = '/_titan/tasks/taskmanager/subscribe?key=fake&client_id=foo' response = self.app.post(url, expect_errors=True) self.assertEqual(404, response.status_int) client_id = 'unique-client-id' token = channel.create_channel(client_id) task_manager = tasks.TaskManager.new(broadcast_channel_key='broadcast') url = '/_titan/tasks/taskmanager/subscribe?key=%s&client_id=%s' % ( task_manager.key, client_id) response = self.app.post(url) self.assertEqual(200, response.status_int) # Must connect each client to the channel before broadcast. # This happens automatically by the client scripts in the real world. self.channel_stub.connect_channel(token) task_manager.defer_task('task-key0', GoodCallback) task_manager.defer_task('task-key1', BadCallback) task_manager.finalize() # Weakly assert that messages were sent to the broadcast channel. self.assertTrue(self.channel_stub.pop_first_message(token))
def get(self): # This is the low-level App Engine Channel API client_id, and should # be unique for each individual JavaScript client. # https://developers.google.com/appengine/docs/python/channel/functions user = users.get_current_user() # Make each client unique based on the current user email and request ID. client_id = hashlib.md5(user.email + os.environ["REQUEST_ID_HASH"]) client_id = client_id.hexdigest() token = channel.create_channel(client_id) context = {"client_id": client_id, "broadcast_channel_key": _GetBroadcastChannelKey(), "token": token} template = jinja_environment.get_template("templates/index.html") self.response.out.write(template.render(context))
def get(self): template = jinja_environment.get_template('templates/index.html') # This is the low-level App Engine Channel API client_id, and should # be unique for each individual JavaScript client. # https://developers.google.com/appengine/docs/python/channel/functions user = users.get_current_user() client_id = hashlib.md5(user.email + os.environ['REQUEST_ID_HASH']) client_id = client_id.hexdigest() token = channel.create_channel(client_id) context = { 'client_id': client_id, 'token': token, } self.response.out.write(template.render(context))
def testTaskManager(self): task_manager = tasks.TaskManager.new( group='group', description='desc', broadcast_channel_key='broadcast') self.assertEqual('group', task_manager.group) self.assertEqual('desc', task_manager.description) self.assertEqual('broadcast', task_manager._broadcast_channel.key) self.assertFalse(task_manager._finalized) self.assertTrue(task_manager.exists) token = channel.create_channel('foo') task_manager.subscribe('foo') self.channel_stub.connect_channel(token) self.assertRaises( tasks.TaskManagerNotFinalizedError, lambda: task_manager.status) # Get a new task manager from the key, like a new request would. task_manager = tasks.TaskManager(key=task_manager.key, group='group') # First task fails. task_manager.defer_task('key0', BadCallback) self.assertEqual(1, len(self.channel_stub.get_channel_messages(token))) # 10 tasks succeed. for i in range(1, 11): task_manager.defer_task('key%s' % i, GoodCallback, i) # Can't add a task with the same key. self.assertRaises( tasks.DuplicateTaskError, lambda: task_manager.defer_task('key0', lambda: None)) task_manager.finalize() # Cannot add tasks after finalization. self.assertRaises( tasks.TaskManagerFinalizedError, lambda: task_manager.defer_task('foo', lambda: None)) self.assertTrue(task_manager.exists) self.assertTrue(task_manager._finalized) self.assertRaises(tasks.InvalidTaskError, task_manager.get_task, 'fake-key') self.assertEqual(11, task_manager.num_total) self.assertEqual(0, task_manager.num_completed) self.assertEqual(0, task_manager.num_successful) self.assertEqual(0, task_manager.num_failed) self.assertEqual(0, len(task_manager.successful_tasks)) self.assertEqual(0, len(task_manager.failed_tasks)) self.assertEqual(tasks.STATUS_RUNNING, task_manager.status) self.assertEqual('*****@*****.**', task_manager.created_by.email) self.assertTrue(isinstance(task_manager.created, datetime.datetime)) for task in task_manager.tasks: self.assertEqual(tasks.STATUS_RUNNING, task.status) # Verify number of broadcasted messages. self.assertEqual(11, len(self.channel_stub.get_channel_messages(token))) # Run three deferred tasks and re-check stats. try: self.RunDeferredTasks(runs=1) except tasks.TaskError: pass # Expected for BadCallback(). self.RunDeferredTasks(runs=2) # Get a new task manager from the key, like a new request would. task_manager = tasks.TaskManager(key=task_manager.key, group='group') # Ensure that the task_manager can be pickled and unpickled correctly. task_manager = pickle.loads(pickle.dumps(task_manager)) # Cannot add tasks after finalization. self.assertRaises( tasks.TaskManagerFinalizedError, lambda: task_manager.defer_task('foo', lambda: None)) self.assertEqual('group', task_manager.group) self.assertEqual('desc', task_manager.description) self.assertEqual('broadcast', task_manager._broadcast_channel.key) self.assertTrue(task_manager._finalized) self.assertTrue(task_manager.exists) self.assertEqual(11, task_manager.num_total) self.assertEqual(3, task_manager.num_completed) self.assertEqual(2, task_manager.num_successful) self.assertEqual(1, task_manager.num_failed) self.assertEqual(2, len(task_manager.successful_tasks)) self.assertEqual(1, len(task_manager.failed_tasks)) self.assertEqual(tasks.STATUS_RUNNING, task_manager.status) for task in task_manager.successful_tasks: self.assertEqual(task.status, tasks.STATUS_SUCCESSFUL) for task in task_manager.failed_tasks: self.assertEqual(task.status, tasks.STATUS_FAILED) # Verify number of broadcasted messages (11 queued + 2 per completed task). self.assertEqual(17, len(self.channel_stub.get_channel_messages(token))) # Run the rest of the deferred tasks and re-check stats. self.RunDeferredTasks() task_manager = tasks.TaskManager(key=task_manager.key, group='group') self.assertEqual(11, task_manager.num_total) self.assertEqual(11, task_manager.num_completed) self.assertEqual(10, task_manager.num_successful) self.assertEqual(1, task_manager.num_failed) self.assertEqual(10, len(task_manager.successful_tasks)) self.assertEqual(1, len(task_manager.failed_tasks)) self.assertEqual(tasks.STATUS_FAILED, task_manager.status) for task in task_manager.successful_tasks: self.assertEqual(task.status, tasks.STATUS_SUCCESSFUL) for task in task_manager.failed_tasks: self.assertEqual(task.status, tasks.STATUS_FAILED) # Verify number of broadcasted messages (11 queued + 2 per completed task). self.assertEqual(33, len(self.channel_stub.get_channel_messages(token))) failed_task = list(task_manager.failed_tasks)[0] self.assertEqual('key0', failed_task.key) self.assertEqual( 'Task was too awesome to succeed.', failed_task.error_message) # Verify actual broadcasted messages. actual_messages = self.channel_stub.get_channel_messages(token) actual_messages = [json.loads(msg) for msg in actual_messages] for message in actual_messages: # Each channel message contains a JSON-encoded task message like this: # { # u'message': u'{"status": "successful", "task_key": "key9", # "task_manager_key": "53b642869769c75db38d384deff529e6"}' # } message = json.loads(message['message']) allowed_statuses = ( tasks.STATUS_QUEUED, tasks.STATUS_RUNNING, tasks.STATUS_SUCCESSFUL, tasks.STATUS_FAILED, ) self.assertIn(message['status'], allowed_statuses) self.assertIn('task_manager_key', message) self.assertTrue(message['task_key'].startswith('key')) if message['status'] == tasks.STATUS_FAILED: self.assertEqual('Task was too awesome to succeed.', message['error']) else: self.assertNotIn('error', message) # Verify group is part of what uniquely identifies a task manager. task_manager = tasks.TaskManager(key=task_manager.key, group='fake') self.assertFalse(task_manager.exists) # And verify that the filename is always the keyname. task_manager = tasks.TaskManager(key='key', group='group') self.assertEqual( '/_titan/tasks/group/key/tasks', task_manager._tasks_dir_path) # Error handling. self.assertRaises( ValueError, lambda: tasks.TaskManager.new(group='Invalid Group')) self.assertRaises( tasks.InvalidTaskManagerError, lambda: tasks.TaskManager('fake-key').defer_task('foo', lambda: None)) self.assertFalse(tasks.TaskManager(key='fake').exists)