aboutsummaryrefslogtreecommitdiff
path: root/bestflags/builder_test.py
blob: a705ee1abd49e723731f8c5191a47dc1b3c06b17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
"""Builder unittest.

This module tests the build helper method and the worker method.
"""

__author__ = 'yuhenglong@google.com (Yuheng Long)'

import multiprocessing
import random
import sys
import unittest

import builder
import pipeline_process


def MockTaskCostGenerator():
  """Calls a random number generator and returns a negative number."""
  return random.randint(-sys.maxint - 1, -1)


class MockTask(object):
  """This class emulates an actual task.

  It does not do the actual compile, but simply returns the build result as when
  this task is constructed.
  """

  def __init__(self, flags, cost):
    """Set up the compile results for this task.

    Args:
      flags: the optimization flags of this task.
      cost: the mork build cost of this task.

      The _pre_cost field stored the 'compiled' cost. Once this task is
      compiled, i.e., by calling the compile method , the _cost field will have
      this 'compiled' cost.
    """

    self._flags = flags
    self._pre_cost = cost

  def get_flags(self):
    return self._flags

  def __eq__(self, other):
    if isinstance(other, MockTask):
      return self._flags == other._flags and self._cost == other._cost
    return False

  def set_build_result(self, cost):
    self._cost = cost

  def compile(self):
    self._cost = self._pre_cost

  def get_build_result(self):
    return self._cost

  def compiled(self):
    """Indicates whether the task has been compiled."""

    return '_cost' in self.__dict__


class BuilderTest(unittest.TestCase):
  """This class tests the Builder.

  Given the same flags set, the image and the cost should result the same from
  the builder.
  """

  def testHelper(self):
    """"Test the build helper.

    Call the build method twice, and test the results. The results should be the
    same, i.e., the cost should be the same.
    """

    # Set up the input, helper and output queue for the worker method.
    manager = multiprocessing.Manager()
    helper_queue = manager.Queue()
    output_queue = manager.Queue()
    built_queue = manager.Queue()

    # Set up the helper process that holds the helper method.
    helper_process = multiprocessing.Process(target=builder.build_helper,
                                             args=({}, helper_queue,
                                                   built_queue, output_queue))
    helper_process.start()

    # A dictionary defines the mock compile result to the build_helper.
    mock_compile_result = {1: 1995, 2: 59, 9: 1027}

    # Test if there is a task that is done before, whether the duplicate task
    # will have the same result. Here, two different scenarios are tested. That
    # is the mock results are added to the built_queue before and after the
    # corresponding mock tasks being ;added to the input queue.
    built_queue.put((9, mock_compile_result[9]))

    # The output of the helper should contain all the following tasks.
    results = [1, 1, 2, 9]

    # Testing the correctness of having tasks having the same flags key, here 1.
    for result in results:
      helper_queue.put(MockTask(result, MockTaskCostGenerator()))

    built_queue.put((2, mock_compile_result[2]))
    built_queue.put((1, mock_compile_result[1]))

    # Signal there is no more duplicate task.
    helper_queue.put(pipeline_process.POISONPILL)
    helper_process.join()

    while results:
      task = output_queue.get()
      flags = task._flags
      cost = task._cost
      self.assertTrue(flags in results)
      if flags in mock_compile_result:
        self.assertTrue(cost, mock_compile_result[flags])
      results.remove(task._flags)

  def testWorker(self):
    """"Test the actual build worker method.

    The worker should process all the input tasks and output the tasks to the
    helper and result queue.
    """

    manager = multiprocessing.Manager()
    output_queue = manager.Queue()
    built_queue = manager.Queue()

    # A dictionary defines the mock tasks and their corresponding compile
    # results.
    mock_compile_tasks = {1: 86, 2: 788}

    mock_tasks = []

    for flag, cost in mock_compile_tasks.iteritems():
      mock_tasks.append(MockTask(flag, cost))

    # Submit the mock tasks to the build worker.
    for mock_task in mock_tasks:
      builder.build_worker(mock_task, built_queue, output_queue)

    # The tasks, from the output queue, should be the same as the input and
    # should be compiled.
    for task in mock_tasks:
      output = output_queue.get()
      self.assertEqual(output, task)
      self.assertTrue(output.compiled())

    # The tasks, from the built queue, should be defined in the
    # mock_compile_tasks dictionary.
    for flag, cost in mock_compile_tasks.iteritems():
      helper_input = built_queue.get()
      self.assertEqual(helper_input, (flag, cost))


if __name__ == '__main__':
  unittest.main()