def test_get_store_view_fail_categories(self): payload_categories = {} payload_featured_snaps = {} responses.add( responses.Response( method="GET", url=self.categories_api_url, json=payload_categories, status=500, ) ) responses.add( responses.Response( method="GET", url=self.featured_snaps_api_url, json=payload_featured_snaps, status=200, ) ) response = self.client.get(self.endpoint_url) assert len(responses.calls) == 2 assert response.status_code == 502 self.assert_template_used("store/store.html")
def start_mocked_http_server(self, test_api_responses): # redfish root api responses.add(responses.Response( method=GET, url=self.address + '/redfish/v1', json=self.load_json_file('redfish.json') )) # fetch session credential api responses.add(self.get_mocked_new_session_response( self.session_location)) # get manager api responses.add(responses.Response( method=GET, url=self.address + '/redfish/v1/Managers', json=self.load_json_file('manager-collection.json') )) for res in test_api_responses: responses.add(res) # delete session credential api responses.add(responses.Response( method=DELETE, url=self.address + self.session_location ))
def test_search_q_with_results_but_no_total(self): responses.add( responses.Response( method="GET", url=self.categories_api_url, json={}, status=200 ) ) payload = { "_embedded": { "clickindex:package": [ {"package_name": "toto"}, {"package_name": "tata"}, {"package_name": "tutu"}, ] }, "_links": { "last": {"href": "http://url.c?q=snap&size=1&page=1"}, "next": {"href": "http://url.c?q=snap&size=1&page=1"}, "self": {"href": "http://url.c?q=snap&size=1&page=1"}, }, } search_api_formated = self.search_snap_api_url.format( snap_name="snap", page="1", size="25" ) responses.add( responses.Response( method="GET", url=search_api_formated, json=payload, status=200 ) ) endpoint = self.endpoint_url.format(q="snap", category="") response = self.client.get(endpoint) self.assertEqual(response.status_code, 200) self.assert_context("query", "snap") self.assert_context("category", "") self.assert_context("category_display", None) self.assert_context("categories", []) self.assert_context( "snaps", [ {"package_name": "toto"}, {"package_name": "tata"}, {"package_name": "tutu"}, ], ) self.assert_context("total", None) self.assert_context( "links", { "last": "http://localhost/search?q=snap&limit=1&offset=0", "next": "http://localhost/search?q=snap&limit=1&offset=0", "self": "http://localhost/search?q=snap&limit=1&offset=0", }, ) self.assert_context("error_info", {})
def test_user_not_connected(self): payload = { "snap-id": "id", "name": "snapName", "default-track": None, "snap": { "title": "Snap Title", "summary": "This is a summary", "description": "this is a description", "media": [], "license": "license", "prices": 0, "publisher": { "display-name": "Toto", "username": "******", "validation": True, }, "categories": [{ "name": "test" }], "trending": False, "unlisted": False, }, "channel-map": [{ "channel": { "architecture": "amd64", "name": "stable", "risk": "stable", "track": "latest", }, "created-at": "2018-09-18T14:45:28.064633+00:00", "version": "1.0", "confinement": "conf", "download": { "size": 100000 }, }], } responses.add( responses.Response(method="GET", url=self.api_url, json=payload, status=200)) metrics_url = "https://api.snapcraft.io/api/v1/snaps/metrics" responses.add( responses.Response(method="POST", url=metrics_url, json={}, status=200)) response = self.client.get(self.endpoint_url) assert response.status_code == 200 self.assert_context("is_users_snap", False)
def test_get_remote_zd_user_for_local_user_with_allauth_email(): user = mommy.make("auth.User", id=1) # no search results when searching by external ID responses.add( responses.Response( method="GET", url=api_url_base + "search.json?query=external_id:1%20type:user", match_querystring=True, json=api_responses.search_no_results, status=200, )) # same as above, but sometimes the params are reversed responses.add( responses.Response( method="GET", url=api_url_base + "search.json?query=type:user%20external_id:1", match_querystring=True, json=api_responses.search_no_results, status=200, )) email = mommy.make("account.EmailAddress", user=user, verified=False, email="*****@*****.**") responses.add( responses.Response( method="GET", url=api_url_base + "search.json?query=email:[email protected]%20type:user", match_querystring=True, json=api_responses.search_one_result, status=200, )) # same as above but sometimes query params are reversed in order responses.add( responses.Response( method="GET", url=api_url_base + "search.json?query=type:user%20email:[email protected]", match_querystring=True, json=api_responses.search_one_result, status=200, )) remote, is_definite = service.ZengoService( ).get_remote_zd_user_for_local_user(user) assert not is_definite assert remote.email == email.email # adjust the local email to be verified email.verified = True email.save(update_fields=("verified", )) remote, is_definite = service.ZengoService( ).get_remote_zd_user_for_local_user(user) assert is_definite assert remote.email == email.email
def test_update_remote_zd_user_for_local_user(): user = mommy.make("auth.User", email="*****@*****.**") # any search returns our one user responses.add( responses.Response( method="GET", url=api_url_base + "search.json" "", match_querystring=False, json=api_responses.search_one_result, status=200, )) remote, is_definite = service.ZengoService( ).get_or_create_remote_zd_user_for_local_user(user) assert remote is not None assert remote.email == "*****@*****.**" # make a change of the user's email, triggering an identity update user.email = "*****@*****.**" # our individual user updated responses.add( responses.Response( method="PUT", url=api_url_base + "users/1.json", match_querystring=False, json=api_responses.update_user_ok, status=200, )) # add support for looking up a user's identities responses.add( responses.Response( method="GET", url="https:////example.zendesk.com/api/v2/users/1/identities.json", match_querystring=False, json=api_responses.user_identities, status=200, )) # and when the second identity is found, it will be made primary responses.add( responses.Response( method="PUT", url=api_url_base + "users/1/identities/2/make_primary", match_querystring=False, json=api_responses.identity_make_primary, status=200, )) service.ZengoService().update_remote_zd_user_for_local_user(user, remote) assert len(responses.calls) == 4
def test_recursive_upload_retry(self, node, greg, egap_assets_path, egap_project_name): responses.add( responses.Response( responses.PUT, '{}/v1/resources/{}/providers/osfstorage/?name=test_folder&kind=folder'.format( WATERBUTLER_INTERNAL_URL, node._id, ), json={'data': {'attributes': {'path': 'parent'}}}, status=201, ) ) responses.add( responses.Response( responses.PUT, '{}/v1/resources/{}/providers/osfstorage/parent?name=test-2.txt&kind=file'.format( WATERBUTLER_INTERNAL_URL, node._id, ), status=500, ) ) responses.add( responses.Response( responses.PUT, '{}/v1/resources/{}/providers/osfstorage/parent?name=test-2.txt&kind=file'.format( WATERBUTLER_INTERNAL_URL, node._id, ), json={'metadata': 'for test-2!'}, status=201, ) ) responses.add( responses.Response( responses.PUT, '{}/v1/resources/{}/providers/osfstorage/?name=test-1.txt&kind=file'.format( WATERBUTLER_INTERNAL_URL, node._id, ), json={'metadata': 'for test-1!'}, status=201, ) ) token = ApiOAuth2PersonalTokenFactory(owner=greg) token.save() auth = {'Authorization': 'Bearer {}'.format(token.token_id)} egap_project_path = os.path.join(egap_assets_path, egap_project_name, 'data', 'nonanonymous') metadata = recursive_upload(auth, node, egap_project_path) assert metadata[0] == {'metadata': 'for test-2!'} assert metadata[1] == {'data': {'attributes': {'path': 'parent'}}} assert metadata[2] == {'metadata': 'for test-1!'}
def test_sync_using_sources_list__one(self): statement_data = self.get_statement_valid_data() statement_attrs = statement_data['attributes'] responses.add( responses.Response(method='GET', url="{}{}".format(settings.DEMAGOG_API_URL, self.get_sources_list_path), match_querystring=False, content_type='application/json', body=json.dumps({ 'data': { 'attributes': { 'sources': [self.SOURCE_URL] } } }))) responses.add( responses.Response(method='GET', url="{}{}?{}".format( settings.DEMAGOG_API_URL, self.get_statements_path, urlencode({'uri': self.SOURCE_URL})), content_type='application/json', match_querystring=False, body=json.dumps({'data': [statement_data]}, cls=DjangoJSONEncoder))) annotation_count = Annotation.objects.count() sync_using_sources_list() self.assertEqual(Annotation.objects.count(), annotation_count + 1) # Do no re-add sync_using_sources_list() self.assertEqual(Annotation.objects.count(), annotation_count + 1) annotation = Annotation.objects.last() self.assertEqual(annotation.publisher_annotation_id, statement_data['id']) self.assertEqual(annotation.url, statement_attrs['sources'][0]) self.assertEqual( annotation.pp_category, demagog_to_pp_category[statement_attrs['rating'].upper()]) self.assertEqual(annotation.demagog_category, statement_attrs['rating'].upper()) self.assertEqual(annotation.quote, statement_attrs['text']) self.assertEqual(annotation.annotation_link, statement_attrs['factchecker_uri']) # JSON converting is a bit inaccurate, so compare two json dates, to same inaccurate self.assertEqual( json.dumps(annotation.create_date, cls=DjangoJSONEncoder), json.dumps(statement_attrs['timestamp_factcheck'], cls=DjangoJSONEncoder))
def test_wiki_dump_retry(self): responses.add( responses.Response( responses.GET, 'http://localhost:8000/v2/registrations/fxehm/wikis/', status=429, headers={'Retry-After': '1'}, ) ) responses.add( responses.Response( responses.GET, 'http://localhost:8000/v2/registrations/fxehm/wikis/', json=wiki_metadata(), ) ) responses.add( responses.Response( responses.GET, 'https://localhost:8000/v2/wikis/dtns3/content/', body=b'dtns3 data', ), ) responses.add( responses.Response( responses.GET, 'https://localhost:8000/v2/wikis/md549/content/', body=b'md549 data', ), ) responses.add( responses.Response( responses.GET, 'https://localhost:8000/v2/wikis/p8kxa/content/', body=b'p8kxa data', ), ) with mock.patch('builtins.open', mock.mock_open()) as m: asyncio.run(main('fxehm')) assert m.call_args_list == [ call('/home.md', 'wb'), call('/test1Ω≈ç√∫˜µ≤≥≥÷åß∂ƒ©˙∆∆˚¬…æ.md', 'wb'), call('/test2.md', 'wb') ] handle = m() assert handle.write.call_args_list == [ call(b'dtns3 data'), call(b'md549 data'), call(b'p8kxa data') ]
def test_invalid_user_token(client, user_access_headers, public_keys, app_settings): responses.add( responses.Response(method=responses.GET, url=app_settings['auth_keys_url'], json=public_keys, status=200)) responses.add( responses.Response(method=responses.POST, url=app_settings['user_scopes_api'], json=dict(active=True, response=dict()), status=403)) resp = client.get('/v1/hello', headers=user_access_headers) assert resp.status_code == 403
def register_response(url, status_code, json_data=None): """Register fake response.""" response_kwargs = { 'method': 'GET', 'url': url, 'status': status_code, 'content_type': 'application/json' } if status_code == 200: response = responses.Response(json=json_data, **response_kwargs) else: response = responses.Response(**response_kwargs) responses.add(response)
def test_auth_cache_expiration(app_settings): from framework.auth.oauth import get_service_access_token responses.add( responses.Response(method=responses.POST, url=app_settings['auth_url'], json=dict(access_token='1', expires_in=0), status=200)) responses.add( responses.Response(method=responses.POST, url=app_settings['auth_url'], json=dict(access_token='2', expires_in=300), status=200)) token_a = get_service_access_token(service_name='test_2') token_b = get_service_access_token(service_name='test_2') assert token_a != token_b
def test_request_retries_server_error_automatically(request_methods): from framework.core.requests import safe_json_request responses.add( responses.Response(method=request_methods['response'], url=url, body=error_body, status=500)) responses.add( responses.Response(method=request_methods['response'], url=url, json=test_json, status=200)) status_code, js = safe_json_request(method=request_methods['response'], url=url) assert status_code == 200
def test_fulfillment_unknown_client_error_retry_success(self): """Verify that the task is capable of successfully retrying after client error.""" responses.add( responses.Response(responses.PUT, self.API_URL, status=404, body="{}"), ) responses.add( responses.Response(responses.PUT, self.API_URL, status=200, body="{}"), ) result = fulfill_order.delay(self.ORDER_NUMBER).get() self.assertIsNone(result)
def test_sync_using_sources_list__two(self): statement_data = self.get_statement_valid_data() statement_attrs = statement_data['attributes'] statement_data2 = self.get_statement_valid_data() statement_attrs2 = statement_data2['attributes'] statement_data2['id'] = statement_data['id'] + '_anything_different' statement_attrs2['source'] = self.SOURCE_URL2 responses.add( responses.Response(method='GET', url="{}{}".format(settings.DEMAGOG_API_URL, self.get_sources_list_path), match_querystring=False, content_type='application/json', body=json.dumps({ 'data': { 'attributes': { 'sources': [self.SOURCE_URL, self.SOURCE_URL2] } } }))) responses.add( responses.Response(method='GET', url="{}{}?{}".format( settings.DEMAGOG_API_URL, self.get_statements_path, urlencode({'uri': self.SOURCE_URL})), content_type='application/json', match_querystring=False, body=json.dumps({'data': [statement_data]}, cls=DjangoJSONEncoder))) responses.add( responses.Response(method='GET', url="{}{}?{}".format( settings.DEMAGOG_API_URL, self.get_statements_path, urlencode({'uri': self.SOURCE_URL2})), content_type='application/json', match_querystring=False, body=json.dumps({'data': [statement_data2]}, cls=DjangoJSONEncoder))) annotation_count = Annotation.objects.count() sync_using_sources_list() self.assertEqual(Annotation.objects.count(), annotation_count + 2)
def test_update_or_create_remote_zd_user_update(): # all searches return no results responses.add( responses.Response( method="GET", url=api_url_base + "search.json" "", match_querystring=False, json=api_responses.search_one_result, status=200, )) user = mommy.make("auth.User") user.email = "*****@*****.**" user.save(update_fields=("email", )) # our individual user updated responses.add( responses.Response( method="PUT", url=api_url_base + "users/1.json", match_querystring=False, json=api_responses.update_user_ok, status=200, )) # add support for looking up a user's identities responses.add( responses.Response( method="GET", url="https:////example.zendesk.com/api/v2/users/1/identities.json", match_querystring=False, json=api_responses.user_identities, status=200, )) # and when the second identity is found, it will be made primary responses.add( responses.Response( method="PUT", url=api_url_base + "users/1/identities/2/make_primary", match_querystring=False, json=api_responses.identity_make_primary, status=200, )) remote = service.ZengoService().update_or_create_remote_zd_user(user) assert remote is not None assert len(responses.calls) == 4
def test_account_no_username_logged_in(self): payload = { "error_list": [{ "code": "user-not-ready", "message": "missing store username", }] } responses.add( responses.Response( method=self.method_api, url=self.api_url, json=payload, status=403, )) if self.method_endpoint == "GET": response = self.client.get(self.endpoint_url) else: if self.data: response = self.client.post(self.endpoint_url, data=self.data) else: response = self.client.post(self.endpoint_url, json=self.json) self.check_call_by_api_url(responses.calls) self.assertEqual(302, response.status_code) self.assertEqual("http://localhost/account/username", response.location)
def test_custom_error(self): payload = { "error_list": [ { "code": "error-code1" }, { "code": "error-code2" }, ] } responses.add( responses.Response( method=self.method_api, url=self.api_url, json=payload, status=400, )) if self.method_endpoint == "GET": response = self.client.get(self.endpoint_url) else: if self.data: response = self.client.post(self.endpoint_url, data=self.data) else: response = self.client.post(self.endpoint_url, json=self.json) self.check_call_by_api_url(responses.calls) assert response.status_code == 502
def test_expired_macaroon(self): responses.add( responses.Response( method=self.method_api, url=self.api_url, json={}, status=500, headers={"WWW-Authenticate": "Macaroon needs_refresh=1"}, )) responses.add( responses.POST, "https://login.ubuntu.com/api/v2/tokens/refresh", json={"discharge_macaroon": "macaroon"}, status=200, ) if self.method_endpoint == "GET": response = self.client.get(self.endpoint_url) else: if self.data: response = self.client.post(self.endpoint_url, data=self.data) else: response = self.client.post(self.endpoint_url, json=self.json) called = responses.calls[len(responses.calls) - 1] self.assertEqual( "https://login.ubuntu.com/api/v2/tokens/refresh", called.request.url, ) assert response.status_code == 302 assert response.location == self._get_location()
def test_account_no_username_logged_in(self): payload = { 'error_list': [ { 'code': 'user-not-ready', 'message': 'missing namespace' } ] } responses.add( responses.Response( method=self.method_api, url=self.api_url, json=payload, status=403 ) ) if self.method_endpoint == 'GET': response = self.client.get(self.endpoint_url) else: response = self.client.post(self.endpoint_url, data=self.data) called = responses.calls[len(responses.calls)-1] self.assertEqual( self.api_url, called.request.url) self.assertEqual( self.authorization, called.request.headers.get('Authorization')) self.assertEqual(302, response.status_code) self.assertEqual( 'http://localhost/account/username', response.location)
def test_custom_error(self): payload = { 'error_list': [ { 'code': 'error-code1' }, { 'code': 'error-code2' } ] } responses.add( responses.Response( method=self.method_api, url=self.api_url, json=payload, status=400, ) ) if self.method_endpoint == 'GET': response = self.client.get(self.endpoint_url) else: response = self.client.post(self.endpoint_url, data=self.data) called = responses.calls[len(responses.calls)-1] self.assertEqual( self.api_url, called.request.url) self.assertEqual( self.authorization, called.request.headers.get('Authorization')) assert response.status_code == 502
def test_expired_macaroon(self): responses.add( responses.Response( method=self.method_api, url=self.api_url, json={}, status=500, headers={'WWW-Authenticate': 'Macaroon needs_refresh=1'} ) ) responses.add( responses.POST, 'https://login.ubuntu.com/api/v2/tokens/refresh', json={'discharge_macaroon': 'macaroon'}, status=200) if self.method_endpoint == 'GET': response = self.client.get(self.endpoint_url) else: response = self.client.post(self.endpoint_url, data=self.data) called = responses.calls[len(responses.calls)-1] self.assertEqual( 'https://login.ubuntu.com/api/v2/tokens/refresh', called.request.url) assert response.status_code == 302 assert response.location == self._get_location()
def test_broken_json(self): # To test this I return no json from the server, this makes the # call to the function response.json() raise a ValueError exception responses.add( responses.Response( method=self.method_api, url=self.api_url, status=500 ) ) if self.method_endpoint == 'GET': response = self.client.get(self.endpoint_url) else: response = self.client.post(self.endpoint_url, data=self.data) called = responses.calls[len(responses.calls)-1] self.assertEqual( self.api_url, called.request.url) self.assertEqual( self.authorization, called.request.headers.get('Authorization')) assert response.status_code == 502
def test_metadata_for_deleted_node(self, crossref_client, preprint): responses.add( responses.Response(responses.POST, crossref_client.base_url, body=crossref_success_response, content_type='text/html;charset=ISO-8859-1', status=200)) with mock.patch( 'osf.models.Preprint.get_doi_client') as mock_get_doi_client: mock_get_doi_client.return_value = crossref_client preprint.is_public = False preprint.save() crossref_xml = crossref_client.build_metadata(preprint, status='unavailable') root = lxml.etree.fromstring(crossref_xml) # body assert not root.find( './/{%s}contributors' % crossref.CROSSREF_NAMESPACE) assert root.find( './/{%s}group_title' % crossref.CROSSREF_NAMESPACE).text == preprint.provider.name assert not root.find('.//{%s}title' % crossref.CROSSREF_NAMESPACE).text assert not root.find('.//{%s}abstract/' % crossref.JATS_NAMESPACE) assert not root.find( './/{%s}license_ref' % crossref.CROSSREF_ACCESS_INDICATORS) assert root.find( './/{%s}doi' % crossref.CROSSREF_NAMESPACE).text == settings.DOI_FORMAT.format( prefix=preprint.provider.doi_prefix, guid=preprint._id) assert not root.find('.//{%s}resource' % crossref.CROSSREF_NAMESPACE)
def test_long_retry_not_required(api, caplog): '''Some 502 errors do not require a long delay''' responses.add(responses.Response( method='POST', url=api._url, status=502, )) caplog.set_level(logging.DEBUG, logger='cirrus_run') time_start = time() with pytest.raises(CirrusHTTPError): api('fake query text') time_end = time() assert time_end - time_start > api.RETRY_DELAY * 3 assert time_end - time_start < api.RETRY_LONG_DELAY + api.RETRY_DELAY * 2 long_delay_log_message_count = 0 for record in caplog.records: if 'API server asked for longer retry delay' in record.message: long_delay_log_message_count += 1 assert long_delay_log_message_count == 0 assert responses.assert_call_count(api._url, 1 + 3), \ 'Incorrect number of _post calls before raising CirrusHTTPError'
def test_long_retry_delay_required(api, caplog): '''Wait out intermittent API server errors''' responses.add( responses.Response( method='POST', url=api._url, status=502, body= 'The server encountered a temporary error and could not complete your request. Please try again in 30 seconds.', )) caplog.set_level(logging.DEBUG, logger='cirrus_run') time_start = time() with pytest.raises(CirrusHTTPError): api('fake query text') time_end = time() assert time_end - time_start > api.RETRY_LONG_DELAY + api.RETRY_DELAY * 2 assert time_end - time_start < api.RETRY_LONG_DELAY * 3 long_delay_log_message_count = 0 for record in caplog.records: if 'API server asked for longer retry delay' in record.message: long_delay_log_message_count += 1 assert long_delay_log_message_count == 1 assert responses.assert_call_count(api._url, 1 + 3), \ 'Incorrect number of _post calls before raising CirrusHTTPError'
def test_long_retry_internal_server_error_unrecoverable(api, caplog): '''Retry GraphQL internal server error - unrecoverable''' caplog.set_level(logging.DEBUG, logger='cirrus_run') for params in [ { 'status': 200, 'json': { 'errors': [{ 'locations': [], 'message': 'Internal Server Error(s) while executing query' }] } }, ]: responses.add(responses.Response(method='POST', url=api._url, **params)) time_start = time() with pytest.raises(CirrusAPIError): reply = api('fake query text', delay=0) time_end = time() assert responses.assert_call_count(api._url, 1 + 3) assert time_end - time_start > api.RETRY_DELAY * 3 assert time_end - time_start < api.RETRY_LONG_DELAY * 2 + api.RETRY_DELAY long_delay_log_message_count = 0 for record in caplog.records: if 'API server asked for longer retry delay' in record.message: long_delay_log_message_count += 1 assert long_delay_log_message_count == 1
def test_download_file_with_token(self, mock_get_client): cas_base_url = 'http://accounts.test.test' client = cas.CasClient(cas_base_url) mock_get_client.return_value = client base_url = '/download/{}/' file = create_test_file(node=self.node, user=self.user) responses.add( responses.Response( responses.GET, '{}/oauth2/profile'.format(cas_base_url), body=json.dumps({'id': '{}'.format(self.user._id)}), status=200, )) download_url = base_url.format(file.get_guid()._id) token = ApiOAuth2PersonalTokenFactory(owner=self.user) headers = {'Authorization': str('Bearer {}'.format(token.token_id))} redirect = self.app.get(download_url, headers=headers) assert mock_get_client.called assert settings.WATERBUTLER_URL in redirect.location assert redirect.status_code == 302
def test_no_channel_map(self): payload = { "snap-id": "id", "name": "snapName", "default-track": None, "snap": { "title": "Snap Title", "summary": "This is a summary", "description": "this is a description", "media": [], "license": "license", "prices": 0, "publisher": { "display-name": "Toto", "username": "******", "validation": True, }, "categories": [{ "name": "test" }], "trending": False, }, } responses.add( responses.Response(method="GET", url=self.api_url, json=payload, status=200)) response = self.client.get(self.endpoint_url) assert response.status_code == 404
def test_does_not_need_refresh(self): self.provider.refresh_time = 1 external_account = ExternalAccountFactory( provider='mock2', provider_id='mock_provider_id', provider_name='Mock Provider', oauth_key='old_key', oauth_secret='old_secret', refresh_token='old_refresh', expires_at=datetime.utcfromtimestamp(time.time() + 200).replace(tzinfo=pytz.utc), ) # mock a successful call to the provider to refresh tokens responses.add( responses.Response(responses.POST, self.provider.auto_refresh_url, body=json.dumps( {'err_msg': 'Should not be hit'}), status=500)) # .reload() has the side effect of rounding the microsends down to 3 significant figures # (e.g. DT(YMDHMS, 365420) becomes DT(YMDHMS, 365000)), # but must occur after possible refresh to reload tokens. # Doing so before allows the `old_expiry == EA.expires_at` comparison to work. external_account.reload() old_expiry = external_account.expires_at self.provider.account = external_account self.provider.refresh_oauth_key(force=False) external_account.reload() assert_equal(external_account.oauth_key, 'old_key') assert_equal(external_account.refresh_token, 'old_refresh') assert_equal(external_account.expires_at, old_expiry)