示例#1
0
    def test_cached_health(self):
        storage_service = StorageService()
        storage_service.create_bucket()
        # No health object is available in S3 bucket, yielding an error
        with ResponsesHelper() as helper:
            helper.add_passthru(self.base_url)
            response = requests.get(self.base_url + '/health/cached')
            self.assertEqual(500, response.status_code)
            self.assertEqual(
                'ChaliceViewError: Cached health object does not exist',
                response.json()['Message'])

        # A successful response is obtained when all the systems are functional
        self._create_mock_queues()
        endpoint_states = self._endpoint_states()
        app = load_app_module(self.lambda_name())
        with ResponsesHelper() as helper:
            helper.add_passthru(self.base_url)
            with self._mock_service_endpoints(helper, endpoint_states):
                app.update_health_cache(MagicMock(), MagicMock())
                response = requests.get(self.base_url + '/health/cached')
                self.assertEqual(200, response.status_code)

        # Another failure is observed when the cache health object is older than 2 minutes
        future_time = time.time() + 3 * 60
        with ResponsesHelper() as helper:
            helper.add_passthru(self.base_url)
            with patch('time.time', new=lambda: future_time):
                response = requests.get(self.base_url + '/health/cached')
                self.assertEqual(500, response.status_code)
                self.assertEqual(
                    'ChaliceViewError: Cached health object is stale',
                    response.json()['Message'])
示例#2
0
 def _mock_other_lambdas(self, helper: ResponsesHelper, up: bool):
     for lambda_name in self._other_lambda_names():
         helper.add(
             responses.Response(method='GET',
                                url=config.lambda_endpoint(lambda_name) +
                                '/health/basic',
                                status=200 if up else 500,
                                json={'up': up}))
示例#3
0
 def _mock_service_endpoints(self, helper: ResponsesHelper,
                             endpoint_states: Mapping[str, bool]) -> None:
     for endpoint, endpoint_up in endpoint_states.items():
         helper.add(
             responses.Response(method='HEAD',
                                url=config.service_endpoint() + endpoint,
                                status=200 if endpoint_up else 503,
                                json={}))
     yield
示例#4
0
 def test_export_append_items_to_collection_raises_expired_access_token_error(
         self, _dynamodb_client):
     expected_collection = dict(uuid='abc', version='123')
     expected_get_content_result = dict(
         resume_token='rt1', items=[1, 2, 3,
                                    4])  # NOTE: This is just for the test.
     service = CartExportService()
     with self.assertRaises(ExpiredAccessTokenError):
         with patch.object(service,
                           'get_content',
                           side_effect=[expected_get_content_result]):
             with ResponsesHelper() as helper:
                 url = CollectionDataAccess.endpoint_url(
                     'collections', expected_collection['uuid'])
                 helper.add(
                     responses.Response(responses.PATCH,
                                        url,
                                        status=401,
                                        json=dict(code='abc')))
                 service.export(export_id='export1',
                                user_id='user1',
                                cart_id='cart1',
                                access_token='at1',
                                collection_uuid=expected_collection['uuid'],
                                collection_version='ver1',
                                resume_token='rt0')
示例#5
0
 def test_export_create_new_collection(self, _dynamodb_client):
     expected_collection = dict(uuid='abc', version='123')
     expected_get_content_result = dict(
         resume_token='rt1', items=[1, 2, 3,
                                    4])  # NOTE: This is just for the test.
     service = CartExportService()
     with patch.object(service.cart_item_manager,
                       'get_cart',
                       side_effect=[dict(CartName='abc123')]):
         with patch.object(service,
                           'get_content',
                           side_effect=[expected_get_content_result]):
             with ResponsesHelper() as helper:
                 helper.add(
                     responses.Response(
                         responses.PUT,
                         CollectionDataAccess.endpoint_url('collections'),
                         status=201,
                         json=expected_collection))
                 result = service.export(
                     export_id='export1',
                     user_id='user1',
                     cart_id='cart1',
                     access_token='at1',
                     collection_uuid=expected_collection['uuid'],
                     collection_version='ver1',
                     resume_token=None)
     self.assertEqual(expected_collection, result['collection'])
     self.assertEqual(expected_get_content_result['resume_token'],
                      result['resume_token'])
     self.assertEqual(len(expected_get_content_result['items']),
                      result['exported_item_count'])
