예제 #1
0
파일: cli.py 프로젝트: ryan-rs/zigzag
def main(zigzag_config_file, junit_input_file, pprint_on_fail):
    """Upload JUnitXML results to qTest manager.

    \b
    Required Arguments:
        ZIGZAG_CONFIG_FILE      A valid json config file for zigzag.
        JUNIT_INPUT_FILE        A valid JUnit XML results file.
    \b
    Required Environment Variables:
        QTEST_API_TOKEN         The qTest API token to use for authorization
    """

    api_token_env_var = 'QTEST_API_TOKEN'

    try:
        if not os.environ.get(api_token_env_var):
            raise RuntimeError(
                'The "{}" environment variable is not defined! '
                'See help for more details.'.format(api_token_env_var))

        zz = ZigZag(junit_input_file, zigzag_config_file,
                    os.environ[api_token_env_var], pprint_on_fail)
        zz.parse()

        job_id = zz.upload_test_results()

        click.echo(click.style("\nQueue Job ID: {}".format(str(job_id))))
        click.echo(click.style("\nSuccess!", fg='green'))
    except (RuntimeError, ZigZagError) as e:
        click.echo(click.style(str(e), fg='red'))
        click.echo(click.style("\nFailed!", fg='red'))

        sys.exit(1)
예제 #2
0
def pytest_sessionfinish(session):
    """This hook is used by pytest to build the junit XML
    Using ZigZag as a library we upload in the pytest runtime

    Args:
        session (_pytest.main.Session): The pytest session object
    """

    SESSION_MESSAGES.drain(
    )  # need to reset this on every pass through this hook
    if session.config.pluginmanager.hasplugin('junitxml'):
        zz_option = _get_option_of_highest_precedence(session.config, 'zigzag')
        pytest_zigzag_config = _get_option_of_highest_precedence(
            session.config, 'pytest-zigzag-config')
        if zz_option and pytest_zigzag_config:
            try:
                junit_file_path = getattr(session.config, '_xml', None).logfile

                # noinspection PyTypeChecker
                # validate token
                token = _validate_qtest_token(os.environ['QTEST_API_TOKEN'])
                zz = ZigZag(junit_file_path, pytest_zigzag_config, token)
                job_id = zz.upload_test_results()
                SESSION_MESSAGES.append("ZigZag upload was successful!")
                SESSION_MESSAGES.append("Queue Job ID: {}".format(job_id))
            except Exception as e:  # we want this super broad so we dont break test execution
                SESSION_MESSAGES.append('The ZigZag upload was not successful')
                SESSION_MESSAGES.append("Original error message:\n\n{}".format(
                    str(e)))
예제 #3
0
    def test_schema_violation_with_pprint_on_fail(self, missing_test_id_xml,
                                                  mocker):
        """Verify that JUnitXML that violates the schema with 'pprint_on_fail' enabled with emit an error message with
        the XML pretty printed in the error message."""

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'Failure Output'
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])

        # Expectations
        error_msg_exp = '---DEBUG XML PRETTY PRINT---'

        # Test
        try:
            zz = ZigZag(missing_test_id_xml,
                        TOKEN,
                        PROJECT_ID,
                        TEST_CYCLE,
                        pprint_on_fail=True)
            zz.parse()
        except RuntimeError as e:
            assert error_msg_exp in str(e)
예제 #4
0
    def invoke_zigzag(self, force_clean_up=True):
        """Execute the ZigZag CLI.

        Args:
            force_clean_up (bool): Flag indicating whether previous test data should be cleaned up first before
                execution. (Default: True)

        """

        if force_clean_up:
            self.clean_up()
        self.tests.reset(
        )  # This is for super safety in case a developer was being tricky with execution

        with open(self._junit_xml_file_path, 'w') as f:
            f.write(
                self._junit_template.render(tests=self._tests,
                                            global_props=self._global_props))

        zz = ZigZag(self._junit_xml_file_path, self._qtest_api_token,
                    self._qtest_project_id, self._qtest_root_test_cycle.name,
                    False)
        zz.parse()

        self._last_invocation_queue_job_id = zz.upload_test_results()
