Beispiel #1
0
class TestAppianBase(unittest.TestCase):

    dir_path = os.path.dirname(os.path.realpath(__file__))
    form_content = read_mock_file("form_content_response.json")
    form_content_2 = read_mock_file("sites_record_nav.json")
    form_content_3 = read_mock_file("sites_record_recordType_resp.json")
    nested_dynamic_link_json = read_mock_file(
        "nested_dynamic_link_response.json")

    def setUp(self) -> None:
        self.custom_locust = CustomLocust(Locust())
        self.parent_task_set = TaskSet(self.custom_locust)
        setattr(self.parent_task_set, "host", "")
        setattr(self.parent_task_set, "credentials", [["", ""]])
        setattr(self.parent_task_set, "auth", ["a", "b"])

        self.task_set = AppianTaskSet(self.parent_task_set)
        self.task_set.host = ""

        self.task_set.on_start()

    def tearDown(self) -> None:
        if '__appianMultipartCsrfToken' in self.task_set.appian.client.cookies:
            self.task_set.on_stop()

    def test_determine_auth_with_only_auth_key(self) -> None:
        # Given
        for bad_creds in [[], "", None, 30]:
            setattr(self.parent_task_set, "credentials", bad_creds)

            # When
            auth = self.task_set.determine_auth()

            # Then
            self.assertEqual(["a", "b"], auth)

    def test_determine_auth_with_only_credentials_key(self) -> None:
        # Given
        setattr(self.parent_task_set, "auth", "")
        setattr(self.parent_task_set, "credentials",
                [["aa", "bb"], ["c", "d"]])

        # When the first hit is done
        auth1 = self.task_set.determine_auth()
        auth2 = self.task_set.determine_auth()
        auth3 = self.task_set.determine_auth()
        auth4 = self.task_set.determine_auth()

        # Then
        self.assertEqual(["aa", "bb"], auth1)  # Pop is FIFO
        self.assertEqual(["c", "d"], auth2)
        self.assertEqual(["c", "d"], auth3)
        self.assertEqual(["c", "d"], auth4)

    def test_determine_auth_with_credentials_and_auth_keys(self) -> None:
        # Given
        setattr(self.parent_task_set, "credentials",
                [["aa", "bb"], ["c", "d"]])

        # When the first hit is done
        auth1 = self.task_set.determine_auth()
        auth2 = self.task_set.determine_auth()
        auth3 = self.task_set.determine_auth()
        auth4 = self.task_set.determine_auth()

        # Then
        self.assertEqual(["aa", "bb"], auth1)  # Pop is FIFO
        self.assertEqual(["c", "d"], auth2)
        self.assertEqual(["a", "b"], auth3)
        self.assertEqual(["a", "b"], auth4)

    def test_login_good_auth(self) -> None:
        # Given
        init_cookies = {'JSESSIONID': 'abc', '__appianCsrfToken': '123'}
        cookies = {
            'JSESSIONID': 'abc123',
            '__appianCsrfToken': 'different cookie',
            '__appianMultipartCsrfToken': 'these cookies'
        }
        self.custom_locust.set_response("/suite/",
                                        200,
                                        '<html>A huge html blob</html>',
                                        cookies=init_cookies)
        self.custom_locust.set_response("/suite/auth?appian_environment=tempo",
                                        200,
                                        '<html>A huge html blob</html>',
                                        cookies=cookies)

        self.task_set.appian.login(["", ""])
        self.assertEqual(cookies, self.task_set.appian.client.cookies)

    def test_login_bad_auth(self) -> None:
        # Given
        self.custom_locust.set_response(
            "/suite/auth?appian_environment=tempo", 401,
            'The username/password entered is invalid')

        with self.assertRaisesRegex(BadCredentialsException,
                                    "Could not log in"):
            self.task_set.appian.login(["", ""])

    def test_login_bad_auth_bad_cookies(self) -> None:
        # Given
        cookies = {'JSESSIONID': 'abc', '__appianCsrfToken': '123'}
        self.custom_locust.set_response("/suite/",
                                        200,
                                        '<html>A huge html blob</html>',
                                        cookies=cookies)
        self.custom_locust.set_response("/suite/auth?appian_environment=tempo",
                                        200,
                                        '<html>A huge html blob</html>',
                                        cookies=cookies)

        with self.assertRaisesRegex(
                MissingCsrfTokenException,
                "Login unsuccessful, no multipart cookie found"):
            self.task_set.on_start()

    def test_instantiating_task_set(self) -> None:
        # Given
        ts = SampleAppianTaskSequence(self.custom_locust)

        # When
        task_name_1 = ts.get_next_task().__name__

        # Then
        self.assertEqual("first_task", task_name_1)

        # When called again
        task_name_2 = ts.get_next_task().__name__

        # Then the next task
        self.assertEqual("second_task", task_name_2)

        # When called the last time
        task_name_3 = ts.get_next_task().__name__

        # Then it wraps around
        self.assertEqual("first_task", task_name_3)

    def test_appian_client_on_its_own(self) -> None:
        # Given
        inner_client = MockClient()

        dir_path = os.path.dirname(os.path.realpath(__file__))
        actions = read_mock_file("actions_response.json")
        host = "https://my-fake-host.com"
        inner_client.set_response(
            f"{host}/suite/api/tempo/open-a-case/available-actions?ids=%5B%5D",
            200, actions)
        appian_client = AppianClient(inner_client, "https://my-fake-host.com")

        # When
        client, resp = appian_client.login(["a", "1"])
        appian_client.actions.get_all()

        # Then
        self.assertEqual(200, resp.status_code)

    def test_procedurally_generate_credentials(self) -> None:
        # Given
        CONFIG = {
            "procedural_credentials_prefix": "employee",
            "procedural_credentials_count": 3,
            "procedural_credentials_password": "******"
        }

        expected_credentials = [['employee1', 'pass'], ['employee2', 'pass'],
                                ['employee3', 'pass']]
        # When
        procedurally_generate_credentials(CONFIG)

        # Then
        self.assertEqual(expected_credentials, CONFIG["credentials"])

    def test_procedurally_generate_credentials_keys_missing(self) -> None:
        # Given
        CONFIG = {
            "procedural_credentials_prefix": "employee",
            "procedural_credentials_password": "******"
        }

        # When
        with self.assertRaisesRegex(MissingConfigurationException,
                                    '["procedural_credentials_count"]'):
            procedurally_generate_credentials(CONFIG)

    def test_procedurally_generate_credentials_multiple_keys_missing(
            self) -> None:
        # Given
        CONFIG2 = {'unrelated': 'config'}

        # When
        with self.assertRaisesRegex(
                MissingConfigurationException,
                '["procedural_credentials_prefix", "procedural_credentials_count", "procedural_credentials_password"]'
        ):
            procedurally_generate_credentials(CONFIG2)

    def test_setup_distributed_creds(self) -> None:
        # Given
        CONFIG = {
            "credentials": [['employee1', 'pass'], ['employee2', 'pass'],
                            ['employee3', 'pass']]
        }
        os.environ["STY"] = "64331.locustdriver-2-0"
        expected_config = [['employee1', 'pass'], ['employee3', 'pass']]

        # When
        setup_distributed_creds(CONFIG)
        self.assertEqual(CONFIG["credentials"], expected_config)

    def test_setup_distributed_creds_2(self) -> None:
        # Given
        CONFIG = {
            "credentials": [['employee1', 'pass'], ['employee2', 'pass'],
                            ['employee3', 'pass']]
        }
        os.environ["STY"] = "64331.locustdriver-2-1"
        expected_config = [['employee2', 'pass']]

        # When
        setup_distributed_creds(CONFIG)
        self.assertEqual(CONFIG["credentials"], expected_config)

    def test_setup_distributed_creds_fewer_credentials_than_workers(
            self) -> None:
        # Given
        CONFIG = {"credentials": [['employee1', 'pass']]}
        os.environ["STY"] = "64331.locustdriver-2-1"
        expected_config = [['employee1', 'pass']]

        # When
        setup_distributed_creds(CONFIG)
        self.assertEqual(CONFIG["credentials"], expected_config)

    def test_setup_distributed_creds_fails_missing_key(self) -> None:
        # Given
        CONFIG = {'unrelated': 'config'}

        # When
        with self.assertRaisesRegex(MissingConfigurationException,
                                    '["credentials"]'):
            setup_distributed_creds(CONFIG)