示例#6
0
 def test_health_endpoint_keys(self):
     endpoint_states = self._endpoint_states()
     expected = {
         keys: {
             'up': True,
             **expected_response
         }
         for keys, expected_response in [
             ('elasticsearch', self._expected_elasticsearch(True)),
             ('queues', self._expected_queues(True)),
             ('other_lambdas', self._expected_other_lambdas(True)),
             ('api_endpoints',
              self._expected_api_endpoints(endpoint_states)),
             ('progress', self._expected_progress()),
             ('progress,queues', {
                 **self._expected_progress(),
                 **self._expected_queues(True)
             }),
         ]
     }
     self._create_mock_queues()
     for keys, expected_response in expected.items():
         with self.subTest(msg=keys):
             with ResponsesHelper() as helper:
                 helper.add_passthru(self.base_url)
                 self._mock_other_lambdas(helper, up=True)
                 with self._mock_service_endpoints(helper, endpoint_states):
                     response = requests.get(self.base_url + '/health/' +
                                             keys)
                     self.assertEqual(200, response.status_code)
                     self.assertEqual(expected_response, response.json())
示例#7
0
 def _test(self,
           endpoint_states: Mapping[str, bool],
           lambdas_up: bool,
           path: str = '/health/fast'):
     with ResponsesHelper() as helper:
         helper.add_passthru(self.base_url)
         self._mock_other_lambdas(helper, lambdas_up)
         with self._mock_service_endpoints(helper, endpoint_states):
             return requests.get(self.base_url + path)
示例#8
0
 def _shorten_query_url(self, url, expect_status=None):
     with ResponsesHelper() as helper:
         helper.add_passthru(self.base_url)
         response = requests.post(self.base_url + '/url', json={'url': url})
         if expect_status is None:
             response.raise_for_status()
         else:
             self.assertEqual(response.status_code, expect_status)
         return response.json()
 def test_manifest_endpoint_start_execution(self, mock_uuid,
                                            step_function_helper):
     """
     Calling start manifest generation without a token should start an
     execution and return a response with Retry-After and Location in the
     headers.
     """
     with ResponsesHelper() as helper:
         helper.add_passthru(self.base_url)
         for fetch in True, False:
             with self.subTest(fetch=fetch):
                 execution_name = '6c9dfa3f-e92e-11e8-9764-ada973595c11'
                 mock_uuid.return_value = execution_name
                 step_function_helper.describe_execution.return_value = {
                     'status': 'RUNNING'
                 }
                 format_ = ManifestFormat.compact.value
                 filters = {'organ': {'is': ['lymph node']}}
                 params = {
                     'catalog': self.catalog,
                     'filters': json.dumps(filters),
                     'format': format_
                 }
                 if fetch:
                     response = requests.get(self.base_url +
                                             '/fetch/manifest/files',
                                             params=params)
                     response.raise_for_status()
                     response = response.json()
                 else:
                     response = requests.get(self.base_url +
                                             '/manifest/files',
                                             params=params,
                                             allow_redirects=False)
                 self.assertEqual(
                     301,
                     response['Status'] if fetch else response.status_code)
                 self.assertIn('Retry-After',
                               response if fetch else response.headers)
                 self.assertIn('Location',
                               response if fetch else response.headers)
                 if fetch:
                     # The 'CommandLine' value is verified in TestManifestResponse,
                     # here we only need to confirm the key exists in the response.
                     self.assertIn('CommandLine', response)
                 step_function_helper.start_execution.assert_called_once_with(
                     config.manifest_state_machine_name,
                     execution_name,
                     execution_input=dict(catalog=self.catalog,
                                          format=format_,
                                          filters=filters,
                                          object_key=None))
                 step_function_helper.describe_execution.assert_called_once(
                 )
                 step_function_helper.reset_mock()
示例#10
0
 def test_get_raises_retrival_error(self):
     test_collection_uuid = 'abcdef123456'
     test_collection_version = '1980-01-01'
     with ResponsesHelper() as helper:
         helper.add(
             responses.CallbackResponse(responses.GET,
                                        self.cda.endpoint_url(
                                            'collections',
                                            test_collection_uuid),
                                        callback=RequestCallback(567, '{}'),
                                        content_type='application/json'))
         with self.assertRaises(RetrievalError):
             self.cda.get(test_collection_uuid, test_collection_version)
