示例#1
0
def test_negative_create_missing_data(src_type, cleanup, shared_client, field):
    """Attempt to create a source missing various data.

    The requests should be met with a 4XX response.

    :id: 4b176997-0be2-4bd8-81fd-8b4ef5045382
    :description: Attempt to create sources missing required data.
    :steps: Attempt to create a source missing:
            a) a name
            b) hosts
            c) credential id's
    :expectedresults: Error is thrown and no new source is created.
    """
    cred = Credential(cred_type=src_type, client=shared_client, password=uuid4())
    cred.create()
    cleanup.append(cred)
    src = Source(
        source_type=src_type,
        client=api.Client(response_handler=api.echo_handler),
        hosts=["localhost"],
        credential_ids=[cred._id],
    )

    # remove field from payload
    delattr(src, field)
    create_response = src.create()
    assert create_response.status_code == 400
    if create_response.status_code in [200, 201]:
        cleanup.append(src)
示例#2
0
def test_negative_create_key_and_pass(cleanup, isolated_filesystem):
    """Attempt to create a network credential with sshkey and password.

    The request should be met with a 4XX response.

    :id: 22a2ca65-5f9d-4c43-89ad-d7ab53223896
    :description: Create a network credential with username, sshkey, and
        password.
    :steps: Send POST with necessary data to the credential api endpoint.
    :expectedresults: Error is thrown and no new network credential is created.
    """
    ssh_keyfile = Path(uuid4())
    ssh_keyfile.touch()

    client = api.Client(api.echo_handler)
    cred = Credential(
        cred_type="network",
        client=client,
        ssh_keyfile=str(ssh_keyfile.resolve()),
        password=uuid4(),
    )
    response = cred.create()
    assert response.status_code == 400
    assert "either a password or an ssh_keyfile, not both" in response.text
    assert cred._id is None
示例#3
0
def test_delete(src_type, cleanup, shared_client):
    """After creating several {network, vcenter} sources, delete one.

    :id: 24d811b1-655d-4278-ab9f-64ca46a7121b
    :description: Test that we can delete an individual {network, vcenter}
        source by id
    :steps:
        1) Create collection of {network, vcenter} sources, saving the
           information.
        2) Send a DELETE request to destroy individual source
        3) Confirm that all sources are on the server except the deleted one.
        4) Repeat until all sources are deleted.
    :expectedresults: All sources are present on the server except the
        deleted source.
    """
    created_srcs = []
    num_srcs = random.randint(2, 20)
    echo_client = api.Client(response_handler=api.echo_handler)
    for i in range(num_srcs):
        # gen_valid_srcs will take care of cleanup
        created_srcs.append(gen_valid_source(cleanup, src_type, "localhost"))
    for i in range(num_srcs):
        delete_src = created_srcs.pop()
        delete_src.delete()
        delete_src.client = echo_client
        delete_response = delete_src.read()
        assert delete_response.status_code == 404
        for p in created_srcs:
            assert_matches_server(p)
示例#4
0
def test_negative_create_invalid_data(src_type, cleanup, shared_client, data):
    """Attempt to create a source with invalid data.

    The requests should be met with a 4XX response.

    :id: e8754fd4-8d03-4899-bfde-0fc587d78ae1
    :description: Attempt to create sources missing required data.
    :steps: Attempt to create a source with invalid:
        a) creds
        b) host
        c) name
    :expectedresults: Error is thrown and no new source is created.
    """
    cred = Credential(cred_type=src_type, client=shared_client, password=uuid4())
    cred.create()
    cleanup.append(cred)
    data["credential_ids"] = cred._id if not data["credential_ids"] else [-1]
    src = Source(
        source_type=src_type,
        client=api.Client(response_handler=api.echo_handler),
        # unpack parametrized arguments
        **data
    )
    create_response = src.create()
    assert create_response.status_code == 400
    if create_response.status_code in [200, 201]:
        cleanup.append(src)