Beispiel #2
0
class TestTask(unittest.TestCase):

    task_feed_resp = read_mock_file("tasks_response.json")
    task_feed_with_next = read_mock_file("tasks_response_with_next.json")

    def get_task_attributes(self, is_auto_acceptable: bool) -> str:
        return f"""
        {{
            "isOfflineTask": false,
            "isSailTask": true,
            "isQuickTask": false,
            "taskId": "1",
            "isAutoAcceptable": {'true' if is_auto_acceptable else 'false'}
        }}"""

    def setUp(self) -> None:
        self.custom_locust = CustomLocust(Locust())
        parent_task_set = TaskSet(self.custom_locust)
        setattr(parent_task_set, "host", "")
        setattr(parent_task_set, "auth", ["", ""])
        self.task_set = AppianTaskSet(parent_task_set)
        self.task_set.host = ""

        # test_on_start_auth_success is covered here.
        self.custom_locust.set_response("auth?appian_environment=tempo", 200,
                                        '{}')
        self.custom_locust.set_default_response(200, "{}")
        self.task_set.on_start()
        self.custom_locust.set_response(
            "/suite/rest/a/task/latest/1/attributes", 200,
            self.get_task_attributes(is_auto_acceptable=True))
        self.custom_locust.set_response(_Tasks.INITIAL_FEED_URI, 200,
                                        self.task_feed_resp)

    def tearDown(self) -> None:
        self.task_set.on_stop()

    def test_task_get_all(self) -> None:
        self.custom_locust.enqueue_response(200, self.task_feed_with_next)
        self.custom_locust.enqueue_response(200, self.task_feed_resp)
        all_task = self.task_set.appian.tasks.get_all()

        self.assertEqual(len(all_task.keys()), 21)
        # TODO: These keys are bad, as are the record/ report keys, consider just using the names/ IDs
        self.assertEqual(
            all_task['t-2109072_34 Task_Assign SR#0G56-W7N3 to Case Worker']
            ['id'], 't-2109072')

    def test_task_get(self) -> None:
        task = self.task_set.appian.tasks.get_task("t-1", False)
        self.assertIsInstance(task, dict)

    def test_task_get_missing_task(self) -> None:
        with self.assertRaisesRegex(
                Exception,
                "There is no task with name .* in the system under test.*"):
            self.task_set.appian.tasks.get_task("some random word")

    def test_task_visit(self) -> None:
        output = self.task_set.appian.tasks.visit("t-1", False)
        self.assertEqual(output, {})

    def test_task_visit_and_get_form(self) -> None:
        task_to_accept = read_mock_file('task_accept_resp.json')
        self.custom_locust.set_response("/suite/rest/a/task/latest/1/status",
                                        200, task_to_accept)
        self.custom_locust.set_response(
            "/suite/rest/a/task/latest/1/attributes", 200,
            self.get_task_attributes(is_auto_acceptable=False))
        output = self.task_set.appian.tasks.visit_and_get_form("t-1", False)

        self.assertEqual(output.form_url, "/suite/rest/a/task/latest/1/form")
Beispiel #3
0
class TestSites(unittest.TestCase):
    def setUp(self) -> None:
        self.custom_locust = CustomLocust(Locust())
        parent_task_set = TaskSet(self.custom_locust)
        setattr(parent_task_set, "host", "")
        setattr(parent_task_set, "auth", ["", ""])
        self.task_set = AppianTaskSet(parent_task_set)
        self.task_set.host = ""

        # test_on_start_auth_success is covered here.
        self.custom_locust.set_response("auth?appian_environment=tempo", 200,
                                        '{}')
        self.task_set.on_start()

        all_sites_str = read_mock_file("all_sites.json")
        self.custom_locust.set_response(_Sites.TEMPO_SITE_PAGE_NAV, 200,
                                        all_sites_str)

        # Default responses are page responses
        page_resp_json = read_mock_file("page_resp.json")
        self.custom_locust.client.set_default_response(200, page_resp_json)

    def tearDown(self) -> None:
        self.task_set.on_stop()

    def test_sites_get_all(self) -> None:
        page_resp_json = read_mock_file("page_resp.json")
        site_nav_resp = read_mock_file("sites_nav_resp.json")
        all_sites_str = read_mock_file("all_sites.json")
        self.custom_locust.client.enqueue_response(200, all_sites_str)
        for i in range(136):
            self.custom_locust.client.enqueue_response(200, site_nav_resp)
            for i in range(5):
                self.custom_locust.client.enqueue_response(200, page_resp_json)

        self.task_set.appian.sites.get_all()
        all_sites = self.task_set.appian.sites._sites
        self.assertEqual(len(all_sites.keys()), 136)
        self.assertTrue("rla" in all_sites, "rla not found in list of sites")

        # Spot check
        rla_site = all_sites["rla"]
        self.assertEqual(len(rla_site.pages.keys()), 5)
        self.assertEqual(rla_site.pages['create-mrn'].page_type,
                         PageType.REPORT)

    def set_sites_json(self, site_name: str) -> None:
        sites_nav_resp = read_mock_file("sites_nav_resp.json")
        self.custom_locust.set_response(
            f"/suite/rest/a/sites/latest/{site_name}/nav", 200, sites_nav_resp)

    def test_sites_get(self) -> None:
        site_name = 'mrn'
        self.set_sites_json(site_name)
        site = self.task_set.appian.sites.get_site_data_by_site_name('mrn')

    def test_sites_link_type(self) -> None:
        for type_pair in [('InternalActionLink', 'action'),
                          ('InternalReportLink', 'report'),
                          ('SiteRecordTypeLink', 'recordType')]:
            original_link_type = type_pair[0]
            expected_link_type = type_pair[1]
            link_full = f"{{http://www.host.net/ae/types/2009}}{original_link_type}"
            link_type = self.task_set.appian.sites._get_type_from_link_type(
                link_full)
            self.assertEqual(link_type.value, expected_link_type)

    def test_sites_bad_link_type(self) -> None:
        with self.assertRaises(Exception) as e:
            bad_link_type = "this is garbage"
            self.task_set.appian.sites._get_type_from_link_type(bad_link_type)
        self.assertEqual(e.exception.args[0],
                         f"Invalid Link Type: {bad_link_type}")

    def test_navigate_to_tab_error_cases(self) -> None:
        site_name = "abc"
        self.set_sites_json(site_name)
        with self.assertRaises(SiteNotFoundException):
            self.task_set.appian.sites.navigate_to_tab("other_site", "123")
        with self.assertRaises(PageNotFoundException):
            self.task_set.appian.sites.navigate_to_tab(site_name, "123")

    def test_navigate_to_tab_success(self) -> None:
        site_name = "abc"
        page_name = "create-mrn"
        link_type = "report"  # Default Page Info

        self.set_sites_json(site_name)

        self.custom_locust.set_response(
            f"/suite/rest/a/sites/latest/{site_name}/pages/{page_name}/{link_type}",
            200, '{"test":"abc"}')
        tab_resp = self.task_set.appian.sites.navigate_to_tab(
            site_name, page_name)
        self.assertEqual({'test': 'abc'}, tab_resp.json())

    def test_visit_and_get_form_success(self) -> None:
        site_name = "abc"
        page_name = "create-mrn"
        link_type = "report"  # Default Page Info

        self.set_sites_json(site_name)
        expected_uuid = 'abc123'
        expected_context = '{"abc":"123"}'
        form_content = f'{{"context":{expected_context}, "uuid":"{expected_uuid}"}}'
        expected_url = f"/suite/rest/a/sites/latest/{site_name}/pages/{page_name}/{link_type}"
        self.custom_locust.set_response(expected_url, 200, form_content)
        ui_form: SailUiForm = self.task_set.appian.sites.visit_and_get_form(
            site_name, page_name)
        self.assertEqual(expected_uuid, ui_form.uuid)
        self.assertEqual(json.loads(expected_context), ui_form.context)
        self.assertEqual(expected_url, ui_form.form_url)

    def test_navigate_to_tab_and_record_report_success(self) -> None:
        site_name = "abc"
        page_name = "create-mrn"
        link_type = "report"  # Default Page Info

        self.set_sites_json(site_name)

        self.custom_locust.set_response(
            f"/suite/rest/a/sites/latest/{site_name}/pages/{page_name}/{link_type}",
            200, '{"test":"abc"}')
        tab_resp = self.task_set.appian.sites.navigate_to_tab_and_record_if_applicable(
            site_name, page_name)
        self.assertEqual({'test': 'abc'}, tab_resp.json())

    def test_get_sites_records(self) -> None:
        site_name = "orders"
        page_name = "orders"
        link_type = "recordType"

        nav_resp = read_mock_file("sites_record_nav.json")
        page_resp = read_mock_file("sites_record_page_resp.json")
        record_resp = read_mock_file("sites_record_recordType_resp.json")

        for endpoint in [
                f"/suite/rest/a/sites/latest/{site_name}/nav",
                f"/suite/rest/a/sites/latest/{site_name}/pages/{page_name}/nav"
        ]:
            self.custom_locust.set_response(endpoint, 200, nav_resp)

        nav_ui = json.loads(nav_resp)
        for mocked_page_name in self.task_set.appian.sites.get_page_names_from_ui(
                nav_ui):
            self.custom_locust.set_response(
                f"/suite/rest/a/applications/latest/legacy/sites/{site_name}/page/{mocked_page_name}",
                200, page_resp)
        self.custom_locust.set_response(
            f"/suite/rest/a/sites/latest/{site_name}/pages/{page_name}/{link_type}",
            200, record_resp)

        self.custom_locust.set_default_response(200, record_resp)

        resp = self.task_set.appian.sites.navigate_to_tab_and_record_if_applicable(
            site_name, page_name)

        self.assertEqual(resp.text, record_resp)