예제 #5
0
    def test_invalid_classname(self, invalid_classname_xml, mocker):
        """Verify that JUnitXML that has an invalid 'classname' attribute for a testcase raises a RuntimeError."""

        object_id = 12345

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = object_id
        mock_field_resp.label = 'Failure Output'
        response = {
            'items': [{
                'name': 'insert name here',
                'id': object_id
            }],
            'total': 1
        }
        mock_link_response = mocker.Mock(
            spec=swagger_client.LinkedArtifactContainer)
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response)
        mocker.patch('requests.post', return_value=mock_post_response)
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])
        mocker.patch('swagger_client.ObjectlinkApi.link_artifacts',
                     return_value=[mock_link_response])
        # Setup
        zz = ZigZag(invalid_classname_xml, TOKEN, PROJECT_ID, TEST_CYCLE)
        zz.parse()

        # Test
        with pytest.raises(RuntimeError):
            # noinspection PyStatementEffect
            zz.test_logs[0].qtest_test_log
    def test_link_test_case_not_created_yet(self, single_passing_xml, mocker):
        """The happy path"""

        response_body = {
            "links": [],
            "page": 1,
            "page_size": 1,
            "total": 0,
            "items": []
        }
        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'Failure Output'
        mocker.patch('swagger_client.FieldApi.get_fields', return_value=[mock_field_resp])
        mocker.patch('swagger_client.SearchApi.search', return_value=response_body)
        mocker.patch('swagger_client.ObjectlinkApi.link_artifacts')
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response_body)
        mocker.patch('requests.post', return_value=mock_post_response)

        # Setup
        zz = ZigZag(single_passing_xml, TOKEN, PROJECT_ID, TEST_CYCLE)
        zz.parse()
        rlf = RequirementsLinkFacade(zz)
        log = zz.test_logs[0]

        # Test
        rlf.link()

        # After think link we should have much more information about linked resource
        assert ['ASC-123', 'ASC-456'] == log.jira_issues
        assert [] == log.qtest_requirements
        assert log.qtest_testcase_id is None
예제 #7
0
    def test_happy_path(self, single_passing_xml, mocker):
        """Verify that the function can upload results from a JUnitXML file that contains a single passing test"""

        # Expectation
        job_id = '54321'

        # Mock
        test_cycle_name = 'queens'
        test_cycle_pid = 'CL-1'
        mock_get_tc_resp = mocker.Mock(spec=swagger_client.TestCycleResource)
        mock_create_tc_resp = mocker.Mock(
            spec=swagger_client.TestCycleResource)
        mock_get_tc_resp.to_dict.return_value = {
            'name': 'queens',
            'pid': 'CL-2'
        }
        mock_create_tc_resp.to_dict.return_value = {
            'name': test_cycle_name,
            'pid': test_cycle_pid
        }
        mock_queue_resp = mocker.Mock(state='IN_WAITING', id=job_id)
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'Failure Output'
        response = {
            'items': [{
                'name': 'insert name here',
                'id': 12345
            }],
            'total': 1
        }
        mock_link_response = mocker.Mock(
            spec=swagger_client.LinkedArtifactContainer)
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response)
        mocker.patch('requests.post', return_value=mock_post_response)
        mocker.patch('swagger_client.TestlogApi.submit_automation_test_logs_0',
                     return_value=mock_queue_resp)
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])
        mocker.patch('swagger_client.ObjectlinkApi.link_artifacts',
                     return_value=[mock_link_response])
        mocker.patch('swagger_client.TestcycleApi.get_test_cycles',
                     return_value=[mock_get_tc_resp])
        mocker.patch('swagger_client.TestcycleApi.create_cycle',
                     return_value=mock_create_tc_resp)

        # Setup
        zz = ZigZag(single_passing_xml, TOKEN, PROJECT_ID, TEST_CYCLE)
        zz.parse()

        # Test
        response = zz.upload_test_results()
        assert int(job_id) == response
