| # -*- coding: utf-8 -*- |
| # Copyright (c) 2011 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 cros_portage_upgrade.py.""" |
| |
| from __future__ import print_function |
| |
| import os |
| import sys |
| import tempfile |
| |
| from chromite.lib import cros_test_lib |
| from chromite.lib import table |
| from chromite.scripts import merge_package_status as mps |
| |
| |
| assert sys.version_info >= (3, 6), 'This module requires Python 3.6+' |
| |
| |
| # pylint: disable=protected-access |
| |
| |
| class MergeTest(cros_test_lib.OutputTestCase, cros_test_lib.TempDirTestCase): |
| """Test the functionality of merge_package_status.""" |
| |
| # These taken from cros_portage_upgrade column names. |
| COL_VER_x86 = 'Current x86 Version' |
| COL_VER_arm = 'Current arm Version' |
| |
| COL_CROS_TARGET = 'ChromeOS Root Target' |
| COL_HOST_TARGET = 'Host Root Target' |
| COL_CMP_ARCH = 'Comparing arm vs x86 Versions' |
| |
| COLUMNS = [mps.COL_PACKAGE, |
| mps.COL_SLOT, |
| mps.COL_OVERLAY, |
| COL_VER_x86, |
| COL_VER_arm, |
| mps.COL_TARGET] |
| |
| ROW0 = {mps.COL_PACKAGE: 'lib/foo', |
| mps.COL_SLOT: '0', |
| mps.COL_OVERLAY: 'portage', |
| COL_VER_x86: '1.2.3', |
| COL_VER_arm: '1.2.3', |
| mps.COL_TARGET: 'virtual/target-os-dev virtual/target-sdk'} |
| ROW0_FINAL = dict(ROW0) |
| ROW0_FINAL[mps.COL_PACKAGE] = ROW0[mps.COL_PACKAGE] + ':' + ROW0[mps.COL_SLOT] |
| ROW0_FINAL[COL_CROS_TARGET] = 'virtual/target-os-dev' |
| ROW0_FINAL[COL_HOST_TARGET] = 'virtual/target-sdk' |
| ROW0_FINAL[COL_CMP_ARCH] = 'same' |
| |
| ROW1 = {mps.COL_PACKAGE: 'dev/bar', |
| mps.COL_SLOT: '0', |
| mps.COL_OVERLAY: 'chromiumos-overlay', |
| COL_VER_x86: '1.2.3', |
| COL_VER_arm: '1.2.3-r1', |
| mps.COL_TARGET: 'virtual/target-os'} |
| ROW1_FINAL = dict(ROW1) |
| ROW1_FINAL[COL_CROS_TARGET] = 'virtual/target-os' |
| ROW1_FINAL[COL_HOST_TARGET] = '' |
| ROW1_FINAL[COL_CMP_ARCH] = 'different' |
| |
| ROW2 = {mps.COL_PACKAGE: 'lib/foo', |
| mps.COL_SLOT: '1', |
| mps.COL_OVERLAY: 'portage', |
| COL_VER_x86: '1.2.3', |
| COL_VER_arm: '', |
| mps.COL_TARGET: 'virtual/target-os-dev world'} |
| ROW2_FINAL = dict(ROW2) |
| ROW2_FINAL[mps.COL_PACKAGE] = ROW2[mps.COL_PACKAGE] + ':' + ROW2[mps.COL_SLOT] |
| ROW2_FINAL[COL_CROS_TARGET] = 'virtual/target-os-dev' |
| ROW2_FINAL[COL_HOST_TARGET] = 'world' |
| ROW2_FINAL[COL_CMP_ARCH] = '' |
| |
| def setUp(self): |
| self._table = self._CreateTableWithRows(self.COLUMNS, |
| [self.ROW0, self.ROW1, self.ROW2]) |
| |
| def _CreateTableWithRows(self, cols, rows): |
| mytable = table.Table(list(cols)) |
| if rows: |
| for row in rows: |
| mytable.AppendRow(dict(row)) |
| return mytable |
| |
| def _CreateTmpCsvFile(self, table_obj): |
| _fd, path = tempfile.mkstemp(text=True) |
| tmpfile = open(path, 'w') |
| table_obj.WriteCSV(tmpfile) |
| tmpfile.close() |
| return path |
| |
| def _GetFullRowFor(self, row, cols): |
| return dict((col, row.get(col, '')) for col in cols) |
| |
| def assertRowsEqual(self, row1, row2): |
| # Determine column superset |
| cols = set(row1) | set(row2) |
| self.assertEqual(self._GetFullRowFor(row1, cols), |
| self._GetFullRowFor(row2, cols)) |
| |
| def testGetCrosTargetRank(self): |
| cros_rank = mps._GetCrosTargetRank('virtual/target-os') |
| crosdev_rank = mps._GetCrosTargetRank('virtual/target-os-dev') |
| crostest_rank = mps._GetCrosTargetRank('virtual/target-os-test') |
| other_rank = mps._GetCrosTargetRank('foobar') |
| |
| self.assertTrue(cros_rank) |
| self.assertTrue(crosdev_rank) |
| self.assertTrue(crostest_rank) |
| self.assertFalse(other_rank) |
| self.assertTrue(cros_rank < crosdev_rank) |
| self.assertTrue(crosdev_rank < crostest_rank) |
| |
| def testProcessTargets(self): |
| test_in = [ |
| ['virtual/target-os', 'virtual/target-os-dev'], |
| ['world', 'virtual/target-os', 'virtual/target-os-dev', |
| 'virtual/target-os-test'], |
| ['world', 'virtual/target-sdk', 'virtual/target-os-dev', |
| 'virtual/target-os-test'], |
| ] |
| test_out = [ |
| ['virtual/target-os-dev'], |
| ['virtual/target-os-test', 'world'], |
| ['virtual/target-os-test', 'virtual/target-sdk', 'world'], |
| ] |
| test_rev_out = [ |
| ['virtual/target-os'], |
| ['virtual/target-os', 'world'], |
| ['virtual/target-os-dev', 'virtual/target-sdk', 'world'], |
| ] |
| |
| for targets, good_out, rev_out in zip(test_in, test_out, test_rev_out): |
| output = mps.ProcessTargets(targets) |
| self.assertEqual(output, good_out) |
| output = mps.ProcessTargets(targets, reverse_cros=True) |
| self.assertEqual(output, rev_out) |
| |
| def testLoadTable(self): |
| path = self._CreateTmpCsvFile(self._table) |
| csv_table = mps.LoadTable(path) |
| self.assertEqual(self._table, csv_table) |
| os.unlink(path) |
| |
| def testLoadAndMergeTables(self): |
| # Create a second table to merge with standard table. |
| row0_2 = {mps.COL_PACKAGE: 'lib/foo', |
| mps.COL_SLOT: '1', |
| mps.COL_OVERLAY: 'portage', |
| self.COL_VER_arm: '1.2.4', |
| mps.COL_TARGET: 'virtual/target-os-dev world'} |
| row1_2 = {mps.COL_PACKAGE: 'dev/bar', |
| mps.COL_SLOT: '0', |
| mps.COL_OVERLAY: 'chromiumos-overlay', |
| self.COL_VER_arm: '1.2.3-r1', |
| mps.COL_TARGET: 'virtual/target-os-test'} |
| row2_2 = {mps.COL_PACKAGE: 'dev/newby', |
| mps.COL_SLOT: '2', |
| mps.COL_OVERLAY: 'chromiumos-overlay', |
| self.COL_VER_arm: '3.2.1', |
| mps.COL_TARGET: 'virtual/target-os virtual/target-sdk'} |
| cols = [col for col in self.COLUMNS if col != self.COL_VER_x86] |
| table_2 = self._CreateTableWithRows(cols, |
| [row0_2, row1_2, row2_2]) |
| |
| # Minor patch to main table for this test. |
| self._table.GetRowByIndex(2)[self.COL_VER_arm] = '1.2.4' |
| |
| with self.OutputCapturer(): |
| path1 = self._CreateTmpCsvFile(self._table) |
| path2 = self._CreateTmpCsvFile(table_2) |
| |
| combined_table1 = mps.MergeTables([self._table, table_2]) |
| combined_table2 = mps.LoadAndMergeTables([path1, path2]) |
| |
| final_row0 = {mps.COL_PACKAGE: 'dev/bar', |
| mps.COL_SLOT: '0', |
| mps.COL_OVERLAY: 'chromiumos-overlay', |
| self.COL_VER_x86: '1.2.3', |
| self.COL_VER_arm: '1.2.3-r1', |
| mps.COL_TARGET: 'virtual/target-os'} |
| final_row1 = {mps.COL_PACKAGE: 'dev/newby', |
| mps.COL_SLOT: '2', |
| mps.COL_OVERLAY: 'chromiumos-overlay', |
| self.COL_VER_x86: '', |
| self.COL_VER_arm: '3.2.1', |
| mps.COL_TARGET: 'virtual/target-os virtual/target-sdk'} |
| final_row2 = {mps.COL_PACKAGE: 'lib/foo', |
| mps.COL_SLOT: '0', |
| mps.COL_OVERLAY: 'portage', |
| self.COL_VER_x86: '1.2.3', |
| self.COL_VER_arm: '1.2.3', |
| mps.COL_TARGET: 'virtual/target-os-dev virtual/target-sdk'} |
| final_row3 = {mps.COL_PACKAGE: 'lib/foo', |
| mps.COL_SLOT: '1', |
| mps.COL_OVERLAY: 'portage', |
| self.COL_VER_x86: '1.2.3', |
| self.COL_VER_arm: '1.2.4', |
| mps.COL_TARGET: 'virtual/target-os-dev world'} |
| |
| final_rows = (final_row0, final_row1, final_row2, final_row3) |
| for ix, row_out in enumerate(final_rows): |
| self.assertRowsEqual(row_out, combined_table1[ix]) |
| self.assertRowsEqual(row_out, combined_table2[ix]) |
| |
| os.unlink(path1) |
| os.unlink(path2) |
| |
| def testFinalizeTable(self): |
| self.assertEqual(3, self._table.GetNumRows()) |
| self.assertEqual(len(self.COLUMNS), self._table.GetNumColumns()) |
| |
| with self.OutputCapturer(): |
| mps.FinalizeTable(self._table) |
| |
| self.assertEqual(3, self._table.GetNumRows()) |
| self.assertEqual(len(self.COLUMNS) + 3, self._table.GetNumColumns()) |
| |
| final_rows = (self.ROW0_FINAL, self.ROW1_FINAL, self.ROW2_FINAL) |
| for ix, row_out in enumerate(final_rows): |
| self.assertRowsEqual(row_out, self._table[ix]) |
| |
| |
| class MainTest(cros_test_lib.MockOutputTestCase): |
| """Test argument handling at the main method level.""" |
| |
| def testHelp(self): |
| """Test that --help is functioning""" |
| with self.OutputCapturer() as output: |
| # Running with --help should exit with code==0 |
| try: |
| mps.main(['--help']) |
| except SystemExit as e: |
| self.assertEqual(e.args[0], 0) |
| |
| # Verify that a message beginning with "Usage: " was printed |
| stdout = output.GetStdout() |
| self.assertTrue(stdout.startswith('usage: '), |
| msg='Expected output starting with "usage: " but got:\n%s' % |
| stdout) |
| |
| def testMissingOut(self): |
| """Test that running without --out exits with an error.""" |
| with self.OutputCapturer() as output: |
| # Running without --out should exit with code!=0 |
| try: |
| mps.main(['pkg']) |
| except SystemExit as e: |
| self.assertNotEqual(e.args[0], 0) |
| |
| # Verify that output ends in error. |
| stderr = output.GetStderr() |
| # Python changed argparse output style. |
| # TODO(vapier): Drop this once we require Python 3 everywhere. |
| if sys.version_info.major < 3: |
| self.assertIn('error: argument --out is required', stderr) |
| else: |
| self.assertIn('error: the following arguments are required: --out', |
| stderr) |
| |
| def testMissingPackage(self): |
| """Test that running without a package argument exits with an error.""" |
| with self.OutputCapturer() as output: |
| # Running without a package should exit with code!=0 |
| try: |
| mps.main(['--out=any-out']) |
| except SystemExit as e: |
| self.assertNotEqual(e.args[0], 0) |
| |
| # Verify that output ends in error. |
| stderr = output.GetStderr() |
| # Python changed argparse output style. |
| # TODO(vapier): Drop this once we require Python 3 everywhere. |
| if sys.version_info.major < 3: |
| self.assertIn('error: too few arguments', stderr) |
| else: |
| self.assertIn('error: the following arguments are required', stderr) |
| |
| def testMain(self): |
| """Verify that running main method runs expected functons. |
| |
| Expected: LoadAndMergeTables, WriteTable. |
| """ |
| self.PatchObject(mps, 'LoadAndMergeTables', return_value='csv_table') |
| m = self.PatchObject(mps, 'WriteTable') |
| |
| mps.main(['--out=any-out', 'any-package']) |
| |
| m.assert_called_with('csv_table', os.path.join(os.getcwd(), 'any-out')) |