From f361d96819ad56a8d8beb8462df7a8aadb075cf2 Mon Sep 17 00:00:00 2001 From: Felipe Monteiro Date: Wed, 26 Sep 2018 20:24:02 +0100 Subject: [PATCH] tests: Add more Pegleg CLI site tests Currently Pegleg really needs CLI tests that test the CLI workflow end to end. This continues off the initial legwork for it here: https://review.openstack.org/#/c/605289/ This adds positive tests for all CLI site actions. Negative tests will be added in the future. Change-Id: Icf6737c6204edf518f2b384dd8369de793cb303a --- tests/unit/test_cli.py | 140 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index c5a60476..480cae94 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -41,6 +41,17 @@ def is_connected(): @pytest.mark.skipif( not is_connected(), reason='git clone requires network connectivity.') class BaseCLIActionTest(object): + """Tests end-to-end flows for all Pegleg CLI actions, with minimal mocking. + + General pattern should be to include exactly one test that uses a remote + repo URL and as many other tests that are required that use a local repo + path for runtime optimization. + + """ + + # TODO(felipemonteiro): Need tests that validate repository overrides. Also + # need to write tests that use a site-defintion.yaml with repositories key. + @classmethod def setup_class(cls): cls.runner = CliRunner() @@ -189,6 +200,135 @@ class TestSiteCliActions(BaseCLIActionTest): # output warnings. assert result.output + ### List tests ### + + def test_list_sites_using_remote_repo_url(self): + """Validates list action using remote repo URL.""" + # Scenario: + # + # 1) List sites (should clone repo automatically) + + repo_url = 'https://github.com/openstack/%s@%s' % (self.repo_name, + self.repo_rev) + + # NOTE(felipemonteiro): Pegleg currently doesn't dump a table to stdout + # for this CLI call so mock out the csv DictWriter to determine output. + with mock.patch('pegleg.engine.site.csv.DictWriter') as mock_writer: + result = self.runner.invoke(cli.site, ['-r', repo_url, 'list']) + + assert result.exit_code == 0 + m_writer = mock_writer.return_value + m_writer.writerow.assert_called_once_with({ + 'site_type': 'foundry', + 'site_name': self.site_name + }) + + def test_list_sites_using_local_path(self): + """Validates list action using local repo path.""" + # Scenario: + # + # 1) List sites (should skip clone repo) + + repo_path = self.treasuremap_path + + # NOTE(felipemonteiro): Pegleg currently doesn't dump a table to stdout + # for this CLI call so mock out the csv DictWriter to determine output. + with mock.patch('pegleg.engine.site.csv.DictWriter') as mock_writer: + result = self.runner.invoke(cli.site, ['-r', repo_path, 'list']) + + assert result.exit_code == 0 + m_writer = mock_writer.return_value + m_writer.writerow.assert_called_once_with({ + 'site_type': 'foundry', + 'site_name': self.site_name + }) + + ### Show tests ### + + def test_show_site_using_remote_repo_url(self): + """Validates show action using remote repo URL.""" + # Scenario: + # + # 1) Show site (should clone repo automatically) + + repo_url = 'https://github.com/openstack/%s@%s' % (self.repo_name, + self.repo_rev) + + with mock.patch('pegleg.engine.site.json') as mock_json: + result = self.runner.invoke( + cli.site, ['-r', repo_url, 'show', self.site_name]) + + assert result.exit_code == 0 + assert mock_json.dump.called + mock_calls = mock_json.dump.mock_calls + assert mock_calls[0][1][0] == { + 'files': mock.ANY, + 'site_type': 'foundry', + 'site_name': self.site_name + } + + def test_show_site_using_local_path(self): + """Validates show action using local repo path.""" + # Scenario: + # + # 1) Show site (should skip clone repo) + + repo_path = self.treasuremap_path + with mock.patch('pegleg.engine.site.json') as mock_json: + result = self.runner.invoke( + cli.site, ['-r', repo_path, 'show', self.site_name]) + + assert result.exit_code == 0 + assert mock_json.dump.called + mock_calls = mock_json.dump.mock_calls + assert mock_calls[0][1][0] == { + 'files': mock.ANY, + 'site_type': 'foundry', + 'site_name': self.site_name + } + + ### Render tests ### + + def test_render_site_using_remote_repo_url(self): + """Validates render action using remote repo URL.""" + # Scenario: + # + # 1) Mock out Deckhand render (so we can ignore P005 issues) + # 2) Render site (should clone repo automatically) + + repo_url = 'https://github.com/openstack/%s@%s' % (self.repo_name, + self.repo_rev) + + render_command = ['-r', repo_url, 'render', self.site_name] + + with mock.patch('pegleg.engine.site.yaml') as mock_yaml: + with mock.patch( + 'pegleg.engine.site.util.deckhand') as mock_deckhand: + mock_deckhand.deckhand_render.return_value = ([], []) + result = self.runner.invoke(cli.site, render_command) + + assert result.exit_code == 0 + mock_yaml.dump_all.assert_called_once() + + def test_render_site_using_local_path(self): + """Validates render action using local repo path.""" + # Scenario: + # + # 1) Mock out Deckhand render (so we can ignore P005 issues) + # 2) Render site (should skip clone repo) + + repo_path = self.treasuremap_path + render_command = ['-r', repo_path, 'render', self.site_name] + + with mock.patch('pegleg.engine.site.yaml') as mock_yaml: + with mock.patch( + 'pegleg.engine.site.util.deckhand') as mock_deckhand: + mock_deckhand.deckhand_render.return_value = ([], []) + result = self.runner.invoke(cli.site, render_command) + + assert result.exit_code == 0 + mock_yaml.dump_all.assert_called_once() + class TestRepoCliActions(BaseCLIActionTest): """Tests repo-level CLI actions."""