示例#11
0
 def test_data_object_not_found(self):
     file_uuid = 'NOT_A_GOOD_IDEA'
     error_body = 'DRS should just proxy the DSS for error responses'
     with ResponsesHelper() as helper:
         helper.add_passthru(self.base_url)
         url = f'{config.dss_endpoint}/files/{file_uuid}'
         helper.add(responses.Response(method=responses.GET,
                                       body=error_body,
                                       url=url,
                                       status=404))
         drs_response = requests.get(
             dss_drs_object_url(file_uuid, base_url=self.base_url))
         self.assertEqual(drs_response.status_code, 404)
         self.assertEqual(drs_response.text, error_body)
示例#12
0
 def test_append_raises_update_error(self):
     test_collection_uuid = 'abcdef123456'
     test_collection_version = '1980-01-01'
     with ResponsesHelper() as helper:
         helper.add(
             responses.CallbackResponse(responses.PATCH,
                                        self.cda.endpoint_url(
                                            'collections',
                                            test_collection_uuid),
                                        callback=RequestCallback(405, '{}'),
                                        content_type='application/json'))
         with self.assertRaises(UpdateError):
             self.cda.append(test_collection_uuid, test_collection_version,
                             [])
示例#13
0
 def test_create_raises_creation_error(self):
     test_collection_uuid = 'abcdef123456'
     test_collection_version = '1980-01-01'
     fake_dss_response = {"code": "unknown"}
     with ResponsesHelper() as helper:
         helper.add(
             responses.CallbackResponse(
                 responses.PUT,
                 self.cda.endpoint_url('collections'),
                 callback=RequestCallback(500,
                                          json.dumps(fake_dss_response)),
                 content_type='application/json'))
         with self.assertRaises(CreationError):
             self.cda.create(test_collection_uuid, 'foo bar', 'bar',
                             test_collection_version, [])
示例#14
0
 def test_send_request_successful_with_auto_retry_on_http_504_timeout(self):
     test_collection_uuid = 'abcdef123456'
     expected_response = {'code': 'hello_world'}
     with ResponsesHelper() as helper:
         url = self.cda.endpoint_url(test_collection_uuid)
         helper.add(
             responses.CallbackResponse(responses.GET,
                                        url,
                                        callback=RequestCallback(
                                            200,
                                            json.dumps(expected_response),
                                            delay=True),
                                        content_type='application/json'))
         response = self.cda.send_request(test_collection_uuid, 'get', url,
                                          {})
     self.assertEqual(response.json(), expected_response)
示例#15
0
 def test_append_with_no_items_successful(self):
     test_collection_uuid = 'abcdef123456'
     test_collection_version = '1980-01-01'
     expected_collection = dict(uuid=test_collection_uuid,
                                version=test_collection_version)
     with ResponsesHelper() as helper:
         helper.add(
             responses.CallbackResponse(
                 responses.PATCH,
                 self.cda.endpoint_url('collections', test_collection_uuid),
                 callback=RequestCallback(200,
                                          json.dumps(expected_collection)),
                 content_type='application/json'))
         collection = self.cda.append(test_collection_uuid,
                                      test_collection_version, [])
     self.assertEqual(collection, expected_collection)
示例#16
0
 def test_create_ok(self):
     test_collection_uuid = 'abcdef123456'
     test_collection_version = '1980-01-01'
     expected_collection = dict(uuid=test_collection_uuid,
                                version=test_collection_version)
     with ResponsesHelper() as helper:
         helper.add(
             responses.CallbackResponse(
                 responses.PUT,
                 self.cda.endpoint_url('collections'),
                 callback=RequestCallback(201,
                                          json.dumps(expected_collection)),
                 content_type='application/json'))
         collection = self.cda.create(test_collection_uuid, 'foo bar',
                                      'bar', test_collection_version, [])
     self.assertEqual(collection, expected_collection)
示例#17
0
 def test_laziness(self):
     # Note the absence of moto decorators on this test.
     with ResponsesHelper() as helper:
         helper.add_passthru(self.base_url)
         self._mock_other_lambdas(helper, up=True)
         # If Health weren't lazy, it would fail due the lack of mocks for SQS.
         response = requests.get(self.base_url + '/health/other_lambdas')
         # The use of subTests ensures that we see the result of both
         # assertions. In the case of the health endpoint, the body of a 503
         # may carry a body with additional information.
         self.assertEqual(200, response.status_code)
         expected_response = {
             'up': True,
             **self._expected_other_lambdas(up=True)
         }
         self.assertEqual(expected_response, response.json())
