1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#
4# Copyright 2018 The Chromium OS Authors. All rights reserved.
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8"""Unittest for buildbot_utils.py."""
9
10from __future__ import print_function
11
12import time
13
14import unittest
15from unittest.mock import patch
16
17from cros_utils import buildbot_utils
18from cros_utils import command_executer
19
20
21class TrybotTest(unittest.TestCase):
22  """Test for CommandExecuter class."""
23
24  tryjob_out = (
25      '[{"buildbucket_id": "8952721143823688176", "build_config": '
26      '"cave-llvm-toolchain-tryjob", "url": '
27      # pylint: disable=line-too-long
28      '"http://cros-goldeneye/chromeos/healthmonitoring/buildDetails?buildbucketId=8952721143823688176"}]'
29  )
30
31  GSUTILS_LS = '\n'.join([
32      'gs://chromeos-image-archive/{0}/R78-12421.0.0/',
33      'gs://chromeos-image-archive/{0}/R78-12422.0.0/',
34      'gs://chromeos-image-archive/{0}/R78-12423.0.0/',
35  ])
36
37  GSUTILS_LS_RECIPE = '\n'.join([
38      'gs://chromeos-image-archive/{0}/R83-12995.0.0-30031-8885075268947031/',
39      'gs://chromeos-image-archive/{0}/R83-13003.0.0-30196-8884755532184725/',
40      'gs://chromeos-image-archive/{0}/R83-13003.0.0-30218-8884712858556419/',
41  ])
42
43  buildresult_out = (
44      '{"8952721143823688176": {"status": "pass", "artifacts_url":'
45      '"gs://chromeos-image-archive/trybot-elm-release-tryjob/R67-10468.0.0-'
46      'b20789"}}')
47
48  buildbucket_id = '8952721143823688176'
49  counter_1 = 10
50
51  def testGetTrybotImage(self):
52    with patch.object(buildbot_utils, 'SubmitTryjob') as mock_submit:
53      with patch.object(buildbot_utils, 'PeekTrybotImage') as mock_peek:
54        with patch.object(time, 'sleep', return_value=None):
55
56          def peek(_chromeos_root, _buildbucket_id):
57            self.counter_1 -= 1
58            if self.counter_1 >= 0:
59              return ('running', '')
60            return ('pass',
61                    'gs://chromeos-image-archive/trybot-elm-release-tryjob/'
62                    'R67-10468.0.0-b20789')
63
64          mock_peek.side_effect = peek
65          mock_submit.return_value = self.buildbucket_id
66
67          # sync
68          buildbucket_id, image = buildbot_utils.GetTrybotImage(
69              '/tmp', 'falco-release-tryjob', [])
70          self.assertEqual(buildbucket_id, self.buildbucket_id)
71          self.assertEqual('trybot-elm-release-tryjob/'
72                           'R67-10468.0.0-b20789', image)
73
74          # async
75          buildbucket_id, image = buildbot_utils.GetTrybotImage(
76              '/tmp', 'falco-release-tryjob', [], asynchronous=True)
77          self.assertEqual(buildbucket_id, self.buildbucket_id)
78          self.assertEqual(' ', image)
79
80  def testSubmitTryjob(self):
81    with patch.object(command_executer.CommandExecuter,
82                      'RunCommandWOutput') as mocked_run:
83      mocked_run.return_value = (0, self.tryjob_out, '')
84      buildbucket_id = buildbot_utils.SubmitTryjob('/', 'falco-release-tryjob',
85                                                   [], [])
86      self.assertEqual(buildbucket_id, self.buildbucket_id)
87
88  def testPeekTrybotImage(self):
89    with patch.object(command_executer.CommandExecuter,
90                      'RunCommandWOutput') as mocked_run:
91      # pass
92      mocked_run.return_value = (0, self.buildresult_out, '')
93      status, image = buildbot_utils.PeekTrybotImage('/', self.buildbucket_id)
94      self.assertEqual('pass', status)
95      self.assertEqual(
96          'gs://chromeos-image-archive/trybot-elm-release-tryjob/'
97          'R67-10468.0.0-b20789', image)
98
99      # running
100      mocked_run.return_value = (1, '', '')
101      status, image = buildbot_utils.PeekTrybotImage('/', self.buildbucket_id)
102      self.assertEqual('running', status)
103      self.assertEqual(None, image)
104
105      # fail
106      buildresult_fail = self.buildresult_out.replace('\"pass\"', '\"fail\"')
107      mocked_run.return_value = (0, buildresult_fail, '')
108      status, image = buildbot_utils.PeekTrybotImage('/', self.buildbucket_id)
109      self.assertEqual('fail', status)
110      self.assertEqual(
111          'gs://chromeos-image-archive/trybot-elm-release-tryjob/'
112          'R67-10468.0.0-b20789', image)
113
114  def testParseTryjobBuildbucketId(self):
115    buildbucket_id = buildbot_utils.ParseTryjobBuildbucketId(self.tryjob_out)
116    self.assertEqual(buildbucket_id, self.buildbucket_id)
117
118  def testGetLatestImageValid(self):
119    with patch.object(command_executer.CommandExecuter,
120                      'ChrootRunCommandWOutput') as mocked_run:
121      with patch.object(buildbot_utils, 'DoesImageExist') as mocked_imageexist:
122        IMAGE_DIR = 'lulu-release'
123        mocked_run.return_value = (0, self.GSUTILS_LS.format(IMAGE_DIR), '')
124        mocked_imageexist.return_value = True
125        image = buildbot_utils.GetLatestImage('', IMAGE_DIR)
126        self.assertEqual(image, '{0}/R78-12423.0.0'.format(IMAGE_DIR))
127
128  def testGetLatestImageInvalid(self):
129    with patch.object(command_executer.CommandExecuter,
130                      'ChrootRunCommandWOutput') as mocked_run:
131      with patch.object(buildbot_utils, 'DoesImageExist') as mocked_imageexist:
132        IMAGE_DIR = 'kefka-release'
133        mocked_run.return_value = (0, self.GSUTILS_LS.format(IMAGE_DIR), '')
134        mocked_imageexist.return_value = False
135        image = buildbot_utils.GetLatestImage('', IMAGE_DIR)
136        self.assertIsNone(image)
137
138  def testGetLatestRecipeImageValid(self):
139    with patch.object(command_executer.CommandExecuter,
140                      'ChrootRunCommandWOutput') as mocked_run:
141      with patch.object(buildbot_utils, 'DoesImageExist') as mocked_imageexist:
142        IMAGE_DIR = 'lulu-llvm-next-nightly'
143        mocked_run.return_value = (0, self.GSUTILS_LS_RECIPE.format(IMAGE_DIR),
144                                   '')
145        mocked_imageexist.return_value = True
146        image = buildbot_utils.GetLatestRecipeImage('', IMAGE_DIR)
147        self.assertEqual(
148            image, '{0}/R83-13003.0.0-30218-8884712858556419'.format(IMAGE_DIR))
149
150  def testGetLatestRecipeImageInvalid(self):
151    with patch.object(command_executer.CommandExecuter,
152                      'ChrootRunCommandWOutput') as mocked_run:
153      with patch.object(buildbot_utils, 'DoesImageExist') as mocked_imageexist:
154        IMAGE_DIR = 'kefka-llvm-next-nightly'
155        mocked_run.return_value = (0, self.GSUTILS_LS_RECIPE.format(IMAGE_DIR),
156                                   '')
157        mocked_imageexist.return_value = False
158        image = buildbot_utils.GetLatestRecipeImage('', IMAGE_DIR)
159        self.assertIsNone(image)
160
161  def testGetLatestRecipeImageTwodays(self):
162    with patch.object(command_executer.CommandExecuter,
163                      'ChrootRunCommandWOutput') as mocked_run:
164      with patch.object(buildbot_utils, 'DoesImageExist') as mocked_imageexist:
165        IMAGE_DIR = 'lulu-llvm-next-nightly'
166        mocked_run.return_value = (0, self.GSUTILS_LS_RECIPE.format(IMAGE_DIR),
167                                   '')
168        mocked_imageexist.side_effect = [False, False, True]
169        image = buildbot_utils.GetLatestRecipeImage('', IMAGE_DIR)
170        self.assertIsNone(image)
171        mocked_imageexist.side_effect = [False, True, True]
172        image = buildbot_utils.GetLatestRecipeImage('', IMAGE_DIR)
173        self.assertEqual(
174            image, '{0}/R83-13003.0.0-30196-8884755532184725'.format(IMAGE_DIR))
175
176
177if __name__ == '__main__':
178  unittest.main()
179