示例#5
0
def sort_and_delete(trash):
    """Sort and delete a list of QPCObject typed items in the correct order."""
    creds = []
    sources = []
    scans = []
    # first sort into types because we have to delete scans before sources
    # and sources before scans
    for obj in trash:
        if isinstance(obj, Credential):
            creds.append(obj)
            continue
        if isinstance(obj, Source):
            sources.append(obj)
            continue
        if isinstance(obj, Scan):
            scans.append(obj)
            continue

    client = api.Client(response_handler=api.echo_handler)
    for collection in [scans, sources, creds]:
        for obj in collection:
            # Override client to use a fresh one. It may have been a while
            # since the object was created and its token may be invalid.
            obj.client = client
            # Only assert that we do not hit an internal server error, in case
            # for some reason the object was allready cleaned up by the test
            response = obj.delete()
            assert response.status_code < 500, response.content
示例#6
0
def assert_source_update_fails(original_data, source):
    """Assert that the update method on this source fails.

    :param original_data: This should be the json you expect to match the
        server. This can be collected from your object via source.fields()
        before altering the object with the invalid data.
    """
    # replace whatever client the source had with one that won't raise
    # exceptions
    orig_client = source.client
    source.client = api.Client(response_handler=api.echo_handler)
    update_response = source.update()
    assert update_response.status_code == 400
    server_data = source.read().json()
    for key, value in server_data.items():
        if key == "options" and original_data.get(key) is None:
            continue
        if key == "credentials":
            # the server creds are dicts with other data besides the id
            cred_ids = []
            for cred in value:
                cred_ids.append(cred.get("id"))
            assert sorted(original_data.get(key)) == sorted(cred_ids)
        else:
            assert original_data.get(key) == value
    # give the source its original client back
    source.client = orig_client
示例#7
0
def test_type_mismatch(src_type, cleanup, shared_client):
    """Attempt to create sources with credentials of the wrong type.

    For example, if we create a 'network' typed credential, we can not create a
    'vcenter' typed source using this credential.

    :id: 89bc1bb5-127b-48da-b106-82cd1ef7e00a
    :description: Test that we cannot create a source with the wrong type
        of credential.
    :steps:
        1) Create a credential of one type
        2) Attempt to create a source with that credential of a different type
    :expectedresults: An error is thrown and no new source is created.
    :caseautomation: notautomated
    """
    src = gen_valid_source(cleanup, src_type, "localhost", create=False)
    other_types = set(QPC_SOURCE_TYPES).difference(set((src_type,)))
    other_cred = Credential(
        password=uuid4(), cred_type=random.choice(list(other_types))
    )
    other_cred.create()
    cleanup.append(other_cred)
    src.credentials = [other_cred._id]
    src.client = api.Client(api.echo_handler)
    create_response = src.create()
    assert create_response.status_code == 400
    if create_response.status_code in [200, 201]:
        cleanup.append(src)
    assert "source_type" in create_response.json().keys()
示例#8
0
 def test_create_override_config(self):
     """If a base url is specified, we use that instead of config file."""
     with mock.patch.object(config, "_CONFIG", self.config):
         other_host = "http://hostname.com"
         client = api.Client(url=other_host, authenticate=False)
         cfg_host = self.config["qpc"]["hostname"]
         self.assertNotEqual(cfg_host, client.url)
         self.assertEqual(other_host, client.url)
示例#9
0
 def test_create_no_config(self):
     """If a base url is specified we use it."""
     with mock.patch.object(config, "_CONFIG", {}):
         self.assertEqual(config.get_config(), {})
         other_host = "http://hostname.com"
         client = api.Client(url=other_host, authenticate=False)
         self.assertNotEqual("http://example.com/api/v1/", client.url)
         self.assertEqual(other_host, client.url)
示例#10
0
def shared_client():
    """Yeild a single instance of api.Client() to a test.

    yeilds an api.Client() instance with the standard return code handler.

    .. warning::
       If you intend to change the return code handler, it would be best not to
       use the shared client to avoid possible problems when running tests in
       parallel.
    """
    client = api.Client()
    yield client
示例#11
0
def get_report_entity_src_ids(entity):
    """Given an entity from a deployment report, find the source ids."""
    entity_src_ids = []
    client = api.Client()
    for s in entity["sources"]:
        s_info = client.get("sources/?name={}".format(s["source_name"]))
        # the source is returned in a list, but there should only be one item
        # because names should be unique
        s_info = s_info.json().get("results", {})
        assert len(s_info) == 1
        s_info = s_info[0]
        if s_info.get("id"):
            entity_src_ids.append(s_info.get("id"))
    return entity_src_ids
