chromium/infra/config/scripts/tests/milestones_integration_test.py

#!/usr/bin/env vpython3
# Copyright 2020 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Integration test for milestones.py"""

import json
import os
import subprocess
import tempfile
import textwrap
import unittest

INFRA_CONFIG_DIR = os.path.abspath(os.path.join(__file__, '..', '..', '..'))
MILESTONES_PY = os.path.join(INFRA_CONFIG_DIR, 'scripts', 'milestones.py')

class MilestonesIntgrationTest(unittest.TestCase):

  def setUp(self):
    self._temp_dir = tempfile.TemporaryDirectory()
    self._milestones_json = os.path.join(self._temp_dir.name, 'milestones.json')

  def tearDown(self):
    self._temp_dir.cleanup()

  def _execute_milestones_py(self, args):
    cmd = [MILESTONES_PY, '--milestones-json', self._milestones_json]
    if os.name == 'nt':
      cmd = ['vpython3.bat'] + cmd
    return subprocess.run((cmd + (args or [])), text=True, capture_output=True)

  def test_activate_fails_when_missing_required_args(self):
    result = self._execute_milestones_py(['activate'])
    self.assertNotEqual(result.returncode, 0)
    self.assertIn(
        'the following arguments are required: --milestone, --branch',
        result.stderr)

  def test_activate_fails_when_milestone_already_active(self):
    milestones = {
        '99': {
            'name': 'm99',
            'project': 'chromium-m99',
            'ref': 'refs/branch-heads/AAAA',
        },
    }
    with open(self._milestones_json, 'w') as f:
      json.dump(milestones, f, indent=4)

    result = self._execute_milestones_py(
        ['activate', '--milestone', '99', '--branch', 'BBBB'])
    self.assertNotEqual(result.returncode, 0)
    self.assertIn(
        "there is already an active milestone with id '99'",
        result.stderr)

  def test_activate_rewrites_milestones_json(self):
    milestones = {
        '99': {
            'name': 'm99',
            'project': 'chromium-m99',
            'ref': 'refs/branch-heads/AAAA',
        },
        '101': {
            'name': 'm101',
            'project': 'chromium-m101',
            'ref': 'refs/branch-heads/BBBB',
        },
    }
    with open(self._milestones_json, 'w') as f:
      json.dump(milestones, f, indent=4)

    result = self._execute_milestones_py(
        ['activate', '--milestone', '100', '--branch', 'CCCC'])
    self.assertEqual(
        result.returncode, 0,
        (f'subprocess failed\n***COMMAND***\n{result.args}\n'
         f'***STDERR***\n{result.stderr}'))

    with open(self._milestones_json) as f:
      milestones = f.read()
    self.assertEqual(milestones,  textwrap.dedent("""\
        {
            "99": {
                "name": "m99",
                "project": "chromium-m99",
                "ref": "refs/branch-heads/AAAA"
            },
            "100": {
                "name": "m100",
                "project": "chromium-m100",
                "ref": "refs/branch-heads/CCCC"
            },
            "101": {
                "name": "m101",
                "project": "chromium-m101",
                "ref": "refs/branch-heads/BBBB"
            }
        }
        """))

  def test_deactivate_fails_when_missing_required_args(self):
    result = self._execute_milestones_py(['deactivate'])
    self.assertNotEqual(result.returncode, 0)
    self.assertIn(
        'the following arguments are required: --milestone',
        result.stderr)

  def test_deactivate_fails_when_milestone_not_active(self):
    milestones = {}
    with open(self._milestones_json, 'w') as f:
      json.dump(milestones, f, indent=4)

    result = self._execute_milestones_py(['deactivate', '--milestone', '99'])
    self.assertNotEqual(result.returncode, 0)
    self.assertIn(
        "'99' does not refer to an active milestone", result.stderr)

  def test_deactivate_rewrites_milestones_json(self):
    milestones = {
        '99': {
            'name': 'm99',
            'project': 'chromium-m99',
            'ref': 'refs/branch-heads/AAAA',
        },
        '101': {
            'name': 'm101',
            'project': 'chromium-m101',
            'ref': 'refs/branch-heads/BBBB',
        },
        '100': {
            'name': 'm100',
            'project': 'chromium-m100',
            'ref': 'refs/branch-heads/CCCC'
        },
    }
    with open(self._milestones_json, 'w') as f:
      json.dump(milestones, f, indent=4)

    result = self._execute_milestones_py(['deactivate', '--milestone', '99'])
    self.assertEqual(
        result.returncode, 0,
        (f'subprocess failed\n***COMMAND***\n{result.args}\n'
         f'***STDERR***\n{result.stderr}'))

    with open(self._milestones_json) as f:
      milestones = f.read()
    self.assertEqual(milestones,  textwrap.dedent("""\
        {
            "100": {
                "name": "m100",
                "project": "chromium-m100",
                "ref": "refs/branch-heads/CCCC"
            },
            "101": {
                "name": "m101",
                "project": "chromium-m101",
                "ref": "refs/branch-heads/BBBB"
            }
        }
        """))

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