aboutsummaryrefslogtreecommitdiff
path: root/llvm_tools/get_llvm_hash_unittest.py
blob: dc23b2901224c34159ba6216891f720b9600d48b (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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# Copyright 2019 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Unit tests for retrieving the LLVM hash."""

from __future__ import print_function

import mock
import tempfile
import unittest

from cros_utils import command_executer
from get_google3_llvm_version import LLVMVersion
from get_llvm_hash import LLVMHash


class TestGetLLVMHash(unittest.TestCase):
  """The LLVMHash test class."""

  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
  def testCloneRepoSucceeds(self, mock_run_commmand_output):
    # Test function to emulate RunCommandWOutput behavior in succeeds case.
    def GoodCloneRepo(clone_cmd, print_to_console):
      # Expected argument to RunCommandWOutput.
      self.assertEqual(clone_cmd.split()[-1], '/tmp/tmpTest')

      # Returns shell error code, stdout, stderr.
      return 0, None, 0

    # Use the test function to simulate RunCommandWOutput behavior.
    mock_run_commmand_output.side_effect = GoodCloneRepo

    TestLLVMHash = LLVMHash()

    # Test the call to _CloneLLVMRepo function.
    TestLLVMHash._CloneLLVMRepo('/tmp/tmpTest')

    mock_run_commmand_output.assert_called_once()

  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
  def testCloneRepoFails(self, mock_run_command_output):
    # Test function to simulate RunCommandWOutput behavior in a failed case.
    def BadCloneRepo(clone_cmd, print_to_console):
      # Make sure an invalid argument is passed in.
      self.assertNotEqual(clone_cmd.split()[-1], '/tmp/tmpTest')

      # Returns shell error code, stdout, stderr.
      return 1, None, 'Invalid path provided'

    # Use the test function to simulate RunCommandWOutput behavior.
    mock_run_command_output.side_effect = BadCloneRepo

    TestLLVMHash = LLVMHash()

    # Verify the exception is raised when cloning the repo fails.
    with self.assertRaises(ValueError) as err:
      TestLLVMHash._CloneLLVMRepo('/tmp/tmp1')

    self.assertEqual(err.exception.message, 'Failed to clone the llvm repo: ' \
                     'Invalid path provided')

    mock_run_command_output.assert_called_once()

  @mock.patch.object(tempfile, 'mkdtemp')
  def testCreateTempDirectory(self, mock_create_temp_dir):
    # Test function to simulate mkdtemp behavior.
    def FakeMakeDir():
      # Returns a directory in '/tmp/'.
      return '/tmp/tmpTest'

    # Use the test function to simulate mkdtemp behavior.
    mock_create_temp_dir.side_effect = FakeMakeDir

    TestLLVMHash = LLVMHash()

    self.assertEqual(TestLLVMHash._CreateTempDirectory(), '/tmp/tmpTest')

    mock_create_temp_dir.assert_called_once()

  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
  def testFailToParseCommitMessage(self, mock_commit_message):
    # Test function to simulate RunCommandWOutput behavior.
    def FakeCommitMessageOutput(find_llvm_cmd, print_to_console):
      # Returns shell error code, stdout, stderr.
      return 1, None, 'Unable to find the llvm version'

    # Use the test function to simulate RunCommandWOutput behavior.
    mock_commit_message.side_effect = FakeCommitMessageOutput

    TestLLVMHash = LLVMHash()

    # Verify the exception is raised when failed to parse a commit message.
    with self.assertRaises(ValueError) as err:
      TestLLVMHash._ParseCommitMessages('/tmp/tmpTest',
                                        'a13testhash2 This is a test', 100)

    self.assertEqual(err.exception.message, 'Failed to parse commit message: ' \
                     'Unable to find the llvm version')

    mock_commit_message.assert_called_once()

  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
  def testUnableToFindCommitHash(self, mock_commit_message):
    # Test function to simulate RunCommandWOutput when parsing a
    # commit message body.
    def CustomCommitMessage(find_llvm_cmd, print_to_console):
      commit_message = ('[Test] Test sentence.\n\n'
                        'A change was made.\n\n'
                        'llvm-svn: 1000')

      # Returns shell error code, stdout, stderr.
      return 0, commit_message, 0

    # Use test function to simulate RunCommandWOutput behavior.
    mock_commit_message.side_effect = CustomCommitMessage

    TestLLVMHash = LLVMHash()

    # Verify the exception is raised when failed to find the commit hash.
    with self.assertRaises(ValueError) as err:
      TestLLVMHash._ParseCommitMessages('/tmp/tmpTest',
                                        'a13testhash2 This is a test', 100)

    self.assertEqual(err.exception.message, 'Could not find commit hash.')

    mock_commit_message.assert_called_once()

  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
  def testFindCommitHashSuccessfully(self, mock_commit_message):
    # Test function will be called 3 times, so
    # 'loop_counter' determines which commit message to return
    loop_counter = [0]

    # Test function to simulate RunCommandWOutput when
    # returning a commit message.
    def MultipleCommitMessages(find_llvm_cmd, print_to_console):
      if loop_counter[0] == 0:  # first iteration
        commit_message_1 = ('[Test] Test sentence.\n\n'
                            'A change was made.\n\n'
                            'llvm-svn: 1001')

        loop_counter[0] += 1

        # Returns shell error code, stdout, stderr.
        return 0, commit_message_1, 0
      if loop_counter[0] == 1:  # second iteration
        # nested commit message containing two 'llvm-svn'
        commit_message_2 = ('[Revert] Reverted commit.\n\n'
                            'This reverts r1000:\n\n'
                            '  [Test2] Update.\n\n'
                            '    This updates stuff.\n\n'
                            '    llvm-svn: 1000\n\n'
                            'llvm-svn: 58')

        loop_counter[0] += 1

        # Returns shell error code, stdout, stderr.
        return 0, commit_message_2, 0
      if loop_counter[0] == 2:  # third iteration
        # nested commit message containing two 'llvm-svn'
        commit_message_3 = ('[Revert] Reverted commit.\n\n'
                            'This reverts r958:\n\n'
                            '  [Test2] Update.\n\n'
                            '    This updates stuff.\n\n'
                            '    llvm-svn: 958\n\n'
                            'llvm-svn: 1000')

        # Returns shell error code, stdout, stderr.
        return 0, commit_message_3, 0

      # Testing function was called more times than expected (3 times)
      assert False, 'RunCommandWOutput was called more than 3 times.'

    # Use test function to simulate RunCommandWOutput behavior.
    mock_commit_message.side_effect = MultipleCommitMessages

    TestLLVMHash = LLVMHash()

    # Test hashes used for parsing.
    #
    # Format:
    #   [Hash] [Commit Summary]
    hash_vals = ('a13testhash2 [Test] Test sentence.\n'
                 'a13testhash3 [Revert] Reverted commit.\n'
                 'a13testhash4 [Revert] Reverted commit.')

    self.assertEqual(
        TestLLVMHash._ParseCommitMessages('/tmp/tmpTest', hash_vals, 1000),
        'a13testhash4')

    self.assertEqual(mock_commit_message.call_count, 3)

  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
  def testUnableToGetGitHash(self, mock_hash_val_output):
    # Test function to simulate RunCommandWOuput when unable to
    # find the 'llvm-svn' passed in.
    def FailedHashValOutput(hash_cmd, print_to_console):
      # Returns shell error code, stdout, stderr.
      return 1, None, 'Failed to find specific llvm-svn'

    # Use test function to simulate RunCommandWOutput behavior.
    mock_hash_val_output.side_effect = FailedHashValOutput

    TestLLVMHash = LLVMHash()

    # Verify the exception is raised when unable to get the hash for the llvm
    # version.
    with self.assertRaises(ValueError) as err:
      TestLLVMHash.GetGitHashForVersion('/tmp/tmpTest', 100)

    self.assertEqual(err.exception.message,
                     'Hash not found: Failed to find specific llvm-svn')

    mock_hash_val_output.assert_called_once()

  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
  @mock.patch.object(LLVMHash, '_ParseCommitMessages')
  def testGetGitHashSuccess(self, mock_return_hash_val, mock_hash_val_output):
    # Test function to simulate RunCommandWOutput when parsing the git log
    # history.
    #
    # Format:
    #   [Hash] [Commit Summary]
    def CustomHashValsOutput(hash_cmd, print_to_console):
      hash_val = 'a13testhash2 [Test] Test sentence.'

      # Returns shell error code, stdout, stderr.
      return 0, hash_val, 0

    # Test function to simulate _ParseCommitMessages when a commit hash is
    # returned.
    def CustomReturnHash(subdir, hash_vals, llvm_version):
      return 'a13testhash2'

    # Use test functions to simulate behavior.
    mock_hash_val_output.side_effect = CustomHashValsOutput
    mock_return_hash_val.side_effect = CustomReturnHash

    TestLLVMHash = LLVMHash()

    self.assertEqual(
        TestLLVMHash.GetGitHashForVersion('/tmp/tmpTest', 100), 'a13testhash2')

    mock_return_hash_val.assert_called_once_with(
        '/tmp/tmpTest/llvm', 'a13testhash2 [Test] Test sentence.', 100)
    mock_hash_val_output.assert_called_once()

  @mock.patch.object(LLVMHash, '_CloneLLVMRepo')
  @mock.patch.object(LLVMHash, '_DeleteTempDirectory')
  @mock.patch.object(LLVMHash, '_CreateTempDirectory')
  def testExceptionWhenGetLLVMHash(self, mock_create_temp_dir,
                                   mock_del_temp_dir, mock_clone_repo):

    # Test function to simulate _CloneLLVMRepo when exception is thrown.
    def FailedCloneRepo(llvm_git_dir):
      raise ValueError('Failed to clone LLVM repo.')

    # Test function to simulate _DeleteTempDirectory when successfully
    # deleted the temp directory.
    def DeletedTempDirectory(llvm_git_dir):
      return True

    # Test function to simulate _CreateTempDirectory when temp directory
    # is returned.
    def CreatedTempDirectory():
      return '/tmp/tmpTest'

    # Use test functions to simulate the behavior.
    mock_clone_repo.side_effect = FailedCloneRepo
    mock_del_temp_dir.side_effect = DeletedTempDirectory
    mock_create_temp_dir.side_effect = CreatedTempDirectory

    TestLLVMHash = LLVMHash()

    # Verify the exception is raised when an exception is thrown
    # within the 'try' block
    #
    # Cloning the repo will raise the exception.
    with self.assertRaises(ValueError) as err:
      TestLLVMHash.GetLLVMHash(100)

    self.assertEqual(err.exception.message, 'Failed to clone LLVM repo.')

    mock_del_temp_dir.assert_called_once_with('/tmp/tmpTest')
    mock_clone_repo.assert_called_once()
    mock_create_temp_dir.assert_called_once()

  @mock.patch.object(LLVMHash, '_CloneLLVMRepo')
  @mock.patch.object(LLVMHash, '_DeleteTempDirectory')
  @mock.patch.object(LLVMHash, '_CreateTempDirectory')
  @mock.patch.object(LLVMHash, 'GetGitHashForVersion')
  def testReturnWhenGetLLVMHash(self, mock_get_git_hash, mock_create_temp_dir,
                                mock_del_temp_dir, mock_clone_repo):

    # Test function to simulate _CloneLLVMRepo when successfully cloned the
    # repo.
    def ClonedRepo(llvm_git_dir):
      return True

    # Test function to simulate _DeleteTempDirectory when successfully
    # deleted the temp directory.
    def DeletedTempDirectory(llvm_git_dir):
      return True

    # Test function to simulate _CreateTempDirectory when successfully
    # created the temp directory.
    def CreatedTempDirectory():
      return '/tmp/tmpTest'

    # Test function to simulate GetGitHashForVersion when a hash is returned
    # of its llvm version.
    def ReturnGitHashForVersion(llvm_git_dir, llvm_version):
      return 'a13testhash2'

    # Use test functions to simulate behavior.
    mock_clone_repo.side_effect = ClonedRepo
    mock_del_temp_dir.side_effect = DeletedTempDirectory
    mock_create_temp_dir.side_effect = CreatedTempDirectory
    mock_get_git_hash.side_effect = ReturnGitHashForVersion

    TestLLVMHash = LLVMHash()

    self.assertEqual(TestLLVMHash.GetLLVMHash(100), 'a13testhash2')

    mock_create_temp_dir.assert_called_once()
    mock_clone_repo.assert_called_once_with('/tmp/tmpTest')
    mock_get_git_hash.assert_called_once_with('/tmp/tmpTest', 100)
    mock_del_temp_dir.assert_called_once()

  @mock.patch.object(LLVMHash, 'GetLLVMHash')
  @mock.patch.object(LLVMVersion, 'GetGoogle3LLVMVersion')
  def testReturnGoogle3LLVMHash(self, mock_google3_llvm_version,
                                mock_get_llvm_hash):

    # Test function to simulate GetLLVMHash that returns
    # the hash of the google3 llvm version.
    def ReturnGoogle3LLVMHash(google3_llvm_version):
      return 'a13testhash3'

    # Test function to simulate GetGoogle3LLVMVersion that returns
    # the google3 llvm version.
    def ReturnGoogle3LLVMVersion():
      return 1000

    # Use test functions to simulate behavior.
    mock_get_llvm_hash.side_effect = ReturnGoogle3LLVMHash
    mock_google3_llvm_version.side_effect = ReturnGoogle3LLVMVersion

    TestLLVMHash = LLVMHash()

    self.assertEqual(TestLLVMHash.GetGoogle3LLVMHash(), 'a13testhash3')

    mock_get_llvm_hash.assert_called_once_with(1000)
    mock_google3_llvm_version.assert_called_once()

  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
  def testFailedToGetHashFromTopOfTrunk(self, mock_run_cmd):
    # Simulate the behavior of 'RunCommandWOutput()' when failed to get the
    # latest git hash from top of tree of LLVM.
    #
    # Returns shell error code, stdout, stderr.
    mock_run_cmd.return_value = (1, None, 'Could not get git hash from HEAD.')

    TestLLVMHash = LLVMHash()

    # Verify the exception is raised when failed to get the git hash of HEAD
    # from LLVM.
    with self.assertRaises(ValueError) as err:
      TestLLVMHash.GetTopOfTrunkGitHash()

    self.assertEqual(
        err.exception.message,
        'Failed to get the latest git hash from the top of trunk '
        'of LLVM: Could not get git hash from HEAD.')

    mock_run_cmd.assert_called_once()

  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
  def testSuccessfullyGetGitHashFromToTOfLLVM(self, mock_run_cmd):
    # Simulate the behavior of 'RunCommandWOutput()' when successfully retrieved
    # the git hash from top of tree of LLVM.
    #
    # Returns shell error code, stdout, stderr.
    mock_run_cmd.return_value = (0, 'a123testhash1 path/to/master\n', 0)

    TestLLVMHash = LLVMHash()

    self.assertEqual(TestLLVMHash.GetTopOfTrunkGitHash(), 'a123testhash1')

    mock_run_cmd.assert_called_once()


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