예제 #8
0
    def test_classname_containing_dashes(self, classname_with_dashes_xml,
                                         mocker):
        """Verify that JUnitXML that has a 'classname' containing dashes (captured from the py.test filename) is
        validated correctly.
        """

        object_id = 12345

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = object_id
        mock_field_resp.label = 'Failure Output'
        response = {
            'items': [{
                'name': 'insert name here',
                'id': object_id
            }],
            'total': 1
        }
        mock_link_response = mocker.Mock(
            spec=swagger_client.LinkedArtifactContainer)
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response)
        mocker.patch('requests.post', return_value=mock_post_response)
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])
        mocker.patch('swagger_client.ObjectlinkApi.link_artifacts',
                     return_value=[mock_link_response])

        # Setup
        zz = ZigZag(classname_with_dashes_xml, TOKEN, PROJECT_ID, TEST_CYCLE)
        zz.parse()
        # noinspection PyUnresolvedReferences
        test_log_dict = zz.test_logs[0].qtest_test_log.to_dict()

        # Expectation
        test_name = 'test_verify_kibana_horizon_access_with_no_ssh'
        module_names = [
            'r16.2.0',
            'PM_rpc-openstack-pike-rc-xenial_mnaio_no_artifacts-swift-system',
            'molecule-validate-neutron-deploy', 'default', 'test_for_acs-150',
            'TestForRPC10PlusPostDeploymentQCProcess'
        ]
        test_log_exp = pytest.helpers.merge_dicts(SHARED_TEST_LOG_EXP, {
            'name': test_name,
            'status': 'PASSED',
            'module_names': module_names
        })

        # Test
        for exp in test_log_exp:
            assert test_log_exp[exp] == test_log_dict[exp]
예제 #9
0
    def test_invalid_file_path(self, mocker):
        """Verify that an invalid file path raises an exception"""

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'Failure Output'
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])

        # Test
        with pytest.raises(RuntimeError):
            zz = ZigZag('/path/does/not/exist', TOKEN, PROJECT_ID, TEST_CYCLE)
            zz.parse()
예제 #10
0
    def test_missing_junit_xml_root(self, bad_junit_root, mocker):
        """Verify that XML files missing the expected JUnitXML root element raises an exception"""

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'Failure Output'
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])

        # Test
        with pytest.raises(RuntimeError):
            zz = ZigZag(bad_junit_root, TOKEN, PROJECT_ID, TEST_CYCLE)
            zz.parse()
예제 #11
0
    def test_missing_test_id_xml(self, missing_test_id_xml, mocker):
        """Verify that JUnitXML that is missing the 'test_id' test case property causes a RuntimeError."""

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'Failure Output'
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])

        # Test
        with pytest.raises(RuntimeError):
            zz = ZigZag(missing_test_id_xml, TOKEN, PROJECT_ID, TEST_CYCLE)
            zz.parse()
예제 #12
0
    def test_invalid_xml_content(self, bad_xml, mocker):
        """Verify that invalid XML file content raises an exception"""

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'Failure Output'
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])

        # Test
        with pytest.raises(RuntimeError):
            zz = ZigZag(bad_xml, TOKEN, PROJECT_ID, TEST_CYCLE)
            zz.parse()