class TestActions(unittest.TestCase):

    actions = read_mock_file("actions_response.json")

    action_under_test = "Create a Case::koBOPgHGLIgHRQzrdseY6-wW_trk0FY-87TIog3LDZ9dbSn9dYtlSaOQlWaz7PcZgV5FWdIgYk8QRlv1ARbE4czZL_8fj4ckCLzqA"

    def setUp(self) -> None:
        self.custom_locust = CustomLocust(Locust())
        parent_task_set = TaskSet(self.custom_locust)
        setattr(parent_task_set, "host", "")
        setattr(parent_task_set, "auth", ["", ""])
        self.task_set = AppianTaskSet(parent_task_set)
        self.task_set.host = ""

        # test_on_start_auth_success is covered here.
        self.custom_locust.set_response("auth?appian_environment=tempo", 200,
                                        '{}')
        self.task_set.on_start()

        self.custom_locust.set_response(
            "/suite/api/tempo/open-a-case/available-actions?ids=%5B%5D", 200,
            self.actions)

    def tearDown(self) -> None:
        self.task_set.on_stop()

    def test_actions_get_all(self) -> None:
        all_actions = self.task_set.appian.actions.get_all()
        self.assertTrue(len(list(all_actions.keys())) > 0)

    def test_actions_get(self) -> None:
        action = self.task_set.appian.actions.get_action(
            self.action_under_test)
        self.assertEqual(action['displayLabel'], 'Create a Case')

    def test_actions_get_corrupt_action(self) -> None:
        corrupt_actions = self.actions.replace(
            '"opaqueId": "koBOPgHGLIgHRQzrdseZ66wChtz5aQqM_RBTDeSBi9lWr4b18XPJqrikBSQYzzp8_e2Wgw0ku-apJjK94StAV1R3DU5zipwSXfCTA"',
            '"corrupt_opaqueId": "koBOPgHGLIgHRQzrdseZ66wChtz5aQqM_RBTDeSBi9lWr4b18XPJqrikBSQYzzp8_e2Wgw0ku-apJjK94StAV1R3DU5zipwSXfCTA"'
        )
        self.custom_locust.set_response(
            "/suite/api/tempo/open-a-case/available-actions?ids=%5B%5D", 200,
            corrupt_actions)
        all_actions = self.task_set.appian.actions.get_all()
        self.assertTrue("ERROR::1" in str(all_actions))
        self.assertTrue(self.task_set.appian.actions._errors == 1)

    def test_actions_zero_actions(self) -> None:
        corrupt_actions = self.actions.replace('"actions"',
                                               '"nonexistent_actions"')
        self.custom_locust.set_response(
            "/suite/api/tempo/open-a-case/available-actions?ids=%5B%5D", 200,
            corrupt_actions)
        all_actions = self.task_set.appian.actions.get_all()
        self.assertTrue(all_actions == {})

    def test_actions_get_partial_match(self) -> None:
        action = self.task_set.appian.actions.get_action(
            "Create a Case", False)
        self.assertEqual(action['displayLabel'], 'Create a Case')

    def test_actions_get_multiple_matches(self) -> None:
        self.task_set.appian.actions._actions = dict()  # Resetting the cache.
        action = self.task_set.appian.actions.get_action("Create a C", False)
        self.assertTrue("Create a C" in action['displayLabel'])

    def test_actions_get_missing_action(self) -> None:
        with self.assertRaisesRegex(
                Exception,
                "There is no action with name .* in the system under test.*"):
            self.task_set.appian.actions.get_action("Create a Case",
                                                    exact_match=True)

    def setup_action_response_no_ui(self) -> None:
        action = self.task_set.appian.actions.get_action(
            "Create a Case", False)
        self.custom_locust.set_response(action['formHref'], 200, "{}")

    def setup_action_response_with_ui(
            self, file_name: str = "form_content_response.json") -> None:
        action = self.task_set.appian.actions.get_action(
            "Create a Case", False)
        resp_json = read_mock_file(file_name)
        self.custom_locust.set_response(action['formHref'], 200, resp_json)

    def test_actions_visit(self) -> None:
        self.setup_action_response_no_ui()
        action = self.task_set.appian.actions.visit("Create a Case", False)
        self.assertIsInstance(action, dict)

    def test_actions_start(self) -> None:
        self.setup_action_response_no_ui()
        self.task_set.appian.actions.start_action(self.action_under_test)

    def test_actions_start_skip_design_call(self) -> None:
        self.task_set.appian.actions.start_action(self.action_under_test, True)

    def test_actions_form_example_success(self) -> None:
        # output of get_page of a form (SAIL)
        self.setup_action_response_with_ui()
        self.custom_locust.set_response(
            '/suite/rest/a/model/latest/228/form', 200,
            '{"context":"12345","ui": {"#t": "UiComponentsDelta", "modifiedComponents":[]}}'
        )
        sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form(
            "Create a Case", False)

        label = 'Title'
        value = "Look at me, I am filling out a form"
        button_label = 'Submit'
        latest_form = sail_form.fill_text_field(label,
                                                value).click(button_label)

        resp = latest_form.get_response()
        self.assertEqual("12345", resp['context'])

    def test_actions_form_example_activity_chained(self) -> None:
        action = self.task_set.appian.actions.get_action(
            "Create a Case", False)
        resp_json = read_mock_file("form_content_response.json")

        self.custom_locust.set_response(
            action['formHref'], 200,
            '{"mobileEnabled": "false", "empty": "true", "formType": "START_FORM"}'
        )
        self.custom_locust.set_response(action['initiateActionHref'], 200,
                                        resp_json)
        self.custom_locust.set_response(
            '/suite/rest/a/model/latest/228/form', 200,
            '{"context":"12345","ui": {"#t": "UiComponentsDelta", "modifiedComponents":[]}}'
        )
        sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form(
            "Create a Case")

        label = 'Title'
        value = "Look at me, I am filling out a form"
        button_label = 'Submit'
        latest_form = sail_form.fill_text_field(label,
                                                value).click(button_label)

        resp = latest_form.get_response()
        self.assertEqual("12345", resp['context'])

    def test_actions_form_example_missing_field(self) -> None:
        self.setup_action_response_with_ui()
        sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form(
            "Create a Case", False)

        value = "Look at me, I am filling out a form"
        label = "missingText"
        with self.assertRaises(ComponentNotFoundException) as context:
            sail_form.fill_text_field(label, value)
        self.assertEqual(
            context.exception.args[0],
            f"Could not find the component with label '{label}' in the provided form"
        )

        button_label = 'press me'
        with self.assertRaises(ComponentNotFoundException) as context:
            sail_form.click(button_label)
        self.assertEqual(
            context.exception.args[0],
            f"Could not find the component with label '{button_label}' in the provided form"
        )

    def test_actions_form_example_bad_response(self) -> None:
        self.setup_action_response_with_ui()
        sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form(
            "Create a Case", False)

        self.custom_locust.set_response('/suite/rest/a/model/latest/228/form',
                                        200, 'null')

        value = "Look at me, I am filling out a form"
        label = "Title"
        with self.assertRaises(Exception) as context:
            sail_form.fill_text_field(label, value)
        self.assertEqual(
            context.exception.args[0],
            f"No response returned when trying to update field with label '{label}'"
        )

        button_label = 'Submit'
        with self.assertRaises(Exception) as context:
            sail_form.click(button_label)
        self.assertEqual(
            context.exception.args[0],
            f"No response returned when trying to click button with label '{button_label}'"
        )

    def test_actions_form_dropdown_errors(self) -> None:
        self.setup_action_response_with_ui('dropdown_test_ui.json')

        sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form(
            "Create a Case", False)

        dropdown_label = "missing dropdown"
        with self.assertRaises(ComponentNotFoundException) as context:
            sail_form.select_dropdown_item(dropdown_label, 'some choice')
        self.assertEqual(
            context.exception.args[0],
            f"Could not find the component with label '{dropdown_label}' in the provided form"
        )

        dropdown_label = "Name"
        with self.assertRaises(InvalidComponentException):
            sail_form.select_dropdown_item(dropdown_label, 'some choice')

        dropdown_label = "Customer Type"
        with self.assertRaises(ChoiceNotFoundException):
            sail_form.select_dropdown_item(dropdown_label,
                                           'some missing choice')

    @patch('appian_locust.SailUiForm._get_update_url_for_reeval',
           return_value="/mocked/re-eval/url")
    @patch('appian_locust.uiform._Interactor.send_dropdown_update')
    def test_actions_form_dropdown_success(
            self, mock_send_dropdown_update: MagicMock,
            mock_get_update_url_for_reeval: MagicMock) -> None:
        self.setup_action_response_with_ui('dropdown_test_ui.json')

        sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form(
            "Create a Case", False)
        initial_state = sail_form.state

        dropdown_label = "Customer Type"
        sail_form.select_dropdown_item(dropdown_label,
                                       'Buy Side Asset Manager')

        mock_get_update_url_for_reeval.assert_called_once_with(initial_state)
        mock_send_dropdown_update.assert_called_once()
        args, kwargs = mock_send_dropdown_update.call_args
        self.assertEqual(args[0], "/mocked/re-eval/url")
        self.assertIsNone(kwargs["url_stub"])
        self.assertNotEqual(sail_form.state, initial_state)

    @patch('appian_locust.SailUiForm._get_update_url_for_reeval',
           return_value="/mocked/re-eval/url")
    @patch('appian_locust.uiform._Interactor.send_dropdown_update')
    def test_actions_form_record_list_dropdown_success(
            self, mock_send_dropdown_update: MagicMock,
            mock_get_update_url_for_reeval: MagicMock) -> None:
        # 'dropdown_test_record_list_ui.json' contains a 'sail-application-url' field
        self.setup_action_response_with_ui('dropdown_test_record_list_ui.json')

        sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form(
            "Create a Case", False)
        initial_state = sail_form.state

        dropdown_label = "Customer Type"
        sail_form.select_dropdown_item(dropdown_label,
                                       'Buy Side Asset Manager')

        mock_get_update_url_for_reeval.assert_called_once_with(initial_state)
        mock_send_dropdown_update.assert_called_once()
        args, kwargs = mock_send_dropdown_update.call_args
        self.assertEqual(args[0], "/mocked/re-eval/url")
        self.assertEqual(kwargs["url_stub"], "url_stub123")
        self.assertNotEqual(sail_form.state, initial_state)

    @patch('appian_locust.uiform._Interactor.send_multiple_dropdown_update')
    def test_multiple_dropdown_not_found(
            self, mock_send_multiple_dropdown_update: MagicMock) -> None:
        self.setup_action_response_with_ui('dropdown_test_ui.json')
        sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form(
            "Create a Case", False)

        dropdown_label = "Regions wrong label"
        with self.assertRaises(ComponentNotFoundException) as context:
            sail_form.select_multi_dropdown_item(dropdown_label, ["Asia"])
        self.assertEqual(
            context.exception.args[0],
            f"Could not find the component with label '{dropdown_label}' in the provided form"
        )

        dropdown_label = "Regions"
        sail_form.select_multi_dropdown_item(dropdown_label, ["Asia"])
        mock_send_multiple_dropdown_update.assert_called_once()
        args, kwargs = mock_send_multiple_dropdown_update.call_args

    @patch('appian_locust.uiform.find_component_by_attribute_in_dict')
    @patch('appian_locust.uiform._Interactor.select_radio_button')
    def test_actions_form_radio_button_by_label_success(
            self, mock_select_radio_button: MagicMock,
            mock_find_component_by_label: MagicMock) -> None:
        self.setup_action_response_with_ui('dropdown_test_ui.json')

        sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form(
            "Create a Case", False)
        state1 = sail_form.state

        button_label = "test-radio-button"
        sail_form.select_radio_button_by_test_label(button_label, 1)

        button_label = "Qualified Institutional Buyer"
        sail_form.select_radio_button_by_label(button_label, 1)

        args, kwargs = mock_find_component_by_label.call_args_list[0]
        self.assertEqual('testLabel', args[0])

        args_next_call, kwargs_next_call = mock_find_component_by_label.call_args_list[
            1]
        self.assertEqual('label', args_next_call[0])
        self.assertEqual(2, len(mock_select_radio_button.call_args_list))

    def test_actions_form_radio_button_by_label_error(self) -> None:
        self.setup_action_response_with_ui('dropdown_test_ui.json')

        sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form(
            "Create a Case", False)

        button_label = "missing button"
        with self.assertRaises(ComponentNotFoundException) as context:
            sail_form.select_radio_button_by_test_label(button_label, 1)
        self.assertEqual(
            context.exception.args[0],
            f"Could not find the component with label '{button_label}' in the provided form"
        )

        with self.assertRaises(ComponentNotFoundException) as context:
            sail_form.select_radio_button_by_label(button_label, 1)
        self.assertEqual(
            context.exception.args[0],
            f"Could not find the component with label '{button_label}' in the provided form"
        )

    @patch('appian_locust.uiform.find_component_by_index_in_dict')
    @patch('appian_locust.uiform._Interactor.select_radio_button')
    def test_actions_form_radio_button_by_index_success(
            self, mock_select_radio_button: MagicMock,
            mock_find_component_by_index: MagicMock) -> None:
        self.setup_action_response_with_ui('dropdown_test_ui.json')
        sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form(
            "Create a Case", False)
        initial_state = sail_form.state
        button_index = 1
        sail_form.select_radio_button_by_index(button_index, 1)

        mock_select_radio_button.assert_called_once()
        mock_find_component_by_index.assert_called_with(
            'RadioButtonField', button_index, initial_state)
        self.assertNotEqual(sail_form.state, initial_state)

    def test_actions_form_radio_button_by_index_error(self) -> None:
        self.setup_action_response_with_ui('dropdown_test_ui.json')

        sail_form: SailUiForm = self.task_set.appian.actions.visit_and_get_form(
            "Create a Case", False)

        index_too_low = -1
        with self.assertRaises(Exception) as context:
            sail_form.select_radio_button_by_index(index_too_low, 1)
        self.assertEqual(
            context.exception.args[0],
            f"Invalid index: '{index_too_low}'.  Please enter a positive number"
        )

        index_too_high = 4
        with self.assertRaises(Exception) as context:
            sail_form.select_radio_button_by_index(index_too_high, 1)
        self.assertEqual(
            context.exception.args[0],
            f"Bad index: only '3' components of type 'RadioButtonField' found on page, requested '{index_too_high}'"
        )

        index_invalid = "bad index"
        with self.assertRaises(Exception) as context:
            sail_form.select_radio_button_by_index(index_invalid, 1)
        self.assertEqual(
            context.exception.args[0],
            f"Invalid index: '{index_invalid}'.  Please enter a positive number"
        )
