diff --git a/.github/workflows/ci-unittest.yml b/.github/workflows/ci-unittest.yml new file mode 100644 index 0000000..a66c401 --- /dev/null +++ b/.github/workflows/ci-unittest.yml @@ -0,0 +1,28 @@ +name: Unit Tests + +on: + pull_request: + branches: + - main + push: + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.11] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install -r test-requirements.txt + - name: Test with unittest + run: | + as_api="http://localhost:4567" as_un="admin" as_pw="admin" python -m unittest diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..e402505 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1 @@ +vcrpy~=7.0.0 \ No newline at end of file diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/authorityids_tests.py b/test/authorityids_tests.py similarity index 100% rename from tests/authorityids_tests.py rename to test/authorityids_tests.py diff --git a/tests/dometadata_tests.py b/test/dometadata_tests.py similarity index 100% rename from tests/dometadata_tests.py rename to test/dometadata_tests.py diff --git a/tests/eepacameroon_tests.py b/test/eepacameroon_tests.py similarity index 100% rename from tests/eepacameroon_tests.py rename to test/eepacameroon_tests.py diff --git a/test/fixtures/vcr_cassettes/test_updatefileuri/setUpModule.yaml b/test/fixtures/vcr_cassettes/test_updatefileuri/setUpModule.yaml new file mode 100644 index 0000000..d6875d1 --- /dev/null +++ b/test/fixtures/vcr_cassettes/test_updatefileuri/setUpModule.yaml @@ -0,0 +1,40 @@ +interactions: +- request: + body: password=[REDACTED]&expiring=False + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '29' + Content-Type: + - application/x-www-form-urlencoded + User-Agent: + - ArchivesSnake/0.1 + method: POST + uri: http://localhost:4567/users/admin/login + response: + body: + string: '{"session":"16f12b6efaadd4ad3acb0caa56c7c7314b4fda82bc1b259df5b62e860848ec49","user":{"lock_version":2,"username":"admin","name":"Administrator","is_system_user":true,"create_time":"2025-03-19T14:16:31Z","system_mtime":"2025-03-19T14:17:36Z","user_mtime":"2025-03-19T14:17:36Z","is_active_user":true,"jsonmodel_type":"user","groups":[],"is_admin":true,"uri":"/users/1","agent_record":{"ref":"/agents/people/1"},"permissions":{"/repositories/1":["update_location_record","delete_vocabulary_record","update_subject_record","delete_subject_record","update_agent_record","delete_agent_record","update_vocabulary_record","update_enumeration_record","merge_subject_record","merge_agent_record","update_container_profile_record","update_location_profile_record","administer_system","manage_users","become_user","view_all_records","create_repository","delete_repository","transfer_repository","index_system","manage_repository","update_accession_record","update_resource_record","update_digital_object_record","update_event_record","delete_event_record","suppress_archival_record","transfer_archival_record","delete_archival_record","view_suppressed","view_repository","update_classification_record","delete_classification_record","mediate_edits","import_records","cancel_importer_job","create_job","cancel_job","manage_subject_record","manage_agent_record","view_agent_contact_record","manage_vocabulary_record","manage_enumeration_record","merge_agents_and_subjects","merge_archival_record","manage_rde_templates","update_container_record","manage_container_record","manage_container_profile_record","manage_location_profile_record","update_assessment_record","delete_assessment_record","manage_assessment_attributes","manage_custom_report_templates"],"_archivesspace":["administer_system","manage_users","become_user","view_all_records","create_repository","delete_repository","transfer_repository","index_system","manage_repository","update_accession_record","update_resource_record","update_digital_object_record","update_event_record","delete_event_record","suppress_archival_record","transfer_archival_record","delete_archival_record","view_suppressed","view_repository","update_classification_record","delete_classification_record","mediate_edits","import_records","cancel_importer_job","create_job","cancel_job","manage_subject_record","manage_agent_record","view_agent_contact_record","manage_vocabulary_record","manage_enumeration_record","merge_agents_and_subjects","merge_archival_record","manage_rde_templates","update_container_record","manage_container_record","manage_container_profile_record","manage_location_profile_record","update_assessment_record","delete_assessment_record","manage_assessment_attributes","manage_custom_report_templates","update_location_record","delete_vocabulary_record","update_subject_record","delete_subject_record","update_agent_record","delete_agent_record","update_vocabulary_record","update_enumeration_record","merge_subject_record","merge_agent_record","update_container_profile_record","update_location_profile_record"]}},"expire_after_seconds":604800} + + ' + headers: + Cache-Control: + - private, must-revalidate, max-age=0 + Content-Length: + - '3098' + Content-Type: + - application/json + Date: + - Wed, 19 Mar 2025 14:17:36 GMT + Server: + - Jetty(9.4.44.v20210927) + X-Content-Type-Options: + - nosniff + status: + code: 200 + message: OK +version: 1 diff --git a/test/fixtures/vcr_cassettes/test_updatefileuri/test_aspace_post_response.yaml b/test/fixtures/vcr_cassettes/test_updatefileuri/test_aspace_post_response.yaml new file mode 100644 index 0000000..2fa9da5 --- /dev/null +++ b/test/fixtures/vcr_cassettes/test_updatefileuri/test_aspace_post_response.yaml @@ -0,0 +1,46 @@ +interactions: +- request: + body: '{"lock_version": 0, "digital_object_id": "1234567", "title": "Test digital + object", "publish": false, "jsonmodel_type": "digital_object", "file_versions": + [{"lock_version": 0, "file_uri": "https://mads.si.edu/mads/id/NASM-Young_interview_transcript_mwaohi_NASM.2020.0005", + "jsonmodel_type": "file_version"}], "uri": "/repositories/2/digital_objects/1", + "repository": {"ref": "/repositories/2"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '394' + Content-Type: + - application/json + User-Agent: + - ArchivesSnake/0.1 + X-ArchivesSpace-Session: + - '[REDACTED]' + method: POST + uri: http://localhost:4567/repositories/2/digital_objects/1 + response: + body: + string: '{"status":"Updated","id":1,"lock_version":1,"stale":true,"uri":"/repositories/2/digital_objects/1","warnings":[]} + + ' + headers: + Cache-Control: + - private, must-revalidate, max-age=0 + Content-Length: + - '114' + Content-Type: + - application/json + Date: + - Wed, 19 Mar 2025 14:17:36 GMT + Server: + - Jetty(9.4.44.v20210927) + X-Content-Type-Options: + - nosniff + status: + code: 200 + message: OK +version: 1 diff --git a/test/fixtures/vcr_cassettes/test_updatefileuri/test_bad_post.yaml b/test/fixtures/vcr_cassettes/test_updatefileuri/test_bad_post.yaml new file mode 100644 index 0000000..fd9d9c2 --- /dev/null +++ b/test/fixtures/vcr_cassettes/test_updatefileuri/test_bad_post.yaml @@ -0,0 +1,46 @@ +interactions: +- request: + body: '{"lock_version": 0, "digital_object_id": "1234567", "title": "Test digital + object", "publish": false, "jsonmodel_type": "digital_object", "file_versions": + [{"lock_version": 0, "file_uri": "https://mads.si.edu/mads/id/NASM-Young_interview_transcript_mwaohi_NASM.2020.0005", + "jsonmodel_type": "file_version"}], "uri": "/repositories/2/digital_objects/1", + "repository": {"ref": "/repositories/2"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '394' + Content-Type: + - application/json + User-Agent: + - ArchivesSnake/0.1 + X-ArchivesSpace-Session: + - '[REDACTED]' + method: POST + uri: http://localhost:4567/repositories/2/digital_objects/600 + response: + body: + string: '{"error":"DigitalObject not found"} + + ' + headers: + Cache-Control: + - private, must-revalidate, max-age=0 + Content-Length: + - '36' + Content-Type: + - application/json + Date: + - Wed, 19 Mar 2025 14:17:36 GMT + Server: + - Jetty(9.4.44.v20210927) + X-Content-Type-Options: + - nosniff + status: + code: 404 + message: Not Found +version: 1 diff --git a/test/fixtures/vcr_cassettes/test_updatefileuri/test_get_digital_object.yaml b/test/fixtures/vcr_cassettes/test_updatefileuri/test_get_digital_object.yaml new file mode 100644 index 0000000..9a4f2be --- /dev/null +++ b/test/fixtures/vcr_cassettes/test_updatefileuri/test_get_digital_object.yaml @@ -0,0 +1,39 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - ArchivesSnake/0.1 + X-ArchivesSpace-Session: + - '[REDACTED]' + method: GET + uri: http://localhost:4567/repositories/2/digital_objects/1 + response: + body: + string: '{"lock_version":1,"digital_object_id":"1234567","title":"Test digital + object","publish":false,"restrictions":false,"created_by":"admin","last_modified_by":"admin","create_time":"2025-03-19T14:17:27Z","system_mtime":"2025-03-19T14:17:36Z","user_mtime":"2025-03-19T14:17:36Z","suppressed":false,"is_slug_auto":true,"jsonmodel_type":"digital_object","external_ids":[],"subjects":[],"linked_events":[],"extents":[],"lang_materials":[],"dates":[],"external_documents":[],"rights_statements":[],"linked_agents":[],"file_versions":[{"lock_version":0,"file_uri":"https://mads.si.edu/mads/id/NASM-Young_interview_transcript_mwaohi_NASM.2020.0005","publish":false,"created_by":"admin","last_modified_by":"admin","create_time":"2025-03-19T14:17:36Z","system_mtime":"2025-03-19T14:17:36Z","user_mtime":"2025-03-19T14:17:36Z","jsonmodel_type":"file_version","is_representative":false,"identifier":"2"}],"classifications":[],"notes":[],"linked_instances":[],"metadata_rights_declarations":[],"uri":"/repositories/2/digital_objects/1","repository":{"ref":"/repositories/2"},"tree":{"ref":"/repositories/2/digital_objects/1/tree"}} + + ' + headers: + Cache-Control: + - private, must-revalidate, max-age=0 + Content-Length: + - '1116' + Content-Type: + - application/json + Date: + - Wed, 19 Mar 2025 14:17:36 GMT + Server: + - Jetty(9.4.44.v20210927) + X-Content-Type-Options: + - nosniff + status: + code: 200 + message: OK +version: 1 diff --git a/test/fixtures/vcr_cassettes/test_updatefileuri/test_get_missing_digital_object.yaml b/test/fixtures/vcr_cassettes/test_updatefileuri/test_get_missing_digital_object.yaml new file mode 100644 index 0000000..88b47aa --- /dev/null +++ b/test/fixtures/vcr_cassettes/test_updatefileuri/test_get_missing_digital_object.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - ArchivesSnake/0.1 + X-ArchivesSpace-Session: + - '[REDACTED]' + method: GET + uri: http://localhost:4567/repositories/2/digital_objects/600 + response: + body: + string: '{"error":"DigitalObject not found"} + + ' + headers: + Cache-Control: + - private, must-revalidate, max-age=0 + Content-Length: + - '36' + Content-Type: + - application/json + Date: + - Wed, 19 Mar 2025 14:17:36 GMT + Server: + - Jetty(9.4.44.v20210927) + X-Content-Type-Options: + - nosniff + status: + code: 404 + message: Not Found +version: 1 diff --git a/tests/grouppermissions_tests.py b/test/grouppermissions_tests.py similarity index 100% rename from tests/grouppermissions_tests.py rename to test/grouppermissions_tests.py diff --git a/tests/mergesubjects_tests.py b/test/mergesubjects_tests.py similarity index 100% rename from tests/mergesubjects_tests.py rename to test/mergesubjects_tests.py diff --git a/tests/missingtitles_tests.py b/test/missingtitles_tests.py similarity index 100% rename from tests/missingtitles_tests.py rename to test/missingtitles_tests.py diff --git a/tests/newsubjects_tests.py b/test/newsubjects_tests.py similarity index 100% rename from tests/newsubjects_tests.py rename to test/newsubjects_tests.py diff --git a/tests/resids_tests.py b/test/resids_tests.py similarity index 100% rename from tests/resids_tests.py rename to test/resids_tests.py diff --git a/tests/suppressobjects_tests.py b/test/suppressobjects_tests.py similarity index 100% rename from tests/suppressobjects_tests.py rename to test/suppressobjects_tests.py diff --git a/tests/updatefileuri_tests.py b/test/test_updatefileuri.py similarity index 69% rename from tests/updatefileuri_tests.py rename to test/test_updatefileuri.py index 844b6f5..46e56ca 100644 --- a/tests/updatefileuri_tests.py +++ b/test/test_updatefileuri.py @@ -1,28 +1,31 @@ # This script consists of unittests for update_fileuri.py import unittest +from test.vcr_utils import vcr from python_scripts.repeatable.update_fileuri import * from test_data.fileuri_testdata import * -# Hardcode to dev env -env_file = find_dotenv(f'.env.dev') -load_dotenv(env_file) -local_aspace = client_login(os.getenv('as_api'), os.getenv('as_un'), os.getenv('as_pw')) +@vcr.use_cassette() +def setUpModule(): + # Hardcode to dev env + env_file = find_dotenv(f'.env.dev') + load_dotenv(env_file) + global local_aspace + local_aspace = client_login(os.getenv('as_api'), os.getenv('as_un'), os.getenv('as_pw')) class TestGetDigitalObject(unittest.TestCase): + @vcr.use_cassette def test_get_digital_object(self): """Tests that the existing digital object can be retrieved""" - repo_id = test_update_file_uri_metadata['repository']['ref'].split('/repositories/')[1] - digital_object_id = test_update_file_uri_metadata['uri'].rsplit('/',1)[1] - test_response = get_digital_object(local_aspace, repo_id, digital_object_id) + test_response = get_digital_object(local_aspace, 2, 1) self.assertIsInstance(test_response, dict) self.assertNotIn('error', test_response) + @vcr.use_cassette def test_get_missing_digital_object(self): """Tests that a missing digital object returns an error""" - repo_id = test_update_file_uri_metadata['repository']['ref'].split('/repositories/')[1] - test_response = get_digital_object(local_aspace, repo_id, '600') # Some unusually high made up number + test_response = get_digital_object(local_aspace, 2, 600) # Some unusually high made up number self.assertIsNone(test_response) class TestBuildDigitalObject(unittest.TestCase): @@ -50,16 +53,16 @@ def test_build_digital_object_mp3(self): class TestDigitalObjects(unittest.TestCase): + @vcr.use_cassette def test_aspace_post_response(self): - repo_id = test_update_file_uri_metadata['repository']['ref'].split('/repositories/')[1] - digital_object_id = test_update_file_uri_metadata['uri'].rsplit('/',1)[1] - test_response = update_digital_object(local_aspace, repo_id, digital_object_id, test_update_file_uri_metadata) + test_response = update_digital_object(local_aspace, 2, 1, test_update_file_uri_metadata) self.assertEqual(test_response['status'], 'Updated') self.assertEqual(test_response['warnings'], []) + @vcr.use_cassette def test_bad_post(self): repo_id = test_update_file_uri_metadata['repository']['ref'].split('/repositories/')[1] - test_response = update_digital_object(local_aspace, repo_id, '600', test_update_file_uri_metadata) # Some unusually high made up number + test_response = update_digital_object(local_aspace, 2, 600, test_update_file_uri_metadata) # Some unusually high made up number self.assertIn('error', test_response) self.assertEqual(test_response['error'], 'DigitalObject not found') diff --git a/tests/updatelocations_tests.py b/test/updatelocations_tests.py similarity index 100% rename from tests/updatelocations_tests.py rename to test/updatelocations_tests.py diff --git a/tests/updatesubjects_tests.py b/test/updatesubjects_tests.py similarity index 100% rename from tests/updatesubjects_tests.py rename to test/updatesubjects_tests.py diff --git a/tests/utilities_tests.py b/test/utilities_tests.py similarity index 100% rename from tests/utilities_tests.py rename to test/utilities_tests.py diff --git a/test/vcr_utils.py b/test/vcr_utils.py new file mode 100644 index 0000000..2dca139 --- /dev/null +++ b/test/vcr_utils.py @@ -0,0 +1,10 @@ +import inspect +import os + +from vcr import VCR + +vcr = VCR( + filter_headers=[('X-ArchivesSpace-Session', '[REDACTED]')], + filter_post_data_parameters=[('password', '[REDACTED]')], + func_path_generator = lambda test: "test/fixtures/vcr_cassettes/{}/{}.yaml".format(os.path.basename(inspect.getfile(test)).replace('.py', ''), test.__name__) +) \ No newline at end of file diff --git a/tests/znames_tests.py b/test/znames_tests.py similarity index 100% rename from tests/znames_tests.py rename to test/znames_tests.py