예제 #13
0
    def test_missing_build_url_xml(self, missing_build_url_xml,
                                   simple_json_config, mocker):
        """Verify that JUnitXML that is missing the test suite 'BUILD_URL' property element causes a RuntimeError."""

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'Failure Output'
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])

        # Test
        with pytest.raises(RuntimeError):
            zz = ZigZag(missing_build_url_xml, simple_json_config, TOKEN)
            zz.parse()
    def test_failure_to_get_test_cycles(self, single_passing_xml, mocker):
        """Verify that API failure when retrieving test cycles is caught."""

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'Failure Output'
        response = {
            'items': [{
                'name': 'insert name here',
                'id': 12345
            }],
            'total': 1
        }
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response)
        mocker.patch('requests.post', return_value=mock_post_response)
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])
        mocker.patch('swagger_client.TestcycleApi.get_test_cycles',
                     side_effect=ApiException('Super duper failure!'))

        # Setup
        test_cycle_name = 'TestCycle1'
        zz = ZigZag(single_passing_xml, TOKEN, PROJECT_ID, TEST_CYCLE)
        mhf = ModuleHierarchyFacade(zz)

        # Test
        with pytest.raises(RuntimeError):
            mhf.discover_root_test_cycle(test_cycle_name)
예제 #15
0
    def test_junit_xml_attachment(self, single_passing_xml, simple_json_config,
                                  mocker):
        """Verify that an xml file is attached to the qTest testlog
        """

        object_id = 12345

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = object_id
        mock_field_resp.label = 'Failure Output'
        response = {
            'items': [{
                'name': 'insert name here',
                'id': object_id
            }],
            'total': 1
        }
        mock_link_response = mocker.Mock(
            spec=swagger_client.LinkedArtifactContainer)
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response)
        mocker.patch('requests.post', return_value=mock_post_response)
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])
        mocker.patch('swagger_client.ObjectlinkApi.link_artifacts',
                     return_value=[mock_link_response])

        # Setup
        zz = ZigZag(single_passing_xml, simple_json_config, TOKEN)
        zz.parse()
        # noinspection PyUnresolvedReferences
        test_log_dict = zz.test_logs[0].qtest_test_log.to_dict()

        # Expectation
        attachment_exp_name_regex = re.compile(r'^junit_.+\.xml$')
        attachment_exp_content_type = 'application/xml'
        attachment_exp_data_md5 = 'f3b2303ccf8a76a9e20d2099e9b2f29c'

        # Test
        assert attachment_exp_name_regex.match(
            test_log_dict['attachments'][0]['name']) is not None
        assert attachment_exp_content_type == test_log_dict['attachments'][0][
            'content_type']
        assert attachment_exp_data_md5 == md5(
            test_log_dict['attachments'][0]['data'].encode(
                'UTF-8')).hexdigest()
예제 #16
0
    def test_exceeds_max_file_size(self, flat_all_passing_xml, mocker):
        """Verify that XML files that exceed the max file size are rejected"""

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'Failure Output'
        file_size = 52428801

        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])
        mocker.patch('os.path.getsize', return_value=file_size)

        # Test
        with pytest.raises(RuntimeError):
            zz = ZigZag(flat_all_passing_xml, TOKEN, PROJECT_ID, TEST_CYCLE)
            zz.parse()
예제 #17
0
    def test_error(self, single_error_xml, mocker):
        """Verify that a JUnitXML error test will parse into a single TestLog.
        """

        object_id = 12345

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = object_id
        mock_field_resp.label = 'Failure Output'
        response = {
            'items': [{
                'name': 'insert name here',
                'id': object_id
            }],
            'total': 1
        }
        mock_link_response = mocker.Mock(
            spec=swagger_client.LinkedArtifactContainer)
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response)
        mocker.patch('requests.post', return_value=mock_post_response)
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])
        mocker.patch('swagger_client.ObjectlinkApi.link_artifacts',
                     return_value=[mock_link_response])

        # Setup
        zz = ZigZag(single_error_xml, TOKEN, PROJECT_ID, TEST_CYCLE)
        zz.parse()
        # noinspection PyUnresolvedReferences
        test_log = zz.test_logs[0]

        assert 'test_error' == test_log.name
        assert 'FAILED' == test_log.status
        assert 'def error_fixture(host):' in test_log.failure_output \
            or 'log truncated. Please see attached log file.' in test_log.failure_output
        assert '2018-04-10T21:38:18Z' == test_log.start_date
        assert '2018-04-10T21:38:19Z' == test_log.end_date
        assert ['ASC-123', 'ASC-456'] == test_log.jira_issues
        assert '1' == test_log.automation_content
        assert [object_id, object_id] == test_log.qtest_requirements
        assert object_id == test_log.qtest_testcase_id