Beispiel #5
0
class TestNews(unittest.TestCase):

    news = read_mock_file("news_response.json")

    def setUp(self) -> None:
        self.custom_locust = CustomLocust(Locust())
        parent_task_set = TaskSet(self.custom_locust)
        setattr(parent_task_set, "host", "")
        setattr(parent_task_set, "auth", ["", ""])
        self.task_set = AppianTaskSet(parent_task_set)
        self.task_set.host = ""

        # test_on_start_auth_success is covered here.
        self.custom_locust.set_response("auth?appian_environment=tempo", 200, '{}')
        self.task_set.on_start()

        self.custom_locust.set_response(NEWS_URI, 200, self.news)

    def tearDown(self) -> None:
        self.task_set.on_stop()

    def test_news_get_all(self) -> None:
        all_news = self.task_set.appian.news.get_all()
        self.assertIsInstance(all_news, dict)

    def test_news_search(self) -> None:
        self.custom_locust.set_response("/suite/api/feed/tempo?q=appian", 200, self.news)
        all_news = self.task_set.appian.news.search("appian")
        self.assertIsInstance(all_news, dict)

    def test_news_get(self) -> None:
        news = self.task_set.appian.news.get_news(
            "x-1::Administrator Custom")
        self.assertIsInstance(news, dict)

    def test_news_get_corrupt_news_post(self) -> None:
        corrupt_news = self.news.replace('"id": "x-3"', '"corrupt_id": "x-3"')
        self.custom_locust.set_response(NEWS_URI, 200, corrupt_news)
        all_news = self.task_set.appian.news.get_all()
        self.assertTrue("ERROR::1" in str(all_news))
        self.assertTrue(self.task_set.appian.news._errors == 1)

    def test_actions_get_retry(self) -> None:
        self.task_set.appian.news._news = dict()  # Resetting the cache.
        self.custom_locust.set_response("/suite/api/feed/tempo?q=Admin", 200, self.news)
        action = self.task_set.appian.news.get_news(
            "x-1::Administrator Custom", True, "Admin")
        self.assertIsInstance(action, dict)

    def test_news_get_missing_news(self) -> None:
        with self.assertRaisesRegex(Exception, "There is no news with name .* in the system under test.*"):
            self.task_set.appian.news.get_news("some random word")

    def test_news_visit(self) -> None:
        self.task_set.appian.news.visit("x-1", False)

    def test_news_visit_entry(self) -> None:
        self.custom_locust.set_response("/suite/api/feed/tempo?q=appian", 200, self.news)
        self.assertEqual((200, 200), self.task_set.appian.news.visit_news_entry("x-1", False))

    def test_news_visit_entry_no_share_link(self) -> None:
        self.custom_locust.set_response("/suite/api/feed/tempo?q=appian", 200, self.news)
        self.assertEqual(self.task_set.appian.news.visit_news_entry("x-2", False), (None, 200))

    def test_news_visit_entry_no_edit_link(self) -> None:
        self.custom_locust.set_response("/suite/api/feed/tempo?q=appian", 200, self.news)
        self.assertEqual(self.task_set.appian.news.visit_news_entry("x-3", False), (200, None))

    def test_news_get_all_logic(self) -> None:
        test_cases = [
            {
                "input": '{"feed":{"entries":[{"title": "valid_test", "id": "123"}]}}',
                "expected": {'123::valid_test': {'title': 'valid_test', 'id': '123'}}
            },
            {
                "input": '{"feed":{"not_entries":[{"title": "valid_test", "id": "123"}]}}',
                "expected": {}
            },
            {
                "input": '{"not_feed":{"entries":[{"title": "valid_test", "id": "123"}]}}',
                "expected": {}
            },
            {
                "input": '{"feed":{"entries":[{"not_title": "valid_test", "id": "123"}]}}',
                "expected": {}
            }
        ]
        for test_case in test_cases:
            # Given
            self.custom_locust.set_response(NEWS_URI,
                                            200,
                                            str(test_case['input']))
            # When
            response = self.task_set.appian.news.get_all()
            # Then
            self.assertEqual(response, test_case['expected'])