示例#18
0
 def test_get_ok(self):
     test_collection_uuid = 'abcdef123456'
     test_collection_version = '1980-01-01'
     fake_collection = {'hello': 'world'}
     with ResponsesHelper() as helper:
         helper.add(
             responses.Response(responses.GET,
                                self.cda.endpoint_url(
                                    'collections', test_collection_uuid),
                                json=fake_collection))
         collection = self.cda.get(test_collection_uuid,
                                   test_collection_version)
     self.assertEqual(
         collection,
         dict(uuid=test_collection_uuid,
              version=test_collection_version,
              collection=fake_collection))
示例#19
0
 def test_send_request_with_unexpected_response_code_raises_unauthorized_client_access_error(
         self):
     test_collection_uuid = 'abcdef123456'
     expected_response = {'code': 'mock_error'}
     with ResponsesHelper() as helper:
         url = self.cda.endpoint_url(test_collection_uuid)
         helper.add(
             responses.CallbackResponse(responses.GET,
                                        url,
                                        callback=RequestCallback(
                                            401,
                                            json.dumps(expected_response)),
                                        content_type='application/json'))
         with self.assertRaises(UnauthorizedClientAccessError):
             self.cda.send_request(test_collection_uuid,
                                   'get',
                                   url, {},
                                   expected_status_code=200)
示例#20
0
    def test_send_request_successful_with_auto_retry_on_http_502(self):
        test_collection_uuid = 'abcdef123456'
        expected_response = {'code': 'hello_world'}

        mock_response_sequence = [(502, {}, '{"code": "mock_error"}'),
                                  (200, {}, json.dumps(expected_response))]

        def mock_request_handler(_request):
            return mock_response_sequence.pop(0)

        with ResponsesHelper() as helper:
            url = self.cda.endpoint_url(test_collection_uuid)
            helper.add(
                responses.CallbackResponse(responses.GET,
                                           url,
                                           callback=mock_request_handler,
                                           content_type='application/json'))
            response = self.cda.send_request(test_collection_uuid, 'get', url,
                                             {})
        self.assertEqual(response.json(), expected_response)
示例#21
0
 def _get_data_object(self, file_uuid, file_version):
     with ResponsesHelper() as helper:
         helper.add_passthru(self.base_url)
         drs_url = dss_dos_object_url(file_uuid=file_uuid,
                                      catalog=self.catalog,
                                      file_version=file_version,
                                      base_url=self.base_url)
         with mock.patch('time.time', new=lambda: 1547691253.07010):
             dss_url = config.dss_endpoint + '/files/7b07f99e-4a8a-4ad0-bd4f-db0d7a00c7bb'
             helper.add(responses.Response(method=responses.GET,
                                           url=dss_url,
                                           status=301,
                                           headers={'location': dss_url}))
             helper.add(responses.Response(method=responses.GET,
                                           url=dss_url,
                                           status=302,
                                           headers={'location': 'gs://foo/bar'}))
             drs_response = requests.get(drs_url)
         drs_response.raise_for_status()
         drs_response_json = drs_response.json()
         data_object = drs_response_json['data_object']
         return data_object