示例#12
0
 def test_equivalent(self):
     """If a hostname is specified in the config file, we use it."""
     with mock.patch.object(config, "_CONFIG", self.config):
         client = api.Client(authenticate=False)
         h = Credential(
             cred_type="network",
             username=MOCK_CREDENTIAL["username"],
             name=MOCK_CREDENTIAL["name"],
             client=client,
         )
         h._id = MOCK_CREDENTIAL["id"]
         self.assertTrue(h.equivalent(MOCK_CREDENTIAL))
         self.assertTrue(h.equivalent(h))
         with self.assertRaises(TypeError):
             h.equivalent([])
示例#13
0
def test_negative_update_to_invalid(shared_client, cleanup,
                                    isolated_filesystem):
    """Attempt to update valid credential with invalid data.

    :id: c34ea917-ee36-4b93-8907-24a5f87bbed3
    :description: Create valid network credentials, then attempt to update to
        be invalid.
    :steps:
        1) Create valid credentials with passwords or sshkey.
        2) Update the network credentials:
            a) using both password and sshkey
            b) missing both password and sshkey
    :expectedresults: Error codes are returned and the network credentials are
        not updated.
    """
    sshkeyfile_name = utils.uuid4()
    tmp_dir = os.path.basename(os.getcwd())
    sshkeyfile = Path(sshkeyfile_name)
    sshkeyfile.touch()

    cred = Credential(
        cred_type="network",
        client=shared_client,
        ssh_keyfile=f"/sshkeys/{tmp_dir}/{sshkeyfile_name}",
    )
    cred.create()
    # add the id to the list to destroy after the test is done
    cleanup.append(cred)
    assert_matches_server(cred)

    cred.client = api.Client(api.echo_handler)

    # Try to update with both sshkeyfile and password
    cred.password = uuid4()
    response = cred.update()
    assert response.status_code == 400
    assert "either a password or an ssh_keyfile, not both" in response.text
    cred.password = None
    assert_matches_server(cred)

    # Try to update with both sshkeyfile and password missing
    old = cred.ssh_keyfile
    del cred.ssh_keyfile
    response = cred.update()
    assert response.status_code == 400
    assert "must have either a password or an ssh_keyfile" in response.text
    cred.ssh_keyfile = old
    assert_matches_server(cred)
示例#14
0
def test_negative_update_invalid(src_type, shared_client, cleanup, scan_host,
                                 invalid_host):
    """Create a host manager source and then update it with invalid data.

    :id: d57d8481-54e3-4d9a-b330-80edc9364f37
    :description: Create host manager source of single host and credential,
        then attempt to update it with multiple {hosts, credentials}
    :steps:
        1) Create a valid host manager credential and source
        2) Attempt to update with multiple {hosts, credentials}
    :expectedresults: An error is thrown and no new host is created.
    """
    # initialize & create original credential & source
    pwd_cred = Credential(cred_type=src_type,
                          client=shared_client,
                          password=uuid4())
    pwd_cred.create()

    src = Source(
        source_type=src_type,
        client=shared_client,
        hosts=scan_host,
        credential_ids=[pwd_cred._id],
    )
    src.create()

    # Create extra credential for update
    cred2 = Credential(cred_type="network",
                       client=shared_client,
                       password=uuid4())
    cred2.create()

    # add the ids to the lists to destroy after the test is done
    cleanup.extend([pwd_cred, src, cred2])
    original_data = copy.deepcopy(src.fields())
    src.client = api.Client(api.echo_handler)

    # Try to update with multiple credentials
    src.credentials = [pwd_cred._id, cred2._id]
    assert_source_update_fails(original_data, src)

    # Try to update with multiple hosts
    src.hosts = invalid_host
    assert_source_update_fails(original_data, src)

    # Try to update with multiple hosts & creds
    src.hosts = invalid_host
    src.credentials = [pwd_cred._id, cred2._id]