class TestReports(unittest.TestCase):
    reports = read_mock_file("reports_response.json")

    def setUp(self) -> None:
        self.custom_locust = CustomLocust(Locust())
        parent_task_set = TaskSet(self.custom_locust)
        setattr(parent_task_set, "host", "")
        setattr(parent_task_set, "auth", ["", ""])
        self.task_set = AppianTaskSet(parent_task_set)
        self.task_set.host = ""

        # test_on_start_auth_success is covered here.
        self.custom_locust.set_response("auth?appian_environment=tempo", 200,
                                        '{}')
        self.task_set.on_start()

        self.custom_locust.set_response(
            "/suite/rest/a/uicontainer/latest/reports", 200, self.reports)

    def tearDown(self) -> None:
        self.task_set.on_stop()

    def test_reports_get_all(self) -> None:
        all_reports = self.task_set.appian.reports.get_all()
        self.assertIsInstance(all_reports, dict)

    def test_reports_get(self) -> None:
        reports = self.task_set.appian.reports.get_report(
            "RTE Basic Test Report::qdjDPA")
        self.assertIsInstance(reports, dict)

    def test_reports_get_corrupt_report(self) -> None:
        corrupt_reports = self.reports.replace(
            '"title": "!!SAIL test charts"',
            '"corrupt_title": "!!SAIL test charts"')
        self.custom_locust.set_response(
            "/suite/rest/a/uicontainer/latest/reports", 200, corrupt_reports)
        all_reports = self.task_set.appian.reports.get_all()
        self.assertTrue("ERROR::1" in str(all_reports))
        self.assertEqual(1, self.task_set.appian.reports._errors)

    def test_reports_zero_reports(self) -> None:
        corrupt_reports = self.reports.replace('"entries"',
                                               '"nonexistent_entries"')
        self.custom_locust.set_response(
            "/suite/rest/a/uicontainer/latest/reports", 200, corrupt_reports)
        all_reports = self.task_set.appian.reports.get_all()
        self.assertTrue(all_reports == {})

    def test_reports_get_missing_report(self) -> None:
        with self.assertRaisesRegex(
                Exception,
                "There is no report with name .* in the system under test.*"):
            self.task_set.appian.reports.get_report("some random word")

    def test_reports_visit(self) -> None:
        self.custom_locust.set_response(
            "/suite/rest/a/sites/latest/D6JMim/pages/reports/report/qdjDPA/reportlink",
            200, "{}")
        output = self.task_set.appian.reports.visit(
            "RTE Basic Test Report::qdjDPA")
        self.assertEqual(output, dict())

    def test_reports_form_example_success(self) -> None:
        self.custom_locust.set_response(
            "/suite/rest/a/sites/latest/D6JMim/pages/reports/report/qdjDPA/reportlink",
            200, '{"context":123, "uuid":123}')

        sail_form = self.task_set.appian.reports.visit_and_get_form(
            "RTE Basic Test Report", False)
        self.assertTrue(isinstance(sail_form, SailUiForm))

    def test_reports_form_example_failure(self) -> None:
        self.custom_locust.set_response(
            "/suite/rest/a/sites/latest/D6JMim/pages/reports/report/qdjDPA/reportlink",
            200, '{"context":123, "uuid":123}')

        report_name = "Fake Report"
        exact_match = False
        with self.assertRaises(Exception) as context:
            self.task_set.appian.reports.visit_and_get_form(
                report_name, exact_match)
        self.assertEqual(
            context.exception.args[0],
            f"There is no report with name {report_name} in the system under test (Exact match = {exact_match})"
        )