示例#22
0
 def test_drs(self):
     """
     Mocks the DSS backend, then uses the DRS endpoints as a client is
     expected to.
     """
     file_uuid = '7b07f99e-4a8a-4ad0-bd4f-db0d7a00c7bb'
     file_version = '2018-11-02T113344.698028Z'
     for redirects in (0, 1, 2, 6):
         with self.subTest(redirects=redirects):
             with ResponsesHelper() as helper:
                 helper.add_passthru(self.base_url)
                 self._mock_responses(helper, redirects, file_uuid, file_version=file_version)
                 # Make first client request
                 drs_response = requests.get(
                     dss_drs_object_url(file_uuid,
                                        file_version=file_version,
                                        base_url=self.base_url))
                 drs_response.raise_for_status()
                 drs_object = drs_response.json()
                 expected = {
                     'checksums': [
                         {'sha1': '7ad306f154ce7de1a9a333cfd9100fc26ef652b4'},
                         {'sha-256': '77337cb51b2e584b5ae1b99db6c163b988cbc5b894dda2f5d22424978c3bfc7a'}
                     ],
                     'created_time': '2018-11-02T11:33:44.698028Z',
                     'id': '7b07f99e-4a8a-4ad0-bd4f-db0d7a00c7bb',
                     'self_uri': dss_drs_object_uri(file_uuid='7b07f99e-4a8a-4ad0-bd4f-db0d7a00c7bb',
                                                    file_version='2018-11-02T113344.698028Z'),
                     'size': '195142097',
                     'version': '2018-11-02T113344.698028Z',
                 }
                 if not redirects:
                     # We expect a DRS object with an access URL
                     expected['access_methods'] = [
                         {
                             'access_url': {'url': 'https://org-hca-dss-checkout-prod.s3.amazonaws.com/'
                                                   'blobs/307.a72.eb6?foo=bar&et=cetera'},
                             'type': 'https'
                         },
                         {
                             'access_url': {'url': 'gs://important-bucket/object/path'},
                             'type': 'gs'
                         }
                     ]
                     self.assertEqual(drs_object, expected)
                 else:
                     # The access IDs are so similar because the mock tokens are the same...
                     expected['access_methods'] = [
                         {
                             'access_id': 'KCd7ImV4ZWN1dGlvbl9pZCI6ICI5NWIxZmNkMC01OGMyLTRmMmMtYmI0OC0xM2FkODU2YzI0Z'
                                          'mMiLCAic3RhcnRfdGltZSI6IDE1NzUzMjQzODEuMTk4Mzg2NywgImF0dGVtcHRzIjogMH0nLC'
                                          'AnYXdzJyk',
                             #               ^ ...but they do differ
                             'type': 'https'
                         },
                         {
                             'access_id': 'KCd7ImV4ZWN1dGlvbl9pZCI6ICI5NWIxZmNkMC01OGMyLTRmMmMtYmI0OC0xM2FkODU2YzI0Z'
                                          'mMiLCAic3RhcnRfdGltZSI6IDE1NzUzMjQzODEuMTk4Mzg2NywgImF0dGVtcHRzIjogMH0nLC'
                                          'AnZ2NwJyk',
                             'type': 'gs'
                         }
                     ]
                     # We must make another request with the access ID
                     self.assertEqual(expected, drs_object)
                     for method in drs_object['access_methods']:
                         access_id = method['access_id']
                         for _ in range(redirects - 1):
                             # The first redirect gave us the access ID, the rest are retries on 202
                             drs_access_url = dss_drs_object_url(file_uuid,
                                                                 file_version=file_version,
                                                                 base_url=self.base_url,
                                                                 access_id=access_id)
                             drs_response = requests.get(drs_access_url)
                             self.assertEqual(drs_response.status_code, 202)
                             self.assertEqual(drs_response.text, '')
                         # The final request should give us just the access URL
                         drs_access_url = dss_drs_object_url(file_uuid,
                                                             file_version=file_version,
                                                             base_url=self.base_url,
                                                             access_id=access_id)
                         drs_response = requests.get(drs_access_url)
                         self.assertEqual(drs_response.status_code, 200)
                         if method['type'] == AccessMethod.https.scheme:
                             self.assertEqual(drs_response.json(), {'url': self.signed_url})
                         elif method['type'] == AccessMethod.gs.scheme:
                             self.assertEqual(drs_response.json(), {'url': self.gs_url})
                         else:
                             assert False, f'Access type {method["type"]} is not supported'
