{"action":"created","comment":{"url":"https://api.github.com/repos/rcbops/zigzag/pulls/comments/203524970","pull_request_review_id":138432791,"id":203524970,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIwMzUyNDk3MA==","diff_hunk":"@@ -0,0 +1,1064 @@\n+# -*- coding: utf-8 -*-\n+\n+# ======================================================================================================================\n+# Imports\n+# ======================================================================================================================\n+import os\n+import re\n+import uuid\n+import json\n+import pytest\n+import string\n+import requests\n+import swagger_client\n+from time import sleep\n+from random import choice\n+from zigzag.zigzag import ZigZag\n+from datetime import datetime, timedelta\n+from swagger_client.rest import ApiException\n+from jinja2 import Environment, FileSystemLoader\n+try:\n+    # noinspection PyCompatibility\n+    from collections.abc import Sequence\n+except ImportError:\n+    from collections import Sequence\n+pytest_plugins = ['helpers_namespace']\n+\n+# ======================================================================================================================\n+# Globals\n+# ======================================================================================================================\n+DEFAULT_ASC_GLOBAL_PROPERTIES = {\"BUILD_URL\": \"BUILD_URL\",\n+                                 \"BUILD_NUMBER\": \"BUILD_NUMBER\",\n+                                 \"RE_JOB_ACTION\": \"RE_JOB_ACTION\",\n+                                 \"RE_JOB_IMAGE\": \"RE_JOB_IMAGE\",\n+                                 \"RE_JOB_SCENARIO\": \"RE_JOB_SCENARIO\",\n+                                 \"RE_JOB_BRANCH\": \"RE_JOB_BRANCH\",\n+                                 \"RPC_RELEASE\": \"RPC_RELEASE\",\n+                                 \"RPC_PRODUCT_RELEASE\": \"RPC_PRODUCT_RELEASE\",\n+                                 \"OS_ARTIFACT_SHA\": \"OS_ARTIFACT_SHA\",\n+                                 \"PYTHON_ARTIFACT_SHA\": \"PYTHON_ARTIFACT_SHA\",\n+                                 \"APT_ARTIFACT_SHA\": \"APT_ARTIFACT_SHA\",\n+                                 \"REPO_URL\": \"REPO_URL\",\n+                                 \"JOB_NAME\": \"JOB_NAME\",\n+                                 \"MOLECULE_TEST_REPO\": \"MOLECULE_TEST_REPO\",\n+                                 \"MOLECULE_SCENARIO_NAME\": \"MOLECULE_SCENARIO_NAME\",\n+                                 \"ci-environment\": \"asc\"}\n+\n+DEFAULT_MK8S_GLOBAL_PROPERTIES = {\"BUILD_URL\": \"BUILD_URL\",\n+                                  \"BUILD_NUMBER\": \"BUILD_NUMBER\",\n+                                  \"RE_JOB_ACTION\": \"RE_JOB_ACTION\",\n+                                  \"RE_JOB_IMAGE\": \"RE_JOB_IMAGE\",\n+                                  \"RE_JOB_SCENARIO\": \"RE_JOB_SCENARIO\",\n+                                  \"RE_JOB_BRANCH\": \"RE_JOB_BRANCH\",\n+                                  \"RPC_RELEASE\": \"RPC_RELEASE\",\n+                                  \"RPC_PRODUCT_RELEASE\": \"RPC_PRODUCT_RELEASE\",\n+                                  \"OS_ARTIFACT_SHA\": \"OS_ARTIFACT_SHA\",\n+                                  \"PYTHON_ARTIFACT_SHA\": \"PYTHON_ARTIFACT_SHA\",\n+                                  \"APT_ARTIFACT_SHA\": \"APT_ARTIFACT_SHA\",\n+                                  \"REPO_URL\": \"REPO_URL\",\n+                                  \"JOB_NAME\": \"JOB_NAME\",\n+                                  \"MOLECULE_TEST_REPO\": \"MOLECULE_TEST_REPO\",\n+                                  \"MOLECULE_SCENARIO_NAME\": \"MOLECULE_SCENARIO_NAME\",\n+                                  \"ci-environment\": \"asc\"}\n+\n+\n+# ======================================================================================================================\n+# Classes\n+# ======================================================================================================================\n+class TestCaseInfo(object):\n+    def __init__(self,\n+                 qtest_api_token,\n+                 qtest_project_id,\n+                 state,\n+                 name=None,\n+                 class_name=None,\n+                 file_path=None,\n+                 line=None,\n+                 start=None,\n+                 duration=None,\n+                 message=None,\n+                 jira_tickets=None):\n+        \"\"\"Capture or generate test case information to be used in validation of JUnitXML documents.\n+\n+        Args:\n+            qtest_api_token (str): The API token for the target qTest project.\n+            qtest_project_id (int): The target qTest project under test.\n+            state (str): The state of the test. (Valid values: 'passed', 'skipped', 'failed', 'errored')\n+            name (str): The desired name of the test. (Automatically generated if value is None)\n+            class_name (str): The desired classname of the test. (Automatically generated if value is None)\n+            file_path (str): The desired file path of the test. (Automatically generated if value is None)\n+            line (int): The line number at which the test case can be found in the \"file_path\".\n+                (Automatically generated if value is None)\n+            start (datetime.datetime): Execution start time. (Automatically generated if value is None)\n+            duration (int): The desired duration of the test in seconds. (Automatically generated if value is None)\n+            message (str): The desired message for the test which is only used for 'skipped', 'failed', 'errored'\n+                test states. (Automatically generated if value is None)\n+            jira_tickets (list(str)): A list of Jira ticket IDs to associated with the test case.\n+                (Automatically generated if value is None)\n+\n+        Raises:\n+            RuntimeError: Invalid value provided for the 'state' argument.\n+        \"\"\"\n+\n+        if state not in ('passed', 'skipped', 'failed', 'errored'):\n+            raise RuntimeError(\"Invalid value provided for the 'state' argument!\")\n+\n+        self._state = state\n+        self._qtest_api_token = qtest_api_token\n+        self._qtest_project_id = qtest_project_id\n+        self._name = name if name else \"test_{}\".format(str(uuid.uuid1()))\n+        self._class_name = class_name\n+        self._file_path = file_path\n+        self._line = line\n+        self._duration = duration if duration else 1\n+        self._message = message\n+        self._jira_tickets = jira_tickets if jira_tickets \\\n+            else [\"JIRA-{}\".format(''.join(choice(string.digits) for _ in range(4)))]\n+\n+        self._test_id = str(uuid.uuid1())\n+        self._start_time = start if start else datetime.utcnow()\n+        self._end_time = self._start_time + timedelta(seconds=self._duration)\n+        self._qtest_testcase_id = None\n+        self._qtest_test_run_ids = None\n+        self._qtest_parent_module_id = None\n+        self._qtest_root_module_id = None\n+\n+    @property\n+    def state(self):\n+        \"\"\"The execution state of the test case. ('passed', 'skipped', 'failed', 'errored')\n+\n+        Returns:\n+            str: Execution state of the test case. ('passed', 'skipped', 'failed', 'errored')\n+        \"\"\"\n+\n+        return self._state\n+\n+    @property\n+    def name(self):\n+        \"\"\"The name of the test case.\n+\n+        Returns:\n+            str: Test case name.\n+        \"\"\"\n+\n+        return self._name\n+\n+    @property\n+    def class_name(self):\n+        \"\"\"The 'classname' for the test case. (JUnitXML 'testcase' attribute)\n+\n+        Returns:\n+            str: Test case 'classname' JUnitXML attribute.\n+        \"\"\"\n+\n+        return self._class_name\n+\n+    @property\n+    def file_path(self):\n+        \"\"\"The 'file' for the test case which is usually a file path. (JUnitXML 'testcase' attribute)\n+\n+        Returns:\n+            str: Test case 'file' JUnitXML attribute.\n+        \"\"\"\n+\n+        return self._file_path\n+\n+    @property\n+    def line(self):\n+        \"\"\"The 'line' number at which the test case can be found in the 'file' path. (JUnitXML 'testcase' attribute)\n+\n+        Returns:\n+            int: Test case 'line' JUnitXML attribute.\n+        \"\"\"\n+\n+        return self._line\n+\n+    @property\n+    def duration(self):\n+        \"\"\"The execution duration for the test case in seconds.\n+\n+        Returns:\n+            int: Execution duration for the test case in seconds.\n+        \"\"\"\n+\n+        return self._duration\n+\n+    @property\n+    def short_msg(self):\n+        \"\"\"The short message for non-passed test case states.\n+\n+        Returns:\n+            int: Short message.\n+        \"\"\"\n+\n+        return \"{} (short)\".format(self._message)\n+\n+    @property\n+    def long_msg(self):\n+        \"\"\"The long message for non-passed test case states.\n+\n+        Returns:\n+            int: Long message.\n+        \"\"\"\n+\n+        return \"{} (long)\".format(self._message)\n+\n+    @property\n+    def jira_tickets(self):\n+        \"\"\"A list of 'jira' properties for the test case which represent associated Jira tickets.\n+\n+        Returns:\n+            str: A list of 'jira' properties for the test case.\n+        \"\"\"\n+\n+        return self._jira_tickets\n+\n+    @property\n+    def test_id(self):\n+        \"\"\"The 'test_id' property for the test case.\n+\n+        Returns:\n+            str:  Test case 'test_id' property.\n+        \"\"\"\n+\n+        return self._test_id\n+\n+    @property\n+    def start_time(self):\n+        \"\"\"The 'start_time' property for the test case.\n+\n+        Returns:\n+            str: Test case 'start_time' property. (In UTC format in Zulu timezone.)\n+        \"\"\"\n+\n+        return self._start_time.strftime('%Y-%m-%dT%H:%M:%SZ')\n+\n+    @property\n+    def end_time(self):\n+        \"\"\"The 'start_time' property for the test case.\n+\n+        Returns:\n+            str: Test case 'start_time' property. (In UTC format in Zulu timezone.)\n+        \"\"\"\n+\n+        return self._end_time.strftime('%Y-%m-%dT%H:%M:%SZ')\n+\n+    @property\n+    def qtest_parent_module_id(self):\n+        \"\"\"The qTest parent module ID for the given test case.\n+\n+        Returns:\n+            int: The qTest parent module ID for the given test case.\n+\n+        Raises:\n+            AssertionError: Test case does not exist.\n+            RuntimeError: General qTest API failure.\n+        \"\"\"\n+\n+        if not self._qtest_parent_module_id:\n+            testcase_api = swagger_client.TestcaseApi()\n+\n+            try:\n+                self._qtest_parent_module_id = \\\n+                    testcase_api.get_test_case(self._qtest_project_id, self.qtest_test_case_id).parent_id\n+            except ApiException as e:\n+                raise RuntimeError(\"The qTest API reported an error!\\n\"\n+                                   \"Status code: {}\\n\"\n+                                   \"Reason: {}\\n\"\n+                                   \"Message: {}\".format(e.status, e.reason, e.body))\n+\n+        return self._qtest_parent_module_id\n+\n+    @property\n+    def qtest_root_module_id(self):\n+        \"\"\"The qTest root module ID of the \"Test Design\" module hierarchy for the given test case.\n+\n+        Returns:\n+            int: The qTest parent module ID for the given test case.\n+\n+        Raises:\n+            AssertionError: Test case does not exist.\n+            RuntimeError: General qTest API failure.\n+        \"\"\"\n+\n+        def _find_root_module(module_id, last_id=None):\n+            module_api = swagger_client.ModuleApi()\n+\n+            try:\n+                parent_module_id = module_api.get_module(self._qtest_project_id, module_id).parent_id\n+            except ApiException as e:\n+                if e.status == 404 and 'Module does not exist' in e.body:\n+                    parent_module_id = None\n+                else:\n+                    raise RuntimeError(\"The qTest API reported an error!\\n\"\n+                                       \"Status code: {}\\n\"\n+                                       \"Reason: {}\\n\"\n+                                       \"Message: {}\".format(e.status, e.reason, e.body))\n+\n+            if parent_module_id:\n+                return _find_root_module(parent_module_id, last_id=module_id)\n+            else:\n+                return last_id\n+\n+        if not self._qtest_root_module_id:\n+            self._qtest_root_module_id = _find_root_module(self.qtest_parent_module_id)\n+\n+        return self._qtest_root_module_id\n+\n+    @property\n+    def qtest_test_case_id(self):\n+        \"\"\"The qTest test case ID for the given test case.\n+\n+        Returns:\n+            int: The qTest test case ID for the given test case.\n+\n+        Raises:\n+            AssertionError: Test case does not exist.\n+        \"\"\"\n+\n+        if not self._qtest_testcase_id:\n+            self.assert_exists()\n+\n+        return self._qtest_testcase_id\n+\n+    @property\n+    def qtest_test_run_ids(self):\n+        \"\"\"The test run IDs associated with test case.\n+\n+        Returns:\n+            list(int): A list of test run IDs associated with test case.\n+\n+        Raises:\n+            AssertionError: Test case does not exist.\n+        \"\"\"\n+\n+        if not self._qtest_test_run_ids:\n+            self.assert_executed()\n+\n+        return self._qtest_test_run_ids\n+\n+    def clean_up(self):\n+        \"\"\"Delete the test case and associated test runs from the qTest project under test.\n+\n+        Use this method with caution as it will only delete the test case and associated runs. It will NOT move the\n+        \"Test Design\" module hierarchy or \"Test Execution\" test cycle hierarchy. Use the \"clean_up\" method on the\n+        TestSuiteInfo as a first preference given it can clean-up everything.\n+\n+        Raises:\n+            RuntimeError: Failed to clean-up.\n+        \"\"\"\n+\n+        testcase_api = swagger_client.TestcaseApi()\n+\n+        try:\n+            testcase_api.delete_test_case(self._qtest_project_id, self.qtest_test_case_id)\n+        except ApiException as e:\n+            raise RuntimeError(\"The qTest API reported an error!\\n\"\n+                               \"Status code: {}\\n\"\n+                               \"Reason: {}\\n\"\n+                               \"Message: {}\".format(e.status, e.reason, e.body))\n+\n+    def assert_exists(self):\n+        \"\"\"Verify that the given test case is present in the \"Test Design\" view.\n+\n+        Raises:\n+            AssertionError: Test case does not exist.\n+        \"\"\"\n+\n+        query = \"'name' ~ '{}'\".format(self.name)\n+        result = search_qtest(self._qtest_api_token, self._qtest_project_id, 'test-cases', query, ['id'])\n+\n+        if result['items']:\n+            self._qtest_testcase_id = result['items'][0]['id']\n+        else:\n+            raise AssertionError(\"Test case '{}' does not exist!\".format(self.name))\n+\n+    def assert_executed(self):\n+        \"\"\"Verify that the given test case has been executed at least once.\n+\n+        Raises:\n+            AssertionError: Test case does not exist.\n+        \"\"\"\n+\n+        query = \"'name' ~ '{}'\".format(self.name)\n+        result = search_qtest(self._qtest_api_token, self._qtest_project_id, 'test-runs', query, ['id'])\n+\n+        if result['items']:\n+            self._qtest_test_run_ids = [test_run['id'] for test_run in result['items']]\n+        else:\n+            raise AssertionError(\"Test case '{}' has no associate test runs!\".format(self.name))\n+\n+    def reset(self):\n+        \"\"\"Reset cached data on this test case.\"\"\"\n+\n+        self._qtest_testcase_id = None\n+        self._qtest_test_run_ids = None\n+        self._qtest_parent_module_id = None\n+        self._qtest_root_module_id = None\n+\n+\n+class TestSuiteInfo(Sequence):\n+    def __init__(self, qtest_api_token, qtest_project_id):\n+        \"\"\"Create a collection of TestCaseInfo objects to be used in validation of JUnitXML documents.\n+\n+        Args:\n+            qtest_api_token (str): The API token for the target qTest project.\n+            qtest_project_id (int): The target qTest project under test.\n+        \"\"\"\n+\n+        self._qtest_api_token = qtest_api_token\n+        self._qtest_project_id = qtest_project_id\n+        self._tests = []\n+        self._total_count = 0\n+        self._skip_count = 0\n+        self._failure_count = 0\n+        self._error_count = 0\n+        self._total_duration = 0\n+        self._start_time = datetime.utcnow()\n+\n+    @property\n+    def total_count(self):\n+        \"\"\"The total number of test cases in this collection.\n+\n+        Returns:\n+            int:  The total number of test cases in this collection.\n+        \"\"\"\n+\n+        return self._total_count\n+\n+    @property\n+    def skip_count(self):\n+        \"\"\"The total number of test cases with 'skipped' state in this collection.\n+\n+        Returns:\n+            int:  The total number of test cases with 'skipped' state in this collection.\n+        \"\"\"\n+\n+        return self._skip_count\n+\n+    @property\n+    def failure_count(self):\n+        \"\"\"The total number of test cases with 'failed' state in this collection.\n+\n+        Returns:\n+            int:  The total number of test cases with 'failed' state in this collection.\n+        \"\"\"\n+\n+        return self._failure_count\n+\n+    @property\n+    def error_count(self):\n+        \"\"\"The total number of test cases with 'errored' state in this collection.\n+\n+        Returns:\n+            int:  The total number of test cases with 'errored' state in this collection.\n+        \"\"\"\n+\n+        return self._error_count\n+\n+    @property\n+    def total_duration(self):\n+        \"\"\"The total duration for all tests in this collection.\n+\n+        Returns:\n+            int:  The total duration for all tests in this collection.\n+        \"\"\"\n+\n+        return self._total_duration\n+\n+    def add_test_case(self,\n+                      state,\n+                      name=None,\n+                      class_name=None,\n+                      file_path=None,\n+                      line=None,\n+                      start=None,\n+                      duration=None,\n+                      message=None,\n+                      jira_tickets=None):\n+        \"\"\"Add a test case to the collection of test cases.\n+\n+        Args:\n+            state (str): The state of the test. ('passed', 'skipped', 'failed', 'errored')\n+            name (str): The desired name of the test. (Automatically generated if value is None)\n+            class_name (str): The desired classname of the test. (Automatically generated if value is None)\n+            file_path (str): The desired file path of the test. (Automatically generated if value is None)\n+            line (int): The line number at which the test case can be found in the \"file_path\".\n+                (Automatically generated if value is None)\n+            start (datetime.datetime): Execution start time. (Automatically generated if value is None)\n+            duration (int): The desired duration of the test in seconds. (Automatically generated if value is None)\n+            message (str): The desired message for the test which is only used for 'skipped', 'failed', 'errored'\n+                test states. (Automatically generated if value is None)\n+            jira_tickets (list(str)): A list of Jira ticket IDs to associated with the test case.\n+                (Automatically generated if value is None)\n+\n+        Raises:\n+            RuntimeError: Invalid value provided for the 'state' argument.\n+        \"\"\"\n+\n+        start = start if start else self._start_time\n+        duration = duration if duration else choice(range(1, 11))\n+        test_case = TestCaseInfo(self._qtest_api_token,\n+                                 self._qtest_project_id,\n+                                 state,\n+                                 name,\n+                                 class_name,\n+                                 file_path,\n+                                 line,\n+                                 start,\n+                                 duration,\n+                                 message,\n+                                 jira_tickets)\n+        self._tests.append(test_case)\n+\n+        if test_case.state == 'skipped':\n+            self._skip_count += 1\n+        elif test_case.state == 'failed':\n+            self._failure_count += 1\n+        elif test_case.state == 'errored':\n+            self._error_count += 1\n+\n+        self._total_count += 1\n+        self._total_duration += duration\n+        self._start_time = self._start_time + timedelta(duration)\n+\n+    def clean_up(self):\n+        \"\"\"Delete all test cases and associated test runs from the qTest project under test. This will also clean-up\n+        the \"Test Design\" module hierarchy.\n+\n+        Raises:\n+            RuntimeError: Failed to clean-up.\n+        \"\"\"\n+\n+        root_module_ids = []\n+        module_api = swagger_client.ModuleApi()\n+\n+        for test in self._tests:\n+            if test.qtest_root_module_id not in root_module_ids:\n+                root_module_ids.append(test.qtest_root_module_id)\n+\n+        for root_module_id in root_module_ids:\n+            try:\n+                module_api.delete_module(qtest_env_vars['QTEST_SANDBOX_PROJECT_ID'], root_module_id, force=True)\n+            except ApiException as e:\n+                if not (e.status == 404 and 'Module does not exist' in e.body):\n+                    raise RuntimeError(\"The qTest API reported an error!\\n\"\n+                                       \"Status code: {}\\n\"\n+                                       \"Reason: {}\\n\"\n+                                       \"Message: {}\".format(e.status, e.reason, e.body))\n+\n+        self.reset()\n+\n+    def count(self, value):\n+        \"\"\"Return the number of times x appears in the list.\n+\n+        Args:\n+            value (object): Desired value to search for within the list.\n+\n+        Returns:\n+            int: number of times 'value' appears in the list.\n+        \"\"\"\n+\n+        return self._tests.count(value)\n+\n+    def index(self, value, start=None, stop=None):\n+        \"\"\"Return zero-based index in the list of the first item whose value is equal to 'value'.\n+\n+        The optional arguments start and stop are interpreted as in the slice notation and are used to limit the search\n+        to a particular subsequence of the list. The returned index is computed relative to the beginning of the full\n+        sequence rather than the start argument.\n+\n+        Args:\n+            value (object): Desired value to search for within the list.\n+            start (int): Starting slice index. (Optional)\n+            stop (int): Ending slice index. (Optional)\n+\n+        Returns:\n+            int: Zero-based index in the list of the first item whose value is equal to 'value'\n+\n+        Raises:\n+            ValueError: No such value exists in collection.\n+        \"\"\"\n+\n+        return self._tests.index(value, start, stop)\n+\n+    def reset(self):\n+        \"\"\"Reset cached data for all the tests in this suite.\"\"\"\n+\n+        for test in self._tests:\n+            test.reset()\n+\n+    def __reversed__(self):\n+        \"\"\"Sequence ABC override.\"\"\"","path":"tests/integration/conftest.py","position":592,"original_position":592,"commit_id":"82470ec176bf033213cf74f961c4456f7634f691","original_commit_id":"82470ec176bf033213cf74f961c4456f7634f691","user":{"login":"johnduarte","id":1040859,"node_id":"MDQ6VXNlcjEwNDA4NTk=","avatar_url":"https://avatars2.githubusercontent.com/u/1040859?v=4","gravatar_id":"","url":"https://api.github.com/users/johnduarte","html_url":"https://github.com/johnduarte","followers_url":"https://api.github.com/users/johnduarte/followers","following_url":"https://api.github.com/users/johnduarte/following{/other_user}","gists_url":"https://api.github.com/users/johnduarte/gists{/gist_id}","starred_url":"https://api.github.com/users/johnduarte/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/johnduarte/subscriptions","organizations_url":"https://api.github.com/users/johnduarte/orgs","repos_url":"https://api.github.com/users/johnduarte/repos","events_url":"https://api.github.com/users/johnduarte/events{/privacy}","received_events_url":"https://api.github.com/users/johnduarte/received_events","type":"User","site_admin":false},"body":"What does this mean?","created_at":"2018-07-18T20:50:53Z","updated_at":"2018-07-18T20:57:44Z","html_url":"https://github.com/rcbops/zigzag/pull/36#discussion_r203524970","pull_request_url":"https://api.github.com/repos/rcbops/zigzag/pulls/36","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/rcbops/zigzag/pulls/comments/203524970"},"html":{"href":"https://github.com/rcbops/zigzag/pull/36#discussion_r203524970"},"pull_request":{"href":"https://api.github.com/repos/rcbops/zigzag/pulls/36"}}},"pull_request":{"url":"https://api.github.com/repos/rcbops/zigzag/pulls/36","id":202339572,"node_id":"MDExOlB1bGxSZXF1ZXN0MjAyMzM5NTcy","html_url":"https://github.com/rcbops/zigzag/pull/36","diff_url":"https://github.com/rcbops/zigzag/pull/36.diff","patch_url":"https://github.com/rcbops/zigzag/pull/36.patch","issue_url":"https://api.github.com/repos/rcbops/zigzag/issues/36","number":36,"state":"open","locked":false,"title":"ASC-734 Implement Integration Test Layer","user":{"login":"ryan-rs","id":34456596,"node_id":"MDQ6VXNlcjM0NDU2NTk2","avatar_url":"https://avatars3.githubusercontent.com/u/34456596?v=4","gravatar_id":"","url":"https://api.github.com/users/ryan-rs","html_url":"https://github.com/ryan-rs","followers_url":"https://api.github.com/users/ryan-rs/followers","following_url":"https://api.github.com/users/ryan-rs/following{/other_user}","gists_url":"https://api.github.com/users/ryan-rs/gists{/gist_id}","starred_url":"https://api.github.com/users/ryan-rs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ryan-rs/subscriptions","organizations_url":"https://api.github.com/users/ryan-rs/orgs","repos_url":"https://api.github.com/users/ryan-rs/repos","events_url":"https://api.github.com/users/ryan-rs/events{/privacy}","received_events_url":"https://api.github.com/users/ryan-rs/received_events","type":"User","site_admin":false},"body":"Add pytest fixtures, helpers and classes to enable integration of ZigZag with\r\na real qTest instance. The integration test suite can be executed via the\r\n\"test-integration\" Makefile task.\r\n\r\nAdded two integration tests demonstrating how to use the various integration\r\ntest fixture and associated helpers.","created_at":"2018-07-18T18:23:02Z","updated_at":"2018-07-18T20:57:44Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5d6cf8fb3fb49fa5541cabbb0f02aefa39aa0f67","assignee":null,"assignees":[],"requested_reviewers":[{"login":"mwbutcher","id":952354,"node_id":"MDQ6VXNlcjk1MjM1NA==","avatar_url":"https://avatars1.githubusercontent.com/u/952354?v=4","gravatar_id":"","url":"https://api.github.com/users/mwbutcher","html_url":"https://github.com/mwbutcher","followers_url":"https://api.github.com/users/mwbutcher/followers","following_url":"https://api.github.com/users/mwbutcher/following{/other_user}","gists_url":"https://api.github.com/users/mwbutcher/gists{/gist_id}","starred_url":"https://api.github.com/users/mwbutcher/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mwbutcher/subscriptions","organizations_url":"https://api.github.com/users/mwbutcher/orgs","repos_url":"https://api.github.com/users/mwbutcher/repos","events_url":"https://api.github.com/users/mwbutcher/events{/privacy}","received_events_url":"https://api.github.com/users/mwbutcher/received_events","type":"User","site_admin":false},{"login":"zreichert","id":2602509,"node_id":"MDQ6VXNlcjI2MDI1MDk=","avatar_url":"https://avatars2.githubusercontent.com/u/2602509?v=4","gravatar_id":"","url":"https://api.github.com/users/zreichert","html_url":"https://github.com/zreichert","followers_url":"https://api.github.com/users/zreichert/followers","following_url":"https://api.github.com/users/zreichert/following{/other_user}","gists_url":"https://api.github.com/users/zreichert/gists{/gist_id}","starred_url":"https://api.github.com/users/zreichert/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zreichert/subscriptions","organizations_url":"https://api.github.com/users/zreichert/orgs","repos_url":"https://api.github.com/users/zreichert/repos","events_url":"https://api.github.com/users/zreichert/events{/privacy}","received_events_url":"https://api.github.com/users/zreichert/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[{"id":997975379,"node_id":"MDU6TGFiZWw5OTc5NzUzNzk=","url":"https://api.github.com/repos/rcbops/zigzag/labels/v0.11.0","name":"v0.11.0","color":"4a23d3","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/rcbops/zigzag/pulls/36/commits","review_comments_url":"https://api.github.com/repos/rcbops/zigzag/pulls/36/comments","review_comment_url":"https://api.github.com/repos/rcbops/zigzag/pulls/comments{/number}","comments_url":"https://api.github.com/repos/rcbops/zigzag/issues/36/comments","statuses_url":"https://api.github.com/repos/rcbops/zigzag/statuses/82470ec176bf033213cf74f961c4456f7634f691","head":{"label":"ryan-rs:feature/ASC-734/integration_test_framework","ref":"feature/ASC-734/integration_test_framework","sha":"82470ec176bf033213cf74f961c4456f7634f691","user":{"login":"ryan-rs","id":34456596,"node_id":"MDQ6VXNlcjM0NDU2NTk2","avatar_url":"https://avatars3.githubusercontent.com/u/34456596?v=4","gravatar_id":"","url":"https://api.github.com/users/ryan-rs","html_url":"https://github.com/ryan-rs","followers_url":"https://api.github.com/users/ryan-rs/followers","following_url":"https://api.github.com/users/ryan-rs/following{/other_user}","gists_url":"https://api.github.com/users/ryan-rs/gists{/gist_id}","starred_url":"https://api.github.com/users/ryan-rs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ryan-rs/subscriptions","organizations_url":"https://api.github.com/users/ryan-rs/orgs","repos_url":"https://api.github.com/users/ryan-rs/repos","events_url":"https://api.github.com/users/ryan-rs/events{/privacy}","received_events_url":"https://api.github.com/users/ryan-rs/received_events","type":"User","site_admin":false},"repo":{"id":127208797,"node_id":"MDEwOlJlcG9zaXRvcnkxMjcyMDg3OTc=","name":"zigzag","full_name":"ryan-rs/zigzag","owner":{"login":"ryan-rs","id":34456596,"node_id":"MDQ6VXNlcjM0NDU2NTk2","avatar_url":"https://avatars3.githubusercontent.com/u/34456596?v=4","gravatar_id":"","url":"https://api.github.com/users/ryan-rs","html_url":"https://github.com/ryan-rs","followers_url":"https://api.github.com/users/ryan-rs/followers","following_url":"https://api.github.com/users/ryan-rs/following{/other_user}","gists_url":"https://api.github.com/users/ryan-rs/gists{/gist_id}","starred_url":"https://api.github.com/users/ryan-rs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ryan-rs/subscriptions","organizations_url":"https://api.github.com/users/ryan-rs/orgs","repos_url":"https://api.github.com/users/ryan-rs/repos","events_url":"https://api.github.com/users/ryan-rs/events{/privacy}","received_events_url":"https://api.github.com/users/ryan-rs/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/ryan-rs/zigzag","description":"Parse JUnitXML and upload test results to qTest API","fork":true,"url":"https://api.github.com/repos/ryan-rs/zigzag","forks_url":"https://api.github.com/repos/ryan-rs/zigzag/forks","keys_url":"https://api.github.com/repos/ryan-rs/zigzag/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ryan-rs/zigzag/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ryan-rs/zigzag/teams","hooks_url":"https://api.github.com/repos/ryan-rs/zigzag/hooks","issue_events_url":"https://api.github.com/repos/ryan-rs/zigzag/issues/events{/number}","events_url":"https://api.github.com/repos/ryan-rs/zigzag/events","assignees_url":"https://api.github.com/repos/ryan-rs/zigzag/assignees{/user}","branches_url":"https://api.github.com/repos/ryan-rs/zigzag/branches{/branch}","tags_url":"https://api.github.com/repos/ryan-rs/zigzag/tags","blobs_url":"https://api.github.com/repos/ryan-rs/zigzag/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ryan-rs/zigzag/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ryan-rs/zigzag/git/refs{/sha}","trees_url":"https://api.github.com/repos/ryan-rs/zigzag/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ryan-rs/zigzag/statuses/{sha}","languages_url":"https://api.github.com/repos/ryan-rs/zigzag/languages","stargazers_url":"https://api.github.com/repos/ryan-rs/zigzag/stargazers","contributors_url":"https://api.github.com/repos/ryan-rs/zigzag/contributors","subscribers_url":"https://api.github.com/repos/ryan-rs/zigzag/subscribers","subscription_url":"https://api.github.com/repos/ryan-rs/zigzag/subscription","commits_url":"https://api.github.com/repos/ryan-rs/zigzag/commits{/sha}","git_commits_url":"https://api.github.com/repos/ryan-rs/zigzag/git/commits{/sha}","comments_url":"https://api.github.com/repos/ryan-rs/zigzag/comments{/number}","issue_comment_url":"https://api.github.com/repos/ryan-rs/zigzag/issues/comments{/number}","contents_url":"https://api.github.com/repos/ryan-rs/zigzag/contents/{+path}","compare_url":"https://api.github.com/repos/ryan-rs/zigzag/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ryan-rs/zigzag/merges","archive_url":"https://api.github.com/repos/ryan-rs/zigzag/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ryan-rs/zigzag/downloads","issues_url":"https://api.github.com/repos/ryan-rs/zigzag/issues{/number}","pulls_url":"https://api.github.com/repos/ryan-rs/zigzag/pulls{/number}","milestones_url":"https://api.github.com/repos/ryan-rs/zigzag/milestones{/number}","notifications_url":"https://api.github.com/repos/ryan-rs/zigzag/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ryan-rs/zigzag/labels{/name}","releases_url":"https://api.github.com/repos/ryan-rs/zigzag/releases{/id}","deployments_url":"https://api.github.com/repos/ryan-rs/zigzag/deployments","created_at":"2018-03-28T23:05:11Z","updated_at":"2018-07-12T17:51:58Z","pushed_at":"2018-07-18T18:22:20Z","git_url":"git://github.com/ryan-rs/zigzag.git","ssh_url":"git@github.com:ryan-rs/zigzag.git","clone_url":"https://github.com/ryan-rs/zigzag.git","svn_url":"https://github.com/ryan-rs/zigzag","homepage":null,"size":113,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"rcbops:master","ref":"master","sha":"558e5ca7e67f3dd924e4df7c3fb680e9a8414c5e","user":{"login":"rcbops","id":1153548,"node_id":"MDEyOk9yZ2FuaXphdGlvbjExNTM1NDg=","avatar_url":"https://avatars1.githubusercontent.com/u/1153548?v=4","gravatar_id":"","url":"https://api.github.com/users/rcbops","html_url":"https://github.com/rcbops","followers_url":"https://api.github.com/users/rcbops/followers","following_url":"https://api.github.com/users/rcbops/following{/other_user}","gists_url":"https://api.github.com/users/rcbops/gists{/gist_id}","starred_url":"https://api.github.com/users/rcbops/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rcbops/subscriptions","organizations_url":"https://api.github.com/users/rcbops/orgs","repos_url":"https://api.github.com/users/rcbops/repos","events_url":"https://api.github.com/users/rcbops/events{/privacy}","received_events_url":"https://api.github.com/users/rcbops/received_events","type":"Organization","site_admin":false},"repo":{"id":127207789,"node_id":"MDEwOlJlcG9zaXRvcnkxMjcyMDc3ODk=","name":"zigzag","full_name":"rcbops/zigzag","owner":{"login":"rcbops","id":1153548,"node_id":"MDEyOk9yZ2FuaXphdGlvbjExNTM1NDg=","avatar_url":"https://avatars1.githubusercontent.com/u/1153548?v=4","gravatar_id":"","url":"https://api.github.com/users/rcbops","html_url":"https://github.com/rcbops","followers_url":"https://api.github.com/users/rcbops/followers","following_url":"https://api.github.com/users/rcbops/following{/other_user}","gists_url":"https://api.github.com/users/rcbops/gists{/gist_id}","starred_url":"https://api.github.com/users/rcbops/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rcbops/subscriptions","organizations_url":"https://api.github.com/users/rcbops/orgs","repos_url":"https://api.github.com/users/rcbops/repos","events_url":"https://api.github.com/users/rcbops/events{/privacy}","received_events_url":"https://api.github.com/users/rcbops/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/rcbops/zigzag","description":"Parse JUnitXML and upload test results to qTest API","fork":false,"url":"https://api.github.com/repos/rcbops/zigzag","forks_url":"https://api.github.com/repos/rcbops/zigzag/forks","keys_url":"https://api.github.com/repos/rcbops/zigzag/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rcbops/zigzag/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rcbops/zigzag/teams","hooks_url":"https://api.github.com/repos/rcbops/zigzag/hooks","issue_events_url":"https://api.github.com/repos/rcbops/zigzag/issues/events{/number}","events_url":"https://api.github.com/repos/rcbops/zigzag/events","assignees_url":"https://api.github.com/repos/rcbops/zigzag/assignees{/user}","branches_url":"https://api.github.com/repos/rcbops/zigzag/branches{/branch}","tags_url":"https://api.github.com/repos/rcbops/zigzag/tags","blobs_url":"https://api.github.com/repos/rcbops/zigzag/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rcbops/zigzag/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rcbops/zigzag/git/refs{/sha}","trees_url":"https://api.github.com/repos/rcbops/zigzag/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rcbops/zigzag/statuses/{sha}","languages_url":"https://api.github.com/repos/rcbops/zigzag/languages","stargazers_url":"https://api.github.com/repos/rcbops/zigzag/stargazers","contributors_url":"https://api.github.com/repos/rcbops/zigzag/contributors","subscribers_url":"https://api.github.com/repos/rcbops/zigzag/subscribers","subscription_url":"https://api.github.com/repos/rcbops/zigzag/subscription","commits_url":"https://api.github.com/repos/rcbops/zigzag/commits{/sha}","git_commits_url":"https://api.github.com/repos/rcbops/zigzag/git/commits{/sha}","comments_url":"https://api.github.com/repos/rcbops/zigzag/comments{/number}","issue_comment_url":"https://api.github.com/repos/rcbops/zigzag/issues/comments{/number}","contents_url":"https://api.github.com/repos/rcbops/zigzag/contents/{+path}","compare_url":"https://api.github.com/repos/rcbops/zigzag/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rcbops/zigzag/merges","archive_url":"https://api.github.com/repos/rcbops/zigzag/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rcbops/zigzag/downloads","issues_url":"https://api.github.com/repos/rcbops/zigzag/issues{/number}","pulls_url":"https://api.github.com/repos/rcbops/zigzag/pulls{/number}","milestones_url":"https://api.github.com/repos/rcbops/zigzag/milestones{/number}","notifications_url":"https://api.github.com/repos/rcbops/zigzag/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rcbops/zigzag/labels{/name}","releases_url":"https://api.github.com/repos/rcbops/zigzag/releases{/id}","deployments_url":"https://api.github.com/repos/rcbops/zigzag/deployments","created_at":"2018-03-28T22:53:15Z","updated_at":"2018-07-12T14:33:06Z","pushed_at":"2018-07-18T18:23:03Z","git_url":"git://github.com/rcbops/zigzag.git","ssh_url":"git@github.com:rcbops/zigzag.git","clone_url":"https://github.com/rcbops/zigzag.git","svn_url":"https://github.com/rcbops/zigzag","homepage":null,"size":98,"stargazers_count":2,"watchers_count":2,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"archived":false,"open_issues_count":3,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":2,"open_issues":3,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rcbops/zigzag/pulls/36"},"html":{"href":"https://github.com/rcbops/zigzag/pull/36"},"issue":{"href":"https://api.github.com/repos/rcbops/zigzag/issues/36"},"comments":{"href":"https://api.github.com/repos/rcbops/zigzag/issues/36/comments"},"review_comments":{"href":"https://api.github.com/repos/rcbops/zigzag/pulls/36/comments"},"review_comment":{"href":"https://api.github.com/repos/rcbops/zigzag/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/rcbops/zigzag/pulls/36/commits"},"statuses":{"href":"https://api.github.com/repos/rcbops/zigzag/statuses/82470ec176bf033213cf74f961c4456f7634f691"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"johnduarte"}}