Beispiel #7
0
class TestRecords(unittest.TestCase):
    record_types = read_mock_file("record_types_response.json")
    # Record Insance List for a specific RecordType
    records = read_mock_file("records_response.json")
    # Record Summary dashboard response for a specific Record Instance
    record_summary_view = read_mock_file("record_summary_view_response.json")
    record_instance_name = "Actions Page"

    def setUp(self) -> None:
        self.custom_locust = CustomLocust(Locust())
        parent_task_set = TaskSet(self.custom_locust)
        setattr(parent_task_set, "host", "")
        setattr(parent_task_set, "auth", ["", ""])
        self.task_set = AppianTaskSet(parent_task_set)
        self.task_set.host = ""

        # test_on_start_auth_success is covered here.
        self.custom_locust.set_response("auth?appian_environment=tempo", 200,
                                        '{}')
        if not hasattr(self.task_set, 'appian'):
            self.task_set.on_start()

        self.custom_locust.set_response(
            "/suite/rest/a/applications/latest/app/records/view/all", 200,
            self.record_types)
        self.custom_locust.set_response(
            "/suite/rest/a/sites/latest/D6JMim/pages/records/recordType/commit",
            200, self.records)
        self.custom_locust.set_response(
            "/suite/rest/a/applications/latest/legacy/tempo/records/type/commit/view/all",
            200, self.records)
        self.custom_locust.set_response(
            "/suite/rest/a/sites/latest/D6JMim/page/records/record/lQB0K7YxC0UQ2Fhx4pmY1F49C_MjItD4hbtRdKDmOo6V3MOBxI47ipGa_bJKZf86CLtvOCp1cfX-sa2O9hp6WTKZpbGo5MxRaaTwMkcYMeDl8kN8Hg/view/summary",
            200, self.record_summary_view)

    def tearDown(self) -> None:
        self.task_set.on_stop()

    def test_records_get_all(self) -> None:
        all_records = self.task_set.appian.records.get_all()
        self.assertIsInstance(all_records, dict)

    def test_records_get_all_http_error(self) -> None:
        self.custom_locust.set_response(
            "/suite/rest/a/sites/latest/D6JMim/pages/records/recordType/commit",
            500, self.records)
        with self.assertLogs(level="WARN") as msg:
            self.task_set.appian.records.get_all()
        self.assertIn("500 Server Error", msg.output[0])

    def test_records_get_all_bad_response(self) -> None:

        # setting up bad response
        temp_record_types = self.record_types.replace(
            '"rel":"x-web-bookmark"',
            '"rel":"bad_x-web-bookmark_bad"').replace(
                '"#t":"CardLayout"', '"#t":"bad_CardLayout_bad"')
        self.custom_locust.set_response(
            "/suite/rest/a/applications/latest/app/records/view/all", 200,
            temp_record_types)
        with (self.assertRaisesRegex(
                Exception, "Unexpected response on Get call of All Records")):
            self.task_set.appian.records.get_all()

    def test_records_get_corrupt_records(self) -> None:
        # setting up bad response
        corrupt_records = self.records.replace(
            '"_recordRef": "lQB0K7YxC0UQ2Fhx4pmY1F49C_MjItD4hbtRdKDmOo6V3MOBxI47ipGa_bJKZf86CLtvOCp1cfX-sa2O9hu7mTKKv82PEWF9q1lBcroZD_VQpwcQDs"',
            '"corrupt_recordRef": "lQB0K7YxC0UQ2Fhx4pmY1F49C_MjItD4hbtRdKDmOo6V3MOBxI47ipGa_bJKZf86CLtvOCp1cfX-sa2O9hu7mTKKv82PEWF9q1lBcroZD_VQpwcQDs"'
        )
        self.custom_locust.set_response(
            "/suite/rest/a/sites/latest/D6JMim/pages/records/recordType/commit",
            200, corrupt_records)

        all_records = self.task_set.appian.records.get_all()
        self.assertTrue("ERROR::1" in str(all_records))
        self.assertTrue(self.task_set.appian.records._errors == 1)

    def test_records_get_all_mobile(self) -> None:
        all_records = self.task_set.appian.records.get_all_mobile()
        self.assertIsInstance(all_records, dict)

    def test_records_get_by_type_mobile(self) -> None:
        # Given
        record_type = 'Commits'
        self.task_set.appian.records.get_all_record_types()

        # When
        all_records = self.task_set.appian.records.get_all_records_of_record_type_mobile(
            record_type)

        # Then
        self.assertIsInstance(all_records, dict)

    def test_records_fetch_record_instance(self) -> None:
        record = self.task_set.appian.records.fetch_record_instance(
            "Commits", self.record_instance_name, False)
        self.assertIsInstance(record, dict)

    def test_records_fetch_record_instance_no_record_type(self) -> None:
        with self.assertRaisesRegex(
                Exception,
                "There is no record type with name .* in the system under test"
        ):
            self.task_set.appian.records.fetch_record_instance(
                "something else 1", self.record_instance_name, False)

    def test_records_fetch_record_instance_missing(self) -> None:
        with self.assertRaisesRegex(
                Exception,
                "There is no record with name .* found in record type .*"):
            self.task_set.appian.records.fetch_record_instance(
                "Commits", "something else", False)

    def test_records_fetch_record_type(self) -> None:
        self.task_set.appian.records.get_all()
        output = self.task_set.appian.records.fetch_record_type("Commits")
        self.assertIsInstance(output, dict)

    def test_records_fetch_record_type_recaching(self) -> None:
        self.task_set.appian.records._record_types = dict(
        )  # Resetting the cache.
        output = self.task_set.appian.records.fetch_record_type("Commits")
        self.assertIsInstance(output, dict)

    def test_records_fetch_record_type_missing_record_type(self) -> None:
        with self.assertRaisesRegex(
                Exception,
                "There is no record type with name .* in the system under test"
        ):
            self.task_set.appian.records.fetch_record_type("something else")

    def test_records_visit(self) -> None:
        output_json, output_uri = self.task_set.appian.records.visit_record_instance(
            "Commits", self.record_instance_name, exact_match=False)
        self.assertIsInstance(output_json, dict)
        self.assertTrue("summary" in output_uri)

    def test_records_visit_random_success(self) -> None:
        self.custom_locust.set_default_response(200, self.record_summary_view)
        output_json, output_uri = self.task_set.appian.records.visit_record_instance(
        )
        self.assertIsInstance(output_json, dict)
        self.assertTrue("summary" in output_uri)

    def test_records_visit_random_of_selected_record_type_success(
            self) -> None:
        self.custom_locust.set_default_response(200, self.record_summary_view)
        output_json, output_uri = self.task_set.appian.records.visit_record_instance(
            record_type="Commits")
        self.assertIsInstance(output_json, dict)
        self.assertTrue("summary" in output_uri)

    def test_records_visit_random_no_record_type_failure(self) -> None:
        with self.assertRaisesRegex(
                Exception,
                "If record_name parameter is specified, record_type must also be included"
        ):
            self.task_set.appian.records.visit_record_instance(
                record_name=self.record_instance_name, exact_match=False)

    def test_records_visit_with_urlstub(self) -> None:
        output_json, output_uri = self.task_set.appian.records.visit_record_instance(
            "Commits", self.record_instance_name, "summary", exact_match=False)
        self.assertIsInstance(output_json, dict)
        self.assertTrue("summary" in output_uri)

    def test_record_types_visit(self) -> None:
        output_json, output_uri = self.task_set.appian.records.visit_record_type(
            "Commits", exact_match=False)
        self.assertIsInstance(output_json, dict)
        self.assertTrue("commit" in output_uri)

    def test_record_type_visit_random_success(self) -> None:
        self.custom_locust.set_default_response(200, self.records)
        output_json, output_uri = self.task_set.appian.records.visit_record_type(
        )
        self.assertIsInstance(output_json, dict)
        self.assertEqual(output_json.get("#t"), "UiConfig")
        self.assertTrue("commit" in output_uri)

    def test_record_type_visit_failure(self) -> None:
        with self.assertRaises(Exception) as e:
            self.task_set.appian.records.visit_record_type(
                record_type="fake type")

    @unittest.mock.patch(
        'appian_locust.records_helper.find_component_by_attribute_in_dict',
        return_value={'children': [json.dumps({"a": "b"})]})
    def test_records_form_example_success(
            self, find_component_by_attribute_in_dict_function: Any) -> None:
        sail_form = self.task_set.appian.records.visit_record_instance_and_get_form(
            "Commits",
            self.record_instance_name,
            view_url_stub="summary",
            exact_match=False)
        self.assertTrue(isinstance(sail_form, SailUiForm))
        self.assertEqual(sail_form.get_response(), {"a": "b"})

    def test_records_form_incorrect_name(self) -> None:
        record_name = "Fake Record"
        record_type = "Commits"
        exact_match = False
        with self.assertRaises(Exception) as context:
            self.task_set.appian.records.visit_record_instance_and_get_form(
                record_type,
                record_name,
                view_url_stub="summary",
                exact_match=exact_match)
        self.assertEqual(
            context.exception.args[0],
            f"There is no record with name {record_name} found in record type {record_type} (Exact match = {exact_match})"
        )

    def test_records_form_incorrect_type(self) -> None:
        exact_match = False
        with self.assertRaises(Exception) as context:
            self.task_set.appian.records.visit_record_instance_and_get_form(
                "Fake Type",
                self.record_instance_name,
                view_url_stub="summary",
                exact_match=exact_match)
        self.assertEqual(
            context.exception.args[0],
            f"There is no record type with name Fake Type in the system under test (Exact match = {exact_match})"
        )

    @unittest.mock.patch(
        'appian_locust.records_helper.find_component_by_attribute_in_dict',
        return_value={'children': None})
    def test_records_form_no_embedded_summary(
            self, find_component_by_attribute_in_dict_function: Any) -> None:
        with self.assertRaises(Exception) as context:
            self.task_set.appian.records.visit_record_instance_and_get_form(
                record_type="Commits",
                record_name=self.record_instance_name,
                view_url_stub="summary",
                exact_match=False)
        self.assertEqual(
            context.exception.args[0],
            "Parser was not able to find embedded SAIL code within JSON response for the requested Record Instance."
        )

    def test_record_types_form_example_success(self) -> None:
        sail_form = self.task_set.appian.records.visit_record_type_and_get_form(
            "Commits", exact_match=False)
        self.assertTrue(isinstance(sail_form, SailUiForm))

    def test_record_type_random_form_example_success(self) -> None:
        sail_form = self.task_set.appian.records.visit_record_type_and_get_form(
            exact_match=False)
        self.assertTrue(isinstance(sail_form, SailUiForm))

    def test_record_type_form_incorrect_type(self) -> None:
        record_type = "Fake Type"
        exact_match = True
        with self.assertRaises(Exception) as context:
            self.task_set.appian.records.visit_record_type_and_get_form(
                record_type, exact_match)
        self.assertEqual(
            context.exception.args[0],
            f"There is no record type with name {record_type} in the system under test"
        )

    def test_get_random_record(self) -> None:
        self.task_set.appian.records._record_types = dict()
        self.task_set.appian.records._records = dict()
        record_type, record_name = self.task_set.appian.records._get_random_record_instance(
        )
        self.assertEqual(record_type, "Commits")
        self.assertIn(
            record_name,
            list(self.task_set.appian.records._records[record_type].keys()))

    def test_get_random_record_get_all(self) -> None:
        mock_get_all = mock.Mock()
        setattr(self.task_set.appian.records, 'get_all', mock_get_all)
        with self.assertRaises(Exception):
            self.task_set.appian.records._get_random_record_instance()
            mock_get_all.assert_called_once()

    def test_get_record_instance_feed_Response(self) -> None:
        sail_form = self.task_set.appian.records.visit_record_instance_and_get_feed_form(
            "Commits", self.record_instance_name, exact_match=False)

        self.assertTrue(isinstance(sail_form, SailUiForm))
        self.assertEqual(
            sail_form.state.get("feed", {}).get("title", ""),
            self.record_instance_name)
