class TestLoginIntPwdAndConfig(TestLoginBase): CONFIG_FILE = '/tmp/logintest.cfg' TOKEN = { 'user': '******', 'token': '44583f15945b4095afbf57058535ca64', 'expiry': '2017-02-12T00:53:09.632783Z', 'id': '589e607532ed3535707f10eb', 'metadata': {} } @mock.patch.object( requests, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(TOKEN), 200, 'OK'))) @mock.patch.object( requests, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps({}), 200, 'OK'))) @mock.patch('st2client.commands.auth.getpass') def runTest(self, mock_gp): '''Test 'st2 login' functionality with interactive password entry ''' expected_username = self.TOKEN['user'] args = ['--config', self.CONFIG_FILE, 'login', expected_username] mock_gp.getpass.return_value = 'Password1!' self.shell.run(args) expected_kwargs = { 'headers': {'content-type': 'application/json'}, 'auth': ('st2admin', 'Password1!') } requests.post.assert_called_with('http://127.0.0.1:9100/tokens', '{}', **expected_kwargs) with open(self.CONFIG_FILE, 'r') as config_file: for line in config_file.readlines(): # Make sure certain values are not present self.assertFalse('password' in line) self.assertFalse('olduser' in line) # Make sure configured username is what we expect if 'username' in line: self.assertEquals(line.split(' ')[2][:-1], expected_username) # validate token was created self.assertTrue(os.path.isfile('%stoken-%s' % (self.DOTST2_PATH, expected_username))) # Validate token is sent on subsequent requests to st2 API args = ['--config', self.CONFIG_FILE, 'pack', 'list'] self.shell.run(args) expected_kwargs = { 'headers': { 'X-Auth-Token': self.TOKEN['token'] }, 'params': {} } requests.get.assert_called_with('http://127.0.0.1:9101/v1/packs', **expected_kwargs)
class TestActionResourceManager(unittest2.TestCase): @classmethod def setUpClass(cls): super(TestActionResourceManager, cls).setUpClass() cls.client = client.Client() @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock( return_value=base.FakeResponse(json.dumps(ENTRYPOINT), 200, "OK")), ) def test_get_action_entry_point_by_ref(self): actual_entrypoint = self.client.actions.get_entrypoint( EXECUTION["action"]["ref"]) actual_entrypoint = json.loads(actual_entrypoint) endpoint = "/actions/views/entry_point/%s" % EXECUTION["action"]["ref"] httpclient.HTTPClient.get.assert_called_with(endpoint) self.assertEqual(ENTRYPOINT, actual_entrypoint) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock( return_value=base.FakeResponse(json.dumps(ENTRYPOINT), 200, "OK")), ) def test_get_action_entry_point_by_id(self): actual_entrypoint = self.client.actions.get_entrypoint(EXECUTION["id"]) actual_entrypoint = json.loads(actual_entrypoint) endpoint = "/actions/views/entry_point/%s" % EXECUTION["id"] httpclient.HTTPClient.get.assert_called_with(endpoint) self.assertEqual(ENTRYPOINT, actual_entrypoint) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse( json.dumps({}), 404, "404 Client Error: Not Found")), ) def test_get_non_existent_action_entry_point(self): with self.assertRaisesRegexp(Exception, "404 Client Error: Not Found"): self.client.actions.get_entrypoint( "nonexistentpack.nonexistentaction") endpoint = "/actions/views/entry_point/%s" % "nonexistentpack.nonexistentaction" httpclient.HTTPClient.get.assert_called_with(endpoint)
class TestWhoamiUncaughtException(TestLoginBase): CONFIG_FILE = '/tmp/logintest.cfg' USERNAME = '******' CONFIG_CONTENTS = (""" [credentials] username = %s password = Password1! """ % USERNAME) @mock.patch.object( requests, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps({}), 200, 'OK'))) @mock.patch('st2client.commands.auth.BaseCLIApp') def runTest(self, mock_cli): '''Test 'st2 whoami' ability to detect unhandled exceptions ''' # Only mocking "BaseCLIApp" here in order to generate an exception for this specific test mock_cli.return_value._get_config_file_path = mock.MagicMock(side_effect=Exception) retcode = self.shell.run(['--config', self.CONFIG_FILE, 'whoami']) self.assertEqual('Unable to retrieve currently logged-in user', self.stdout.getvalue().strip()) self.assertEqual(retcode, 0)
class TestLoginUncaughtException(TestLoginBase): CONFIG_FILE_NAME = "logintest.cfg" TOKEN = { "user": "******", "token": "44583f15945b4095afbf57058535ca64", "expiry": "2017-02-12T00:53:09.632783Z", "id": "589e607532ed3535707f10eb", "metadata": {}, } @mock.patch.object( requests, "post", mock.MagicMock(return_value=base.FakeResponse(json.dumps(TOKEN), 200, "OK")), ) @mock.patch("st2client.commands.auth.getpass") def runTest(self, mock_gp): """Test 'st2 login' ability to detect unhandled exceptions""" expected_username = self.TOKEN["user"] args = ["--config", self.CONFIG_FILE, "login", expected_username] mock_gp.getpass = mock.MagicMock(side_effect=Exception) self.shell.run(args) retcode = self.shell.run(args) self.assertIn( "Failed to log in as %s" % expected_username, self.stdout.getvalue() ) self.assertNotIn("Logged in as", self.stdout.getvalue()) self.assertEqual(retcode, 1)
class TestLoginUncaughtException(TestLoginBase): CONFIG_FILE = '/tmp/logintest.cfg' TOKEN = { 'user': '******', 'token': '44583f15945b4095afbf57058535ca64', 'expiry': '2017-02-12T00:53:09.632783Z', 'id': '589e607532ed3535707f10eb', 'metadata': {} } @mock.patch.object( requests, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(TOKEN), 200, 'OK'))) @mock.patch('st2client.commands.auth.getpass') def runTest(self, mock_gp): '''Test 'st2 login' ability to detect unhandled exceptions ''' expected_username = self.TOKEN['user'] args = ['--config', self.CONFIG_FILE, 'login', expected_username] mock_gp.getpass = mock.MagicMock(side_effect=Exception) self.shell.run(args) retcode = self.shell.run(args) self.assertTrue('Failed to log in as %s' % expected_username in self.stdout.getvalue()) self.assertTrue('Logged in as' not in self.stdout.getvalue()) self.assertEqual(retcode, 0)
class ActionAliasCommandTestCase(base.BaseCLITestCase): def __init__(self, *args, **kwargs): super(ActionAliasCommandTestCase, self).__init__(*args, **kwargs) self.shell = shell.Shell() @mock.patch.object( httpclient.HTTPClient, "post", mock.MagicMock(return_value=base.FakeResponse( json.dumps(MOCK_MATCH_AND_EXECUTE_RESULT), 200, "OK")), ) def test_match_and_execute(self): ret = self.shell.run( ["action-alias", "execute", "run whoami on localhost"]) self.assertEqual(ret, 0) expected_args = { "command": "run whoami on localhost", "user": "", "source_channel": "cli", } httpclient.HTTPClient.post.assert_called_with( "/aliasexecution/match_and_execute", expected_args) mock_stdout = self.stdout.getvalue() self.assertTrue("Matching Action-alias: 'mock-ref'" in mock_stdout) self.assertTrue("st2 execution get mock-id" in mock_stdout)
class TestKeyValueSet(TestKeyValueBase): @mock.patch.object(requests, 'put', mock.MagicMock(return_value=base.FakeResponse( json.dumps(KEYVALUE_PRE_ENCRYPTED), 200, 'OK'))) def test_set_keyvalue(self): """Test setting key/value pair with optional pre_encrypted field """ args = ['key', 'set', '--encrypted', 'kv_name', 'AAABBBCCC1234'] retcode = self.shell.run(args) self.assertEqual(retcode, 0) def test_encrypt_and_encrypted_flags_are_mutually_exclusive(self): args = [ 'key', 'set', '--encrypt', '--encrypted', 'kv_name', 'AAABBBCCC1234' ] self.assertRaisesRegexp(SystemExit, '2', self.shell.run, args) self.stderr.seek(0) stderr = self.stderr.read() expected_msg = ( 'error: argument --encrypted: not allowed with argument -e/--encrypt' ) self.assertIn(expected_msg, stderr)
class TestActionResourceManager(unittest2.TestCase): @classmethod def setUpClass(cls): super(TestActionResourceManager, cls).setUpClass() cls.client = client.Client() @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock( return_value=base.FakeResponse(json.dumps(ENTRYPOINT), 200, 'OK'))) def test_get_action_entry_point_by_ref(self): actual_entrypoint = self.client.actions.get_entrypoint( EXECUTION['action']['ref']) actual_entrypoint = json.loads(actual_entrypoint) endpoint = '/actions/views/entry_point/%s' % EXECUTION['action']['ref'] httpclient.HTTPClient.get.assert_called_with(endpoint) self.assertEqual(ENTRYPOINT, actual_entrypoint) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock( return_value=base.FakeResponse(json.dumps(ENTRYPOINT), 200, 'OK'))) def test_get_action_entry_point_by_id(self): actual_entrypoint = self.client.actions.get_entrypoint(EXECUTION['id']) actual_entrypoint = json.loads(actual_entrypoint) endpoint = '/actions/views/entry_point/%s' % EXECUTION['id'] httpclient.HTTPClient.get.assert_called_with(endpoint) self.assertEqual(ENTRYPOINT, actual_entrypoint) @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps({}), 404, '404 Client Error: Not Found')) ) def test_get_non_existent_action_entry_point(self): with self.assertRaisesRegexp(Exception, '404 Client Error: Not Found'): self.client.actions.get_entrypoint( 'nonexistentpack.nonexistentaction') endpoint = '/actions/views/entry_point/%s' % 'nonexistentpack.nonexistentaction' httpclient.HTTPClient.get.assert_called_with(endpoint)
def test_policy_list_with_pack_option(self): argv = ["policy", "list", "-p", "test"] mock_obj = mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES), 200, "OK")) with mock.patch.object(httpclient.HTTPClient, "get", mock_obj): self.shell.run(argv) self.assertEqual( mock_obj.mock_calls[0], mock.call("/policies/?include_attributes=ref%2Cresource_ref%2C" "policy_type%2Cenabled&pack=test"), )
class TestLoginWritePwdOkay(TestLoginBase): CONFIG_FILE_NAME = "logintest.cfg" TOKEN = { "user": "******", "token": "44583f15945b4095afbf57058535ca64", "expiry": "2017-02-12T00:53:09.632783Z", "id": "589e607532ed3535707f10eb", "metadata": {}, } @mock.patch.object( requests, "post", mock.MagicMock(return_value=base.FakeResponse(json.dumps(TOKEN), 200, "OK")), ) @mock.patch("st2client.commands.auth.getpass") def runTest(self, mock_gp): """Test 'st2 login' functionality with --write-password flag set""" expected_username = self.TOKEN["user"] args = [ "--config", self.CONFIG_FILE, "login", expected_username, "--password", "Password1!", "--write-password", ] self.shell.run(args) with open(self.CONFIG_FILE, "r") as config_file: for line in config_file.readlines(): # Make sure certain values are not present self.assertNotIn("olduser", line) # Make sure configured username is what we expect if "username" in line: self.assertEqual(line.split(" ")[2][:-1], expected_username) # validate token was created self.assertTrue( os.path.isfile("%stoken-%s" % (self.DOTST2_PATH, expected_username)) )
class TestLoginWritePwdOkay(TestLoginBase): CONFIG_FILE = '/tmp/logintest.cfg' TOKEN = { 'user': '******', 'token': '44583f15945b4095afbf57058535ca64', 'expiry': '2017-02-12T00:53:09.632783Z', 'id': '589e607532ed3535707f10eb', 'metadata': {} } @mock.patch.object( requests, 'post', mock.MagicMock( return_value=base.FakeResponse(json.dumps(TOKEN), 200, 'OK'))) @mock.patch('st2client.commands.auth.getpass') def runTest(self, mock_gp): '''Test 'st2 login' functionality with --write-password flag set ''' expected_username = self.TOKEN['user'] args = [ '--config', self.CONFIG_FILE, 'login', expected_username, '--password', 'Password1!', '--write-password' ] self.shell.run(args) with open(self.CONFIG_FILE, 'r') as config_file: for line in config_file.readlines(): # Make sure certain values are not present self.assertFalse('olduser' in line) # Make sure configured username is what we expect if 'username' in line: self.assertEquals( line.split(' ')[2][:-1], expected_username) # validate token was created self.assertTrue( os.path.isfile('%stoken-%s' % (self.DOTST2_PATH, expected_username)))
class TestWhoamiMissingCreds(TestLoginBase): CONFIG_FILE = '/tmp/logintest.cfg' CONFIG_CONTENTS = (""" [nonsense] foo = bar """) @mock.patch.object( requests, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps({}), 200, 'OK'))) def runTest(self): '''Test 'st2 whoami' functionality with a missing credentials section ''' retcode = self.shell.run(['--config', self.CONFIG_FILE, 'whoami']) self.assertEqual('Unable to retrieve currently logged-in user', self.stdout.getvalue().strip()) self.assertEqual(retcode, 0)
class TestWhoami(TestLoginBase): CONFIG_FILE = '/tmp/logintest.cfg' USERNAME = '******' CONFIG_CONTENTS = """ [credentials] username = %s password = Password1! """ % USERNAME @mock.patch.object( requests, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps({}), 200, 'OK'))) def runTest(self): '''Test 'st2 whoami' functionality ''' retcode = self.shell.run(['--config', self.CONFIG_FILE, 'whoami']) self.assertEqual(retcode, 0) self.assertTrue(self.USERNAME in self.stdout.getvalue())
class TestResourceManager(unittest2.TestCase): @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES), 200, "OK")), ) def test_resource_get_all(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) resources = mgr.get_all() actual = [resource.serialize() for resource in resources] expected = json.loads(json.dumps(base.RESOURCES)) self.assertListEqual(actual, expected) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES), 200, "OK")), ) def test_resource_get_all_with_limit(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) resources = mgr.get_all(limit=50) actual = [resource.serialize() for resource in resources] expected = json.loads(json.dumps(base.RESOURCES)) self.assertListEqual(actual, expected) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock( return_value=base.FakeResponse("", 500, "INTERNAL SERVER ERROR")), ) def test_resource_get_all_failed(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) self.assertRaises(Exception, mgr.get_all) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES[0]), 200, "OK")), ) def test_resource_get_by_id(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) resource = mgr.get_by_id("123") actual = resource.serialize() expected = json.loads(json.dumps(base.RESOURCES[0])) self.assertEqual(actual, expected) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse("", 404, "NOT FOUND")), ) def test_resource_get_by_id_404(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) resource = mgr.get_by_id("123") self.assertIsNone(resource) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock( return_value=base.FakeResponse("", 500, "INTERNAL SERVER ERROR")), ) def test_resource_get_by_id_failed(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) self.assertRaises(Exception, mgr.get_by_id) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse( json.dumps([base.RESOURCES[0]]), 200, "OK", {})), ) def test_resource_query(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) resources = mgr.query(name="abc") actual = [resource.serialize() for resource in resources] expected = json.loads(json.dumps([base.RESOURCES[0]])) self.assertEqual(actual, expected) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock( return_value=base.FakeResponse(json.dumps( [base.RESOURCES[0]]), 200, "OK", {"X-Total-Count": "50"})), ) def test_resource_query_with_count(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) resources, count = mgr.query_with_count(name="abc") actual = [resource.serialize() for resource in resources] expected = json.loads(json.dumps([base.RESOURCES[0]])) self.assertEqual(actual, expected) self.assertEqual(count, 50) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse( json.dumps([base.RESOURCES[0]]), 200, "OK", {})), ) def test_resource_query_with_limit(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) resources = mgr.query(name="abc", limit=50) actual = [resource.serialize() for resource in resources] expected = json.loads(json.dumps([base.RESOURCES[0]])) self.assertEqual(actual, expected) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse( "", 404, "NOT FOUND", {"X-Total-Count": "30"})), ) def test_resource_query_404(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) # No X-Total-Count resources = mgr.query(name="abc") self.assertListEqual(resources, []) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse( "", 404, "NOT FOUND", {"X-Total-Count": "30"})), ) def test_resource_query_with_count_404(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) resources, count = mgr.query_with_count(name="abc") self.assertListEqual(resources, []) self.assertIsNone(count) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock( return_value=base.FakeResponse("", 500, "INTERNAL SERVER ERROR")), ) def test_resource_query_failed(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) self.assertRaises(Exception, mgr.query, name="abc") @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse( json.dumps([base.RESOURCES[0]]), 200, "OK", {})), ) def test_resource_get_by_name(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) # No X-Total-Count resource = mgr.get_by_name("abc") actual = resource.serialize() expected = json.loads(json.dumps(base.RESOURCES[0])) self.assertEqual(actual, expected) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse("", 404, "NOT FOUND")), ) def test_resource_get_by_name_404(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) resource = mgr.get_by_name("abc") self.assertIsNone(resource) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES), 200, "OK")), ) def test_resource_get_by_name_ambiguous(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) self.assertRaises(Exception, mgr.get_by_name, "abc") @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock( return_value=base.FakeResponse("", 500, "INTERNAL SERVER ERROR")), ) def test_resource_get_by_name_failed(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) self.assertRaises(Exception, mgr.get_by_name) @mock.patch.object( httpclient.HTTPClient, "post", mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES[0]), 200, "OK")), ) def test_resource_create(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) instance = base.FakeResource.deserialize('{"name": "abc"}') resource = mgr.create(instance) self.assertIsNotNone(resource) @mock.patch.object( httpclient.HTTPClient, "post", mock.MagicMock( return_value=base.FakeResponse("", 500, "INTERNAL SERVER ERROR")), ) def test_resource_create_failed(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) instance = base.FakeResource.deserialize('{"name": "abc"}') self.assertRaises(Exception, mgr.create, instance) @mock.patch.object( httpclient.HTTPClient, "put", mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES[0]), 200, "OK")), ) def test_resource_update(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) text = '{"id": "123", "name": "cba"}' instance = base.FakeResource.deserialize(text) resource = mgr.update(instance) self.assertIsNotNone(resource) @mock.patch.object( httpclient.HTTPClient, "put", mock.MagicMock( return_value=base.FakeResponse("", 500, "INTERNAL SERVER ERROR")), ) def test_resource_update_failed(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) text = '{"id": "123", "name": "cba"}' instance = base.FakeResource.deserialize(text) self.assertRaises(Exception, mgr.update, instance) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse( json.dumps([base.RESOURCES[0]]), 200, "OK", {})), ) @mock.patch.object( httpclient.HTTPClient, "delete", mock.MagicMock(return_value=base.FakeResponse("", 204, "NO CONTENT")), ) def test_resource_delete(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) instance = mgr.get_by_name("abc") mgr.delete(instance) @mock.patch.object( httpclient.HTTPClient, "delete", mock.MagicMock(return_value=base.FakeResponse("", 404, "NOT FOUND")), ) def test_resource_delete_404(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) instance = base.FakeResource.deserialize(base.RESOURCES[0]) mgr.delete(instance) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse( json.dumps([base.RESOURCES[0]]), 200, "OK", {})), ) @mock.patch.object( httpclient.HTTPClient, "delete", mock.MagicMock( return_value=base.FakeResponse("", 500, "INTERNAL SERVER ERROR")), ) def test_resource_delete_failed(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) instance = mgr.get_by_name("abc") self.assertRaises(Exception, mgr.delete, instance) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse( json.dumps([base.RESOURCES[0]]), 200, "OK", {})), ) @mock.patch.object( httpclient.HTTPClient, "delete", mock.MagicMock(return_value=base.FakeResponse("", 204, "NO CONTENT")), ) def test_resource_delete_action(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) instance = mgr.get_by_name("abc") mgr.delete_action(instance, True) @mock.patch.object( httpclient.HTTPClient, "delete", mock.MagicMock(return_value=base.FakeResponse("", 404, "NOT FOUND")), ) def test_resource_delete_action_404(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) instance = base.FakeResource.deserialize(base.RESOURCES[0]) mgr.delete_action(instance, False) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse( json.dumps([base.RESOURCES[0]]), 200, "OK", {})), ) @mock.patch.object( httpclient.HTTPClient, "delete", mock.MagicMock( return_value=base.FakeResponse("", 500, "INTERNAL SERVER ERROR")), ) def test_resource_delete_action_failed(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) instance = mgr.get_by_name("abc") self.assertRaises(Exception, mgr.delete_action, instance, True) @mock.patch("requests.get") @mock.patch("sseclient.SSEClient") def test_stream_resource_listen(self, mock_sseclient, mock_requests): mock_msg = mock.Mock() mock_msg.data = json.dumps(base.RESOURCES) # checking the case to specify valid 'cacert' parameter to the StreamManager def side_effect_checking_verify_parameter_is(): return [mock_msg] mock_sseclient.return_value.events.side_effect = ( side_effect_checking_verify_parameter_is) mgr = models.StreamManager("https://example.com", cacert="/path/ca.crt") resp = mgr.listen(events=["foo", "bar"]) self.assertEqual(list(resp), [base.RESOURCES]) call_args = tuple(["https://example.com/stream?events=foo%2Cbar"]) call_kwargs = {"stream": True, "verify": "/path/ca.crt"} self.assertEqual(mock_requests.call_args_list[0][0], call_args) self.assertEqual(mock_requests.call_args_list[0][1], call_kwargs) # checking the case not to specify valid 'cacert' parameter to the StreamManager def side_effect_checking_verify_parameter_is_not(): return [mock_msg] mock_sseclient.return_value.events.side_effect = ( side_effect_checking_verify_parameter_is_not) mgr = models.StreamManager("https://example.com") resp = mgr.listen() self.assertEqual(list(resp), [base.RESOURCES]) call_args = tuple(["https://example.com/stream?"]) call_kwargs = {"stream": True} self.assertEqual(mock_requests.call_args_list[1][0], call_args) self.assertEqual(mock_requests.call_args_list[1][1], call_kwargs) @mock.patch.object( httpclient.HTTPClient, "post", mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES[0]), 200, "OK")), ) def test_resource_clone(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) source_ref = "spack.saction" resource = mgr.clone(source_ref, "dpack", "daction", False) self.assertIsNotNone(resource) @mock.patch.object( httpclient.HTTPClient, "post", mock.MagicMock( return_value=base.FakeResponse("", 500, "INTERNAL SERVER ERROR")), ) def test_resource_clone_failed(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) source_ref = "spack.saction" self.assertRaises(Exception, mgr.clone, source_ref, "dpack", "daction")
class ActionCommandTestCase(base.BaseCLITestCase): def __init__(self, *args, **kwargs): super(ActionCommandTestCase, self).__init__(*args, **kwargs) self.shell = shell.Shell() @mock.patch.object(models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object(models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock( return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK')) ) def test_runner_param_bool_conversion(self): self.shell.run(['run', 'mockety.mock1', 'bool=false']) expected = {'action': 'mockety.mock1', 'parameters': {'bool': False}} httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object(models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object(models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock( return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK')) ) def test_runner_param_integer_conversion(self): self.shell.run(['run', 'mockety.mock1', 'int=30']) expected = {'action': 'mockety.mock1', 'parameters': {'int': 30}} httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object(models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object(models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock( return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK')) ) def test_runner_param_float_conversion(self): self.shell.run(['run', 'mockety.mock1', 'float=3.01']) expected = {'action': 'mockety.mock1', 'parameters': {'float': 3.01}} httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object(models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object(models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock( return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK')) ) def test_runner_param_json_conversion(self): self.shell.run(['run', 'mockety.mock1', 'json={"a":1}']) expected = { 'action': 'mockety.mock1', 'parameters': { 'json': { 'a': 1 } } } httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object(models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object(models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock( return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK')) ) def test_param_bool_conversion(self): self.shell.run(['run', 'mockety.mock2', 'bool=false']) expected = {'action': 'mockety.mock2', 'parameters': {'bool': False}} httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object(models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object(models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock( return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK')) ) def test_param_integer_conversion(self): self.shell.run(['run', 'mockety.mock2', 'int=30']) expected = {'action': 'mockety.mock2', 'parameters': {'int': 30}} httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object(models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object(models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock( return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK')) ) def test_param_float_conversion(self): self.shell.run(['run', 'mockety.mock2', 'float=3.01']) expected = {'action': 'mockety.mock2', 'parameters': {'float': 3.01}} httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object(models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object(models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock( return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK')) ) def test_param_json_conversion(self): self.shell.run(['run', 'mockety.mock2', 'json={"a":1}']) expected = { 'action': 'mockety.mock2', 'parameters': { 'json': { 'a': 1 } } } httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object(models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object(models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock( return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK')) ) def test_param_value_with_equal_sign(self): self.shell.run(['run', 'mockety.mock2', 'key=foo=bar&ponies=unicorns']) expected = { 'action': 'mockety.mock2', 'parameters': { 'key': 'foo=bar&ponies=unicorns' } } httpclient.HTTPClient.post.assert_called_with('/executions', expected)
class TestShell(base.BaseCLITestCase): capture_output = True def __init__(self, *args, **kwargs): super(TestShell, self).__init__(*args, **kwargs) self.shell = Shell() def test_endpoints_default(self): base_url = 'http://127.0.0.1' auth_url = 'http://127.0.0.1:9100' api_url = 'http://127.0.0.1:9101/v1' args = ['trigger', 'list'] parsed_args = self.shell.parser.parse_args(args) client = self.shell.get_client(parsed_args) self.assertEqual(client.endpoints['base'], base_url) self.assertEqual(client.endpoints['auth'], auth_url) self.assertEqual(client.endpoints['api'], api_url) def test_endpoints_base_url_from_cli(self): base_url = 'http://www.st2.com' auth_url = 'http://www.st2.com:9100' api_url = 'http://www.st2.com:9101/v1' args = ['--url', base_url, 'trigger', 'list'] parsed_args = self.shell.parser.parse_args(args) client = self.shell.get_client(parsed_args) self.assertEqual(client.endpoints['base'], base_url) self.assertEqual(client.endpoints['auth'], auth_url) self.assertEqual(client.endpoints['api'], api_url) def test_endpoints_base_url_from_env(self): base_url = 'http://www.st2.com' auth_url = 'http://www.st2.com:9100' api_url = 'http://www.st2.com:9101/v1' os.environ['ST2_BASE_URL'] = base_url args = ['trigger', 'list'] parsed_args = self.shell.parser.parse_args(args) client = self.shell.get_client(parsed_args) self.assertEqual(client.endpoints['base'], base_url) self.assertEqual(client.endpoints['auth'], auth_url) self.assertEqual(client.endpoints['api'], api_url) def test_endpoints_override_from_cli(self): base_url = 'http://www.st2.com' auth_url = 'http://www.st2.com:8888' api_url = 'http://www.stackstorm1.com:9101/v1' args = [ '--url', base_url, '--auth-url', auth_url, '--api-url', api_url, 'trigger', 'list' ] parsed_args = self.shell.parser.parse_args(args) client = self.shell.get_client(parsed_args) self.assertEqual(client.endpoints['base'], base_url) self.assertEqual(client.endpoints['auth'], auth_url) self.assertEqual(client.endpoints['api'], api_url) def test_endpoints_override_from_env(self): base_url = 'http://www.st2.com' auth_url = 'http://www.st2.com:8888' api_url = 'http://www.stackstorm1.com:9101/v1' os.environ['ST2_BASE_URL'] = base_url os.environ['ST2_AUTH_URL'] = auth_url os.environ['ST2_API_URL'] = api_url args = ['trigger', 'list'] parsed_args = self.shell.parser.parse_args(args) client = self.shell.get_client(parsed_args) self.assertEqual(client.endpoints['base'], base_url) self.assertEqual(client.endpoints['auth'], auth_url) self.assertEqual(client.endpoints['api'], api_url) @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES), 200, 'OK'))) def test_exit_code_on_success(self): argv = ['trigger', 'list'] self.assertEqual(self.shell.run(argv), 0) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock( return_value=base.FakeResponse(None, 500, 'INTERNAL SERVER ERROR')) ) def test_exit_code_on_error(self): argv = ['trigger', 'list'] self.assertEqual(self.shell.run(argv), 1) def _validate_parser(self, args_list, is_subcommand=True): for args in args_list: ns = self.shell.parser.parse_args(args) func = ( self.shell.commands[args[0]].run_and_print if not is_subcommand else self.shell.commands[args[0]].commands[args[1]].run_and_print) self.assertEqual(ns.func, func) def test_action(self): args_list = [ ['action', 'list'], ['action', 'get', 'abc'], ['action', 'create', '/tmp/action.json'], ['action', 'update', '123', '/tmp/action.json'], ['action', 'delete', 'abc'], ['action', 'execute', '-h'], ['action', 'execute', 'remote', '-h'], [ 'action', 'execute', 'remote', 'hosts=192.168.1.1', 'user=st2', 'cmd="ls -l"' ], ['action', 'execute', 'remote-fib', 'hosts=192.168.1.1', '3', '8'] ] self._validate_parser(args_list) def test_action_execution(self): args_list = [['execution', 'list'], ['execution', 'get', '123'], ['execution', 'get', '123', '-d'], ['execution', 'get', '123', '-k', 'localhost.stdout'], ['execution', 're-run', '123'], ['execution', 're-run', '123', '--tasks', 'x', 'y', 'z'], [ 'execution', 're-run', '123', '--tasks', 'x', 'y', 'z', '--no-reset', 'x' ], ['execution', 're-run', '123', 'a=1', 'b=x', 'c=True']] self._validate_parser(args_list) # Test mutually exclusive argument groups self.assertRaises( SystemExit, self._validate_parser, [['execution', 'get', '123', '-d', '-k', 'localhost.stdout']]) def test_key(self): args_list = [['key', 'list'], ['key', 'get', 'abc'], ['key', 'set', 'abc', '123'], ['key', 'delete', 'abc'], ['key', 'load', '/tmp/keys.json']] self._validate_parser(args_list) def test_policy(self): args_list = [ ['policy', 'list'], ['policy', 'list', '-p', 'core'], ['policy', 'list', '--pack', 'core'], ['policy', 'list', '-r', 'core.local'], ['policy', 'list', '--resource-ref', 'core.local'], ['policy', 'list', '-pt', 'action.type1'], ['policy', 'list', '--policy-type', 'action.type1'], ['policy', 'list', '-r', 'core.local', '-pt', 'action.type1'], [ 'policy', 'list', '--resource-ref', 'core.local', '--policy-type', 'action.type1' ], ['policy', 'get', 'abc'], ['policy', 'create', '/tmp/policy.json'], ['policy', 'update', '123', '/tmp/policy.json'], ['policy', 'delete', 'abc'] ] self._validate_parser(args_list) def test_policy_type(self): args_list = [['policy-type', 'list'], ['policy-type', 'list', '-r', 'action'], ['policy-type', 'list', '--resource-type', 'action'], ['policy-type', 'get', 'abc']] self._validate_parser(args_list) @mock.patch('st2client.shell.ST2_CONFIG_PATH', '/home/does/not/exist') def test_print_config_default_config_no_config(self): os.environ['ST2_CONFIG_FILE'] = '/home/does/not/exist' argv = ['--print-config'] self.assertEqual(self.shell.run(argv), 3) self.stdout.seek(0) stdout = self.stdout.read() self.assertTrue('username = None' in stdout) self.assertTrue('cache_token = True' in stdout) def test_print_config_custom_config_as_env_variable(self): os.environ['ST2_CONFIG_FILE'] = CONFIG_FILE_PATH_FULL argv = ['--print-config'] self.assertEqual(self.shell.run(argv), 3) self.stdout.seek(0) stdout = self.stdout.read() self.assertTrue('username = test1' in stdout) self.assertTrue('cache_token = False' in stdout) def test_print_config_custom_config_as_command_line_argument(self): argv = ['--print-config', '--config-file=%s' % (CONFIG_FILE_PATH_FULL)] self.assertEqual(self.shell.run(argv), 3) self.stdout.seek(0) stdout = self.stdout.read() self.assertTrue('username = test1' in stdout) self.assertTrue('cache_token = False' in stdout) def test_run(self): args_list = [['run', '-h'], ['run', 'abc', '-h'], [ 'run', 'remote', 'hosts=192.168.1.1', 'user=st2', 'cmd="ls -l"' ], ['run', 'remote-fib', 'hosts=192.168.1.1', '3', '8']] self._validate_parser(args_list, is_subcommand=False) def test_runner(self): args_list = [['runner', 'list'], ['runner', 'get', 'abc']] self._validate_parser(args_list) def test_rule(self): args_list = [['rule', 'list'], ['rule', 'get', 'abc'], ['rule', 'create', '/tmp/rule.json'], ['rule', 'update', '123', '/tmp/rule.json'], ['rule', 'delete', 'abc']] self._validate_parser(args_list) def test_trigger(self): args_list = [['trigger', 'list'], ['trigger', 'get', 'abc'], ['trigger', 'create', '/tmp/trigger.json'], ['trigger', 'update', '123', '/tmp/trigger.json'], ['trigger', 'delete', 'abc']] self._validate_parser(args_list)
class TestInquirySubcommands(TestInquiryBase): @mock.patch.object( requests, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps(INQUIRY_1), 200, 'OK'))) def test_get_inquiry(self): """Test retrieval of a single inquiry """ inquiry_id = 'abcdef' args = ['inquiry', 'get', inquiry_id] retcode = self.shell.run(args) self.assertEqual(retcode, 0) @mock.patch.object( requests, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps({}), 404, 'NOT FOUND'))) def test_get_inquiry_not_found(self): """Test retrieval of a inquiry that doesn't exist """ inquiry_id = 'asdbv' args = ['inquiry', 'get', inquiry_id] retcode = self.shell.run(args) self.assertEqual('Inquiry "%s" is not found.\n\n' % inquiry_id, self.stdout.getvalue()) self.assertEqual(retcode, 2) @mock.patch.object( requests, 'get', mock.MagicMock(return_value=(base.FakeResponse( json.dumps([INQUIRY_1]), 200, 'OK', {'X-Total-Count': '1'} )))) def test_list_inquiries(self): """Test retrieval of a list of Inquiries """ args = ['inquiry', 'list'] retcode = self.shell.run(args) self.assertEqual(retcode, 0) self.assertEqual(self.stdout.getvalue().count('1440'), 1) @mock.patch.object( requests, 'get', mock.MagicMock(return_value=(base.FakeResponse( json.dumps(_generate_inquiries(50)), 200, 'OK', {'X-Total-Count': '55'} )))) def test_list_inquiries_limit(self): """Test retrieval of a list of Inquiries while using the "limit" option """ args = ['inquiry', 'list', '-n', '50'] retcode = self.shell.run(args) self.assertEqual(retcode, 0) self.assertEqual(self.stdout.getvalue().count('1440'), 50) self.assertIn('Note: Only first 50 inquiries are displayed.', self.stderr.getvalue()) @mock.patch.object( requests, 'get', mock.MagicMock(return_value=(base.FakeResponse( json.dumps([]), 200, 'OK', {'X-Total-Count': '0'} )))) def test_list_empty_inquiries(self): """Test empty list of Inquiries """ args = ['inquiry', 'list'] retcode = self.shell.run(args) self.assertEqual(retcode, 0) @mock.patch.object( requests, 'get', mock.MagicMock(return_value=(base.FakeResponse( json.dumps(INQUIRY_1), 200, 'OK' )))) @mock.patch.object( requests, 'put', mock.MagicMock(return_value=(base.FakeResponse( json.dumps({"id": "abcdef", "response": RESPONSE_DEFAULT}), 200, 'OK' )))) @mock.patch('st2client.commands.inquiry.InteractiveForm') def test_respond(self, mock_form): """Test interactive response """ form_instance = mock_form.return_value form_instance.initiate_dialog.return_value = RESPONSE_DEFAULT args = ['inquiry', 'respond', 'abcdef'] retcode = self.shell.run(args) self.assertEqual(retcode, 0) @mock.patch.object( requests, 'get', mock.MagicMock(return_value=(base.FakeResponse( json.dumps(INQUIRY_1), 200, 'OK' )))) @mock.patch.object( requests, 'put', mock.MagicMock(return_value=(base.FakeResponse( json.dumps({"id": "abcdef", "response": RESPONSE_DEFAULT}), 200, 'OK' )))) def test_respond_response_flag(self): """Test response without interactive mode """ args = ['inquiry', 'respond', '-r', '"%s"' % RESPONSE_DEFAULT, 'abcdef'] retcode = self.shell.run(args) self.assertEqual(retcode, 0) @mock.patch.object( requests, 'get', mock.MagicMock(return_value=(base.FakeResponse( json.dumps(INQUIRY_1), 200, 'OK' )))) @mock.patch.object( requests, 'put', mock.MagicMock(return_value=(base.FakeResponse( json.dumps({}), 400, '400 Client Error: Bad Request' )))) def test_respond_invalid(self): """Test invalid response """ args = ['inquiry', 'respond', '-r', '"%s"' % RESPONSE_BAD, 'abcdef'] retcode = self.shell.run(args) self.assertEqual(retcode, 1) self.assertEqual('ERROR: 400 Client Error: Bad Request', self.stdout.getvalue().strip()) def test_respond_nonexistent_inquiry(self): """Test responding to an inquiry that doesn't exist """ inquiry_id = '134234' args = ['inquiry', 'respond', '-r', '"%s"' % RESPONSE_DEFAULT, inquiry_id] retcode = self.shell.run(args) self.assertEqual(retcode, 1) self.assertEqual('ERROR: Resource with id "%s" doesn\'t exist.' % inquiry_id, self.stdout.getvalue().strip()) @mock.patch.object( requests, 'get', mock.MagicMock(return_value=(base.FakeResponse( json.dumps({}), 404, '404 Client Error: Not Found' )))) @mock.patch('st2client.commands.inquiry.InteractiveForm') def test_respond_nonexistent_inquiry_interactive(self, mock_form): """Test interactively responding to an inquiry that doesn't exist Interactive mode (omitting -r flag) retrieves the inquiry with GET before responding with PUT, in order to retrieve the desired schema for this inquiry. So, we want to test that interaction separately. """ inquiry_id = '253432' form_instance = mock_form.return_value form_instance.initiate_dialog.return_value = RESPONSE_DEFAULT args = ['inquiry', 'respond', inquiry_id] retcode = self.shell.run(args) self.assertEqual(retcode, 1) self.assertEqual('ERROR: Resource with id "%s" doesn\'t exist.' % inquiry_id, self.stdout.getvalue().strip())
class TestExecutionResultFormatter(unittest2.TestCase): def __init__(self, *args, **kwargs): super(TestExecutionResultFormatter, self).__init__(*args, **kwargs) self.shell = shell.Shell() self.table = table.SingleRowTable() color.DISABLED = True def setUp(self): self.fd, self.path = tempfile.mkstemp() self._redirect_console(self.path) def tearDown(self): self._undo_console_redirect() os.close(self.fd) os.unlink(self.path) def _redirect_console(self, path): sys.stdout = open(path, 'w') sys.stderr = open(path, 'w') def _undo_console_redirect(self): sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ def test_console_redirect(self): message = 'Hello, World!' print(message) self._undo_console_redirect() with open(self.path, 'r') as fd: content = fd.read().replace('\n', '') self.assertEqual(content, message) def test_execution_get_default(self): argv = ['execution', 'get', EXECUTION['id']] content = self._get_execution(argv) self.assertEqual(content, FIXTURES['results']['execution_get_default.txt']) def test_execution_get_attributes(self): argv = [ 'execution', 'get', EXECUTION['id'], '--attr', 'status', 'end_timestamp' ] content = self._get_execution(argv) self.assertEqual(content, FIXTURES['results']['execution_get_attributes.txt']) def test_execution_get_default_in_json(self): argv = ['execution', 'get', EXECUTION['id'], '-j'] content = self._get_execution(argv) self.assertEqual( json.loads(content), jsutil.get_kvps(EXECUTION, ['id', 'status', 'parameters', 'result'])) def test_execution_get_detail(self): argv = ['execution', 'get', EXECUTION['id'], '-d'] content = self._get_execution(argv) self.assertEqual(content, FIXTURES['results']['execution_get_detail.txt']) def test_execution_get_detail_in_json(self): argv = ['execution', 'get', EXECUTION['id'], '-d', '-j'] content = self._get_execution(argv) content_dict = json.loads(content) # Sufficient to check if output contains all expected keys. The entire result will not # match as content will contain characters which improve rendering. for k in six.iterkeys(EXECUTION): if k in content: continue self.assertTrue( False, 'Missing key %s. %s != %s' % (k, EXECUTION, content_dict)) def test_execution_get_result_by_key(self): argv = ['execution', 'get', EXECUTION['id'], '-k', 'localhost.stdout'] content = self._get_execution(argv) self.assertEqual( content, FIXTURES['results']['execution_get_result_by_key.txt']) def test_execution_get_result_by_key_in_json(self): argv = [ 'execution', 'get', EXECUTION['id'], '-k', 'localhost.stdout', '-j' ] content = self._get_execution(argv) self.assertDictEqual( json.loads(content), jsutil.get_kvps(EXECUTION, ['result.localhost.stdout'])) @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps(HAS_CARRIAGE_RETURN), 200, 'OK', {}))) def test_execution_get_detail_with_carriage_return(self): argv = ['execution', 'get', HAS_CARRIAGE_RETURN['id'], '-d'] self.assertEqual(self.shell.run(argv), 0) self._undo_console_redirect() with open(self.path, 'r') as fd: content = fd.read() self.assertEqual( content, FIXTURES['results']['execution_result_has_carriage_return.txt']) @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps([EXECUTION]), 200, 'OK', {}))) def test_execution_list_attribute_provided(self): # Client shouldn't throw if "-a" flag is provided when listing executions argv = ['execution', 'list', '-a', 'start_timestamp'] self.assertEqual(self.shell.run(argv), 0) self._undo_console_redirect() with open(self.path, 'r') as fd: content = fd.read() self.assertEqual( content, FIXTURES['results']['execution_list_attr_start_timestamp.txt']) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock( return_value=base.FakeResponse(json.dumps([]), 200, 'OK', {}))) def test_execution_list_attribute_provided_empty_response(self): # Client shouldn't throw if "-a" flag is provided, but there are no executions argv = ['execution', 'list', '-a', 'start_timestamp'] self.assertEqual(self.shell.run(argv), 0) self._undo_console_redirect() with open(self.path, 'r') as fd: content = fd.read() self.assertEqual( content, FIXTURES['results'] ['execution_list_empty_response_start_timestamp_attr.txt']) @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps(EXECUTION), 200, 'OK', {}))) def _get_execution(self, argv): self.assertEqual(self.shell.run(argv), 0) self._undo_console_redirect() with open(self.path, 'r') as fd: content = fd.read() return content def test_SinlgeRowTable_notebox_one(self): with mock.patch('sys.stderr', new=BytesIO()) as fackety_fake: expected = "Note: Only one action execution is displayed. Use -n/--last flag for " \ "more results." print self.table.note_box("action executions", 1) content = (fackety_fake.getvalue().split("|")[1].strip()) self.assertEquals(content, expected) def test_SinlgeRowTable_notebox_zero(self): with mock.patch('sys.stderr', new=BytesIO()) as fackety_fake: print self.table.note_box("action executions", 0) contents = (fackety_fake.getvalue()) print "sdf", contents self.assertEquals(contents, "") def test_SinlgeRowTable_notebox_default(self): with mock.patch('sys.stderr', new=BytesIO()) as fackety_fake: expected = "Note: Only first 50 action executions are displayed. Use -n/--last flag " \ "for more results." print(self.table.note_box("action executions", 50)) content = (fackety_fake.getvalue().split("|")[1].strip()) self.assertEquals(content, expected) with mock.patch('sys.stderr', new=BytesIO()) as fackety_fake: expected = "Note: Only first 15 action executions are displayed. Use -n/--last flag " \ "for more results." print(self.table.note_box("action executions", 15)) content = (fackety_fake.getvalue().split("|")[1].strip()) self.assertEquals(content, expected)
class TestHttps(base.BaseCLITestCase): def __init__(self, *args, **kwargs): super(TestHttps, self).__init__(*args, **kwargs) self.shell = shell.Shell() def setUp(self): super(TestHttps, self).setUp() # Setup environment. os.environ['ST2_BASE_URL'] = 'http://127.0.0.1' os.environ['ST2_AUTH_URL'] = 'https://127.0.0.1:9100' if 'ST2_CACERT' in os.environ: del os.environ['ST2_CACERT'] # Create a temp file to mock a cert file. self.cacert_fd, self.cacert_path = tempfile.mkstemp() def tearDown(self): super(TestHttps, self).tearDown() # Clean up environment. if 'ST2_CACERT' in os.environ: del os.environ['ST2_CACERT'] if 'ST2_BASE_URL' in os.environ: del os.environ['ST2_BASE_URL'] # Clean up temp files. os.close(self.cacert_fd) os.unlink(self.cacert_path) @mock.patch.object( requests, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps({}), 200, 'OK'))) def test_decorate_https_without_cacert(self): self.shell.run(['auth', USERNAME, '-p', PASSWORD]) kwargs = {'verify': False, 'headers': HEADERS, 'auth': (USERNAME, PASSWORD)} requests.post.assert_called_with(AUTH_URL, json.dumps({}), **kwargs) @mock.patch.object( requests, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps({}), 200, 'OK'))) def test_decorate_https_with_cacert_from_cli(self): self.shell.run(['--cacert', self.cacert_path, 'auth', USERNAME, '-p', PASSWORD]) kwargs = {'verify': self.cacert_path, 'headers': HEADERS, 'auth': (USERNAME, PASSWORD)} requests.post.assert_called_with(AUTH_URL, json.dumps({}), **kwargs) @mock.patch.object( requests, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps({}), 200, 'OK'))) def test_decorate_https_with_cacert_from_env(self): os.environ['ST2_CACERT'] = self.cacert_path self.shell.run(['auth', USERNAME, '-p', PASSWORD]) kwargs = {'verify': self.cacert_path, 'headers': HEADERS, 'auth': (USERNAME, PASSWORD)} requests.post.assert_called_with(AUTH_URL, json.dumps({}), **kwargs) @mock.patch.object( requests, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps([]), 200, 'OK'))) def test_decorate_http_without_cacert(self): self.shell.run(['rule', 'list']) requests.get.assert_called_with(GET_RULES_URL) @mock.patch.object( requests, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps({}), 200, 'OK'))) def test_decorate_http_with_cacert_from_cli(self): self.shell.run(['--cacert', self.cacert_path, 'rule', 'list']) requests.get.assert_called_with(GET_RULES_URL) @mock.patch.object( requests, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps({}), 200, 'OK'))) def test_decorate_http_with_cacert_from_env(self): os.environ['ST2_CACERT'] = self.cacert_path self.shell.run(['rule', 'list']) requests.get.assert_called_with(GET_RULES_URL)
class TestShell(base.BaseCLITestCase): hide_output = True def __init__(self, *args, **kwargs): super(TestShell, self).__init__(*args, **kwargs) self.shell = shell.Shell() def setUp(self): super(TestShell, self).setUp() # Setup environment. for var in ['ST2_BASE_URL', 'ST2_AUTH_URL', 'ST2_API_URL']: if var in os.environ: del os.environ[var] def test_endpoints_default(self): base_url = 'http://localhost' auth_url = 'https://*****:*****@mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES), 200, 'OK'))) def test_exit_code_on_success(self): argv = ['trigger', 'list'] self.assertEqual(self.shell.run(argv), 0) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock( return_value=base.FakeResponse(None, 500, 'INTERNAL SERVER ERROR')) ) def test_exit_code_on_error(self): argv = ['trigger', 'list'] self.assertEqual(self.shell.run(argv), 1) def _validate_parser(self, args_list, is_subcommand=True): for args in args_list: ns = self.shell.parser.parse_args(args) func = ( self.shell.commands[args[0]].run_and_print if not is_subcommand else self.shell.commands[args[0]].commands[args[1]].run_and_print) self.assertEqual(ns.func, func) def test_trigger(self): args_list = [['trigger', 'list'], ['trigger', 'get', 'abc'], ['trigger', 'create', '/tmp/trigger.json'], ['trigger', 'update', '123', '/tmp/trigger.json'], ['trigger', 'delete', 'abc']] self._validate_parser(args_list) def test_rule(self): args_list = [['rule', 'list'], ['rule', 'get', 'abc'], ['rule', 'create', '/tmp/rule.json'], ['rule', 'update', '123', '/tmp/rule.json'], ['rule', 'delete', 'abc']] self._validate_parser(args_list) def test_runner(self): args_list = [['runner', 'list'], ['runner', 'get', 'abc']] self._validate_parser(args_list) def test_action(self): args_list = [ ['action', 'list'], ['action', 'get', 'abc'], ['action', 'create', '/tmp/action.json'], ['action', 'update', '123', '/tmp/action.json'], ['action', 'delete', 'abc'], ['action', 'execute', '-h'], ['action', 'execute', 'remote', '-h'], [ 'action', 'execute', 'remote', 'hosts=192.168.1.1', 'user=st2', 'cmd="ls -l"' ], ['action', 'execute', 'remote-fib', 'hosts=192.168.1.1', '3', '8'] ] self._validate_parser(args_list) def test_run(self): args_list = [['run', '-h'], ['run', 'abc', '-h'], [ 'run', 'remote', 'hosts=192.168.1.1', 'user=st2', 'cmd="ls -l"' ], ['run', 'remote-fib', 'hosts=192.168.1.1', '3', '8']] self._validate_parser(args_list, is_subcommand=False) def test_action_execution(self): args_list = [['execution', 'list'], ['execution', 'get', '123'], ['execution', 'get', '123', '-d'], ['execution', 'get', '123', '-k', 'localhost.stdout']] self._validate_parser(args_list) # Test mutually exclusive argument groups self.assertRaises( SystemExit, self._validate_parser, [['execution', 'get', '123', '-d', '-k', 'localhost.stdout']]) def test_key(self): args_list = [['key', 'list'], ['key', 'get', 'abc'], ['key', 'set', 'abc', '123'], ['key', 'delete', 'abc'], ['key', 'load', '/tmp/keys.json']] self._validate_parser(args_list)
class ActionCommandTestCase(base.BaseCLITestCase): def __init__(self, *args, **kwargs): super(ActionCommandTestCase, self).__init__(*args, **kwargs) self.shell = shell.Shell() @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_runner_param_bool_conversion(self): self.shell.run(['run', 'mockety.mock1', 'bool=false']) expected = {'action': 'mockety.mock1', 'user': None, 'parameters': {'bool': False}} httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_runner_param_integer_conversion(self): self.shell.run(['run', 'mockety.mock1', 'int=30']) expected = {'action': 'mockety.mock1', 'user': None, 'parameters': {'int': 30}} httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_runner_param_float_conversion(self): self.shell.run(['run', 'mockety.mock1', 'float=3.01']) expected = {'action': 'mockety.mock1', 'user': None, 'parameters': {'float': 3.01}} httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_runner_param_json_conversion(self): self.shell.run(['run', 'mockety.mock1', 'json={"a":1}']) expected = {'action': 'mockety.mock1', 'user': None, 'parameters': {'json': {'a': 1}}} httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_runner_param_array_conversion(self): self.shell.run(['run', 'mockety.mock1', 'list=one,two,three']) expected = { 'action': 'mockety.mock1', 'user': None, 'parameters': { 'list': [ 'one', 'two', 'three' ] } } httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_runner_param_array_object_conversion(self): self.shell.run( [ 'run', 'mockety.mock1', 'list=[{"foo":1, "ponies":"rainbows"},{"pluto":false, "earth":true}]' ] ) expected = { 'action': 'mockety.mock1', 'user': None, 'parameters': { 'list': [ { 'foo': 1, 'ponies': 'rainbows' }, { 'pluto': False, 'earth': True } ] } } httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_param_bool_conversion(self): self.shell.run(['run', 'mockety.mock2', 'bool=false']) expected = {'action': 'mockety.mock2', 'user': None, 'parameters': {'bool': False}} httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_param_integer_conversion(self): self.shell.run(['run', 'mockety.mock2', 'int=30']) expected = {'action': 'mockety.mock2', 'user': None, 'parameters': {'int': 30}} httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_param_float_conversion(self): self.shell.run(['run', 'mockety.mock2', 'float=3.01']) expected = {'action': 'mockety.mock2', 'user': None, 'parameters': {'float': 3.01}} httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_param_json_conversion(self): self.shell.run(['run', 'mockety.mock2', 'json={"a":1}']) expected = {'action': 'mockety.mock2', 'user': None, 'parameters': {'json': {'a': 1}}} httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_param_array_conversion(self): self.shell.run(['run', 'mockety.mock2', 'list=one,two,three']) expected = { 'action': 'mockety.mock2', 'user': None, 'parameters': { 'list': [ 'one', 'two', 'three' ] } } httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_param_array_conversion_single_element_str(self): self.shell.run(['run', 'mockety.mock2', 'list=one']) expected = { 'action': 'mockety.mock2', 'user': None, 'parameters': { 'list': [ 'one' ] } } httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_param_array_conversion_single_element_int(self): self.shell.run(['run', 'mockety.mock2', 'list=1']) expected = { 'action': 'mockety.mock2', 'user': None, 'parameters': { 'list': [ 1 ] } } httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_param_array_object_conversion(self): self.shell.run( [ 'run', 'mockety.mock2', 'list=[{"foo":1, "ponies":"rainbows"},{"pluto":false, "earth":true}]' ] ) expected = { 'action': 'mockety.mock2', 'user': None, 'parameters': { 'list': [ { 'foo': 1, 'ponies': 'rainbows' }, { 'pluto': False, 'earth': True } ] } } httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_param_dict_conversion_flag(self): """Ensure that the automatic conversion to dict based on colons only occurs with the flag """ self.shell.run( [ 'run', 'mockety.mock2', 'list=key1:value1,key2:value2', '--auto-dict' ] ) expected = { 'action': 'mockety.mock2', 'user': None, 'parameters': { 'list': [ { 'key1': 'value1', 'key2': 'value2' } ] } } httpclient.HTTPClient.post.assert_called_with('/executions', expected) self.shell.run( [ 'run', 'mockety.mock2', 'list=key1:value1,key2:value2' ] ) expected = { 'action': 'mockety.mock2', 'user': None, 'parameters': { 'list': [ 'key1:value1', 'key2:value2' ] } } httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_param_value_with_equal_sign(self): self.shell.run(['run', 'mockety.mock2', 'key=foo=bar&ponies=unicorns']) expected = {'action': 'mockety.mock2', 'user': None, 'parameters': {'key': 'foo=bar&ponies=unicorns'}} httpclient.HTTPClient.post.assert_called_with('/executions', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'delete', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_cancel_single_execution(self): self.shell.run(['execution', 'cancel', '123']) httpclient.HTTPClient.delete.assert_called_with('/executions/123') @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'delete', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_cancel_multiple_executions(self): self.shell.run(['execution', 'cancel', '123', '456', '789']) calls = [mock.call('/executions/123'), mock.call('/executions/456'), mock.call('/executions/789')] httpclient.HTTPClient.delete.assert_has_calls(calls) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'put', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_pause_single_execution(self): self.shell.run(['execution', 'pause', '123']) expected = {'status': 'pausing'} httpclient.HTTPClient.put.assert_called_with('/executions/123', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'put', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_pause_multiple_executions(self): self.shell.run(['execution', 'pause', '123', '456', '789']) expected = {'status': 'pausing'} calls = [mock.call('/executions/123', expected), mock.call('/executions/456', expected), mock.call('/executions/789', expected)] httpclient.HTTPClient.put.assert_has_calls(calls) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'put', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_resume_single_execution(self): self.shell.run(['execution', 'resume', '123']) expected = {'status': 'resuming'} httpclient.HTTPClient.put.assert_called_with('/executions/123', expected) @mock.patch.object( models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(side_effect=get_by_ref)) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(side_effect=get_by_name)) @mock.patch.object( httpclient.HTTPClient, 'put', mock.MagicMock(return_value=base.FakeResponse(json.dumps(LIVE_ACTION), 200, 'OK'))) def test_resume_multiple_executions(self): self.shell.run(['execution', 'resume', '123', '456', '789']) expected = {'status': 'resuming'} calls = [mock.call('/executions/123', expected), mock.call('/executions/456', expected), mock.call('/executions/789', expected)] httpclient.HTTPClient.put.assert_has_calls(calls)
class TestExecutionResourceManager(unittest2.TestCase): @classmethod def setUpClass(cls): super(TestExecutionResourceManager, cls).setUpClass() cls.client = client.Client() @mock.patch.object( models.ResourceManager, 'get_by_id', mock.MagicMock(return_value=models.Execution(**EXECUTION))) @mock.patch.object(models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(return_value=models.Action(**ACTION))) @mock.patch.object(models.ResourceManager, 'get_by_name', mock.MagicMock(return_value=models.RunnerType(**RUNNER)) ) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock( return_value=base.FakeResponse(json.dumps(EXECUTION), 200, 'OK'))) def test_rerun_with_no_params(self): self.client.executions.re_run(EXECUTION['id'], tasks=['foobar']) endpoint = '/executions/%s/re_run' % EXECUTION['id'] data = { 'tasks': ['foobar'], 'reset': ['foobar'], 'parameters': {}, 'delay': 0 } httpclient.HTTPClient.post.assert_called_with(endpoint, data) @mock.patch.object( models.ResourceManager, 'get_by_id', mock.MagicMock(return_value=models.Execution(**EXECUTION))) @mock.patch.object(models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(return_value=models.Action(**ACTION))) @mock.patch.object(models.ResourceManager, 'get_by_name', mock.MagicMock(return_value=models.RunnerType(**RUNNER)) ) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock( return_value=base.FakeResponse(json.dumps(EXECUTION), 200, 'OK'))) def test_rerun_with_params(self): params = {'var1': 'testing...'} self.client.executions.re_run(EXECUTION['id'], tasks=['foobar'], parameters=params) endpoint = '/executions/%s/re_run' % EXECUTION['id'] data = { 'tasks': ['foobar'], 'reset': ['foobar'], 'parameters': params, 'delay': 0 } httpclient.HTTPClient.post.assert_called_with(endpoint, data) @mock.patch.object( models.ResourceManager, 'get_by_id', mock.MagicMock(return_value=models.Execution(**EXECUTION))) @mock.patch.object(models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(return_value=models.Action(**ACTION))) @mock.patch.object(models.ResourceManager, 'get_by_name', mock.MagicMock(return_value=models.RunnerType(**RUNNER)) ) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock( return_value=base.FakeResponse(json.dumps(EXECUTION), 200, 'OK'))) def test_rerun_with_delay(self): self.client.executions.re_run(EXECUTION['id'], tasks=['foobar'], delay=100) endpoint = '/executions/%s/re_run' % EXECUTION['id'] data = { 'tasks': ['foobar'], 'reset': ['foobar'], 'parameters': {}, 'delay': 100 } httpclient.HTTPClient.post.assert_called_with(endpoint, data) @mock.patch.object( models.ResourceManager, 'get_by_id', mock.MagicMock(return_value=models.Execution(**EXECUTION))) @mock.patch.object(models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(return_value=models.Action(**ACTION))) @mock.patch.object(models.ResourceManager, 'get_by_name', mock.MagicMock(return_value=models.RunnerType(**RUNNER)) ) @mock.patch.object( httpclient.HTTPClient, 'put', mock.MagicMock( return_value=base.FakeResponse(json.dumps(EXECUTION), 200, 'OK'))) def test_pause(self): self.client.executions.pause(EXECUTION['id']) endpoint = '/executions/%s' % EXECUTION['id'] data = {'status': 'pausing'} httpclient.HTTPClient.put.assert_called_with(endpoint, data) @mock.patch.object( models.ResourceManager, 'get_by_id', mock.MagicMock(return_value=models.Execution(**EXECUTION))) @mock.patch.object(models.ResourceManager, 'get_by_ref_or_id', mock.MagicMock(return_value=models.Action(**ACTION))) @mock.patch.object(models.ResourceManager, 'get_by_name', mock.MagicMock(return_value=models.RunnerType(**RUNNER)) ) @mock.patch.object( httpclient.HTTPClient, 'put', mock.MagicMock( return_value=base.FakeResponse(json.dumps(EXECUTION), 200, 'OK'))) def test_resume(self): self.client.executions.resume(EXECUTION['id']) endpoint = '/executions/%s' % EXECUTION['id'] data = {'status': 'resuming'} httpclient.HTTPClient.put.assert_called_with(endpoint, data) @mock.patch.object(models.core.Resource, 'get_url_path_name', mock.MagicMock(return_value='executions')) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock( return_value=base.FakeResponse(json.dumps([EXECUTION]), 200, 'OK')) ) def test_get_children(self): self.client.executions.get_children(EXECUTION['id']) endpoint = '/executions/%s/children' % EXECUTION['id'] data = {'depth': -1} httpclient.HTTPClient.get.assert_called_with(url=endpoint, params=data) @mock.patch.object( models.ResourceManager, 'get_all', mock.MagicMock(return_value=[models.Execution(**EXECUTION)])) @mock.patch.object(warnings, 'warn') def test_st2client_liveactions_has_been_deprecated_and_emits_warning( self, mock_warn): self.assertEqual(mock_warn.call_args, None) self.client.liveactions.get_all() expected_msg = 'st2client.liveactions has been renamed' self.assertTrue(len(mock_warn.call_args_list) >= 1) self.assertTrue(expected_msg in mock_warn.call_args_list[0][0][0]) self.assertEqual(mock_warn.call_args_list[0][0][1], DeprecationWarning)
class TestResourceManager(unittest2.TestCase): @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES), 200, 'OK'))) def test_resource_get_all(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) resources = mgr.get_all() actual = [resource.serialize() for resource in resources] expected = json.loads(json.dumps(base.RESOURCES)) self.assertListEqual(actual, expected) @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES), 200, 'OK'))) def test_resource_get_all_with_limit(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) resources = mgr.get_all(limit=50) actual = [resource.serialize() for resource in resources] expected = json.loads(json.dumps(base.RESOURCES)) self.assertListEqual(actual, expected) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock( return_value=base.FakeResponse('', 500, 'INTERNAL SERVER ERROR'))) def test_resource_get_all_failed(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) self.assertRaises(Exception, mgr.get_all) @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES[0]), 200, 'OK'))) def test_resource_get_by_id(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) resource = mgr.get_by_id('123') actual = resource.serialize() expected = json.loads(json.dumps(base.RESOURCES[0])) self.assertEqual(actual, expected) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse('', 404, 'NOT FOUND'))) def test_resource_get_by_id_404(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) resource = mgr.get_by_id('123') self.assertIsNone(resource) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock( return_value=base.FakeResponse('', 500, 'INTERNAL SERVER ERROR'))) def test_resource_get_by_id_failed(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) self.assertRaises(Exception, mgr.get_by_id) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock( return_value=base.FakeResponse(json.dumps( [base.RESOURCES[0]]), 200, 'OK', {'X-Total-Count': '40'}))) def test_resource_query(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) resources, count = mgr.query(name='abc') actual = [resource.serialize() for resource in resources] expected = json.loads(json.dumps([base.RESOURCES[0]])) self.assertEqual(actual, expected) self.assertEqual(count, '40') @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock( return_value=base.FakeResponse(json.dumps( [base.RESOURCES[0]]), 200, 'OK', {'X-Total-Count': '30'}))) def test_resource_query_with_limit(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) resources, count = mgr.query(name='abc', limit=50) actual = [resource.serialize() for resource in resources] expected = json.loads(json.dumps([base.RESOURCES[0]])) self.assertEqual(actual, expected) self.assertEqual(count, '30') @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( '', 404, 'NOT FOUND', {'X-Total-Count': '30'}))) def test_resource_query_404(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) # No X-Total-Count resources = mgr.query(name='abc') self.assertListEqual(resources, []) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock( return_value=base.FakeResponse('', 500, 'INTERNAL SERVER ERROR'))) def test_resource_query_failed(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) self.assertRaises(Exception, mgr.query, name='abc') @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps([base.RESOURCES[0]]), 200, 'OK', {}))) def test_resource_get_by_name(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) # No X-Total-Count resource = mgr.get_by_name('abc') actual = resource.serialize() expected = json.loads(json.dumps(base.RESOURCES[0])) self.assertEqual(actual, expected) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse('', 404, 'NOT FOUND'))) def test_resource_get_by_name_404(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) resource = mgr.get_by_name('abc') self.assertIsNone(resource) @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES), 200, 'OK'))) def test_resource_get_by_name_ambiguous(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) self.assertRaises(Exception, mgr.get_by_name, 'abc') @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock( return_value=base.FakeResponse('', 500, 'INTERNAL SERVER ERROR'))) def test_resource_get_by_name_failed(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) self.assertRaises(Exception, mgr.get_by_name) @mock.patch.object(httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES[0]), 200, 'OK'))) def test_resource_create(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) instance = base.FakeResource.deserialize('{"name": "abc"}') resource = mgr.create(instance) self.assertIsNotNone(resource) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock( return_value=base.FakeResponse('', 500, 'INTERNAL SERVER ERROR'))) def test_resource_create_failed(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) instance = base.FakeResource.deserialize('{"name": "abc"}') self.assertRaises(Exception, mgr.create, instance) @mock.patch.object(httpclient.HTTPClient, 'put', mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES[0]), 200, 'OK'))) def test_resource_update(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) text = '{"id": "123", "name": "cba"}' instance = base.FakeResource.deserialize(text) resource = mgr.update(instance) self.assertIsNotNone(resource) @mock.patch.object( httpclient.HTTPClient, 'put', mock.MagicMock( return_value=base.FakeResponse('', 500, 'INTERNAL SERVER ERROR'))) def test_resource_update_failed(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) text = '{"id": "123", "name": "cba"}' instance = base.FakeResource.deserialize(text) self.assertRaises(Exception, mgr.update, instance) @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps([base.RESOURCES[0]]), 200, 'OK', {}))) @mock.patch.object( httpclient.HTTPClient, 'delete', mock.MagicMock(return_value=base.FakeResponse('', 204, 'NO CONTENT'))) def test_resource_delete(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) instance = mgr.get_by_name('abc') mgr.delete(instance) @mock.patch.object( httpclient.HTTPClient, 'delete', mock.MagicMock(return_value=base.FakeResponse('', 404, 'NOT FOUND'))) def test_resource_delete_404(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) instance = base.FakeResource.deserialize(base.RESOURCES[0]) mgr.delete(instance) @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps([base.RESOURCES[0]]), 200, 'OK', {}))) @mock.patch.object( httpclient.HTTPClient, 'delete', mock.MagicMock( return_value=base.FakeResponse('', 500, 'INTERNAL SERVER ERROR'))) def test_resource_delete_failed(self): mgr = models.ResourceManager(base.FakeResource, base.FAKE_ENDPOINT) instance = mgr.get_by_name('abc') self.assertRaises(Exception, mgr.delete, instance)
class ActionExecutionTailCommandTestCase(BaseCLITestCase): capture_output = True def __init__(self, *args, **kwargs): super(ActionExecutionTailCommandTestCase, self).__init__(*args, **kwargs) self.shell = Shell() @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps(MOCK_LIVEACTION_1_SUCCEEDED), 200, 'OK')) ) def test_tail_simple_execution_already_finished_succeeded(self): argv = ['execution', 'tail', 'idfoo1'] self.assertEqual(self.shell.run(argv), 0) stdout = self.stdout.getvalue() stderr = self.stderr.getvalue() self.assertTrue( 'Execution idfoo1 has completed (status=succeeded)' in stdout) self.assertEqual(stderr, '') @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps(MOCK_LIVEACTION_2_FAILED), 200, 'OK'))) def test_tail_simple_execution_already_finished_failed(self): argv = ['execution', 'tail', 'idfoo2'] self.assertEqual(self.shell.run(argv), 0) stdout = self.stdout.getvalue() stderr = self.stderr.getvalue() self.assertTrue( 'Execution idfoo2 has completed (status=failed)' in stdout) self.assertEqual(stderr, '') @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps(MOCK_LIVEACTION_1_RUNNING), 200, 'OK'))) @mock.patch('st2client.client.StreamManager', autospec=True) def test_tail_simple_execution_running_no_data_produced( self, mock_stream_manager): argv = ['execution', 'tail', 'idfoo1'] MOCK_EVENTS = [MOCK_LIVEACTION_1_SUCCEEDED] mock_cls = mock.Mock() mock_cls.listen = mock.Mock() mock_listen_generator = mock.Mock() mock_listen_generator.return_value = MOCK_EVENTS mock_cls.listen.side_effect = mock_listen_generator mock_stream_manager.return_value = mock_cls self.assertEqual(self.shell.run(argv), 0) self.assertEqual(mock_listen_generator.call_count, 1) stdout = self.stdout.getvalue() stderr = self.stderr.getvalue() expected_result = """ Execution idfoo1 has completed (status=succeeded). """ self.assertEqual(stdout, expected_result) self.assertEqual(stderr, '') @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps(MOCK_LIVEACTION_3_RUNNING), 200, 'OK'))) @mock.patch('st2client.client.StreamManager', autospec=True) def test_tail_simple_execution_running_with_data(self, mock_stream_manager): argv = ['execution', 'tail', 'idfoo3'] MOCK_EVENTS = [ MOCK_LIVEACTION_3_RUNNING, MOCK_OUTPUT_1, MOCK_OUTPUT_2, MOCK_LIVEACTION_3_SUCCEDED ] mock_cls = mock.Mock() mock_cls.listen = mock.Mock() mock_listen_generator = mock.Mock() mock_listen_generator.return_value = MOCK_EVENTS mock_cls.listen.side_effect = mock_listen_generator mock_stream_manager.return_value = mock_cls self.assertEqual(self.shell.run(argv), 0) self.assertEqual(mock_listen_generator.call_count, 1) stdout = self.stdout.getvalue() stderr = self.stderr.getvalue() expected_result = """ line 1 line 2 Execution idfoo3 has completed (status=succeeded). """.lstrip() self.assertEqual(stdout, expected_result) self.assertEqual(stderr, '') @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps(MOCK_LIVEACTION_3_RUNNING), 200, 'OK'))) @mock.patch('st2client.client.StreamManager', autospec=True) def test_tail_action_chain_workflow_execution(self, mock_stream_manager): argv = ['execution', 'tail', 'idfoo3'] MOCK_EVENTS = [ # Workflow started running MOCK_LIVEACTION_3_RUNNING, # Child task 1 started running MOCK_LIVEACTION_3_CHILD_1_RUNNING, # Output produced by the child task MOCK_LIVEACTION_3_CHILD_1_OUTPUT_1, MOCK_LIVEACTION_3_CHILD_1_OUTPUT_2, # Child task 1 finished MOCK_LIVEACTION_3_CHILD_1_SUCCEEDED, # Child task 2 started running MOCK_LIVEACTION_3_CHILD_2_RUNNING, # Output produced by child task MOCK_LIVEACTION_3_CHILD_2_OUTPUT_1, # Child task 2 finished MOCK_LIVEACTION_3_CHILD_2_FAILED, # Parent workflow task finished MOCK_LIVEACTION_3_SUCCEDED ] mock_cls = mock.Mock() mock_cls.listen = mock.Mock() mock_listen_generator = mock.Mock() mock_listen_generator.return_value = MOCK_EVENTS mock_cls.listen.side_effect = mock_listen_generator mock_stream_manager.return_value = mock_cls self.assertEqual(self.shell.run(argv), 0) self.assertEqual(mock_listen_generator.call_count, 1) stdout = self.stdout.getvalue() stderr = self.stderr.getvalue() expected_result = """ Child execution (task=task_1) idchild1 has started. line ac 4 line ac 5 Child execution (task=task_1) idchild1 has finished (status=succeeded). Child execution (task=task_2) idchild2 has started. line ac 100 Child execution (task=task_2) idchild2 has finished (status=failed). Execution idfoo3 has completed (status=succeeded). """.lstrip() self.assertEqual(stdout, expected_result) self.assertEqual(stderr, '') @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps(MOCK_LIVEACTION_4_RUNNING), 200, 'OK'))) @mock.patch('st2client.client.StreamManager', autospec=True) def test_tail_mistral_workflow_execution(self, mock_stream_manager): argv = ['execution', 'tail', 'idfoo4'] MOCK_EVENTS = [ # Workflow started running MOCK_LIVEACTION_4_RUNNING, # Child task 1 started running MOCK_LIVEACTION_4_CHILD_1_RUNNING, # Output produced by the child task MOCK_LIVEACTION_4_CHILD_1_OUTPUT_1, MOCK_LIVEACTION_4_CHILD_1_OUTPUT_2, # Child task 1 finished MOCK_LIVEACTION_4_CHILD_1_SUCCEEDED, # Child task 2 started running MOCK_LIVEACTION_4_CHILD_2_RUNNING, # Output produced by child task MOCK_LIVEACTION_4_CHILD_2_OUTPUT_1, # Child task 2 finished MOCK_LIVEACTION_4_CHILD_2_TIMED_OUT, # Parent workflow task finished MOCK_LIVEACTION_4_SUCCEDED ] mock_cls = mock.Mock() mock_cls.listen = mock.Mock() mock_listen_generator = mock.Mock() mock_listen_generator.return_value = MOCK_EVENTS mock_cls.listen.side_effect = mock_listen_generator mock_stream_manager.return_value = mock_cls self.assertEqual(self.shell.run(argv), 0) self.assertEqual(mock_listen_generator.call_count, 1) stdout = self.stdout.getvalue() stderr = self.stderr.getvalue() expected_result = """ Child execution (task=task_1) idmistralchild1 has started. line mistral 4 line mistral 5 Child execution (task=task_1) idmistralchild1 has finished (status=succeeded). Child execution (task=task_2) idmistralchild2 has started. line mistral 100 Child execution (task=task_2) idmistralchild2 has finished (status=timeout). Execution idfoo4 has completed (status=succeeded). """.lstrip() self.assertEqual(stdout, expected_result) self.assertEqual(stderr, '')
class TestExecutionResultFormatter(unittest2.TestCase): def __init__(self, *args, **kwargs): super(TestExecutionResultFormatter, self).__init__(*args, **kwargs) self.shell = shell.Shell() self.table = table.SingleRowTable() color.DISABLED = True def setUp(self): self.fd, self.path = tempfile.mkstemp() self._redirect_console(self.path) self.maxDiff = None def tearDown(self): self._undo_console_redirect() os.close(self.fd) os.unlink(self.path) def _redirect_console(self, path): sys.stdout = open(path, "w") sys.stderr = open(path, "w") def _undo_console_redirect(self): sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ def test_console_redirect(self): message = "Hello, World!" print(message) self._undo_console_redirect() with open(self.path, "r") as fd: content = fd.read().replace("\n", "") self.assertEqual(content, message) def test_execution_get_default(self): argv = ["execution", "get", EXECUTION["id"]] content = self._get_execution(argv) self.assertEqual(content, FIXTURES["results"]["execution_get_default.txt"]) def test_execution_get_attributes(self): argv = [ "execution", "get", EXECUTION["id"], "--attr", "status", "end_timestamp", ] content = self._get_execution(argv) self.assertEqual(content, FIXTURES["results"]["execution_get_attributes.txt"]) def test_execution_get_default_in_json(self): argv = ["execution", "get", EXECUTION["id"], "-j"] content = self._get_execution(argv) self.assertEqual( json.loads(content), jsutil.get_kvps( EXECUTION, [ "id", "action.ref", "context.user", "start_timestamp", "end_timestamp", "status", "parameters", "result", ], ), ) def test_execution_get_detail(self): argv = ["execution", "get", EXECUTION["id"], "-d"] content = self._get_execution(argv) self.assertEqual(content, FIXTURES["results"]["execution_get_detail.txt"]) def test_execution_with_schema(self): argv = ["execution", "get", OUTPUT_SCHEMA["id"]] content = self._get_schema_execution(argv) self.assertEqual(content, FIXTURES["results"]["execution_get_has_schema.txt"]) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse(json.dumps(NEWLINE), 200, "OK", {})), ) def test_execution_unescape_newline(self): """Ensure client renders newline characters""" argv = ["execution", "get", NEWLINE["id"]] self.assertEqual(self.shell.run(argv), 0) self._undo_console_redirect() with open(self.path, "r") as fd: content = fd.read() # NOTE: For some reason CI and locally the indent is different sometimes (2 vs 4 spaces) # even though it's using the same code expected = FIXTURES["results"]["execution_unescape_newline.txt"] expected = expected.replace(" '", " '").replace(" '", "'") content = content.replace(" '", " '").replace(" '", "'") content = content.replace(" '", " '") self.assertEqual(content, expected) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse(json.dumps(UNICODE), 200, "OK", {})), ) def test_execution_unicode(self): """Ensure client renders unicode escape sequences""" argv = ["execution", "get", UNICODE["id"]] self.assertEqual(self.shell.run(argv), 0) self._undo_console_redirect() with open(self.path, "r") as fd: content = fd.read() content = content.replace(r"\xE2\x80\xA1", r"\u2021") self.assertEqual(content, FIXTURES["results"]["execution_unicode_py3.txt"]) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse( json.dumps(DOUBLE_BACKSLASH), 200, "OK", {})), ) def test_execution_double_backslash_not_unicode_escape_sequence(self): argv = ["execution", "get", DOUBLE_BACKSLASH["id"]] self.assertEqual(self.shell.run(argv), 0) self._undo_console_redirect() with open(self.path, "r") as fd: content = fd.read() self.assertEqual(content, FIXTURES["results"]["execution_double_backslash.txt"]) def test_execution_get_detail_in_json(self): argv = ["execution", "get", EXECUTION["id"], "-d", "-j"] content = self._get_execution(argv) content_dict = json.loads(content) # Sufficient to check if output contains all expected keys. The entire result will not # match as content will contain characters which improve rendering. for k in six.iterkeys(EXECUTION): if k in ["liveaction", "callback"]: continue if k in content: continue self.assertTrue( False, "Missing key %s. %s != %s" % (k, EXECUTION, content_dict)) def test_execution_get_result_by_key(self): argv = ["execution", "get", EXECUTION["id"], "-k", "localhost.stdout"] content = self._get_execution(argv) self.assertEqual( content, FIXTURES["results"]["execution_get_result_by_key.txt"]) def test_execution_get_result_by_key_in_json(self): argv = [ "execution", "get", EXECUTION["id"], "-k", "localhost.stdout", "-j" ] content = self._get_execution(argv) self.assertDictEqual( json.loads(content), jsutil.get_kvps(EXECUTION, ["result.localhost.stdout"])) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse( json.dumps(HAS_CARRIAGE_RETURN), 200, "OK", {})), ) def test_execution_get_detail_with_carriage_return(self): argv = ["execution", "get", HAS_CARRIAGE_RETURN["id"], "-d"] self.assertEqual(self.shell.run(argv), 0) self._undo_console_redirect() with open(self.path, "r") as fd: content = fd.read() self.assertEqual( content, FIXTURES["results"] ["execution_result_has_carriage_return_py3.txt"]) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse(json.dumps([EXECUTION]), 200, "OK", {})), ) def test_execution_list_attribute_provided(self): # Client shouldn't throw if "-a" flag is provided when listing executions argv = ["execution", "list", "-a", "start_timestamp"] self.assertEqual(self.shell.run(argv), 0) self._undo_console_redirect() with open(self.path, "r") as fd: content = fd.read() self.assertEqual( content, FIXTURES["results"]["execution_list_attr_start_timestamp.txt"]) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock( return_value=base.FakeResponse(json.dumps([]), 200, "OK", {})), ) def test_execution_list_attribute_provided_empty_response(self): # Client shouldn't throw if "-a" flag is provided, but there are no executions argv = ["execution", "list", "-a", "start_timestamp"] self.assertEqual(self.shell.run(argv), 0) self._undo_console_redirect() with open(self.path, "r") as fd: content = fd.read() self.assertEqual( content, FIXTURES["results"] ["execution_list_empty_response_start_timestamp_attr.txt"], ) @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse(json.dumps(EXECUTION), 200, "OK", {})), ) def _get_execution(self, argv): self.assertEqual(self.shell.run(argv), 0) self._undo_console_redirect() with open(self.path, "r") as fd: content = fd.read() return content @mock.patch.object( httpclient.HTTPClient, "get", mock.MagicMock(return_value=base.FakeResponse( json.dumps(OUTPUT_SCHEMA), 200, "OK", {})), ) def _get_schema_execution(self, argv): self.assertEqual(self.shell.run(argv), 0) self._undo_console_redirect() with open(self.path, "r") as fd: content = fd.read() return content def test_SinlgeRowTable_notebox_one(self): with mock.patch("sys.stderr", new=StringIO()) as fackety_fake: expected = ( "Note: Only one action execution is displayed. Use -n/--last flag for " "more results.") print(self.table.note_box("action executions", 1)) content = fackety_fake.getvalue().split("|")[1].strip() self.assertEqual(content, expected) def test_SinlgeRowTable_notebox_zero(self): with mock.patch("sys.stderr", new=BytesIO()) as fackety_fake: contents = fackety_fake.getvalue() self.assertEqual(contents, b"") def test_SinlgeRowTable_notebox_default(self): with mock.patch("sys.stderr", new=StringIO()) as fackety_fake: expected = ( "Note: Only first 50 action executions are displayed. Use -n/--last flag " "for more results.") print(self.table.note_box("action executions", 50)) content = fackety_fake.getvalue().split("|")[1].strip() self.assertEqual(content, expected) with mock.patch("sys.stderr", new=StringIO()) as fackety_fake: expected = ( "Note: Only first 15 action executions are displayed. Use -n/--last flag " "for more results.") print(self.table.note_box("action executions", 15)) content = fackety_fake.getvalue().split("|")[1].strip() self.assertEqual(content, expected)
class ShellTestCase(base.BaseCLITestCase): capture_output = True def __init__(self, *args, **kwargs): super(ShellTestCase, self).__init__(*args, **kwargs) self.shell = Shell() def setUp(self): super(ShellTestCase, self).setUp() if six.PY3: # In python --version outputs to stdout and in 2.x to stderr self.version_output = self.stdout else: self.version_output = self.stderr def test_commands_usage_and_help_strings(self): # No command, should print out user friendly usage / help string self.assertEqual(self.shell.run([]), 2) self.stderr.seek(0) stderr = self.stderr.read() self.assertIn('Usage: ', stderr) self.assertIn('For example:', stderr) self.assertIn('CLI for StackStorm', stderr) self.assertIn('positional arguments:', stderr) self.stdout.truncate() self.stderr.truncate() # --help should result in the same output try: self.assertEqual(self.shell.run(['--help']), 0) except SystemExit as e: self.assertEqual(e.code, 0) self.stdout.seek(0) stdout = self.stdout.read() self.assertIn('Usage: ', stdout) self.assertIn('For example:', stdout) self.assertIn('CLI for StackStorm', stdout) self.assertIn('positional arguments:', stdout) self.stdout.truncate() self.stderr.truncate() # Sub command with no args try: self.assertEqual(self.shell.run(['action']), 2) except SystemExit as e: self.assertEqual(e.code, 2) self.stderr.seek(0) stderr = self.stderr.read() self.assertIn('usage', stderr) if six.PY2: self.assertIn('{list,get,create,update', stderr) self.assertIn('error: too few arguments', stderr) def test_endpoints_default(self): base_url = 'http://127.0.0.1' auth_url = 'http://127.0.0.1:9100' api_url = 'http://127.0.0.1:9101/v1' stream_url = 'http://127.0.0.1:9102/v1' args = ['trigger', 'list'] parsed_args = self.shell.parser.parse_args(args) client = self.shell.get_client(parsed_args) self.assertEqual(client.endpoints['base'], base_url) self.assertEqual(client.endpoints['auth'], auth_url) self.assertEqual(client.endpoints['api'], api_url) self.assertEqual(client.endpoints['stream'], stream_url) def test_endpoints_base_url_from_cli(self): base_url = 'http://www.st2.com' auth_url = 'http://www.st2.com:9100' api_url = 'http://www.st2.com:9101/v1' stream_url = 'http://www.st2.com:9102/v1' args = ['--url', base_url, 'trigger', 'list'] parsed_args = self.shell.parser.parse_args(args) client = self.shell.get_client(parsed_args) self.assertEqual(client.endpoints['base'], base_url) self.assertEqual(client.endpoints['auth'], auth_url) self.assertEqual(client.endpoints['api'], api_url) self.assertEqual(client.endpoints['stream'], stream_url) def test_endpoints_base_url_from_env(self): base_url = 'http://www.st2.com' auth_url = 'http://www.st2.com:9100' api_url = 'http://www.st2.com:9101/v1' stream_url = 'http://www.st2.com:9102/v1' os.environ['ST2_BASE_URL'] = base_url args = ['trigger', 'list'] parsed_args = self.shell.parser.parse_args(args) client = self.shell.get_client(parsed_args) self.assertEqual(client.endpoints['base'], base_url) self.assertEqual(client.endpoints['auth'], auth_url) self.assertEqual(client.endpoints['api'], api_url) self.assertEqual(client.endpoints['stream'], stream_url) def test_endpoints_override_from_cli(self): base_url = 'http://www.st2.com' auth_url = 'http://www.st2.com:8888' api_url = 'http://www.stackstorm1.com:9101/v1' stream_url = 'http://www.stackstorm1.com:9102/v1' args = [ '--url', base_url, '--auth-url', auth_url, '--api-url', api_url, '--stream-url', stream_url, 'trigger', 'list' ] parsed_args = self.shell.parser.parse_args(args) client = self.shell.get_client(parsed_args) self.assertEqual(client.endpoints['base'], base_url) self.assertEqual(client.endpoints['auth'], auth_url) self.assertEqual(client.endpoints['api'], api_url) self.assertEqual(client.endpoints['stream'], stream_url) def test_endpoints_override_from_env(self): base_url = 'http://www.st2.com' auth_url = 'http://www.st2.com:8888' api_url = 'http://www.stackstorm1.com:9101/v1' stream_url = 'http://www.stackstorm1.com:9102/v1' os.environ['ST2_BASE_URL'] = base_url os.environ['ST2_AUTH_URL'] = auth_url os.environ['ST2_API_URL'] = api_url os.environ['ST2_STREAM_URL'] = stream_url args = ['trigger', 'list'] parsed_args = self.shell.parser.parse_args(args) client = self.shell.get_client(parsed_args) self.assertEqual(client.endpoints['base'], base_url) self.assertEqual(client.endpoints['auth'], auth_url) self.assertEqual(client.endpoints['api'], api_url) self.assertEqual(client.endpoints['stream'], stream_url) @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES), 200, 'OK'))) def test_exit_code_on_success(self): argv = ['trigger', 'list'] self.assertEqual(self.shell.run(argv), 0) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock( return_value=base.FakeResponse(None, 500, 'INTERNAL SERVER ERROR')) ) def test_exit_code_on_error(self): argv = ['trigger', 'list'] self.assertEqual(self.shell.run(argv), 1) def _validate_parser(self, args_list, is_subcommand=True): for args in args_list: ns = self.shell.parser.parse_args(args) func = ( self.shell.commands[args[0]].run_and_print if not is_subcommand else self.shell.commands[args[0]].commands[args[1]].run_and_print) self.assertEqual(ns.func, func) def test_action(self): args_list = [ ['action', 'list'], ['action', 'get', 'abc'], ['action', 'create', '/tmp/action.json'], ['action', 'update', '123', '/tmp/action.json'], ['action', 'delete', 'abc'], ['action', 'execute', '-h'], ['action', 'execute', 'remote', '-h'], [ 'action', 'execute', 'remote', 'hosts=192.168.1.1', 'user=st2', 'cmd="ls -l"' ], ['action', 'execute', 'remote-fib', 'hosts=192.168.1.1', '3', '8'] ] self._validate_parser(args_list) def test_action_execution(self): args_list = [['execution', 'list'], ['execution', 'list', '-a', 'all'], ['execution', 'list', '--attr=all'], ['execution', 'get', '123'], ['execution', 'get', '123', '-d'], ['execution', 'get', '123', '-k', 'localhost.stdout'], ['execution', 're-run', '123'], ['execution', 're-run', '123', '--tasks', 'x', 'y', 'z'], [ 'execution', 're-run', '123', '--tasks', 'x', 'y', 'z', '--no-reset', 'x' ], ['execution', 're-run', '123', 'a=1', 'b=x', 'c=True'], ['execution', 'cancel', '123'], ['execution', 'cancel', '123', '456'], ['execution', 'pause', '123'], ['execution', 'pause', '123', '456'], ['execution', 'resume', '123'], ['execution', 'resume', '123', '456']] self._validate_parser(args_list) # Test mutually exclusive argument groups self.assertRaises( SystemExit, self._validate_parser, [['execution', 'get', '123', '-d', '-k', 'localhost.stdout']]) def test_key(self): args_list = [['key', 'list'], ['key', 'list', '-n', '2'], ['key', 'get', 'abc'], ['key', 'set', 'abc', '123'], ['key', 'delete', 'abc'], ['key', 'load', '/tmp/keys.json']] self._validate_parser(args_list) def test_policy(self): args_list = [ ['policy', 'list'], ['policy', 'list', '-p', 'core'], ['policy', 'list', '--pack', 'core'], ['policy', 'list', '-r', 'core.local'], ['policy', 'list', '--resource-ref', 'core.local'], ['policy', 'list', '-pt', 'action.type1'], ['policy', 'list', '--policy-type', 'action.type1'], ['policy', 'list', '-r', 'core.local', '-pt', 'action.type1'], [ 'policy', 'list', '--resource-ref', 'core.local', '--policy-type', 'action.type1' ], ['policy', 'get', 'abc'], ['policy', 'create', '/tmp/policy.json'], ['policy', 'update', '123', '/tmp/policy.json'], ['policy', 'delete', 'abc'] ] self._validate_parser(args_list) def test_policy_type(self): args_list = [['policy-type', 'list'], ['policy-type', 'list', '-r', 'action'], ['policy-type', 'list', '--resource-type', 'action'], ['policy-type', 'get', 'abc']] self._validate_parser(args_list) def test_pack(self): args_list = [['pack', 'list'], ['pack', 'get', 'abc'], ['pack', 'search', 'abc'], ['pack', 'show', 'abc'], ['pack', 'remove', 'abc'], ['pack', 'remove', 'abc', '--detail'], ['pack', 'install', 'abc'], ['pack', 'install', 'abc', '--force'], ['pack', 'install', 'abc', '--detail'], ['pack', 'config', 'abc']] self._validate_parser(args_list) @mock.patch('st2client.base.ST2_CONFIG_PATH', '/home/does/not/exist') def test_print_config_default_config_no_config(self): os.environ['ST2_CONFIG_FILE'] = '/home/does/not/exist' argv = ['--print-config'] self.assertEqual(self.shell.run(argv), 3) self.stdout.seek(0) stdout = self.stdout.read() self.assertIn('username = None', stdout) self.assertIn('cache_token = True', stdout) def test_print_config_custom_config_as_env_variable(self): os.environ['ST2_CONFIG_FILE'] = CONFIG_FILE_PATH_FULL argv = ['--print-config'] self.assertEqual(self.shell.run(argv), 3) self.stdout.seek(0) stdout = self.stdout.read() self.assertIn('username = test1', stdout) self.assertIn('cache_token = False', stdout) def test_print_config_custom_config_as_command_line_argument(self): argv = ['--print-config', '--config-file=%s' % (CONFIG_FILE_PATH_FULL)] self.assertEqual(self.shell.run(argv), 3) self.stdout.seek(0) stdout = self.stdout.read() self.assertIn('username = test1', stdout) self.assertIn('cache_token = False', stdout) def test_run(self): args_list = [['run', '-h'], ['run', 'abc', '-h'], [ 'run', 'remote', 'hosts=192.168.1.1', 'user=st2', 'cmd="ls -l"' ], ['run', 'remote-fib', 'hosts=192.168.1.1', '3', '8']] self._validate_parser(args_list, is_subcommand=False) def test_runner(self): args_list = [['runner', 'list'], ['runner', 'get', 'abc']] self._validate_parser(args_list) def test_rule(self): args_list = [['rule', 'list'], ['rule', 'list', '-n', '1'], ['rule', 'get', 'abc'], ['rule', 'create', '/tmp/rule.json'], ['rule', 'update', '123', '/tmp/rule.json'], ['rule', 'delete', 'abc']] self._validate_parser(args_list) def test_trigger(self): args_list = [['trigger', 'list'], ['trigger', 'get', 'abc'], ['trigger', 'create', '/tmp/trigger.json'], ['trigger', 'update', '123', '/tmp/trigger.json'], ['trigger', 'delete', 'abc']] self._validate_parser(args_list) def test_workflow(self): args_list = [[ 'workflow', 'inspect', '--file', '/path/to/workflow/definition' ], ['workflow', 'inspect', '--action', 'mock.foobar']] self._validate_parser(args_list) @mock.patch('sys.exit', mock.Mock()) @mock.patch('st2client.shell.__version__', 'v2.8.0') def test_get_version_no_package_metadata_file_stable_version(self): # stable version, package metadata file doesn't exist on disk - no git revision should be # included shell = Shell() shell.parser.parse_args(args=['--version']) self.version_output.seek(0) stderr = self.version_output.read() self.assertIn('v2.8.0, on Python', stderr) @mock.patch('sys.exit', mock.Mock()) @mock.patch('st2client.shell.__version__', 'v2.8.0') def test_get_version_package_metadata_file_exists_stable_version(self): # stable version, package metadata file exists on disk - no git revision should be included package_metadata_path = self._write_mock_package_metadata_file() st2client.shell.PACKAGE_METADATA_FILE_PATH = package_metadata_path shell = Shell() shell.run(argv=['--version']) self.version_output.seek(0) stderr = self.version_output.read() self.assertIn('v2.8.0, on Python', stderr) @mock.patch('sys.exit', mock.Mock()) @mock.patch('st2client.shell.__version__', 'v2.9dev') @mock.patch('st2client.shell.PACKAGE_METADATA_FILE_PATH', '/tmp/doesnt/exist.1') def test_get_version_no_package_metadata_file_dev_version(self): # dev version, package metadata file doesn't exist on disk - no git revision should be # included since package metadata file doesn't exist on disk shell = Shell() shell.parser.parse_args(args=['--version']) self.version_output.seek(0) stderr = self.version_output.read() self.assertIn('v2.9dev, on Python', stderr) @mock.patch('sys.exit', mock.Mock()) @mock.patch('st2client.shell.__version__', 'v2.9dev') def test_get_version_package_metadata_file_exists_dev_version(self): # dev version, package metadata file exists on disk - git revision should be included # since package metadata file exists on disk and contains server.git_sha attribute package_metadata_path = self._write_mock_package_metadata_file() st2client.shell.PACKAGE_METADATA_FILE_PATH = package_metadata_path shell = Shell() shell.parser.parse_args(args=['--version']) self.version_output.seek(0) stderr = self.version_output.read() self.assertIn('v2.9dev (abcdefg), on Python', stderr) @mock.patch('locale.getdefaultlocale', mock.Mock(return_value=['en_US'])) @mock.patch('locale.getpreferredencoding', mock.Mock(return_value='iso')) @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES), 200, 'OK'))) @mock.patch('st2client.shell.LOGGER') def test_non_unicode_encoding_locale_warning_is_printed(self, mock_logger): shell = Shell() shell.run(argv=['trigger', 'list']) call_args = mock_logger.warn.call_args[0][0] self.assertIn( 'Locale en_US with encoding iso which is not UTF-8 is used.', call_args) @mock.patch('locale.getdefaultlocale', mock.Mock(side_effect=ValueError('bar'))) @mock.patch('locale.getpreferredencoding', mock.Mock(side_effect=ValueError('bar'))) @mock.patch.object(httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse( json.dumps(base.RESOURCES), 200, 'OK'))) @mock.patch('st2client.shell.LOGGER') def test_failed_to_get_locale_encoding_warning_is_printed( self, mock_logger): shell = Shell() shell.run(argv=['trigger', 'list']) call_args = mock_logger.warn.call_args[0][0] self.assertTrue( 'Locale unknown with encoding unknown which is not UTF-8 is used.' in call_args) def _write_mock_package_metadata_file(self): _, package_metadata_path = tempfile.mkstemp() with open(package_metadata_path, 'w') as fp: fp.write(MOCK_PACKAGE_METADATA) return package_metadata_path @unittest2.skipIf(True, 'skipping until checks are re-enabled') @mock.patch.object( requests, 'get', mock.MagicMock(return_value=base.FakeResponse("{}", 200, 'OK'))) def test_dont_warn_multiple_times(self): mock_temp_dir_path = tempfile.mkdtemp() mock_config_dir_path = os.path.join(mock_temp_dir_path, 'testconfig') mock_config_path = os.path.join(mock_config_dir_path, 'config') # Make the temporary config directory os.makedirs(mock_config_dir_path) old_perms = os.stat(mock_config_dir_path).st_mode new_perms = old_perms | 0o7 os.chmod(mock_config_dir_path, new_perms) # Make the temporary config file shutil.copyfile(CONFIG_FILE_PATH_FULL, mock_config_path) os.chmod(mock_config_path, 0o777) # nosec shell = Shell() shell.LOG = mock.Mock() # Test without token. shell.run(['--config-file', mock_config_path, 'action', 'list']) self.assertEqual(shell.LOG.warn.call_count, 2) self.assertEqual( shell.LOG.warn.call_args_list[0][0][0][:63], 'The StackStorm configuration directory permissions are insecure') self.assertEqual( shell.LOG.warn.call_args_list[1][0][0][:58], 'The StackStorm configuration file permissions are insecure') self.assertEqual(shell.LOG.info.call_count, 2) self.assertEqual( shell.LOG.info.call_args_list[0][0][0], "The SGID bit is not " "set on the StackStorm configuration directory.") self.assertEqual(shell.LOG.info.call_args_list[1][0][0], 'Skipping parsing CLI config')
class TestResourceCommand(unittest2.TestCase): def __init__(self, *args, **kwargs): super(TestResourceCommand, self).__init__(*args, **kwargs) self.parser = argparse.ArgumentParser() self.subparsers = self.parser.add_subparsers() self.branch = resource.ResourceBranch( base.FakeResource, 'Test Command', base.FakeApp(), self.subparsers) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps(base.RESOURCES), 200, 'OK'))) def test_command_list(self): args = self.parser.parse_args(['fakeresource', 'list']) self.assertEqual(args.func, self.branch.commands['list'].run_and_print) instances = self.branch.commands['list'].run(args) actual = [instance.serialize() for instance in instances] expected = json.loads(json.dumps(base.RESOURCES)) self.assertListEqual(actual, expected) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse('', 500, 'INTERNAL SERVER ERROR'))) def test_command_list_failed(self): args = self.parser.parse_args(['fakeresource', 'list']) self.assertRaises(Exception, self.branch.commands['list'].run, args) @mock.patch.object( models.ResourceManager, 'get_by_name', mock.MagicMock(return_value=None)) @mock.patch.object( models.ResourceManager, 'get_by_id', mock.MagicMock(return_value=base.FakeResource(**base.RESOURCES[0]))) def test_command_get_by_id(self): args = self.parser.parse_args(['fakeresource', 'get', '123']) self.assertEqual(args.func, self.branch.commands['get'].run_and_print) instance = self.branch.commands['get'].run(args) actual = instance.serialize() expected = json.loads(json.dumps(base.RESOURCES[0])) self.assertEqual(actual, expected) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps(base.RESOURCES[0]), 200, 'OK'))) def test_command_get(self): args = self.parser.parse_args(['fakeresource', 'get', 'abc']) self.assertEqual(args.func, self.branch.commands['get'].run_and_print) instance = self.branch.commands['get'].run(args) actual = instance.serialize() expected = json.loads(json.dumps(base.RESOURCES[0])) self.assertEqual(actual, expected) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse('', 404, 'NOT FOUND'))) def test_command_get_404(self): args = self.parser.parse_args(['fakeresource', 'get', 'cba']) self.assertEqual(args.func, self.branch.commands['get'].run_and_print) self.assertRaises(resource.ResourceNotFoundError, self.branch.commands['get'].run, args) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse('', 500, 'INTERNAL SERVER ERROR'))) def test_command_get_failed(self): args = self.parser.parse_args(['fakeresource', 'get', 'cba']) self.assertRaises(Exception, self.branch.commands['get'].run, args) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(base.RESOURCES[0]), 200, 'OK'))) def test_command_create(self): instance = base.FakeResource(name='abc') fd, path = tempfile.mkstemp(suffix='.json') try: with open(path, 'a') as f: f.write(json.dumps(instance.serialize(), indent=4)) args = self.parser.parse_args(['fakeresource', 'create', path]) self.assertEqual(args.func, self.branch.commands['create'].run_and_print) instance = self.branch.commands['create'].run(args) actual = instance.serialize() expected = json.loads(json.dumps(base.RESOURCES[0])) self.assertEqual(actual, expected) finally: os.close(fd) os.unlink(path) @mock.patch.object( httpclient.HTTPClient, 'post', mock.MagicMock(return_value=base.FakeResponse('', 500, 'INTERNAL SERVER ERROR'))) def test_command_create_failed(self): instance = base.FakeResource(name='abc') fd, path = tempfile.mkstemp(suffix='.json') try: with open(path, 'a') as f: f.write(json.dumps(instance.serialize(), indent=4)) args = self.parser.parse_args(['fakeresource', 'create', path]) self.assertRaises(Exception, self.branch.commands['create'].run, args) finally: os.close(fd) os.unlink(path) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps([base.RESOURCES[0]]), 200, 'OK', {}))) @mock.patch.object( httpclient.HTTPClient, 'put', mock.MagicMock(return_value=base.FakeResponse(json.dumps(base.RESOURCES[0]), 200, 'OK'))) def test_command_update(self): instance = base.FakeResource(id='123', name='abc') fd, path = tempfile.mkstemp(suffix='.json') try: with open(path, 'a') as f: f.write(json.dumps(instance.serialize(), indent=4)) args = self.parser.parse_args( ['fakeresource', 'update', '123', path]) self.assertEqual(args.func, self.branch.commands['update'].run_and_print) instance = self.branch.commands['update'].run(args) actual = instance.serialize() expected = json.loads(json.dumps(base.RESOURCES[0])) self.assertEqual(actual, expected) finally: os.close(fd) os.unlink(path) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps([base.RESOURCES[0]]), 200, 'OK'))) @mock.patch.object( httpclient.HTTPClient, 'put', mock.MagicMock(return_value=base.FakeResponse('', 500, 'INTERNAL SERVER ERROR'))) def test_command_update_failed(self): instance = base.FakeResource(id='123', name='abc') fd, path = tempfile.mkstemp(suffix='.json') try: with open(path, 'a') as f: f.write(json.dumps(instance.serialize(), indent=4)) args = self.parser.parse_args( ['fakeresource', 'update', '123', path]) self.assertRaises(Exception, self.branch.commands['update'].run, args) finally: os.close(fd) os.unlink(path) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps([base.RESOURCES[0]]), 200, 'OK'))) def test_command_update_id_mismatch(self): instance = base.FakeResource(id='789', name='abc') fd, path = tempfile.mkstemp(suffix='.json') try: with open(path, 'a') as f: f.write(json.dumps(instance.serialize(), indent=4)) args = self.parser.parse_args( ['fakeresource', 'update', '123', path]) self.assertRaises(Exception, self.branch.commands['update'].run, args) finally: os.close(fd) os.unlink(path) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps([base.RESOURCES[0]]), 200, 'OK', {}))) @mock.patch.object( httpclient.HTTPClient, 'delete', mock.MagicMock(return_value=base.FakeResponse('', 204, 'NO CONTENT'))) def test_command_delete(self): args = self.parser.parse_args(['fakeresource', 'delete', 'abc']) self.assertEqual(args.func, self.branch.commands['delete'].run_and_print) self.branch.commands['delete'].run(args) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse('', 404, 'NOT FOUND'))) def test_command_delete_404(self): args = self.parser.parse_args(['fakeresource', 'delete', 'cba']) self.assertEqual(args.func, self.branch.commands['delete'].run_and_print) self.assertRaises(resource.ResourceNotFoundError, self.branch.commands['delete'].run, args) @mock.patch.object( httpclient.HTTPClient, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps([base.RESOURCES[0]]), 200, 'OK'))) @mock.patch.object( httpclient.HTTPClient, 'delete', mock.MagicMock(return_value=base.FakeResponse('', 500, 'INTERNAL SERVER ERROR'))) def test_command_delete_failed(self): args = self.parser.parse_args(['fakeresource', 'delete', 'cba']) self.assertRaises(Exception, self.branch.commands['delete'].run, args)
class WorkflowCommandTestCase(st2cli_tests.BaseCLITestCase): def __init__(self, *args, **kwargs): super(WorkflowCommandTestCase, self).__init__(*args, **kwargs) self.shell = shell.Shell() @mock.patch.object( httpclient.HTTPClient, "post_raw", mock.MagicMock(return_value=st2cli_tests.FakeResponse( json.dumps(MOCK_RESULT), 200, "OK")), ) def test_inspect_file(self): fd, path = tempfile.mkstemp(suffix=".yaml") try: with open(path, "a") as f: f.write(MOCK_WF_DEF) retcode = self.shell.run(["workflow", "inspect", "--file", path]) self.assertEqual(retcode, 0) httpclient.HTTPClient.post_raw.assert_called_with( "/inspect", MOCK_WF_DEF, headers={"content-type": "text/plain"}) finally: os.close(fd) os.unlink(path) @mock.patch.object( httpclient.HTTPClient, "post_raw", mock.MagicMock(return_value=st2cli_tests.FakeResponse( json.dumps(MOCK_RESULT), 200, "OK")), ) def test_inspect_bad_file(self): retcode = self.shell.run( ["workflow", "inspect", "--file", "/tmp/foobar"]) self.assertEqual(retcode, 1) self.assertIn("does not exist", self.stdout.getvalue()) self.assertFalse(httpclient.HTTPClient.post_raw.called) @mock.patch.object( models.ResourceManager, "get_by_ref_or_id", mock.MagicMock(side_effect=get_by_ref), ) @mock.patch.object( workflow.WorkflowInspectionCommand, "get_file_content", mock.MagicMock(return_value=MOCK_WF_DEF), ) @mock.patch.object( httpclient.HTTPClient, "post_raw", mock.MagicMock(return_value=st2cli_tests.FakeResponse( json.dumps(MOCK_RESULT), 200, "OK")), ) def test_inspect_action(self): retcode = self.shell.run( ["workflow", "inspect", "--action", "mock.foobar"]) self.assertEqual(retcode, 0) httpclient.HTTPClient.post_raw.assert_called_with( "/inspect", MOCK_WF_DEF, headers={"content-type": "text/plain"}) @mock.patch.object(models.ResourceManager, "get_by_ref_or_id", mock.MagicMock(return_value=None)) @mock.patch.object( httpclient.HTTPClient, "post_raw", mock.MagicMock(return_value=st2cli_tests.FakeResponse( json.dumps(MOCK_RESULT), 200, "OK")), ) def test_inspect_bad_action(self): retcode = self.shell.run( ["workflow", "inspect", "--action", "mock.foobar"]) self.assertEqual(retcode, 1) self.assertIn("Unable to identify action", self.stdout.getvalue()) self.assertFalse(httpclient.HTTPClient.post_raw.called)
class TestAuthToken(base.BaseCLITestCase): def __init__(self, *args, **kwargs): super(TestAuthToken, self).__init__(*args, **kwargs) self.parser = argparse.ArgumentParser() self.parser.add_argument('-t', '--token', dest='token') self.parser.add_argument('--api-key', dest='api_key') self.shell = shell.Shell() def setUp(self): super(TestAuthToken, self).setUp() # Setup environment. os.environ['ST2_BASE_URL'] = 'http://127.0.0.1' def tearDown(self): super(TestAuthToken, self).tearDown() # Clean up environment. if 'ST2_AUTH_TOKEN' in os.environ: del os.environ['ST2_AUTH_TOKEN'] if 'ST2_API_KEY' in os.environ: del os.environ['ST2_API_KEY'] if 'ST2_BASE_URL' in os.environ: del os.environ['ST2_BASE_URL'] @add_auth_token_to_kwargs_from_cli @add_auth_token_to_kwargs_from_env def _mock_run(self, args, **kwargs): return kwargs def test_decorate_auth_token_by_cli(self): token = uuid.uuid4().hex args = self.parser.parse_args(args=['-t', token]) self.assertDictEqual(self._mock_run(args), {'token': token}) args = self.parser.parse_args(args=['--token', token]) self.assertDictEqual(self._mock_run(args), {'token': token}) def test_decorate_api_key_by_cli(self): token = uuid.uuid4().hex args = self.parser.parse_args(args=['--api-key', token]) self.assertDictEqual(self._mock_run(args), {'api_key': token}) def test_decorate_auth_token_by_env(self): token = uuid.uuid4().hex os.environ['ST2_AUTH_TOKEN'] = token args = self.parser.parse_args(args=[]) self.assertDictEqual(self._mock_run(args), {'token': token}) def test_decorate_api_key_by_env(self): token = uuid.uuid4().hex os.environ['ST2_API_KEY'] = token args = self.parser.parse_args(args=[]) self.assertDictEqual(self._mock_run(args), {'api_key': token}) def test_decorate_without_auth_token(self): args = self.parser.parse_args(args=[]) self.assertDictEqual(self._mock_run(args), {}) @add_auth_token_to_headers @add_json_content_type_to_headers def _mock_http(self, url, **kwargs): return kwargs def test_decorate_auth_token_to_http_headers(self): token = uuid.uuid4().hex kwargs = self._mock_http('/', token=token) expected = {'content-type': 'application/json', 'X-Auth-Token': token} self.assertIn('headers', kwargs) self.assertDictEqual(kwargs['headers'], expected) def test_decorate_api_key_to_http_headers(self): token = uuid.uuid4().hex kwargs = self._mock_http('/', api_key=token) expected = {'content-type': 'application/json', 'St2-Api-Key': token} self.assertIn('headers', kwargs) self.assertDictEqual(kwargs['headers'], expected) def test_decorate_without_auth_token_to_http_headers(self): kwargs = self._mock_http('/', auth=('stanley', 'stanley')) expected = {'content-type': 'application/json'} self.assertIn('auth', kwargs) self.assertEqual(kwargs['auth'], ('stanley', 'stanley')) self.assertIn('headers', kwargs) self.assertDictEqual(kwargs['headers'], expected) @mock.patch.object( requests, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps({}), 200, 'OK'))) def test_decorate_resource_list(self): url = 'http://127.0.0.1:9101/v1/rules/?limit=50' # Test without token. self.shell.run(['rule', 'list']) kwargs = {} requests.get.assert_called_with(url, **kwargs) # Test with token from cli. token = uuid.uuid4().hex self.shell.run(['rule', 'list', '-t', token]) kwargs = {'headers': {'X-Auth-Token': token}} requests.get.assert_called_with(url, **kwargs) # Test with token from env. token = uuid.uuid4().hex os.environ['ST2_AUTH_TOKEN'] = token self.shell.run(['rule', 'list']) kwargs = {'headers': {'X-Auth-Token': token}} requests.get.assert_called_with(url, **kwargs) @mock.patch.object( requests, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps(RULE), 200, 'OK'))) def test_decorate_resource_get(self): rule_ref = '%s.%s' % (RULE['pack'], RULE['name']) url = 'http://127.0.0.1:9101/v1/rules/%s' % rule_ref # Test without token. self.shell.run(['rule', 'get', rule_ref]) kwargs = {} requests.get.assert_called_with(url, **kwargs) # Test with token from cli. token = uuid.uuid4().hex self.shell.run(['rule', 'get', rule_ref, '-t', token]) kwargs = {'headers': {'X-Auth-Token': token}} requests.get.assert_called_with(url, **kwargs) # Test with token from env. token = uuid.uuid4().hex os.environ['ST2_AUTH_TOKEN'] = token self.shell.run(['rule', 'get', rule_ref]) kwargs = {'headers': {'X-Auth-Token': token}} requests.get.assert_called_with(url, **kwargs) @mock.patch.object( requests, 'post', mock.MagicMock(return_value=base.FakeResponse(json.dumps(RULE), 200, 'OK'))) def test_decorate_resource_post(self): url = 'http://127.0.0.1:9101/v1/rules' data = {'name': RULE['name'], 'description': RULE['description']} fd, path = tempfile.mkstemp(suffix='.json') try: with open(path, 'a') as f: f.write(json.dumps(data, indent=4)) # Test without token. self.shell.run(['rule', 'create', path]) kwargs = {'headers': {'content-type': 'application/json'}} requests.post.assert_called_with(url, json.dumps(data), **kwargs) # Test with token from cli. token = uuid.uuid4().hex self.shell.run(['rule', 'create', path, '-t', token]) kwargs = {'headers': {'content-type': 'application/json', 'X-Auth-Token': token}} requests.post.assert_called_with(url, json.dumps(data), **kwargs) # Test with token from env. token = uuid.uuid4().hex os.environ['ST2_AUTH_TOKEN'] = token self.shell.run(['rule', 'create', path]) kwargs = {'headers': {'content-type': 'application/json', 'X-Auth-Token': token}} requests.post.assert_called_with(url, json.dumps(data), **kwargs) finally: os.close(fd) os.unlink(path) @mock.patch.object( requests, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps(RULE), 200, 'OK'))) @mock.patch.object( requests, 'put', mock.MagicMock(return_value=base.FakeResponse(json.dumps(RULE), 200, 'OK'))) def test_decorate_resource_put(self): rule_ref = '%s.%s' % (RULE['pack'], RULE['name']) get_url = 'http://127.0.0.1:9101/v1/rules/%s' % rule_ref put_url = 'http://127.0.0.1:9101/v1/rules/%s' % RULE['id'] data = {'name': RULE['name'], 'description': RULE['description'], 'pack': RULE['pack']} fd, path = tempfile.mkstemp(suffix='.json') try: with open(path, 'a') as f: f.write(json.dumps(data, indent=4)) # Test without token. self.shell.run(['rule', 'update', rule_ref, path]) kwargs = {} requests.get.assert_called_with(get_url, **kwargs) kwargs = {'headers': {'content-type': 'application/json'}} requests.put.assert_called_with(put_url, json.dumps(RULE), **kwargs) # Test with token from cli. token = uuid.uuid4().hex self.shell.run(['rule', 'update', rule_ref, path, '-t', token]) kwargs = {'headers': {'X-Auth-Token': token}} requests.get.assert_called_with(get_url, **kwargs) kwargs = {'headers': {'content-type': 'application/json', 'X-Auth-Token': token}} requests.put.assert_called_with(put_url, json.dumps(RULE), **kwargs) # Test with token from env. token = uuid.uuid4().hex os.environ['ST2_AUTH_TOKEN'] = token self.shell.run(['rule', 'update', rule_ref, path]) kwargs = {'headers': {'X-Auth-Token': token}} requests.get.assert_called_with(get_url, **kwargs) kwargs = {'headers': {'content-type': 'application/json', 'X-Auth-Token': token}} requests.put.assert_called_with(put_url, json.dumps(RULE), **kwargs) finally: os.close(fd) os.unlink(path) @mock.patch.object( requests, 'get', mock.MagicMock(return_value=base.FakeResponse(json.dumps(RULE), 200, 'OK'))) @mock.patch.object( requests, 'delete', mock.MagicMock(return_value=base.FakeResponse('', 204, 'OK'))) def test_decorate_resource_delete(self): rule_ref = '%s.%s' % (RULE['pack'], RULE['name']) get_url = 'http://127.0.0.1:9101/v1/rules/%s' % rule_ref del_url = 'http://127.0.0.1:9101/v1/rules/%s' % RULE['id'] # Test without token. self.shell.run(['rule', 'delete', rule_ref]) kwargs = {} requests.get.assert_called_with(get_url, **kwargs) requests.delete.assert_called_with(del_url, **kwargs) # Test with token from cli. token = uuid.uuid4().hex self.shell.run(['rule', 'delete', rule_ref, '-t', token]) kwargs = {'headers': {'X-Auth-Token': token}} requests.get.assert_called_with(get_url, **kwargs) requests.delete.assert_called_with(del_url, **kwargs) # Test with token from env. token = uuid.uuid4().hex os.environ['ST2_AUTH_TOKEN'] = token self.shell.run(['rule', 'delete', rule_ref]) kwargs = {'headers': {'X-Auth-Token': token}} requests.get.assert_called_with(get_url, **kwargs) requests.delete.assert_called_with(del_url, **kwargs)
class TestKeyValueLoad(TestKeyValueBase): @mock.patch.object( requests, 'put', mock.MagicMock(return_value=base.FakeResponse(json.dumps(KEYVALUE), 200, 'OK'))) def test_load_keyvalue_json(self): """Test loading of key/value pair in JSON format """ fd, path = tempfile.mkstemp(suffix='.json') try: with open(path, 'a') as f: f.write(json.dumps(KEYVALUE, indent=4)) args = ['key', 'load', path] retcode = self.shell.run(args) self.assertEqual(retcode, 0) finally: os.close(fd) os.unlink(path) @mock.patch.object( requests, 'put', mock.MagicMock(return_value=base.FakeResponse(json.dumps(KEYVALUE), 200, 'OK'))) def test_load_keyvalue_yaml(self): """Test loading of key/value pair in YAML format """ fd, path = tempfile.mkstemp(suffix='.yaml') try: with open(path, 'a') as f: f.write(yaml.safe_dump(KEYVALUE)) args = ['key', 'load', path] retcode = self.shell.run(args) self.assertEqual(retcode, 0) finally: os.close(fd) os.unlink(path) @mock.patch.object( requests, 'put', mock.MagicMock(return_value=base.FakeResponse(json.dumps(KEYVALUE_USER), 200, 'OK'))) def test_load_keyvalue_user(self): """Test loading of key/value pair with the optional user field """ fd, path = tempfile.mkstemp(suffix='.json') try: with open(path, 'a') as f: f.write(json.dumps(KEYVALUE_USER, indent=4)) args = ['key', 'load', path] retcode = self.shell.run(args) self.assertEqual(retcode, 0) finally: os.close(fd) os.unlink(path) @mock.patch.object( requests, 'put', mock.MagicMock(return_value=base.FakeResponse(json.dumps(KEYVALUE_SECRET), 200, 'OK'))) def test_load_keyvalue_secret(self): """Test loading of key/value pair with the optional secret field """ fd, path = tempfile.mkstemp(suffix='.json') try: with open(path, 'a') as f: f.write(json.dumps(KEYVALUE_SECRET, indent=4)) args = ['key', 'load', path] retcode = self.shell.run(args) self.assertEqual(retcode, 0) finally: os.close(fd) os.unlink(path) @mock.patch.object( requests, 'put', mock.MagicMock(return_value=base.FakeResponse(json.dumps(KEYVALUE_PRE_ENCRYPTED), 200, 'OK'))) def test_load_keyvalue_already_encrypted(self): """Test loading of key/value pair with the pre-encrypted value """ fd, path = tempfile.mkstemp(suffix='.json') try: with open(path, 'a') as f: f.write(json.dumps(KEYVALUE_PRE_ENCRYPTED, indent=4)) args = ['key', 'load', path] retcode = self.shell.run(args) self.assertEqual(retcode, 0) finally: os.close(fd) os.unlink(path) @mock.patch.object( requests, 'put', mock.MagicMock(return_value=base.FakeResponse(json.dumps(KEYVALUE_TTL), 200, 'OK'))) def test_load_keyvalue_ttl(self): """Test loading of key/value pair with the optional ttl field """ fd, path = tempfile.mkstemp(suffix='.json') try: with open(path, 'a') as f: f.write(json.dumps(KEYVALUE_TTL, indent=4)) args = ['key', 'load', path] retcode = self.shell.run(args) self.assertEqual(retcode, 0) finally: os.close(fd) os.unlink(path) @mock.patch.object( requests, 'put', mock.MagicMock(return_value=base.FakeResponse(json.dumps(KEYVALUE_OBJECT), 200, 'OK'))) def test_load_keyvalue_object(self): """Test loading of key/value pair where the value is an object """ fd, path = tempfile.mkstemp(suffix='.json') try: with open(path, 'a') as f: f.write(json.dumps(KEYVALUE_OBJECT, indent=4)) # test converting with short option args = ['key', 'load', '-c', path] retcode = self.shell.run(args) self.assertEqual(retcode, 0) # test converting with long option args = ['key', 'load', '--convert', path] retcode = self.shell.run(args) self.assertEqual(retcode, 0) finally: os.close(fd) os.unlink(path) @mock.patch.object( requests, 'put', mock.MagicMock(return_value=base.FakeResponse(json.dumps(KEYVALUE_OBJECT), 200, 'OK'))) def test_load_keyvalue_object_fail(self): """Test failure to load key/value pair where the value is an object and the -c/--convert option is not passed """ fd, path = tempfile.mkstemp(suffix='.json') try: with open(path, 'a') as f: f.write(json.dumps(KEYVALUE_OBJECT, indent=4)) # test converting with short option args = ['key', 'load', path] retcode = self.shell.run(args) self.assertNotEqual(retcode, 0) finally: os.close(fd) os.unlink(path) @mock.patch.object( requests, 'put', mock.MagicMock(return_value=base.FakeResponse(json.dumps(KEYVALUE_ALL), 200, 'OK'))) def test_load_keyvalue_all(self): """Test loading of key/value pair with all optional fields """ fd, path = tempfile.mkstemp(suffix='.json') try: with open(path, 'a') as f: f.write(json.dumps(KEYVALUE_ALL, indent=4)) args = ['key', 'load', path] retcode = self.shell.run(args) self.assertEqual(retcode, 0) finally: os.close(fd) os.unlink(path) @mock.patch.object( requests, 'put', mock.MagicMock(return_value=base.FakeResponse(json.dumps(KEYVALUE_ALL), 200, 'OK'))) def test_load_keyvalue_array(self): """Test loading an array of key/value pairs """ fd, path = tempfile.mkstemp(suffix='.json') try: array = [KEYVALUE, KEYVALUE_ALL] json_str = json.dumps(array, indent=4) LOG.info(json_str) with open(path, 'a') as f: f.write(json_str) args = ['key', 'load', path] retcode = self.shell.run(args) self.assertEqual(retcode, 0) finally: os.close(fd) os.unlink(path) def test_load_keyvalue_missing_name(self): """Test loading of a key/value pair with the required field 'name' missing """ fd, path = tempfile.mkstemp(suffix='.json') try: with open(path, 'a') as f: f.write(json.dumps(KEYVALUE_MISSING_NAME, indent=4)) args = ['key', 'load', path] retcode = self.shell.run(args) self.assertEqual(retcode, 1) finally: os.close(fd) os.unlink(path) def test_load_keyvalue_missing_value(self): """Test loading of a key/value pair with the required field 'value' missing """ fd, path = tempfile.mkstemp(suffix='.json') try: with open(path, 'a') as f: f.write(json.dumps(KEYVALUE_MISSING_VALUE, indent=4)) args = ['key', 'load', path] retcode = self.shell.run(args) self.assertEqual(retcode, 1) finally: os.close(fd) os.unlink(path) def test_load_keyvalue_missing_file(self): """Test loading of a key/value pair with a missing file """ path = '/some/file/that/doesnt/exist.json' args = ['key', 'load', path] retcode = self.shell.run(args) self.assertEqual(retcode, 1) def test_load_keyvalue_bad_file_extension(self): """Test loading of a key/value pair with a bad file extension """ fd, path = tempfile.mkstemp(suffix='.badext') try: args = ['key', 'load', path] retcode = self.shell.run(args) self.assertEqual(retcode, 1) finally: os.close(fd) os.unlink(path) def test_load_keyvalue_empty_file(self): """ Loading K/V from an empty file shouldn't throw an error """ fd, path = tempfile.mkstemp(suffix='.yaml') try: args = ['key', 'load', path] retcode = self.shell.run(args) self.assertIn('No matching items found', self.stdout.getvalue()) self.assertEqual(retcode, 0) finally: os.close(fd) os.unlink(path)