예제 #18
0
    def test_pass(self, single_passing_xml, mocker):
        """Verify that a valid qTest 'AutomationTestLogResource' swagger model is generated from a JUnitXML file
        that contains a single passing test.
        """
        object_id = 12345

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = object_id
        mock_field_resp.label = 'Failure Output'
        response = {
            'items': [{
                'name': 'insert name here',
                'id': object_id
            }],
            'total': 1
        }
        mock_link_response = mocker.Mock(
            spec=swagger_client.LinkedArtifactContainer)
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response)
        mocker.patch('requests.post', return_value=mock_post_response)
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])
        mocker.patch('swagger_client.ObjectlinkApi.link_artifacts',
                     return_value=[mock_link_response])

        # Setup
        zz = ZigZag(single_passing_xml, TOKEN, PROJECT_ID, TEST_CYCLE)
        zz.parse()
        # noinspection PyUnresolvedReferences
        test_log = zz.test_logs[0]

        assert 'test_pass' == test_log.name
        assert 'PASSED' == test_log.status
        assert '' == test_log.failure_output
        assert '2018-04-10T21:38:18Z' == test_log.start_date
        assert '2018-04-10T21:38:19Z' == test_log.end_date
        assert ['ASC-123', 'ASC-456'] == test_log.jira_issues
        assert '1' == test_log.automation_content
        assert [object_id, object_id] == test_log.qtest_requirements
        assert object_id == test_log.qtest_testcase_id  # We look this up on instantiation of a TestLog
예제 #19
0
    def test_load_file_happy_path(self, flat_all_passing_xml,
                                  simple_json_config, mocker):
        """Verify that a valid JUnitXML file can be loaded"""

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'Failure Output'
        response = {
            'items': [{
                'name': 'insert name here',
                'id': 12345
            }],
            'total': 1
        }
        mock_link_response = mocker.Mock(
            spec=swagger_client.LinkedArtifactContainer)
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response)
        mocker.patch('requests.post', return_value=mock_post_response)
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])
        mocker.patch('swagger_client.ObjectlinkApi.link_artifacts',
                     return_value=[mock_link_response])

        # Setup
        zz = ZigZag(flat_all_passing_xml, simple_json_config, TOKEN)
        zz.parse()

        # Expectations
        root_tag_atribute_exp = {
            'errors': '0',
            'failures': '0',
            'name': 'pytest',
            'skips': '0',
            'tests': '5',
            'time': '1.664'
        }

        # Test
        # noinspection PyProtectedMember
        assert root_tag_atribute_exp == zz._junit_xml.attrib
예제 #20
0
    def test_job_queue_failure(self, single_passing_xml, mocker):
        """Verify that the function fails gracefully if the job queue reports a failure"""

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'Failure Output'
        response = {
            'items': [{
                'name': 'insert name here',
                'id': 12345
            }],
            'total': 1
        }
        mock_link_response = mocker.Mock(
            spec=swagger_client.LinkedArtifactContainer)
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response)
        mocker.patch('requests.post', return_value=mock_post_response)
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])
        mocker.patch('swagger_client.ObjectlinkApi.link_artifacts',
                     return_value=[mock_link_response])

        # Setup
        zz = ZigZag(single_passing_xml, TOKEN, PROJECT_ID, TEST_CYCLE)
        zz.parse()

        # Test
        with pytest.raises(RuntimeError):
            zz.upload_test_results()
