def test_update(update_field, shared_client, cleanup, scan_type): """Create scan, then update it and assert the values are changed. :id: c40a64c1-346e-4fce-ad18-4090066050a1 :description: Create a scan and assert that it completes :steps: 1) Create a network credential 2) Create a network source with the credential 3) Create a scan with the network source 4) Assert that the scan is created and all fields match the request. 5) Update a field and assert that changes are made :expectedresults: A scan is created with all options set as requested. """ 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) scan.create() cleanup.append(scan) remote_scn = scan.read().json() assert scan.equivalent(remote_scn) if update_field == "source": src_type = random.choice(QPC_SOURCE_TYPES) src = gen_valid_source(cleanup, src_type, "localhost") scan.sources.append(src._id) if update_field == "max_concurrency": scan.options.update({"max_concurrecny": random.randint(1, 49)}) if update_field == "name": scan.name = uuid4() scan.update() remote_scn = scan.read().json() assert scan.equivalent(remote_scn)
def test_create_exclude_hosts(shared_client, cleanup, scan_host): """Create a source with the excluded hosts option. :id: 40365ec0-a8b5-4dc9-b7b4-dad826602d66 :description: Create a network source with some excluded host IPs. :steps: 1) Create host credential 2) Send POST with data to create the source using the credential to the source endpoint, with the exclude hosts option. :expectedresults: A new source entry is created with the data. """ gen_valid_source(cleanup, "network", hosts="1.1.1.1", exclude_hosts=scan_host)
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()
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)
def test_scan_with_optional_products(scan_type, shared_client, cleanup): """Create a scan with disabled optional products. :id: 366604ed-e423-4140-b0d8-38626e264688 :description: Perform a scan and disable an optional product. :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. :expectedresults: The scan is created. """ num_products = random.randint(0, 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} products.update({p: False for p in combo}) scan.options.update({OPTIONAL_PROD: products}) scan.create() cleanup.append(scan) assert scan.equivalent(scan.read().json())
def test_update_with_invalid_src_type(src_type, scan_host, cleanup): """Attempt to update exclude_hosts with a non-network source type. :id: 66467eb5-79ab-4430-9957-b49fca4cd9ef :description: Create valid non-network source, and then attempt to update it with an excluded hostname option. :steps: 1) Create valid credential and source that isn't a network type 2) Update the source with an excluded host :expectedresults: Error codes are returned and the source is not updated. """ src = gen_valid_source(cleanup, src_type, scan_host) original_data = copy.deepcopy(src.fields()) src.exclude_hosts = ["10.10.10.10"] assert_source_update_fails(original_data, src)
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)
def test_update_remove_field(src_type, cleanup, field): """Attempt to update valid source with either no hosts or no credentials. :id: 49feb858-319f-4f77-b330-65426dfd1734 :description: Create valid {network, vcenter} source, and then attempt to update it to have either no credentials or no hosts. :steps: 1) Create valid credential and source 2) Update the source with no credentials or no hosts :expectedresults: Error codes are returned and the source is not updated. """ src = gen_valid_source(cleanup, src_type, "localhost") # we have to use deep copy because these are nested dictionaries original_data = copy.deepcopy(src.fields()) setattr(src, field, []) assert_source_update_fails(original_data, src)
def test_update_with_bad_exclude_host(src_type, scan_host, cleanup): """Attempt to update valid source with an invalid excluded host. :id: 62cc08ad-1149-4c2b-a4ad-0e4c07d10ff6 :description: Create valid {network, vcenter} source, and then attempt to update it with an invalid excluded hostname option. :steps: 1) Create valid credential and source 2) Update the source with an invalid excluded host :expectedresults: Error codes are returned and the source is not updated. """ src = gen_valid_source(cleanup, src_type, scan_host) original_data = src.fields() # Test updating source with bad excluded host src.exclude_hosts = ["*invalid!!host&*"] assert_source_update_fails(original_data, src)
def test_update_with_bad_host(src_type, scan_host, cleanup): """Attempt to update valid source with an invalid host. :id: 26176135-b147-46bc-b0b5-57d5bc515b72 :description: Create valid {network, vcenter} source, and then attempt to update it with invalid hostname. :steps: 1) Create valid credential and source 2) Update the source with an invalid host :expectedresults: Error codes are returned and the source is not updated. """ src = gen_valid_source(cleanup, src_type, scan_host) original_data = copy.deepcopy(src.fields()) # Test updating source with bad host src.hosts = ["*invalid!!host&*"] assert_source_update_fails(original_data, src)
def test_create_with_port(src_type, cleanup, shared_client): """Test that we may create with a custom port specified. :id: 9e83e1ed-e229-4822-a9c3-cbb8a7e4282e :description: Test that sources can be created with custom ports. :steps: 1) Create a credential 2) Create a source of the same type and specify a custom port. :expectedresults: A source is created with user specified data. :caseautomation: notautomated """ src = gen_valid_source(cleanup, src_type, "localhost", create=False) src.port = random.randint(20, 9000) src.create() cleanup.append(src) server_src = src.read().json() assert src.equivalent(server_src)
def test_update_bad_credential(src_type, scan_host, cleanup): """Attempt to update valid source with invalid data. :id: 79954c63-608c-46b3-81eb-e2a1e984473e :description: Create valid {network, vcenter} source, and then attempt to update it with an invalid credential. :steps: 1) Create valid credential and source 2) Update the source with invalid credentials :expectedresults: Error codes are returned and the source is not updated. """ src = gen_valid_source(cleanup, src_type, scan_host) original_data = copy.deepcopy(src.fields()) # Case "a" add credential that doesnt exist # The server never assigns negative values src.credentials = [-1] assert_source_update_fails(original_data, src)
def test_read_all(src_type, cleanup, shared_client): """After created, retrieve all network sources with GET to api. :id: e708362c-a289-46f1-ad05-724e3e4383d5 :description: The API should return list with all sources created when a GET request is sent to the {network, vcenter} sources endpoint. :steps: 1) Create collection of sources, saving the information. 2) Send GET request to {network, vcenter} source endpoint to get list of created {network, vcenter} sources 3) Confirm that all sources are in the list. :expectedresults: All sources are present in data returned by API. """ created_src_ids = set() # having a list of the sources locally will be helpful # for understanding failures as pytest will display the # data created_srcs = [] for _ in range(random.randint(2, 10)): # gen_valid_srcs will take care of cleanup src = gen_valid_source(cleanup, src_type, "localhost") created_srcs.append(src) created_src_ids.add(src._id) this_page = Source().list().json() while this_page: for source in this_page["results"]: if source["id"] in created_src_ids: created_src_ids.remove(source["id"]) next_page = this_page.get("next") if next_page: # must strip url of host information next_page = re.sub(r".*/api", "/api", next_page) this_page = shared_client.get(next_page).json() else: break # if we found everything we created, then the list should be empty if created_src_ids: raise AssertionError( "Expected to find all sources with correct data on server,\n" "but the following sources did not match expected or were" "missing from the server: \n" "{}".format(" ".join(created_src_ids)) )
def test_port_default(src_type, cleanup, shared_client): """Test that the correct default port is provided if it is not specified. :id: 22af9909-887a-4bea-811c-6ef438a53fdb :description: Test that the correct default port is chosen for each type. :steps: 1) Create a credential 2) Create a source of the same type and do not specify the port 3) Test that the correct default port is provided based on type. :expectedresults: A source is created with sensible default port. :caseautomation: notautomated """ src = gen_valid_source(cleanup, src_type, "localhost", create=False) src.port = None src.create() cleanup.append(src) server_src = src.read().json() assert server_src.get("port") == DEFAULT_PORT[src_type] assert src.equivalent(server_src)
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
def test_create(shared_client, cleanup, scan_type): """Create scan and assert it has correct values. :id: ee3b0bc8-1489-443e-86bb-e2a2349e9c98 :description: Create a scan and assert that it completes :steps: 1) Create a network credential 2) Create a network source with the credential 3) Create a scan with the network source 4) Assert that the scan is created and all fields match the request. :expectedresults: A scan is created with all options set as requested. """ 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) scan.create() cleanup.append(scan) remote_scn = scan.read().json() assert scan.equivalent(remote_scn)
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()