Beispiel #8
0
class FeatureToggleHelperTest(unittest.TestCase):

    html_snippet = """
                </script><script src="/suite/tempo/ui/sail-client/sites-05d032ca6319b11b6fc9.cache.js?\
                    appian_environment=sites">
                </script><script src="/suite/tempo/ui/sail-client/omnibox-05d032ca6319b11b6fc9.cache.js?\
                    appian_environment=sites" defer="true">
                </script></body></html>
                """
    js_snippet = """
                ADERS=exports.LEGACY_FEATURE_FLAGS=exports.DEFAULT_FEATURE_FLAGS=undefined;
                var RAW_DEFAULT_FEATURE_FLAGS={};var RAW_LEGACY_FEATURE_FLAGS=RAW_DEFAULT_FEATURE_FLAGS&2147483647;
                var DEFAULT_FEATURE_FLAGS=exports.DEFAULT_FEATURE_FLAGS=RAW_DEFAULT_FEATURE_FLAGS.toString(16);
                var LEGACY_FEATURE_FLAGS=exports.LEGACY_FEATURE_FLAGS=RAW_LEGACY_FEATURE_FLAGS.toString(16);var
                """

    def setUp(self) -> None:
        self.custom_locust = CustomLocust(Locust())
        parent_task_set = TaskSet(self.custom_locust)
        setattr(parent_task_set, "host", "")
        setattr(parent_task_set, "credentials", [["", ""]])
        setattr(parent_task_set, "auth", ["", ""])

        self.task_set = AppianTaskSet(parent_task_set)
        self.task_set.host = ""

        # test_on_start_auth_success is covered here.
        self.custom_locust.set_response("auth?appian_environment=tempo", 200, '{}')
        self.task_set.on_start()

    def tearDown(self) -> None:
        self.task_set.on_stop()

    def test_get_javascript_uri_missing(self) -> None:
        # Given
        self.custom_locust.set_response("/suite/sites", 200, "abc")

        # When
        uri = feature_toggle_helper._get_javascript_uri(self.task_set.appian.interactor, {})

        # Then
        self.assertEqual(uri, None)

    def test_get_javascript_uri_present(self) -> None:
        # Given a snippet of the sites page
        self.custom_locust.set_response("/suite/sites", 200, self.html_snippet)

        # When
        uri = feature_toggle_helper._get_javascript_uri(self.task_set.appian.interactor, {})

        # Then
        self.assertEqual(
            uri, "/suite/tempo/ui/sail-client/sites-05d032ca6319b11b6fc9.cache.js")

    def test_get_javascript_and_find_feature_flag_missing_value(self) -> None:
        # Given
        self.custom_locust.set_response("abc", 200, "body")

        # When
        flag = feature_toggle_helper._get_javascript_and_find_feature_flag(
            self.task_set.appian.client, "abc", {})

        # Then
        self.assertEqual(flag, None)

    def test_get_javascript_and_find_feature_flag_value_present_hex(self) -> None:
        # Given a snippet of the minified js
        self.custom_locust.set_response("/suite/file.js",
                                        200, self.js_snippet.format("0xdc9fffceebc"))

        # When
        uri = feature_toggle_helper._get_javascript_and_find_feature_flag(self.task_set.appian.client,
                                                                          "/suite/file.js", {})

        # Then
        self.assertEqual(
            uri, "0xdc9fffceebc")

    def test_get_javascript_and_find_feature_flag_value_present_big_int(self) -> None:
        # Given a snippet of the minified js
        for i in [9, 10]:
            self.custom_locust.set_response("/suite/file.js",
                                            200, self.js_snippet.format(
                                                f'jsbi__WEBPACK_IMPORTED_MODULE_{i}__["default"].BigInt("0b110100100111011100000111111111111111001110111010111100")'))

            # When
            binVal = feature_toggle_helper._get_javascript_and_find_feature_flag(self.task_set.appian.client,
                                                                                 "/suite/file.js", {})

            # Then
            self.assertEqual(
                binVal, "0b110100100111011100000111111111111111001110111010111100")

    def test_get_javascript_and_find_feature_flag_value_present_integer(self) -> None:
        # Given a snippet of the minified js
        self.custom_locust.set_response("/suite/file.js",
                                        200, self.js_snippet.format("5802956083228348"))
        # When
        uri = feature_toggle_helper._get_javascript_and_find_feature_flag(self.task_set.appian.client,
                                                                          "/suite/file.js", {})

        # Then
        self.assertEqual(
            uri, "5802956083228348")

    def test_get_feature_flags_from_regex_match_hex(self) -> None:
        # Given
        hex_val = "0xdc9fffceebc"

        # When
        flag, flag_extended = feature_toggle_helper._get_feature_flags_from_regex_match(
            hex_val)

        # Then
        self.assertEqual(flag, "7ffceebc")
        self.assertEqual(flag_extended, "dc9fffceebc")

    def test_get_feature_flags_from_regex_match_big_int(self) -> None:
        # Given
        hex_val = "0b110100100111011100000111111111111111001110111010111100"

        # When
        flag, flag_extended = feature_toggle_helper._get_feature_flags_from_regex_match(
            hex_val)

        # Then
        self.assertEqual(flag, "7ffceebc")
        self.assertEqual(flag_extended, "349dc1fffceebc")

    def test_get_feature_flags_from_regex_match_integer(self) -> None:
        # Given
        int_val = "5802956083228348"

        # When
        flag, flag_extended = feature_toggle_helper._get_feature_flags_from_regex_match(
            int_val)

        # Then
        self.assertEqual(flag, "7ffceebc")
        self.assertEqual(flag_extended, "149dc1fffceebc")

    def test_end_to_end_get_feature_flags(self) -> None:
        # Given a snippet of the sites page and js snippet
        self.custom_locust.set_response("/suite/sites", 200, self.html_snippet)
        self.custom_locust.set_response("/suite/tempo/ui/sail-client/sites-05d032ca6319b11b6fc9.cache.js",
                                        200, self.js_snippet.format("5802956083228348"))

        # When
        flag, flag_extended = feature_toggle_helper.get_client_feature_toggles(
            self.task_set.appian.interactor,
            self.task_set.appian.client
        )

        # Then
        self.assertEqual(flag, "7ffceebc")
        self.assertEqual(flag_extended, "149dc1fffceebc")

    def test_end_to_end_get_feature_flags_fail_no_sites_link(self) -> None:
        # Given a missing js snippet
        self.custom_locust.set_response("/suite/sites", 200, '')

        # When and Then
        with self.assertRaisesRegex(Exception, "Could not find script uri to retrieve client feature"):
            feature_toggle_helper.get_client_feature_toggles(
                self.task_set.appian.interactor,
                self.task_set.appian.client
            )

    def test_end_to_end_get_feature_flags_fail_no_feature_toggles_found(self) -> None:
        # Given a missing feature toggle
        self.custom_locust.set_response("/suite/sites", 200, self.html_snippet)
        self.custom_locust.set_response("/suite/tempo/ui/sail-client/sites-05d032ca6319b11b6fc9.cache.js",
                                        200, 'missin')

        # When and Then
        with self.assertRaisesRegex(Exception, "Could not find flag string within uri /suite/tempo/ui"):
            feature_toggle_helper.get_client_feature_toggles(
                self.task_set.appian.interactor,
                self.task_set.appian.client
            )

    def test_to_hex_str(self) -> None:
        # Given
        hex_val = "0xdc9fffceebc"
        intVal = int(hex_val, 16)

        # When
        flagHexStr = feature_toggle_helper._to_hex_str(intVal)

        # Then
        self.assertEqual(flagHexStr, "dc9fffceebc")

    def test_truncate_flag_extended_long_input(self) -> None:
        # Given
        longHexVal = 0xdc9fffceebc

        # When
        shortVal = feature_toggle_helper._truncate_flag_extended(longHexVal)

        # Then
        self.assertEqual(shortVal, 0x7ffceebc)

    def test_truncate_flag_extended_short_input(self) -> None:
        # Given
        shortHexVal = 0x7ffceebc

        # When
        shortVal = feature_toggle_helper._truncate_flag_extended(shortHexVal)

        # Then
        self.assertEqual(shortVal, 0x7ffceebc)

    def create_override_flag_mask_runner(self, flags: List[FeatureFlag], expectedResult: int) -> None:
        # When
        feature_flag_mask = feature_toggle_helper._create_override_flag_mask(flags)

        # Then
        self.assertEqual(feature_flag_mask, expectedResult)

    def test_create_override_flag_mask_no_flag(self) -> None:
        # Given
        flags: List[FeatureFlag] = []
        expectedResult = 0

        # Then
        self.create_override_flag_mask_runner(flags, expectedResult)

    def test_create_override_flag_mask_one_flag(self) -> None:
        # Given
        flags = [FeatureFlag.SAIL_FORMS]
        expectedResult = 4

        # Then
        self.create_override_flag_mask_runner(flags, expectedResult)

    def test_create_override_flag_mask_multiple_flags(self) -> None:
        # Given
        flags = [FeatureFlag.SAIL_FORMS, FeatureFlag.COMPACT_URI_TEMPLATES]
        expectedResult = 1028

        # Then
        self.create_override_flag_mask_runner(flags, expectedResult)

    def override_default_flags_runner(self, flags: List[FeatureFlag], expected_featured_flag_extended: str,  expected_feature_flag: str) -> None:
        # Given a snippet of the sites page
        self.task_set.appian.interactor.client.feature_flag_extended = "149dc1fffceebc"
        self.task_set.appian.interactor.client.feature_flag = "7ffceebc"

        # When
        feature_toggle_helper.override_default_flags(self.task_set.appian.interactor, flags)

        # Then
        self.assertEqual(self.task_set.appian.interactor.client.feature_flag_extended, expected_featured_flag_extended)
        self.assertEqual(self.task_set.appian.interactor.client.feature_flag, expected_feature_flag)

    def test_override_default_flags_no_flags(self) -> None:
        # Given a snippet of the sites page
        flags: List[FeatureFlag] = []

        self.override_default_flags_runner(flags, "149dc1fffceebc", "7ffceebc")

    def test_override_default_flags_one_flag(self) -> None:
        # Given a snippet of the sites page
        flags = [FeatureFlag.SHORT_CIRCUIT_PARTIAL_RENDERING]

        self.override_default_flags_runner(flags, "149dc1fffcefbc", "7ffcefbc")

    def test_override_default_flags_multiple_flags(self) -> None:
        # Given a snippet of the sites page
        flags = [FeatureFlag.SHORT_CIRCUIT_PARTIAL_RENDERING, FeatureFlag.INLINE_TASK_CONTROLS]

        self.override_default_flags_runner(flags, "149dc1fffcffbc", "7ffcffbc")

    def test_declare_device_as_mobile(self) -> None:
        # Given a snippet of the sites page
        self.custom_locust.set_response("/suite/sites", 200, self.html_snippet)
        flags = [FeatureFlag.RECORD_LIST_FEED_ITEM_DTO]

        self.override_default_flags_runner(flags, "149dd1fffceebc", "7ffceebc")