def test_ignore_culled_host_on_update_by_elevated_id( api_create_or_update_host): # Culled host host = minimal_host(insights_id=generate_uuid(), stale_timestamp=(now() - timedelta(weeks=3)).isoformat()) # Create the host multi_response_status, multi_response_data = api_create_or_update_host( [host]) assert_response_status(multi_response_status, 207) create_host_response = get_host_from_multi_response(multi_response_data) assert_host_was_created(create_host_response) # Update the host host.ip_addresses = ["10.10.0.2"] multi_response_status, multi_response_data = api_create_or_update_host( [host]) assert_response_status(multi_response_status, 207) update_host_response = get_host_from_multi_response(multi_response_data) assert_host_was_created(update_host_response) assert create_host_response["host"]["id"] != update_host_response["host"][ "id"]
def test_create_host_with_20_byte_mac_address(api_create_or_update_host, api_get): system_profile = { "network_interfaces": [{ "mac_address": "00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33" }] } host = minimal_host(system_profile=system_profile) multi_response_status, multi_response_data = api_create_or_update_host( [host]) assert_response_status(multi_response_status, 207) create_host_response = get_host_from_multi_response(multi_response_data) assert_host_was_created(create_host_response) created_host_id = create_host_response["host"]["id"] response_status, response_data = api_get(f"{HOST_URL}/{created_host_id}") assert_response_status(response_status, 200) host_response = get_host_from_response(response_data) assert_host_data(actual_host=host_response, expected_host=host, expected_id=created_host_id)
def test_ignore_culled_host_on_update_by_canonical_facts( api_create_or_update_host): # Culled host host = minimal_host(fqdn="my awesome fqdn", stale_timestamp=(now() - timedelta(weeks=3)).isoformat()) # Create the host multi_response_status, multi_response_data = api_create_or_update_host( [host]) assert_response_status(multi_response_status, 207) create_host_response = get_host_from_multi_response(multi_response_data) assert_host_was_created(create_host_response) # Update the host multi_response_status, multi_response_data = api_create_or_update_host( [host]) assert_response_status(multi_response_status, 207) update_host_response = get_host_from_multi_response(multi_response_data) assert_host_was_created(update_host_response) assert create_host_response["host"]["id"] != update_host_response["host"][ "id"]
def test_create_host_with_system_profile_sap_fact(api_create_or_update_host, api_get): system_profile = valid_system_profile() system_profile["sap_system"] = True host = minimal_host(system_profile=system_profile) # Create the host multi_response_status, multi_response_data = api_create_or_update_host( [host]) assert_response_status(multi_response_status, 207) create_host_response = get_host_from_multi_response(multi_response_data) assert_host_was_created(create_host_response) created_host = create_host_response["host"] response_status, response_data = api_get( f"{HOST_URL}/{created_host['id']}/system_profile") assert_response_status(response_status, 200) host_response = get_host_from_response(response_data) assert host_response["system_profile"] == host.system_profile assert host_response["system_profile"]["sap_system"] == system_profile[ "sap_system"]
def test_create_and_update_multiple_hosts_with_account_mismatch( api_create_or_update_host): """ Attempt to create multiple hosts, one host has the wrong account number. Verify this causes an error response to be returned. """ host1 = minimal_host(display_name="host1", ip_addresses=["10.0.0.1"], rhel_machine_id=generate_uuid()) host2 = minimal_host(display_name="host2", account="222222", ip_addresses=["10.0.0.2"], rhel_machine_id=generate_uuid()) host_list = [host1, host2] # Create the host multi_response_status, multi_response_data = api_create_or_update_host( host_list) assert_response_status(multi_response_status, 207) assert len(host_list) == len(multi_response_data["data"]) assert multi_response_status, multi_response_data["errors"] == 1 assert_host_response_status(multi_response_data, 201, 0) assert_host_response_status(multi_response_data, 400, 1)
def test_get_system_profile_of_host_that_does_not_have_system_profile( api_create_or_update_host, api_get): host = minimal_host() # Create the host multi_response_status, multi_response_data = api_create_or_update_host( [host]) assert_response_status(multi_response_status, 207) create_host_response = get_host_from_multi_response(multi_response_data) assert_host_was_created(create_host_response) created_host = create_host_response["host"] # verify system_profile is not included assert "system_profile" not in created_host response_status, response_data = api_get( f"{HOST_URL}/{created_host['id']}/system_profile") assert_response_status(response_status, 200) host_response = get_host_from_response(response_data) assert host_response["id"] == created_host["id"] assert host_response["system_profile"] == {}
def test_create_host_with_system_profile_with_different_cloud_providers( api_create_or_update_host, api_get, cloud_provider): host = minimal_host(system_profile={"cloud_provider": cloud_provider}) # Create the host multi_response_status, multi_response_data = api_create_or_update_host( [host]) assert_response_status(multi_response_status, 207) create_host_response = get_host_from_multi_response(multi_response_data) assert_host_was_created(create_host_response) created_host = create_host_response["host"] # verify system_profile is not included assert "system_profile" not in created_host response_status, response_data = api_get( f"{HOST_URL}/{created_host['id']}/system_profile") assert_response_status(response_status, 200) host_response = get_host_from_response(response_data) assert host_response["id"] == created_host["id"] assert host_response["system_profile"] == host.system_profile
def test_create_host_with_system_profile_and_query_with_branch_id( api_create_or_update_host, api_get): host = minimal_host(system_profile=valid_system_profile()) # Create the host multi_response_status, multi_response_data = api_create_or_update_host( [host]) assert_response_status(multi_response_status, 207) create_host_response = get_host_from_multi_response(multi_response_data) assert_host_was_created(create_host_response) created_host = create_host_response["host"] # verify system_profile is not included assert "system_profile" not in created_host response_status, response_data = api_get( f"{HOST_URL}/{created_host['id']}/system_profile", query_parameters={"branch_id": 1234}) assert_response_status(response_status, 200) host_response = get_host_from_response(response_data) assert host_response["id"] == created_host["id"] assert host_response["system_profile"] == host.system_profile
def test_create_host_without_display_name_and_without_fqdn( api_create_or_update_host, api_get): """ This test should verify that the display_name is set to the id when neither the display name or fqdn is set. """ host = minimal_host() del host.display_name del host.fqdn # Create the host multi_response_status, multi_response_data = api_create_or_update_host( [host]) assert_response_status(multi_response_status, 207) create_host_response = get_host_from_multi_response(multi_response_data) assert_host_was_created(create_host_response) created_host_id = create_host_response["host"]["id"] response_status, response_data = api_get(f"{HOST_URL}/{created_host_id}") assert_response_status(response_status, 200) host_response = get_host_from_response(response_data) assert_host_data(actual_host=host_response, expected_host=host, expected_id=created_host_id)
def test_replace_empty_facts_on_multiple_hosts(db_create_multiple_hosts, db_get_hosts, api_put): new_facts = {} created_hosts = db_create_multiple_hosts(how_many=2, extra_data={"facts": DB_FACTS}) host_id_list = get_id_list_from_hosts(created_hosts) facts_url = build_facts_url(host_list_or_id=created_hosts, namespace=DB_FACTS_NAMESPACE) response_status, response_data = api_put(facts_url, new_facts) assert_response_status(response_status, expected_status=200) expected_facts = get_expected_facts_after_update("replace", DB_FACTS_NAMESPACE, DB_FACTS, new_facts) assert all(host.facts == expected_facts for host in db_get_hosts(host_id_list)) response_status, response_data = api_put(facts_url, DB_NEW_FACTS) assert_response_status(response_status, expected_status=200) expected_facts = get_expected_facts_after_update("replace", DB_FACTS_NAMESPACE, DB_FACTS, DB_NEW_FACTS) assert all(host.facts == expected_facts for host in db_get_hosts(host_id_list))
def test_get_host_tags_with_RBAC_bypassed_as_system(db_create_host, api_get, enable_rbac): host = db_create_host() url = build_host_tags_url(host_list_or_id=host.id) response_status, response_data = api_get(url, identity_type="System") assert_response_status(response_status, 200)
def test_delete_host_with_RBAC_allowed( subtests, mocker, api_delete_host, event_datetime_mock, event_producer_mock, db_get_host, db_create_host, enable_rbac, ): get_rbac_permissions_mock = mocker.patch( "lib.middleware.get_rbac_permissions") for response_file in WRITE_ALLOWED_RBAC_RESPONSE_FILES: mock_rbac_response = create_mock_rbac_response(response_file) with subtests.test(): get_rbac_permissions_mock.return_value = mock_rbac_response host = db_create_host() response_status, response_data = api_delete_host(host.id) assert_response_status(response_status, 200) assert_delete_event_is_valid(event_producer=event_producer_mock, host=host, timestamp=event_datetime_mock) assert not db_get_host(host.id)
def test_delete_all_hosts_with_missing_required_params(api_delete_all_hosts, event_producer_mock): # delete all hosts using incomplete filter response_status, response_data = api_delete_all_hosts({}) assert_response_status(response_status, expected_status=400) assert event_producer_mock.event is None
def test_create_then_delete_check_metadata(event_datetime_mock, event_producer_mock, db_create_host, api_delete_host): host = db_create_host(SYSTEM_IDENTITY, extra_data={ "system_profile_facts": { "owner_id": SYSTEM_IDENTITY["system"]["cn"] } }) request_id = generate_uuid() headers = {"x-rh-insights-request-id": request_id} response_status, response_data = api_delete_host(host.id, extra_headers=headers) assert_response_status(response_status, expected_status=200) assert_delete_event_is_valid( event_producer=event_producer_mock, host=host, timestamp=event_datetime_mock, expected_request_id=request_id, expected_metadata={"request_id": request_id}, )
def test_get_tags_sap_sids(patch_xjoin_post, api_get, subtests, query_source_xjoin): patch_xjoin_post( response={"data": { "hostTags": { "meta": { "total": 1 }, "data": [] } }}) filter_paths = ("[system_profile][sap_sids][]", "[system_profile][sap_sids][contains][]") value_sets = (("ABC", ), ("BEN", "A72"), ("CDA", "MK2", "C2C")) for path in filter_paths: for values in value_sets: with subtests.test(values=values, path=path): url = build_tags_url( query="?" + "".join([f"filter{path}={value}&" for value in values])) response_status, response_data = api_get(url) assert_response_status(response_status, 200) assert response_data["total"] == 1
def test_delete_all_hosts(event_producer_mock, db_create_multiple_hosts, db_get_hosts, api_delete_all_hosts, patch_xjoin_post): created_hosts = db_create_multiple_hosts( how_many=len(XJOIN_HOSTS_RESPONSE_FOR_FILTERING["hosts"]["data"])) host_ids = [str(host.id) for host in created_hosts] # set the new host ids in the xjoin search reference. resp = deepcopy(XJOIN_HOSTS_RESPONSE_FOR_FILTERING) for ind, id in enumerate(host_ids): resp["hosts"]["data"][ind]["id"] = id response = {"data": resp} # Make the new hosts available in xjoin-search to make them available # for querying for deletion using filters patch_xjoin_post(response, status=200) # delete all hosts on the account response_status, response_data = api_delete_all_hosts( {"confirm_delete_all": True}) assert '"type": "delete"' in event_producer_mock.event assert response_data.get("hosts_deleted") == len(created_hosts) assert_response_status(response_status, expected_status=202) assert len(host_ids) == response_data["hosts_deleted"] # check db for the deleted hosts using their IDs host_id_list = [str(host.id) for host in created_hosts] deleted_hosts = db_get_hosts(host_id_list) assert deleted_hosts.count() == 0
def test_put_facts_with_RBAC_denied(subtests, mocker, api_put, db_create_host, db_get_host, enable_rbac): get_rbac_permissions_mock = mocker.patch( "lib.middleware.get_rbac_permissions") updated_facts = { "updatedfact1": "updatedvalue1", "updatedfact2": "updatedvalue2" } for response_file in WRITE_PROHIBITED_RBAC_RESPONSE_FILES: mock_rbac_response = create_mock_rbac_response(response_file) host = db_create_host(extra_data={"facts": DB_FACTS}) url = build_facts_url(host_list_or_id=host.id, namespace=DB_FACTS_NAMESPACE) with subtests.test(): get_rbac_permissions_mock.return_value = mock_rbac_response response_status, response_data = api_put(url, updated_facts) assert_response_status(response_status, 403) assert db_get_host( host.id).facts[DB_FACTS_NAMESPACE] != updated_facts
def test_patch_host_with_RBAC_bypassed_as_system(api_patch, db_create_host, event_producer_mock, enable_rbac): host = db_create_host() url = build_hosts_url(host_list_or_id=host.id) response_status, response_data = api_patch(url, {"display_name": "fred_flintstone"}, identity_type="System") assert_response_status(response_status, 200)
def test_update_delete_race(event_producer, db_create_host, db_get_host, api_patch, api_delete_host, mocker): mocker.patch.object(event_producer, "write_event") # slow down the execution of update_display_name so that it's more likely we hit the race condition def sleep(data): time.sleep(1) mocker.patch("app.models.Host.update_display_name", wraps=sleep) host = db_create_host() def patch_host(): url = build_hosts_url(host_list_or_id=host.id) api_patch(url, {"ansible_host": "localhost.localdomain"}) # run PATCH asynchronously patchThread = Thread(target=patch_host) patchThread.start() # as PATCH is running, concurrently delete the host response_status, response_data = api_delete_host(host.id) assert_response_status(response_status, expected_status=200) # wait for PATCH to finish patchThread.join() # the host should be deleted and the last message to be produced should be the delete message assert not db_get_host(host.id) assert event_producer.write_event.call_args_list[-1][0][2]["event_type"] == "delete"
def test_event_producer_instrumentation(mocker, event_producer, future_mock, db_create_host, api_patch): created_host = db_create_host() patch_doc = {"display_name": "patch_event_test"} url = build_hosts_url(host_list_or_id=created_host.id) event_producer._kafka_producer.send.return_value = future_mock message_produced = mocker.patch( "app.queue.event_producer.message_produced") message_not_produced = mocker.patch( "app.queue.event_producer.message_not_produced") response_status, response_data = api_patch(url, patch_doc) assert_response_status(response_status, expected_status=200) for expected_callback, future_callbacks, fire_callbacks in ( (message_produced, future_mock.callbacks, future_mock.success), (message_not_produced, future_mock.errbacks, future_mock.failure), ): assert len(future_callbacks) == 1 assert future_callbacks[0].method == expected_callback fire_callbacks() args = future_callbacks[0].args + (future_callbacks[0].extra_arg, ) expected_callback.assert_called_once_with(*args, **future_callbacks[0].kwargs)
def test_invalid_data(invalid_data, db_create_host, api_patch): host = db_create_host() url = build_hosts_url(host_list_or_id=host.id) response_status, response_data = api_patch(url, invalid_data) assert_response_status(response_status, expected_status=400)
def test_create_host_without_display_name_and_with_fqdn( api_create_or_update_host, api_get): """ This test should verify that the display_name is set to the fqdn when a display_name is not passed in but the fqdn is passed in. """ expected_display_name = "fred.flintstone.bedrock.com" host = minimal_host(fqdn=expected_display_name) del host.display_name multi_response_status, multi_response_data = api_create_or_update_host( [host]) assert_response_status(multi_response_status, 207) create_host_response = get_host_from_multi_response(multi_response_data) assert_host_was_created(create_host_response) created_host_id = create_host_response["host"]["id"] response_status, response_data = api_get(f"{HOST_URL}/{created_host_id}") assert_response_status(response_status, 200) host_response = get_host_from_response(response_data) host.display_name = expected_display_name assert_host_data(actual_host=host_response, expected_host=host, expected_id=created_host_id)
def _test_order_by_id_desc(inventory_config, api_get, subtests, created_hosts, specifications, order_by, order_how): for updates, expected_added_hosts in specifications: # Update hosts to they have a same modified_on timestamp, but different IDs. # New modified_on value must be set explicitly so it’s saved the same to all # records. Otherwise SQLAlchemy would consider it unchanged and update it # automatically to its own "now" only for records whose ID changed. new_modified_on = now() for added_host_index, new_id in updates: host = update_host_in_db(created_hosts[added_host_index].id, id=new_id, modified_on=new_modified_on) created_hosts[added_host_index] = serialize_db_host(host, inventory_config) # Check the order in the response against the expected order. Only indexes # are passed, because self.added_hosts values were replaced during the # update. expected_hosts = tuple(created_hosts[added_host_index] for added_host_index in expected_added_hosts) urls = (HOST_URL, build_hosts_url(created_hosts), build_system_profile_url(created_hosts)) for url in urls: with subtests.test(url=url, updates=updates): order_query_parameters = build_order_query_parameters(order_by=order_by, order_how=order_how) response_status, response_data = api_get(url, query_parameters=order_query_parameters) assert_response_status(response_status, expected_status=200) assert_host_ids_in_response(response_data, expected_hosts)
def test_get_tags_sap_system(patch_xjoin_post, api_get, subtests, query_source_xjoin): patch_xjoin_post( response={"data": { "hostTags": { "meta": { "total": 1 }, "data": [] } }}) values = ("true", "false", "nil", "not_nil") for value in values: with subtests.test(value=value): implicit_url = build_tags_url( query=f"?filter[system_profile][sap_system]={value}") eq_url = build_tags_url( query=f"?filter[system_profile][sap_system][eq]={value}") implicit_response_status, implicit_response_data = api_get( implicit_url) eq_response_status, eq_response_data = api_get(eq_url) assert_response_status(implicit_response_status, 200) assert_response_status(eq_response_status, 200) assert implicit_response_data["total"] == 1 assert eq_response_data["total"] == 1
def test_get_host_tags_with_RBAC_bypassed_as_system(db_create_host, api_get, enable_rbac): host = db_create_host(SYSTEM_IDENTITY, extra_data={"system_profile_facts": {"owner_id": generate_uuid()}}) url = build_host_tags_url(host_list_or_id=host.id) response_status, response_data = api_get(url, SYSTEM_IDENTITY) assert_response_status(response_status, 200)
def test_replace_facts_to_multiple_hosts_including_nonexistent_host(db_create_multiple_hosts, db_get_hosts, api_put): created_hosts = db_create_multiple_hosts(how_many=2, extra_data={"facts": DB_FACTS}) url_host_id_list = f"{build_host_id_list_for_url(created_hosts)},{generate_uuid()},{generate_uuid()}" facts_url = build_facts_url(host_list_or_id=url_host_id_list, namespace=DB_FACTS_NAMESPACE) response_status, response_data = api_put(facts_url, DB_NEW_FACTS) assert_response_status(response_status, expected_status=400)
def test_get_system_profile_sap_system_with_RBAC_bypassed_as_system( query_source_xjoin, graphql_system_profile_sap_system_query_with_response, api_get, enable_rbac ): url = build_system_profile_sap_system_url() response_status, response_data = api_get(url, identity_type="System") assert_response_status(response_status, 200)
def test_checkin_no_canonical_facts(event_producer_mock, db_create_host, db_get_host, api_post, post_doc): response_status, response_data = api_post( build_host_checkin_url(), post_doc, extra_headers={"x-rh-insights-request-id": "123456"} ) assert_response_status(response_status, expected_status=400) assert event_producer_mock.key is None assert event_producer_mock.event is None
def test_patch_with_branch_id_parameter(event_producer_mock, db_create_multiple_hosts, api_patch): patch_doc = {"display_name": "branch_id_test"} hosts = db_create_multiple_hosts(how_many=5) url = build_hosts_url(host_list_or_id=hosts, query="?branch_id=123") response_status, response_data = api_patch(url, patch_doc) assert_response_status(response_status, expected_status=200)
def test_replace_facts_to_namespace_that_does_not_exist(db_create_multiple_hosts, api_patch): new_facts = {} created_hosts = db_create_multiple_hosts(how_many=2, extra_data={"facts": DB_FACTS}) facts_url = build_facts_url(host_list_or_id=created_hosts, namespace="imanonexistentnamespace") response_status, response_data = api_patch(facts_url, new_facts) assert_response_status(response_status, expected_status=400)