예제 #21
0
    def test_api_exception(self, single_passing_xml, simple_json_config,
                           mocker):
        """Verify that the function fails gracefully if the API endpoint reports an API exception"""

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'Failure Output'
        response = {
            'items': [{
                'name': 'insert name here',
                'id': 12345
            }],
            'total': 1
        }
        mock_link_response = mocker.Mock(
            spec=swagger_client.LinkedArtifactContainer)
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response)
        mocker.patch('requests.post', return_value=mock_post_response)
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])
        mocker.patch('swagger_client.TestlogApi.submit_automation_test_logs_0',
                     side_effect=ApiException('Super duper failure!'))
        mocker.patch('swagger_client.ObjectlinkApi.link_artifacts',
                     return_value=[mock_link_response])

        # Setup
        zz = ZigZag(single_passing_xml, simple_json_config, TOKEN)
        zz.parse()

        # Test
        with pytest.raises(RuntimeError):
            zz.upload_test_results()
예제 #22
0
    def test_link(self, single_passing_xml, asc_zigzag_config_file, mocker):
        """The happy path"""

        id = 8675309
        response_body = {
            "links": [],
            "page": 1,
            "page_size": 100,
            "total": 1,
            "items": [{
                "id": id,
                "name": 'This is the name'
            }]
        }
        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'Failure Output'
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])
        mocker.patch('swagger_client.SearchApi.search',
                     return_value=response_body)
        mocker.patch('swagger_client.ObjectlinkApi.link_artifacts')
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response_body)
        mocker.patch('requests.post', return_value=mock_post_response)

        # Setup
        zz = ZigZag(single_passing_xml, asc_zigzag_config_file, TOKEN)
        zz.parse()
        rlf = RequirementsLinkFacade(zz)
        log = zz.test_logs[0]

        # Test
        rlf.link()

        # After think link we should have much more information about linked resource
        assert ['ASC-123', 'ASC-456'] == log.jira_issues
        assert [id, id] == log.qtest_requirements
        assert id == log.qtest_testcase_id
예제 #23
0
def main(junit_input_file, qtest_project_id, qtest_test_cycle, pprint_on_fail,
         test_runner):
    """Upload JUnitXML results to qTest manager.

    \b
    Required Arguments:
        JUNIT_INPUT_FILE        A valid JUnit XML results file.
        QTEST_PROJECT_ID        The the target qTest Project ID for results
    \b
    Required Environment Variables:
        QTEST_API_TOKEN         The qTest API token to use for authorization
    """

    api_token_env_var = 'QTEST_API_TOKEN'

    try:
        if not os.environ.get(api_token_env_var):
            raise RuntimeError(
                'The "{}" environment variable is not defined! '
                'See help for more details.'.format(api_token_env_var))

        zz = ZigZag(junit_input_file, os.environ[api_token_env_var],
                    qtest_project_id, qtest_test_cycle, pprint_on_fail)

        zz.test_runner = test_runner
        zz.parse()
        job_id = zz.upload_test_results()
        click.echo(click.style("\nQueue Job ID: {}".format(str(job_id))))
        click.echo(click.style("\nSuccess!", fg='green'))
    except RuntimeError as e:
        click.echo(click.style(str(e), fg='red'))
        click.echo(click.style("\nFailed!", fg='red'))

        sys.exit(1)
예제 #24
0
    def test_suite_with_tests(self, suite_all_passing_xml, simple_json_config,
                              mocker):
        """Verify that a JUnitXML test suite will parse into multiple TestLogs.
        """

        object_id = 12345

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = object_id
        mock_field_resp.label = 'Failure Output'
        response = {
            'items': [{
                'name': 'insert name here',
                'id': object_id
            }],
            'total': 1
        }
        mock_link_response = mocker.Mock(
            spec=swagger_client.LinkedArtifactContainer)
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response)
        mocker.patch('requests.post', return_value=mock_post_response)
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])
        mocker.patch('swagger_client.ObjectlinkApi.link_artifacts',
                     return_value=[mock_link_response])

        # Setup
        zz = ZigZag(suite_all_passing_xml, simple_json_config, TOKEN)
        zz.parse()
        # noinspection PyUnresolvedReferences
        test_logs = zz.test_logs

        # Test
        for log in test_logs:
            assert 'PASSED' == log.status
            assert re.match(r'test_pass\d', log.name)