示例#15
0
 def test_equivalent_network(self):
     """If a hostname is specified in the config file, we use it."""
     with mock.patch.object(config, "_CONFIG", self.config):
         client = api.Client(authenticate=False)
         src = Source(
             source_type="network",
             name=MOCK_SOURCE["name"],
             hosts=MOCK_SOURCE["hosts"],
             credential_ids=[MOCK_SOURCE["credentials"][0]["id"]],
             client=client,
         )
         src._id = MOCK_SOURCE["id"]
         self.assertTrue(src.equivalent(MOCK_SOURCE))
         self.assertTrue(src.equivalent(src))
         with self.assertRaises(TypeError):
             src.equivalent([])
示例#16
0
    def test_response_handler(self):
        """Test that when we get a 4xx or 5xx response, an error is raised."""
        with mock.patch.object(config, "_CONFIG", self.config):
            self.assertEqual(config.get_config(), self.config)
            client = api.Client(authenticate=False)
            mock_request = mock.Mock(
                body='{"Test Body"}',
                path_url="/example/path/",
                headers='{"Test Header"}',
                text="Some text",
            )
            mock_response = mock.Mock(status_code=404)
            mock_response.request = mock_request
            mock_response.json = MagicMock(return_value=json.dumps(
                '{"The resource you requested was not found"}'))
            with self.subTest(msg="Test code handler"):
                client.response_handler = api.code_handler
                with self.assertRaises(requests.exceptions.HTTPError):
                    client.response_handler(mock_response)

            with self.subTest(msg="Test json handler"):
                client.response_handler = api.json_handler
                with self.assertRaises(requests.exceptions.HTTPError):
                    client.response_handler(mock_response)

            with self.subTest(msg="Test echo handler"):
                client.response_handler = api.echo_handler
                # no error should be raised with the echo handler
                client.response_handler(mock_response)

            # not all responses have valid json
            mock_response.json = MagicMock(return_value="Not valid json")

            with self.subTest(msg="Test code handler without json available"):
                client.response_handler = api.code_handler
                with self.assertRaises(requests.exceptions.HTTPError):
                    client.response_handler(mock_response)

            with self.subTest(msg="Test json handler without json available"):
                client.response_handler = api.json_handler
                with self.assertRaises(requests.exceptions.HTTPError):
                    client.response_handler(mock_response)

            with self.subTest(msg="Test echo handler without json available"):
                client.response_handler = api.echo_handler
                # no error should be raised with the echo handler
                client.response_handler(mock_response)
示例#17
0
def test_negative_update_invalid(
    shared_client, cleanup, isolated_filesystem, scan_host
):
    """Create a network source and then update it with invalid data.

    :id: e0d72f2b-2490-445e-b646-f06ceb4ad23f
    :description: Create network source of single host and credential,
        then attempt to update it with multiple invalid {hosts, credentials}
    :steps:
        1) Create a valid network credential and source
        2) Attempt to update with multiple invalid {hosts, credentials}
    :expectedresults: An error is thrown and no new host is created.
    """
    sshkeyfile_name = utils.uuid4()
    tmp_dir = os.path.basename(os.getcwd())
    sshkeyfile = Path(sshkeyfile_name)
    sshkeyfile.touch()

    net_cred = Credential(
        cred_type=NETWORK_TYPE,
        client=shared_client,
        ssh_keyfile=f"/sshkeys/{tmp_dir}/{sshkeyfile_name}",
    )
    net_cred.create()
    sat_cred = Credential(cred_type="satellite", client=shared_client, password=uuid4())
    sat_cred.create()

    src = Source(
        source_type=NETWORK_TYPE,
        client=shared_client,
        hosts=[scan_host],
        credential_ids=[net_cred._id],
    )
    src.create()

    # add the ids to the lists to destroy after the test is done
    cleanup.extend([net_cred, sat_cred, src])

    original_data = copy.deepcopy(src.fields())
    src.client = api.Client(api.echo_handler)

    # Try to update with invalid credential type
    src.credentials = [sat_cred._id]
    assert_source_update_fails(original_data, src)
    src.hosts = ["1**2@33^"]
    assert_source_update_fails(original_data, src)
