diff --git a/docs/bulk-exports.md b/docs/bulk-exports.md index 5a605a7..1f6558d 100644 --- a/docs/bulk-exports.md +++ b/docs/bulk-exports.md @@ -155,10 +155,11 @@ You can generate a JWKS using the RS384 algorithm and a random ID by running the (Make sure you have `jose` installed first.) ```sh -jose jwk gen -s -i "{\"alg\":\"RS384\",\"kid\":\"`uuidgen`\"}" -o rsa.jwks +jose jwk gen -s -i "{\"alg\":\"RS384\",\"kid\":\"`uuidgen`\"}" -o private.jwks +jose jwk pub -s -i private.jwks -o public.jwks ``` -Then give `rsa.jwks` to your FHIR server and to Cumulus ETL (details on that below). +Then give `public.jwks` to your FHIR server and `private.jwks` to Cumulus ETL (details on that below). ### SMART Arguments @@ -166,7 +167,7 @@ You'll need to pass two new arguments to Cumulus ETL: ```sh --smart-client-id=YOUR_CLIENT_ID ---smart-jwks=/path/to/rsa.jwks +--smart-jwks=/path/to/private.jwks ``` You can also give `--smart-client-id` a path to a file with your client ID, diff --git a/tests/loaders/ndjson/test_bulk_export.py b/tests/loaders/ndjson/test_bulk_export.py index ab3fd8d..e7dfe7e 100644 --- a/tests/loaders/ndjson/test_bulk_export.py +++ b/tests/loaders/ndjson/test_bulk_export.py @@ -3,6 +3,7 @@ import contextlib import datetime import io +import json import os import tempfile from unittest import mock @@ -141,18 +142,21 @@ async def test_happy_path(self): ], }, ) + con1 = json.dumps({"resourceType": "Condition", "id": "1"}) self.respx_mock.get( "https://example.com/con1", headers={"Accept": "application/fhir+ndjson"}, - ).respond(json={"resourceType": "Condition", "id": "1"}) + ).respond(text=con1) + con2 = json.dumps({"resourceType": "Condition", "id": "2"}) self.respx_mock.get( "https://example.com/con2", headers={"Accept": "application/fhir+ndjson"}, - ).respond(json={"resourceType": "Condition", "id": "2"}) + ).respond(text=con2) + pat1 = json.dumps({"resourceType": "Patient", "id": "P"}) self.respx_mock.get( "https://example.com/pat1", headers={"Accept": "application/fhir+ndjson"}, - ).respond(json={"resourceType": "Patient", "id": "P"}) + ).respond(text=pat1) await self.export() @@ -216,7 +220,7 @@ async def test_happy_path(self): ), ( "download_complete", - {"fileSize": 40, "fileUrl": "https://example.com/con1", "resourceCount": 1}, + {"fileSize": len(con1), "fileUrl": "https://example.com/con1", "resourceCount": 1}, ), ( "download_request", @@ -228,7 +232,7 @@ async def test_happy_path(self): ), ( "download_complete", - {"fileSize": 40, "fileUrl": "https://example.com/con2", "resourceCount": 1}, + {"fileSize": len(con2), "fileUrl": "https://example.com/con2", "resourceCount": 1}, ), ( "download_request", @@ -240,11 +244,17 @@ async def test_happy_path(self): ), ( "download_complete", - {"fileSize": 38, "fileUrl": "https://example.com/pat1", "resourceCount": 1}, + {"fileSize": len(pat1), "fileUrl": "https://example.com/pat1", "resourceCount": 1}, ), ( "export_complete", - {"attachments": None, "bytes": 118, "duration": 0, "files": 3, "resources": 3}, + { + "attachments": None, + "bytes": len(con1) + len(con2) + len(pat1), + "duration": 0, + "files": 3, + "resources": 3, + }, ), ) @@ -300,12 +310,11 @@ async def test_export_error(self): "https://example.com/err2", headers={"Accept": "application/fhir+ndjson"}, ).respond(text=err2) + con1 = '{"resourceType": "Condition"}' self.respx_mock.get( "https://example.com/con1", headers={"Accept": "application/fhir+ndjson"}, - ).respond( - json={"resourceType": "Condition"}, - ) + ).respond(text=con1) with self.assertRaisesRegex( errors.FatalError, "Errors occurred during export:\n - err1\n - err2\n - err3\n - err4" @@ -340,7 +349,7 @@ async def test_export_error(self): ), ( "download_complete", - {"fileSize": 29, "fileUrl": "https://example.com/con1", "resourceCount": 1}, + {"fileSize": len(con1), "fileUrl": "https://example.com/con1", "resourceCount": 1}, ), ( "download_request", @@ -352,7 +361,7 @@ async def test_export_error(self): ), ( "download_complete", - {"fileSize": 93, "fileUrl": "https://example.com/err1", "resourceCount": 1}, + {"fileSize": len(err1), "fileUrl": "https://example.com/err1", "resourceCount": 1}, ), ( "download_request", @@ -364,11 +373,17 @@ async def test_export_error(self): ), ( "download_complete", - {"fileSize": 322, "fileUrl": "https://example.com/err2", "resourceCount": 3}, + {"fileSize": len(err2), "fileUrl": "https://example.com/err2", "resourceCount": 3}, ), ( "export_complete", - {"attachments": None, "bytes": 444, "duration": 0, "files": 3, "resources": 5}, + { + "attachments": None, + "bytes": len(con1) + len(err1) + len(err2), + "duration": 0, + "files": 3, + "resources": 5, + }, ), ) @@ -408,20 +423,22 @@ async def test_deleted_resources(self): ], }, ) - deleted1 = { - "resourceType": "Bundle", - "type": "transaction", - "entry": [ - { - "request": {"method": "DELETE", "url": "Patient/123"}, - } - ], - } - self.respx_mock.get("https://example.com/deleted1").respond(json=deleted1) + deleted1 = json.dumps( + { + "resourceType": "Bundle", + "type": "transaction", + "entry": [ + { + "request": {"method": "DELETE", "url": "Patient/123"}, + } + ], + } + ) + self.respx_mock.get("https://example.com/deleted1").respond(text=deleted1) await self.export() - bundle = common.read_json(f"{self.tmpdir}/deleted/Bundle.000.ndjson") + bundle = common.read_text(f"{self.tmpdir}/deleted/Bundle.000.ndjson") self.assertEqual(bundle, deleted1) self.assert_log_equals( @@ -437,11 +454,21 @@ async def test_deleted_resources(self): ), ( "download_complete", - {"fileSize": 117, "fileUrl": "https://example.com/deleted1", "resourceCount": 1}, + { + "fileSize": len(deleted1), + "fileUrl": "https://example.com/deleted1", + "resourceCount": 1, + }, ), ( "export_complete", - {"attachments": None, "bytes": 117, "duration": 0, "files": 1, "resources": 1}, + { + "attachments": None, + "bytes": len(deleted1), + "duration": 0, + "files": 1, + "resources": 1, + }, ), )