예제 #25
0
    def test_data_stored_on_mediator(self, asc_zigzag_config_file,
                                     flat_all_passing_xml, mocker):
        """verify that the ZigZag object stores properties after initialization"""

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 2983472
        mock_field_resp.label = 'Failure Output'
        response = {
            'items': [{
                'name': 'insert name here',
                'id': 12345
            }],
            'total': 1
        }
        mock_link_response = mocker.Mock(
            spec=swagger_client.LinkedArtifactContainer)
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response)
        mocker.patch('requests.post', return_value=mock_post_response)
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])
        mocker.patch('swagger_client.ObjectlinkApi.link_artifacts',
                     return_value=[mock_link_response])

        # Setup
        zz = ZigZag(flat_all_passing_xml, asc_zigzag_config_file, TOKEN)
        zz.parse()

        # Test
        assert "12345" == zz.config_dict.get_config('project_id')
        assert len(zz.test_logs)
        assert 'https://rpc.jenkins.cit.rackspace.net/job/PM_rpc-openstack-pike-rc-xenial_mnaio_no_artifacts-swift-system/78/' == zz.build_url  # noqa
        assert zz.junit_xml is not None
        assert '78' == zz.build_number
        assert False is zz.pprint_on_fail
        assert zz.testsuite_props
    def test_create_test_cycle(self, single_passing_xml, mocker):
        """Verify that a new test cycle will be created when the desired cycle name cannot be found."""

        # Setup
        test_cycle_name = 'Buttons'

        # Expectation
        test_cycle_pid_exp = 'CL-3'

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'Failure Output'
        mock_get_tc_resp = mocker.Mock(spec=swagger_client.TestCycleResource)
        mock_create_tc_resp = mocker.Mock(
            spec=swagger_client.TestCycleResource)
        mock_get_tc_resp.to_dict.return_value = {
            'name': 'queens',
            'pid': 'CL-2'
        }
        mock_create_tc_resp.to_dict.return_value = {
            'name': test_cycle_name,
            'pid': test_cycle_pid_exp
        }
        response = {
            'items': [{
                'name': 'insert name here',
                'id': 12345
            }],
            'total': 1
        }
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response)

        mocker.patch('requests.post', return_value=mock_post_response)
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])
        mocker.patch('swagger_client.TestcycleApi.get_test_cycles',
                     return_value=[mock_get_tc_resp])
        mocker.patch('swagger_client.TestcycleApi.create_cycle',
                     return_value=mock_create_tc_resp)

        # Setup
        zz = ZigZag(single_passing_xml, TOKEN, PROJECT_ID, TEST_CYCLE)
        mhf = ModuleHierarchyFacade(zz)

        # Test
        assert test_cycle_pid_exp == mhf.discover_root_test_cycle(
            test_cycle_name)