示例#18
0
 def test_equivalent_satellite(self):
     """If a hostname is specified in the config file, we use it."""
     with mock.patch.object(config, "_CONFIG", self.config):
         client = api.Client(authenticate=False)
         p = Source(
             source_type="satellite",
             name=MOCK_SAT6_SOURCE["name"],
             hosts=MOCK_SAT6_SOURCE["hosts"],
             credential_ids=[MOCK_SAT6_SOURCE["credentials"][0]["id"]],
             options=MOCK_SAT6_SOURCE["options"],
             port=443,
             client=client,
         )
         p._id = MOCK_SAT6_SOURCE["id"]
         self.assertTrue(p.equivalent(MOCK_SAT6_SOURCE))
         self.assertTrue(p.equivalent(p))
         with self.assertRaises(TypeError):
             p.equivalent([])
示例#19
0
def test_negative_disable_optional_products(scan_type, shared_client, cleanup):
    """Attempt to disable optional products with non-acceptable booleans.

    :id: 2adb483c-578d-4131-b426-9f772c1803de
    :description: Create a scan with bad input for optional products
    :steps:
        1) Create a network credential
        2) Create network source using the network credential.
        3) Create a scan using the network source. When creating the scan
           disable the optional products with bad values.
    :expectedresults: The scan is not created.
    """
    num_products = random.randint(1, len(QPC_OPTIONAL_PRODUCTS))
    product_combinations = combinations(QPC_OPTIONAL_PRODUCTS, num_products)
    for combo in product_combinations:
        source_ids = []
        for _ in range(random.randint(1, 10)):
            src_type = random.choice(QPC_SOURCE_TYPES)
            src = gen_valid_source(cleanup, src_type, "localhost")
            source_ids.append(src._id)
        scan = Scan(source_ids=source_ids, scan_type=scan_type, client=shared_client)
        products = {p: True for p in QPC_OPTIONAL_PRODUCTS if p not in combo}
        bad_choice = random.choice(["hamburger", "87", 42, "*"])
        products.update({p: bad_choice for p in combo})
        scan.options.update({OPTIONAL_PROD: products})
        echo_client = api.Client(response_handler=api.echo_handler)
        scan.client = echo_client
        create_response = scan.create()
        if create_response.status_code == 201:
            cleanup.append(scan)
            raise AssertionError(
                "Optional products should be disabled and\n"
                "enabled with booleans. If invalid input is given, the user\n"
                "should be alerted."
                "The following data was provided: {}".format(products)
            )
        assert create_response.status_code == 400
        message = create_response.json().get("options", {})
        assert message.get(OPTIONAL_PROD) is not None
示例#20
0
def test_negative_invalid_port(src_type, bad_port, cleanup, shared_client):
    """Test that we are prevented from using a nonsense value for the port.

    :id: e64df701-5819-4e80-a5d2-d26cbc6f71a7
    :description: Test that sources cannot be created with bad values for the
        port.
    :steps:
        1) Create a credential
        2) Attempt to create a source of the same type and specify a custom
           port with various nonsense values like 'foo**' or -1 or a Boolean
    :expectedresults: The source is not created
    :caseautomation: notautomated
    """
    src = gen_valid_source(cleanup, src_type, "localhost", create=False)
    src.port = bad_port
    src.client = api.Client(api.echo_handler)
    create_response = src.create()
    assert create_response.status_code == 400
    if create_response.status_code in [200, 201]:
        cleanup.append(src)
    # assert that the server tells us what we did wrong
    assert "port" in create_response.json().keys()
示例#21
0
def assert_merge_fails(ids, errors_found, report):
    """Assert that the merge method on the given report fails.

    :param ids: The scan job identifiers to pass through to
        the merge function.
    :param report: The report object
    :param errors_found: A list of any errors encountered
    """
    # replace whatever client the report had with one that won't raise
    # exceptions
    orig_client = report.client
    report.client = api.Client(response_handler=api.echo_handler)
    merge_response = report.create_from_merge(ids)
    if merge_response.status_code != 400:
        errors_found.append(
            "Merging scan job identifiers {ids} resulted in a response"
            "status code of {response_status} when it should have resulted"
            "in a status code of 400.".format(
                ids=ids, response_status=merge_response.status_code))
    # give the report its original client back
    report.client = orig_client
    return errors_found
