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)
Beispiel #2
0
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)
Beispiel #4
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)
Beispiel #6
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)
Beispiel #7
0
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)
Beispiel #8
0
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)
Beispiel #9
0
 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"),
         )
Beispiel #10
0
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))
            )
Beispiel #11
0
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())
Beispiel #14
0
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")
Beispiel #15
0
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)
Beispiel #16
0
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)
Beispiel #17
0
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())
Beispiel #18
0
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)
Beispiel #19
0
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)
Beispiel #20
0
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)
Beispiel #21
0
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)
Beispiel #22
0
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)
Beispiel #23
0
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)
Beispiel #24
0
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, '')
Beispiel #25
0
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)
Beispiel #26
0
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')
Beispiel #27
0
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)
Beispiel #28
0
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)
Beispiel #30
0
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)