blob: 3c2b9136b2eceb17ad98137efab7f5f138f81f86 [file] [log] [blame]
Yuheng Long761748d2013-06-28 09:32:43 -07001"""Unittest for the pipeline_worker functions in the build/test stage.
2
Yuheng Long49358b72013-07-10 14:45:29 -07003Part of the Chrome build flags optimization.
4
Yuheng Long761748d2013-06-28 09:32:43 -07005This module tests the helper method and the worker method.
6"""
7
8__author__ = 'yuhenglong@google.com (Yuheng Long)'
9
10import multiprocessing
11import random
12import sys
13import unittest
14
15import pipeline_process
16import pipeline_worker
17
18
19TESTSTAGE = 0
20
21
22def MockTaskCostGenerator():
23 """Calls a random number generator and returns a negative number."""
24 return random.randint(-sys.maxint - 1, -1)
25
26
27class MockTask(object):
28 """This class emulates an actual task.
29
30 It does not do the actual work, but simply returns the result as given when
31 this task is constructed.
32 """
33
34 def __init__(self, identifier, cost):
35 """Set up the results for this task.
36
37 Args:
38 identifier: the identifier of this task.
39 cost: the mock cost of this task.
40
41 The _pre_cost field stores the cost. Once this task is performed, i.e., by
42 calling the work method , the _cost field will have this cost.
43 """
44
45 self._identifier = identifier
46 self._pre_cost = cost
47
48 def get_identifier(self, stage):
49 assert stage == TESTSTAGE
50 return self._identifier
51
52 def __eq__(self, other):
53 if isinstance(other, MockTask):
54 return self._identifier == other._identifier and self._cost == other._cost
55 return False
56
57 def set_result(self, stage, cost):
58 assert stage == TESTSTAGE
59 self._cost = cost
60
61 def work(self, stage):
62 assert stage == TESTSTAGE
63 self._cost = self._pre_cost
64
65 def get_result(self, stage):
66 assert stage == TESTSTAGE
67 return self._cost
68
69 def done(self, stage):
70 """Indicates whether the task has been performed."""
71
72 assert stage == TESTSTAGE
73 return '_cost' in self.__dict__
74
75
76class AuxiliaryTest(unittest.TestCase):
77 """This class tests the pipeline_worker functions.
78
79 Given the same identifier, the cost should result the same from the
80 pipeline_worker functions.
81 """
82
83 def testHelper(self):
84 """"Test the helper.
85
86 Call the helper method twice, and test the results. The results should be
87 the same, i.e., the cost should be the same.
88 """
89
90 # Set up the input, helper and output queue for the helper method.
91 manager = multiprocessing.Manager()
92 helper_queue = manager.Queue()
93 result_queue = manager.Queue()
94 completed_queue = manager.Queue()
95
96 # Set up the helper process that holds the helper method.
97 helper_process = multiprocessing.Process(target=pipeline_worker.helper,
98 args=(TESTSTAGE, {}, helper_queue,
99 completed_queue,
100 result_queue))
101 helper_process.start()
102
103 # A dictionary defines the mock result to the helper.
104 mock_result = {1: 1995, 2: 59, 9: 1027}
105
106 # Test if there is a task that is done before, whether the duplicate task
107 # will have the same result. Here, two different scenarios are tested. That
108 # is the mock results are added to the completed_queue before and after the
109 # corresponding mock tasks being added to the input queue.
110 completed_queue.put((9, mock_result[9]))
111
112 # The output of the helper should contain all the following tasks.
113 results = [1, 1, 2, 9]
114
115 # Testing the correctness of having tasks having the same identifier, here
116 # 1.
117 for result in results:
118 helper_queue.put(MockTask(result, MockTaskCostGenerator()))
119
120 completed_queue.put((2, mock_result[2]))
121 completed_queue.put((1, mock_result[1]))
122
123 # Signal there is no more duplicate task.
124 helper_queue.put(pipeline_process.POISONPILL)
125 helper_process.join()
126
127 while results:
128 task = result_queue.get()
129 identifier = task._identifier
130 cost = task._cost
131 self.assertTrue(identifier in results)
132 if identifier in mock_result:
133 self.assertTrue(cost, mock_result[identifier])
134 results.remove(task._identifier)
135
136 def testWorker(self):
137 """"Test the worker method.
138
139 The worker should process all the input tasks and output the tasks to the
140 helper and result queue.
141 """
142
143 manager = multiprocessing.Manager()
144 result_queue = manager.Queue()
145 completed_queue = manager.Queue()
146
147 # A dictionary defines the mock tasks and their corresponding results.
148 mock_work_tasks = {1: 86, 2: 788}
149
150 mock_tasks = []
151
152 for flag, cost in mock_work_tasks.iteritems():
153 mock_tasks.append(MockTask(flag, cost))
154
155 # Submit the mock tasks to the worker.
156 for mock_task in mock_tasks:
157 pipeline_worker.worker(TESTSTAGE, mock_task, completed_queue,
158 result_queue)
159
160 # The tasks, from the output queue, should be the same as the input and
161 # should be performed.
162 for task in mock_tasks:
163 output = result_queue.get()
164 self.assertEqual(output, task)
165 self.assertTrue(output.done(TESTSTAGE))
166
167 # The tasks, from the completed_queue, should be defined in the
168 # mock_work_tasks dictionary.
169 for flag, cost in mock_work_tasks.iteritems():
170 helper_input = completed_queue.get()
171 self.assertEqual(helper_input, (flag, cost))
172
173
174if __name__ == '__main__':
175 unittest.main()