def test_user_cant_modify_others_results( admin_client, user_client, alt_user_client, test_scheduler ): # alt user schedule entry alt_user_entry_name = simulate_frequency_fft_acquisitions( alt_user_client, name="alt_user_single_acq" ) alt_user_acq_url = reverse_result_detail(alt_user_entry_name, 1) new_result_detail = user_client.get(alt_user_acq_url, **HTTPS_KWARG) new_result_detail = new_result_detail.data new_result_detail["task_id"] = 2 user_modify_alt_user_response = update_result_detail( user_client, alt_user_entry_name, 1, new_result_detail ) # admin user schedule entry admin_entry_name = simulate_frequency_fft_acquisitions( admin_client, name="admin_single_acq" ) admin_acq_url = reverse_result_detail(admin_entry_name, 1) new_result_detail = user_client.get(admin_acq_url, **HTTPS_KWARG).data new_result_detail["task_id"] = 2 user_modify_admin_response = update_result_detail( user_client, admin_entry_name, 1, new_result_detail ) validate_response(user_modify_alt_user_response, status.HTTP_403_FORBIDDEN) validate_response(user_modify_admin_response, status.HTTP_403_FORBIDDEN)
def test_overview_for_private_entry_is_private(admin_client, user_client, test_scheduler): simulate_frequency_fft_acquisitions(admin_client, is_private=True) overview = get_results_overview(user_client) assert overview == [] overview, = get_results_overview(admin_client) assert overview["task_results_available"] == 1 assert overview["task_results"] # is non-empty string assert overview["schedule_entry"] # is non-empty string
def test_data_file_created(user_client, test_scheduler): entry_name = simulate_frequency_fft_acquisitions(user_client) tr = TaskResult.objects.get(schedule_entry__name=entry_name, task_id=1) acquisition = Acquisition.objects.get(task_result=tr) assert acquisition.data assert path.exists(acquisition.data.path) os.remove(acquisition.data.path)
def test_metadata_single_acquisition(user_client, test_scheduler): entry_name = simulate_frequency_fft_acquisitions(user_client) tr = TaskResult.objects.get(schedule_entry__name=entry_name, task_id=1) acquisition = Acquisition.objects.get(task_result=tr) assert sigmf_validate(acquisition.metadata) check_metadata_fields(acquisition, entry_name, SINGLE_FREQUENCY_FFT_ACQUISITION)
def test_single_acquisition_archive_download(user_client, test_scheduler): entry_name = simulate_frequency_fft_acquisitions(user_client, n=1) task_id = 1 url = reverse_archive(entry_name, task_id) disposition = 'attachment; filename="{}_test_acq_1.sigmf"' disposition = disposition.format(sensor.settings.FQDN) response = user_client.get(url, **HTTPS_KWARG) assert response.status_code == status.HTTP_200_OK assert response["content-disposition"] == disposition assert response["content-type"] == "application/x-tar" with tempfile.NamedTemporaryFile() as tf: for content in response.streaming_content: tf.write(content) sigmf_archive_contents = sigmf.sigmffile.fromarchive(tf.name) md = sigmf_archive_contents._metadata datafile = sigmf_archive_contents.data_file datafile_actual_size = os.stat(datafile).st_size claimed_sha512 = md["global"]["core:sha512"] total_samples = 0 for annotation in md["annotations"]: if annotation["ntia-core:annotation_type"] == "FrequencyDomainDetection": total_samples += annotation["core:sample_count"] datafile_expected_size = total_samples * np.float32(0.0).nbytes actual_sha512 = sigmf.sigmf_hash.calculate_sha512(datafile) assert datafile_actual_size == datafile_expected_size assert claimed_sha512 == actual_sha512
def test_private_entry_results_list_is_private( admin_client, user_client, test_scheduler ): entry_name = simulate_frequency_fft_acquisitions(admin_client, is_private=True) url = reverse_result_list(entry_name) response = user_client.get(url, **HTTPS_KWARG) validate_response(response, status.HTTP_403_FORBIDDEN)
def test_admin_can_view_private_results(admin_client, alt_admin_client, test_scheduler): private_entry_name = simulate_frequency_fft_acquisitions( alt_admin_client, is_private=True ) private_result_url = reverse_result_detail(private_entry_name, 1) response = admin_client.get(private_result_url, **HTTPS_KWARG) validate_response(response, status.HTTP_200_OK)
def test_admin_can_create_private_results(admin_client, user_client, test_scheduler): private_entry_name = simulate_frequency_fft_acquisitions( admin_client, is_private=True ) private_result_url = reverse_result_detail(private_entry_name, 1) user_response = user_client.get(private_result_url, **HTTPS_KWARG) validate_response(user_response, status.HTTP_403_FORBIDDEN)
def test_detector(user_client, test_scheduler): entry_name = simulate_frequency_fft_acquisitions(user_client) tr = TaskResult.objects.get(schedule_entry__name=entry_name, task_id=1) acquisition = Acquisition.objects.get(task_result=tr) assert sigmf_validate(acquisition.metadata) # FIXME: update schema so that this passes # schema_validate(sigmf_metadata, schema) os.remove(acquisition.data.path)
def test_metadata_multiple_acquisition(user_client, test_scheduler): entry_name = simulate_frequency_fft_acquisitions(user_client, n=2) task_results = TaskResult.objects.filter(schedule_entry__name=entry_name) for task_result in task_results: acquisition = Acquisition.objects.get(task_result=task_result) assert sigmf_validate(acquisition.metadata) check_metadata_fields(acquisition, entry_name, MULTIPLE_FREQUENCY_FFT_ACQUISITIONS)
def test_user_cannot_view_private_result_details( user_client, admin_client, test_scheduler ): """A user should not be able to view the result of a private task.""" entry_name = simulate_frequency_fft_acquisitions(admin_client, is_private=True) task_id = 1 url = reverse_result_detail(entry_name, task_id) response = user_client.get(url, **HTTPS_KWARG) validate_response(response, status.HTTP_403_FORBIDDEN)
def test_admin_can_delete_own_results(admin_client, test_scheduler): entry_name = simulate_frequency_fft_acquisitions(admin_client) result_url = reverse_result_detail(entry_name, 1) first_response = admin_client.delete(result_url, **HTTPS_KWARG) second_response = admin_client.delete(result_url, **HTTPS_KWARG) validate_response(first_response, status.HTTP_204_NO_CONTENT) validate_response(second_response, status.HTTP_404_NOT_FOUND)
def test_user_can_delete_own_results(user_client, test_scheduler): """A user should be able to delete results they own.""" entry_name = simulate_frequency_fft_acquisitions(user_client) result_url = reverse_result_detail(entry_name, 1) first_response = user_client.delete(result_url, **HTTPS_KWARG) second_response = user_client.delete(result_url, **HTTPS_KWARG) validate_response(first_response, status.HTTP_204_NO_CONTENT) validate_response(second_response, status.HTTP_404_NOT_FOUND)
def test_delete_list_data_files_deleted(user_client, test_scheduler): entry_name = simulate_frequency_fft_acquisitions(user_client) task_result = TaskResult.objects.get(schedule_entry__name=entry_name) acquisition = Acquisition.objects.get(task_result__id=task_result.id) data_file = acquisition.data.path assert os.path.exists(data_file) url = reverse_result_list(entry_name) response = user_client.delete(url, **HTTPS_KWARG) validate_response(response, status.HTTP_204_NO_CONTENT) assert not os.path.exists(data_file)
def test_user_cannot_delete_others_results(admin_client, user_client, test_scheduler): # alt admin private schedule entry admin_entry_name = simulate_frequency_fft_acquisitions( admin_client, name="alt_admin_single_acq" ) admin_result_url = reverse_result_detail(admin_entry_name, 1) user_delete_admin_response = user_client.delete(admin_result_url, **HTTPS_KWARG) validate_response(user_delete_admin_response, status.HTTP_403_FORBIDDEN)
def test_max_disk_usage_over_under_limit(admin_client, test_scheduler): """If disk usage is too high, oldest task result of current schedule_entry should be deleted""" with patch("tasks.models.task_result.shutil") as mock_shutil: usage = ((settings.MAX_DISK_USAGE + (100 - settings.MAX_DISK_USAGE) / 2) / 100) * 500e9 mock_shutil.disk_usage.return_value = DiskUsage(total=500e9, used=usage, free=500e9 - usage) simulate_frequency_fft_acquisitions(admin_client, 10) assert TaskResult.objects.count() == 1 assert TaskResult.objects.all( )[0].id == 10 # make sure most recent result kept usage = (settings.MAX_DISK_USAGE / 100) * 500e9 / 2 mock_shutil.disk_usage.return_value = DiskUsage(total=500e9, used=usage, free=500e9 - usage) simulate_frequency_fft_acquisitions(admin_client, 10, name="part2") assert TaskResult.objects.count() == 11
def test_admin_cant_modify_own_results(admin_client, test_scheduler): entry_name = simulate_frequency_fft_acquisitions(admin_client) result_url = reverse_result_detail(entry_name, 1) new_result_detail = admin_client.get(result_url, **HTTPS_KWARG).data new_result_detail["task_id"] = 2 response = update_result_detail(admin_client, entry_name, 1, new_result_detail) validate_response(response, status.HTTP_405_METHOD_NOT_ALLOWED)
def test_user_cant_modify_own_result(user_client, test_scheduler): """Task results are not modifiable.""" entry_name = simulate_frequency_fft_acquisitions(user_client) acq_url = reverse_result_detail(entry_name, 1) new_result_detail = user_client.get(acq_url, **HTTPS_KWARG).data new_result_detail["task_id"] = 2 response = update_result_detail(user_client, entry_name, 1, new_result_detail) validate_response(response, status.HTTP_405_METHOD_NOT_ALLOWED)
def test_user_cant_create_private_acquisition( user_client, alt_user_client, test_scheduler ): # The alt user attempts to create a private acquisition. entry_name = simulate_frequency_fft_acquisitions(alt_user_client, is_private=True) result_url = reverse_result_detail(entry_name, 1) # The user attempts to GET the acquisition that the alt user created. response = user_client.get(result_url, **HTTPS_KWARG) # The user successfully GETs the acquistion that the alt user # created; meaning that the acquisition was not, in fact, private. validate_response(response, status.HTTP_200_OK)
def test_delete_entry_with_acquisitions_fails(admin_client, test_scheduler): """Attempting to delete entry with protected acquisitions should fail.""" entry_name = simulate_frequency_fft_acquisitions(admin_client) entry_url = reverse_detail_url(entry_name) response = admin_client.delete(entry_url, **HTTPS_KWARG) rjson = validate_response(response, status.HTTP_400_BAD_REQUEST) expected_status = status.HTTP_204_NO_CONTENT for acq_url in rjson["protected_objects"]: response = admin_client.delete(acq_url, **HTTPS_KWARG) validate_response(response, expected_status) response = admin_client.delete(entry_url, **HTTPS_KWARG) validate_response(response, expected_status)
def test_admin_can_view_all_results( admin_client, alt_admin_client, user_client, test_scheduler ): # alt admin schedule entry alt_admin_entry_name = simulate_frequency_fft_acquisitions( alt_admin_client, name="alt_admin_single_acq" ) alt_admin_result_url = reverse_result_detail(alt_admin_entry_name, 1) admin_view_alt_admin_response = admin_client.get( alt_admin_result_url, **HTTPS_KWARG ) # user schedule entry user_result_name = simulate_frequency_fft_acquisitions( admin_client, name="admin_single_acq" ) user_result_url = reverse_result_detail(user_result_name, 1) admin_view_user_response = admin_client.get(user_result_url, **HTTPS_KWARG) validate_response(admin_view_alt_admin_response, status.HTTP_200_OK) validate_response(admin_view_user_response, status.HTTP_200_OK)
def test_admin_can_delete_others_results( admin_client, alt_admin_client, test_scheduler ): # alt admin private schedule entry alt_admin_entry_name = simulate_frequency_fft_acquisitions( alt_admin_client, name="alt_admin_single_acq" ) alt_admin_result_url = reverse_result_detail(alt_admin_entry_name, 1) admin_delete_alt_admin_response = admin_client.delete( alt_admin_result_url, **HTTPS_KWARG ) validate_response(admin_delete_alt_admin_response, status.HTTP_204_NO_CONTENT)
def test_deleted_result_deletes_data_file(admin_client, test_scheduler): """A user should be able to delete results they own.""" entry_name = simulate_frequency_fft_acquisitions(admin_client) # schedule_entry = ScheduleEntry.objects.get(name=entry_name) task_result = TaskResult.objects.get(schedule_entry__name=entry_name) acquisition = Acquisition.objects.get(task_result__id=task_result.id) data_file = acquisition.data.path assert os.path.exists(data_file) result_url = reverse_result_detail(entry_name, 1) first_response = admin_client.delete(result_url, **HTTPS_KWARG) second_response = admin_client.delete(result_url, **HTTPS_KWARG) validate_response(first_response, status.HTTP_204_NO_CONTENT) validate_response(second_response, status.HTTP_404_NOT_FOUND) assert not os.path.exists(data_file)
def test_all_acquisitions_archive_download(admin_client, test_scheduler, tmpdir): entry_name = simulate_frequency_fft_acquisitions(admin_client, n=3) url = reverse_archive_all(entry_name) disposition = 'attachment; filename="{}_test_multiple_acq.sigmf"' disposition = disposition.format(sensor.settings.FQDN) response = admin_client.get(url, **HTTPS_KWARG) assert response.status_code == status.HTTP_200_OK assert response["content-disposition"] == disposition assert response["content-type"] == "application/x-tar" with tempfile.NamedTemporaryFile() as tf: for content in response.streaming_content: tf.write(content) tf.flush() sigmf_archive_contents = sigmf.archive.extract(tf.name) assert len(sigmf_archive_contents) == 3
def test_all_acquisitions_archive_download(user_client, test_scheduler, tmpdir): entry_name = simulate_frequency_fft_acquisitions(user_client, n=3) url = reverse_archive_all(entry_name) disposition = 'attachment; filename="{}_test_multiple_acq.sigmf"' disposition = disposition.format(sensor.settings.FQDN) response = user_client.get(url, **HTTPS_KWARG) assert response.status_code == status.HTTP_200_OK assert response["content-disposition"] == disposition assert response["content-type"] == "application/x-tar" import os.path perm_temp_fname = os.path.join(tmpdir, "test_sigmf.tar") with open(perm_temp_fname, "wb+") as tf: for content in response.streaming_content: tf.write(content) sigmf_archive_contents = sigmf.archive.extract(perm_temp_fname) assert len(sigmf_archive_contents) == 3
def test_single_acquisition_archive_download(admin_client, test_scheduler): entry_name = simulate_frequency_fft_acquisitions(admin_client, n=1) task_id = 1 url = reverse_archive(entry_name, task_id) disposition = 'attachment; filename="{}_test_acq_1.sigmf"' disposition = disposition.format(sensor.settings.FQDN) response = admin_client.get(url, **HTTPS_KWARG) assert response.status_code == status.HTTP_200_OK assert response["content-disposition"] == disposition assert response["content-type"] == "application/x-tar" with tempfile.NamedTemporaryFile() as tf: for content in response.streaming_content: tf.write(content) tf.flush() sigmf_archive_contents = sigmf.sigmffile.fromarchive(tf.name) md = sigmf_archive_contents._metadata datafile = sigmf_archive_contents.data_file datafile_actual_size = os.stat(datafile).st_size claimed_sha512 = md["global"]["core:sha512"] # number_of_sample_arrays = len(md["annotations"]) number_of_sample_arrays = 1 cal_annotation = list( filter( lambda a: a["ntia-core:annotation_type"] == "CalibrationAnnotation", md["annotations"], ))[0] samples_per_array = cal_annotation["core:sample_count"] sample_array_size = samples_per_array * np.float32(0.0).nbytes datafile_expected_size = number_of_sample_arrays * sample_array_size actual_sha512 = sigmf.sigmf_hash.calculate_sha512(datafile) assert datafile_actual_size == datafile_expected_size assert claimed_sha512 == actual_sha512
def test_admin_can_create_acquisition(admin_client, test_scheduler): entry_name = simulate_frequency_fft_acquisitions(admin_client) result_url = reverse_result_detail(entry_name, 1) response = admin_client.get(result_url, **HTTPS_KWARG) validate_response(response, status.HTTP_200_OK)