示例#23
0
    def test_dss_files_proxy(self, dss_direct_access_role):
        dss_direct_access_role.return_value = None
        self.maxDiff = None
        key = ("blobs/6929799f227ae5f0b3e0167a6cf2bd683db097848af6ccde6329185212598779"
               ".f2237ad0a776fd7057eb3d3498114c85e2f521d7"
               ".7e892bf8f6aa489ccb08a995c7f017e1."
               "847325b6")
        bucket_name = 'org-humancellatlas-dss-checkout-staging'
        s3 = boto3.client('s3')
        s3.create_bucket(Bucket=bucket_name)
        s3.upload_fileobj(Bucket=bucket_name, Fileobj=io.BytesIO(b'foo'), Key=key)
        file_uuid = '701c9a63-23da-4978-946b-7576b6ad088a'
        file_version = '2018-09-12T121154.054628Z'
        organic_file_name = 'foo.txt'
        file_doc = {
            'name': organic_file_name,
            'version': file_version,
            'drs_path': None,
        }
        with mock.patch.object(IndexQueryService, 'get_data_file', return_value=file_doc):
            dss_url = furl(
                url=config.dss_endpoint,
                path='/v1/files',
                args={
                    'replica': 'aws',
                    'version': file_version
                }).add(path=file_uuid)
            dss_token = 'some_token'
            dss_url_with_token = dss_url.copy().add(args={'token': dss_token})
            for fetch in True, False:
                for wait in None, 0, 1:
                    for file_name, signature in [(None, 'Wg8AqCTzZAuHpCN8AKPKWcsFHAM='),
                                                 (organic_file_name, 'Wg8AqCTzZAuHpCN8AKPKWcsFHAM=',),
                                                 ('foo bar.txt', 'grbM6udwp0n/QE/L/RYfjtQCS/U='),
                                                 ('foo&bar.txt', 'r4C8YxpJ4nXTZh+agBsfhZ2e7fI=')]:
                        with self.subTest(fetch=fetch, file_name=file_name, wait=wait):
                            with ResponsesHelper() as helper:
                                helper.add_passthru(self.base_url)
                                fixed_time = 1547691253.07010
                                expires = str(round(fixed_time + 3600))
                                s3_url = furl(
                                    url=f'https://{bucket_name}.s3.amazonaws.com',
                                    path=key,
                                    args={
                                        'AWSAccessKeyId': 'SOMEACCESSKEY',
                                        'Signature': 'SOMESIGNATURE=',
                                        'x-amz-security-token': 'SOMETOKEN',
                                        'Expires': expires
                                    })
                                helper.add(responses.Response(method='GET',
                                                              url=dss_url.url,
                                                              status=301,
                                                              headers={'Location': dss_url_with_token.url,
                                                                       'Retry-After': '10'}))
                                azul_url = furl(
                                    url=self.base_url,
                                    path='/fetch/dss/files' if fetch else '/dss/files',
                                    args={
                                        'catalog': 'test',
                                        'version': file_version
                                    }).add(path=file_uuid)
                                if wait is not None:
                                    azul_url.args['wait'] = str(wait)
                                if file_name is not None:
                                    azul_url.args['fileName'] = file_name

                                def request_azul(url, expect_status):
                                    retry_after = 1
                                    expect_retry_after = None if wait or expect_status == 302 else retry_after
                                    before = time.monotonic()
                                    with mock.patch.object(type(aws), 'dss_checkout_bucket', return_value=bucket_name):
                                        with mock.patch('time.time', new=lambda: 1547691253.07010):
                                            response = requests.get(url, allow_redirects=False)
                                    if wait and expect_status == 301:
                                        self.assertLessEqual(retry_after, time.monotonic() - before)
                                    if fetch:
                                        self.assertEqual(200, response.status_code)
                                        response = response.json()
                                        self.assertEqual(expect_status, response["Status"])
                                    else:
                                        if response.status_code != expect_status:
                                            response.raise_for_status()
                                        response = dict(response.headers)
                                    if expect_retry_after is None:
                                        self.assertNotIn('Retry-After', response)
                                    else:
                                        actual_retry_after = response['Retry-After']
                                        if fetch:
                                            self.assertEqual(expect_retry_after, actual_retry_after)
                                        else:
                                            self.assertEqual(str(expect_retry_after), actual_retry_after)
                                    return response['Location']

                                location = request_azul(url=azul_url.url, expect_status=301)

                                if file_name is None:
                                    file_name = organic_file_name

                                azul_url.args['token'] = dss_token
                                azul_url.args['requestIndex'] = '1'
                                azul_url.args['fileName'] = file_name
                                azul_url.args['replica'] = 'aws'
                                self.assertUrlEqual(azul_url, location)

                                helper.add(responses.Response(method='GET',
                                                              url=dss_url_with_token.url,
                                                              status=302,
                                                              headers={'Location': s3_url.url}))

                                location = request_azul(url=location, expect_status=302)

                                re_pre_signed_s3_url = furl(
                                    url=f'https://{bucket_name}.s3.amazonaws.com',
                                    path=key,
                                    args={
                                        'response-content-disposition': f'attachment;filename={file_name}',
                                        'AWSAccessKeyId': mock_access_key_id,
                                        'Signature': signature,
                                        'Expires': expires,
                                        'x-amz-security-token': mock_session_token
                                    })
                                self.assertUrlEqual(re_pre_signed_s3_url, location)