示例#22
0
def assert_source_create_fails(source, source_type=""):
    """Assert that the create method of this source fails.

    :param source: The source object.
    """
    # replace whatever client the source had with one that won't raise
    # exceptions
    orig_client = source.client
    source.client = api.Client(response_handler=api.echo_handler)
    create_response = source.create()
    assert create_response.status_code == 400
    expected_errors = [
        {
            "hosts": ["Source of type vcenter must have a single hosts."]
        },
        {
            "credentials":
            ["Source of type vcenter must have a single credential."]
        },
        {
            "hosts": ["Source of type satellite must have a single hosts."]
        },
        {
            "credentials":
            ["Source of type satellite must have a single credential."]
        },
        {
            "exclude_hosts": [
                "The exclude_hosts option is not valid for source of type " +
                source_type + "."
            ]
        },
    ]
    response = create_response.json()
    assert response in expected_errors
    # give the source its original client back
    source.client = orig_client
示例#23
0
def test_delete_with_dependencies(src_type, cleanup, shared_client):
    """Test that cannot delete sources if other objects depend on them.

    :id: 76d79090-a3f7-4750-a8b8-eaf6c2ed4b89
    :description: Test that sources cannot be deleted if they are members
        of a scan.
    :steps:
        1) Create a valid source and one or more scans that use it.
        2) Attempt to delete the source, this should fail
        3) Delete the scan(s)
        4) Assert that we can now delete the source
    :expectedresults: The source is not created
    :caseautomation: notautomated
    """
    src1 = gen_valid_source(cleanup, src_type, "localhost")
    src2 = gen_valid_source(cleanup, src_type, "localhost")
    scns = []
    for i in range(random.randint(2, 6)):
        if i % 2 == 0:
            scn = Scan(source_ids=[src1._id])
        else:
            scn = Scan(source_ids=[src1._id, src2._id])
        scns.append(scn)
        scn.create()
        cleanup.append(scn)
    src1.client = api.Client(api.echo_handler)
    # this should fail
    del_response = src1.delete()
    assert del_response.status_code == 400
    # now delete scan, and then we should be allowed to delete source
    for scn in scns:
        scn.delete()
        cleanup.remove(scn)
    src1.client = shared_client
    src1.delete()
    cleanup.remove(src1)
示例#24
0
 def __init__(self, client=None, _id=None):
     """Provide shared methods for QPC model objects."""
     # we want to allow for an empty string name
     self._id = _id
     self.client = client if client else api.Client()
     self.endpoint = ""
示例#25
0
def test_products_found_deployment_report(scan_info):
    """Test that products reported as present are correct for the source.

    :id: d5d424bb-8183-4b60-b21a-1b4ed1d879c0
    :description: Test that products indicated as present are correctly
        identified.
    :steps:
        1) Request the json report for the scan.
        2) Assert that any products marked as present are expected to be found
           as is listed in the configuration file for the source.
    :expectedresults: There are inspection results for each source we scanned
        and any products found are correctly identified.
    """
    result = get_scan_result(scan_info["name"])
    report_id = result["report_id"]
    if not report_id:
        pytest.xfail(reason="No report id was returned from scan "
                     "named {scan_name}".format(scan_name=scan_info["name"]))
    report = api.Client().get(
        "reports/{}/deployments".format(report_id)).json()
    assert report.get("status") == "completed", report
    report = report.get("system_fingerprints")
    errors_found = []
    for entity in report:
        all_found_products = []
        present_products = []
        for product in entity.get("products"):
            name = "".join(product["name"].lower().split())
            if product["presence"] == "present":
                present_products.append(name)
            if product["presence"] in ["present", "potential"]:
                all_found_products.append(name)
        for source_to_product_map in result["expected_products"]:
            src_id = list(source_to_product_map.keys())[0]
            entity_src_ids = get_report_entity_src_ids(entity)
            hostname = result["source_id_to_hostname"][src_id]
            ex_products = source_to_product_map[src_id]
            expected_product_names = [
                prod for prod in ex_products.keys() if prod != "distribution"
            ]
            if src_id in entity_src_ids:
                # We assert that products marked as present are expected
                # We do not assert that products marked as potential must
                # actually be on server
                unexpected_products = []
                for prod_name in present_products:
                    # Assert that products marked "present"
                    # Are actually expected on machine
                    if prod_name not in expected_product_names:
                        unexpected_products.append(prod_name)
                # after inpsecting all found products,
                # raise assertion error for all unexpected products
                if len(unexpected_products) > 0:
                    errors_found.append(
                        "Found {found_products} but only expected to find\n"
                        "{expected_products} on {host_found_on}.\n"
                        "All information about the entity was as follows\n"
                        "{entity_info}".format(
                            found_products=unexpected_products,
                            expected_products=expected_product_names,
                            host_found_on=hostname,
                            entity_info=pformat(entity),
                        ))
    assert len(errors_found) == 0, (
        "Found {num} unexpected products!\n"
        "Errors are listed below: \n {errors}.\n"
        "Full results for this scan were: {scan_results}".format(
            num=len(errors_found),
            errors="\n\n======================================\n\n".join(
                errors_found),
            scan_results=pformat(result),
        ))