예제 #27
0
    def test_label_not_found(self, single_fail_xml, mocker):
        """Search for a label that does not exist"""
        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'foo'
        mocker.patch('swagger_client.FieldApi.get_fields', return_value=[mock_field_resp])
        response = {'items': [{'name': 'insert name here', 'id': 12345}], 'total': 1}
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response)
        mocker.patch('requests.post', return_value=mock_post_response)

        # Setup
        zz = ZigZag(single_fail_xml, TOKEN, PROJECT_ID, TEST_CYCLE)
        uf = UtilityFacade(zz)

        result = uf.find_custom_field_id_by_label('Failure Output', 'test-runs')
        assert result is None
    def test_discover_existing_test_cycle_with_case_change(
            self, single_passing_xml, mocker):
        """Verify that the PID for an existing test cycle can be discovered when using a different case for search."""

        # Expectation
        test_cycle_pid_exp = 'CL-2'

        # Mock
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'Failure Output'
        mock_tc_resp = mocker.Mock(spec=swagger_client.TestCycleResource)
        mock_tc_resp.to_dict.return_value = {
            'name': 'queens',
            'pid': test_cycle_pid_exp
        }
        response = {
            'items': [{
                'name': 'insert name here',
                'id': 12345
            }],
            'total': 1
        }
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response)

        mocker.patch('requests.post', return_value=mock_post_response)
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])
        mocker.patch('swagger_client.TestcycleApi.get_test_cycles',
                     return_value=[mock_tc_resp])

        # Setup
        test_cycle_name = 'Queens'
        zz = ZigZag(single_passing_xml, TOKEN, PROJECT_ID, TEST_CYCLE)
        mhf = ModuleHierarchyFacade(zz)

        # Test
        assert test_cycle_pid_exp == mhf.discover_root_test_cycle(
            test_cycle_name)
예제 #29
0
    def test_mix_status(self, flat_mix_status_xml, mocker):
        """Verify that a valid qTest 'AutomationRequest' swagger model is generated from a JUnitXML file
        that contains multiple tests with different status results
        """

        # Mock
        test_cycle_name = 'queens'
        test_cycle_pid = 'CL-1'
        mock_get_tc_resp = mocker.Mock(spec=swagger_client.TestCycleResource)
        mock_create_tc_resp = mocker.Mock(
            spec=swagger_client.TestCycleResource)
        mock_get_tc_resp.to_dict.return_value = {
            'name': 'queens',
            'pid': 'CL-2'
        }
        mock_create_tc_resp.to_dict.return_value = {
            'name': test_cycle_name,
            'pid': test_cycle_pid
        }
        mock_field_resp = mocker.Mock(spec=swagger_client.FieldResource)
        mock_field_resp.id = 12345
        mock_field_resp.label = 'Failure Output'
        response = {
            'items': [{
                'name': 'insert name here',
                'id': 12345
            }],
            'total': 1
        }
        mock_link_response = mocker.Mock(
            spec=swagger_client.LinkedArtifactContainer)
        mock_post_response = mocker.Mock(spec=requests.Response)
        mock_post_response.text = json.dumps(response)
        mocker.patch('requests.post', return_value=mock_post_response)
        mocker.patch('swagger_client.FieldApi.get_fields',
                     return_value=[mock_field_resp])
        mocker.patch('swagger_client.ObjectlinkApi.link_artifacts',
                     return_value=[mock_link_response])
        mocker.patch('swagger_client.TestcycleApi.get_test_cycles',
                     return_value=[mock_get_tc_resp])
        mocker.patch('swagger_client.TestcycleApi.create_cycle',
                     return_value=mock_create_tc_resp)

        # Setup
        zz = ZigZag(flat_mix_status_xml, TOKEN, PROJECT_ID, TEST_CYCLE)
        zz.parse()
        auto_req_dict = zz._generate_auto_request().to_dict()

        # Expectation
        test_logs_exp = [
            pytest.helpers.merge_dicts(SHARED_TEST_LOG_EXP, {
                'name': 'test_pass',
                'status': 'PASSED'
            }),
            pytest.helpers.merge_dicts(SHARED_TEST_LOG_EXP, {
                'name': 'test_fail',
                'status': 'FAILED'
            }),
            pytest.helpers.merge_dicts(SHARED_TEST_LOG_EXP, {
                'name': 'test_error',
                'status': 'FAILED'
            }),
            pytest.helpers.merge_dicts(SHARED_TEST_LOG_EXP, {
                'name': 'test_skip',
                'status': 'SKIPPED'
            })
        ]

        # Test
        for x in range(len(auto_req_dict['test_logs'])):
            for key in test_logs_exp[x]:
                expected = test_logs_exp[x][key]
                observed = auto_req_dict['test_logs'][x][key]
                assert expected == observed