blob: bb947a98e9b86ffe25a74cca1ea4a21929995057 [file] [log] [blame]
Xixuan Wu835dee22017-09-07 10:47:29 -07001# Copyright 2017 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Module for task_executor unittests."""
6# pylint: disable=g-bad-import-order
Xinan Lin3ba18a02019-08-13 15:44:55 -07007# pylint: disable=unused-argument
Xixuan Wu835dee22017-09-07 10:47:29 -07008
Xinan Lin9e4917d2019-11-04 10:58:47 -08009import collections
Xixuan Wu835dee22017-09-07 10:47:29 -070010import mock
11import os
12import sys
13import unittest
14
15import task_executor
16
17from google.appengine.api import taskqueue
18from google.appengine.ext import testbed
19
20
Xinan Lin3ba18a02019-08-13 15:44:55 -070021class FakeFrontdoorClient(object):
22
23 # pylint: disable=g-deprecated-member-used
24 def __init__(self, success_num=sys.maxint, error_num=0):
25 self.success_num = success_num
26 self.error_num = error_num
Xinan Lin9e4917d2019-11-04 10:58:47 -080027 self.frontdoor_run_count = collections.defaultdict(list)
Xinan Lin3ba18a02019-08-13 15:44:55 -070028
Xinan Lin9e4917d2019-11-04 10:58:47 -080029 def multirequest_run(self, tasks, suite):
30 executed_tasks = []
31 for task in tasks:
32 params = task.extract_params()
33 num = int(params.get('num', 0))
34 if num > self.success_num and num <= self.success_num + self.error_num:
35 raise ValueError('test')
36 executed_tasks.append(task)
37 self.frontdoor_run_count[suite].append(executed_tasks)
38 return executed_tasks
Xinan Lin3ba18a02019-08-13 15:44:55 -070039
40
Xixuan Wu835dee22017-09-07 10:47:29 -070041class TaskExecutorTestCase(unittest.TestCase):
42
43 def setUp(self):
Prathmesh Prabhu7b961d52020-03-06 23:57:42 -080044 super(TaskExecutorTestCase, self).setUp()
Xixuan Wu835dee22017-09-07 10:47:29 -070045 self.testbed = testbed.Testbed()
46 self.testbed.activate()
47 self.addCleanup(self.testbed.deactivate)
48
49 # root_path must be set the location of queue.yaml.
50 # Otherwise, only the 'default' queue will be available.
51 self.testbed.init_taskqueue_stub(
52 root_path=os.path.join(os.path.dirname(__file__)))
53 self.taskqueue_stub = self.testbed.get_stub(
54 testbed.TASKQUEUE_SERVICE_NAME)
55
Prathmesh Prabhu40f1e1e2020-03-07 00:04:41 -080056 p = mock.patch('global_config.GAE_TESTING', return_value=True)
57 p.start()
58 self.addCleanup(p.stop)
59
Xixuan Wu835dee22017-09-07 10:47:29 -070060 def testPushTask(self):
Prathmesh Prabhu89c814e2020-03-07 00:12:43 -080061 _push_tasks('fake_suite', 1)
Xixuan Wu835dee22017-09-07 10:47:29 -070062 tasks = self.taskqueue_stub.get_filtered_tasks()
63 self.assertEqual(len(tasks), 1)
Prathmesh Prabhu89c814e2020-03-07 00:12:43 -080064 self.assertEqual('fake_suite', tasks[0].extract_params()['suite'])
Xixuan Wu835dee22017-09-07 10:47:29 -070065
Xinan Lin3ba18a02019-08-13 15:44:55 -070066 def testBatchExecuteTask(self):
Xinan Lina18d9882019-12-18 11:16:33 -080067 """Test task_executor executes tasks not greater than the BATCH_SIZE."""
Xinan Lin3b9b6f42020-03-16 16:10:37 -070068 batch_size = 10
Xinan Lin9e4917d2019-11-04 10:58:47 -080069 extra_num = 10
Prathmesh Prabhu89c814e2020-03-07 00:12:43 -080070 _push_tasks('foo_suite', batch_size / 2)
71 _push_tasks('hoo_suite', batch_size / 2 + extra_num)
Prathmesh Prabhu8f43d312020-03-07 00:25:06 -080072
73 task_processor = task_executor.TaskProcessor(
74 task_executor.SUITES_QUEUE,
75 test_platform_client=FakeFrontdoorClient(),
76 options=task_executor.Options(
Prathmesh Prabhu55c40032020-03-07 00:45:15 -080077 batch_size=batch_size,
78 multirequest_size=1,
79 per_suite_multirequest_size={}))
Prathmesh Prabhu8f43d312020-03-07 00:25:06 -080080 task_processor.batch_execute()
81
82 # After batch_execute runs, the extra tasks should remain in the queue.
83 tasks = self.taskqueue_stub.get_filtered_tasks()
84 self.assertEqual(extra_num, len(tasks))
Xixuan Wua5a29442017-10-11 11:03:02 -070085
Xinan Lin9e4917d2019-11-04 10:58:47 -080086 def testBatchExecuteTaskFailedFrontdoorTotally(self):
Xixuan Wu835dee22017-09-07 10:47:29 -070087 """Test task_executor fails at the beginning, and no tasks are deleted."""
Xinan Lin3b9b6f42020-03-16 16:10:37 -070088 batch_size = 10
Prathmesh Prabhu7b961d52020-03-06 23:57:42 -080089 multirequest_size = 30
Xixuan Wu835dee22017-09-07 10:47:29 -070090 extra_num = 10
Prathmesh Prabhu89c814e2020-03-07 00:12:43 -080091 _push_tasks('fake_suite', multirequest_size + extra_num)
Xixuan Wu835dee22017-09-07 10:47:29 -070092 # Before batch_execute
93 tasks = self.taskqueue_stub.get_filtered_tasks()
Prathmesh Prabhu7b961d52020-03-06 23:57:42 -080094 self.assertEqual(len(tasks), multirequest_size + extra_num)
Prathmesh Prabhu8f43d312020-03-07 00:25:06 -080095
96 task_processor = task_executor.TaskProcessor(
97 task_executor.SUITES_QUEUE,
98 test_platform_client=FakeFrontdoorClient(0, error_num=len(tasks)),
99 options=task_executor.Options(
Prathmesh Prabhu55c40032020-03-07 00:45:15 -0800100 batch_size=batch_size,
101 multirequest_size=multirequest_size,
102 per_suite_multirequest_size={}))
Prathmesh Prabhu8f43d312020-03-07 00:25:06 -0800103 task_processor.batch_execute()
104
105 # After batch_execute, no tasks are deleted from task queue, due
106 # to they're all failed to kick off.
107 tasks = self.taskqueue_stub.get_filtered_tasks()
108 self.assertEqual(len(tasks), multirequest_size + extra_num)
Xixuan Wu835dee22017-09-07 10:47:29 -0700109
Xinan Lin9e4917d2019-11-04 10:58:47 -0800110 def testBatchExecuteTaskFailedFrontdoorPartially(self):
Xixuan Wu835dee22017-09-07 10:47:29 -0700111 """Test task_executor fails halfway, and only executed tasks are deleted."""
Prathmesh Prabhu7b961d52020-03-06 23:57:42 -0800112 # Batch large enough to cover all added tasks.
Xinan Lin3b9b6f42020-03-16 16:10:37 -0700113 batch_size = 10
Prathmesh Prabhu7b961d52020-03-06 23:57:42 -0800114 multirequest_size = 30
Xixuan Wu835dee22017-09-07 10:47:29 -0700115 extra_num = 10
Prathmesh Prabhu7b961d52020-03-06 23:57:42 -0800116 success_num = (multirequest_size + extra_num) / 2
117 error_num = multirequest_size + extra_num
Prathmesh Prabhu89c814e2020-03-07 00:12:43 -0800118 _push_tasks('fake_suite', multirequest_size + extra_num)
Xixuan Wu835dee22017-09-07 10:47:29 -0700119
120 # Before batch_execute
121 tasks = self.taskqueue_stub.get_filtered_tasks()
Prathmesh Prabhu7b961d52020-03-06 23:57:42 -0800122 self.assertEqual(len(tasks), multirequest_size + extra_num)
Prathmesh Prabhu8f43d312020-03-07 00:25:06 -0800123
124 task_processor = task_executor.TaskProcessor(
125 task_executor.SUITES_QUEUE,
126 test_platform_client=FakeFrontdoorClient(success_num, error_num),
127 options=task_executor.Options(
Prathmesh Prabhu55c40032020-03-07 00:45:15 -0800128 batch_size=batch_size,
129 multirequest_size=multirequest_size,
130 per_suite_multirequest_size={}))
Prathmesh Prabhu8f43d312020-03-07 00:25:06 -0800131 task_processor.batch_execute()
132
133 # After batch_execute, only failed suites and extra suites are
134 # kept in task queue.
135 tasks = self.taskqueue_stub.get_filtered_tasks()
136 self.assertEqual(len(tasks), error_num)
Xixuan Wu835dee22017-09-07 10:47:29 -0700137
138 def testBatchExecuteTaskFailedLeasing(self):
139 """Test task_executor fails to lease task."""
Prathmesh Prabhu89c814e2020-03-07 00:12:43 -0800140 _push_tasks('fake_suite', 1)
Prathmesh Prabhu8f43d312020-03-07 00:25:06 -0800141
142 task_processor = task_executor.TaskProcessor(
143 'nonExistentQueue',
144 test_platform_client=FakeFrontdoorClient(False),
Prathmesh Prabhu55c40032020-03-07 00:45:15 -0800145 options=task_executor.Options(10, 10, {}))
Prathmesh Prabhu8f43d312020-03-07 00:25:06 -0800146 self.assertRaises(taskqueue.UnknownQueueError,
147 task_processor.batch_execute)
148
149 # After batch_execute fails, no tasks are deleted from task queue.
150 tasks = self.taskqueue_stub.get_filtered_tasks()
151 self.assertEqual(len(tasks), 1)
Xixuan Wu835dee22017-09-07 10:47:29 -0700152
Prathmesh Prabhu55c40032020-03-07 00:45:15 -0800153 def testBatchExecuteTaskWithPerSuiteLimit(self):
154 """Test task_executor executes respects per-suite limit."""
Xinan Lin3b9b6f42020-03-16 16:10:37 -0700155 batch_size = 10
Prathmesh Prabhu55c40032020-03-07 00:45:15 -0800156 multirequest_size = 10
157 foo_suite_limit = 3
Xinan Lin3b9b6f42020-03-16 16:10:37 -0700158 extra_num = 5
159 _push_tasks('foo_suite', batch_size * foo_suite_limit + extra_num)
Prathmesh Prabhu55c40032020-03-07 00:45:15 -0800160
161 frontdoor_client = FakeFrontdoorClient()
162 task_processor = task_executor.TaskProcessor(
163 task_executor.SUITES_QUEUE,
164 test_platform_client=frontdoor_client,
165 options=task_executor.Options(
166 batch_size=batch_size,
167 multirequest_size=multirequest_size,
168 per_suite_multirequest_size={'foo_suite': foo_suite_limit}))
169 task_processor.batch_execute()
170
171 executed_count = 0
172 for tasks in frontdoor_client.frontdoor_run_count['foo_suite']:
173 self.assertEqual(foo_suite_limit, len(tasks))
174 executed_count += len(tasks)
Xinan Lin3b9b6f42020-03-16 16:10:37 -0700175 self.assertEqual(executed_count, batch_size * foo_suite_limit)
176 tasks = self.taskqueue_stub.get_filtered_tasks()
177 self.assertEqual(extra_num, len(tasks))
Prathmesh Prabhu55c40032020-03-07 00:45:15 -0800178
Xixuan Wu835dee22017-09-07 10:47:29 -0700179
Prathmesh Prabhu89c814e2020-03-07 00:12:43 -0800180def _push_tasks(suite, count):
181 """Push count tasks in the executor queue for suite."""
182 for i in range(count):
183 task_executor.push(
184 task_executor.SUITES_QUEUE, tag=suite, suite=suite, num=i + 1)
185
186
Xixuan Wu835dee22017-09-07 10:47:29 -0700187if __name__ == '__main__':
188 unittest.main()