示例#26
0
def test_OS_found_deployment_report(scan_info):
    """Test that OS identified are correct for the source.

    :id: 0b16331c-2431-498a-9e84-65b3d66e4001
    :description: Test that OS type and version are correctly
        identified.
    :steps:
        1) Request the json report for the scan.
        2) Assert that the OS identified is expected to be found
           as is listed in the configuration file for the source.
    :expectedresults: There are inspection results for each source we scanned
        and the operating system is correctly identified.
    """
    result = get_scan_result(scan_info["name"])
    if scan_info["name"].lower() == 'sat6':
        pytest.skip("Skipping sat6 run until Quipucords Issue #2039 "
                    "is resolved")

    report_id = result["report_id"]
    if not report_id:
        pytest.xfail(reason="No report id was returned from scan "
                     "named {scan_name}".format(scan_name=scan_info["name"]))
    report = api.Client().get(
        "reports/{}/deployments".format(report_id)).json()
    assert report.get("status") == "completed", report
    report = report.get("system_fingerprints")
    errors_found = []
    for entity in report:
        for source_to_product_map in result["expected_products"]:
            src_id = list(source_to_product_map.keys())[0]
            entity_src_ids = get_report_entity_src_ids(entity)
            hostname = result["source_id_to_hostname"][src_id]
            ex_products = source_to_product_map[src_id]
            expected_distro = ex_products["distribution"].get("name",
                                                              "").lower()
            expected_version = ex_products["distribution"].get("version",
                                                               "").lower()
            # The key may exist but the value be None
            if entity.get("os_name") is None:
                found_distro = ""
            else:
                found_distro = entity.get("os_name").lower()

            if entity.get("os_version") is None:
                found_version = ""
            else:
                found_version = entity.get("os_version").lower()

            if src_id in entity_src_ids:
                # We assert that the expected distro's name is at least
                # contained in the found name.
                # For example, if "Red Hat" is listed in config file,
                # It will pass if "Red Hat Enterprise Linux Server" is found
                if expected_distro not in found_distro:
                    errors_found.append(
                        "Expected OS named {0} for source {1} but"
                        "found OS named {2}".format(expected_distro, hostname,
                                                    found_distro))
                # We assert that the expected distro's version is at least
                # contained in the found version.
                # For example, if "6.9" is listed in config file,
                # It will pass if "6.9 (Santiago)" is found
                if expected_version not in found_version:
                    errors_found.append(
                        "Expected OS version {0} for source {1} but"
                        "found OS version {2}".format(expected_version,
                                                      hostname, found_version))

    assert len(errors_found) == 0, (
        "Found {num} unexpected OS names and/or versions!\n"
        "Errors are listed below: \n {errors}.\n"
        "Full results for this scan were: {scan_results}".format(
            num=len(errors_found),
            errors="\n\n======================================\n\n".join(
                errors_found),
            scan_results=pformat(result),
        ))
示例#27
0
 def test_create_with_config(self):
     """If a hostname is specified in the config file, we use it."""
     with mock.patch.object(config, "_CONFIG", self.config):
         self.assertEqual(config.get_config(), self.config)
         client = api.Client(authenticate=False)
         self.assertEqual(client.url, "http://example.com/api/v1/")
示例#28
0
 def test_invalid_hostname(self):
     """Raise an error if no config entry is found and no url specified."""
     with mock.patch.object(config, "_CONFIG", self.invalid_config):
         self.assertEqual(config.get_config(), self.invalid_config)
         with self.assertRaises(exceptions.QPCBaseUrlNotFound):
             api.Client(authenticate=False)