import pytest from dev.simulationserver import SimulationServer, RequestInterceptor from backup.time import Time from backup.config import Config, Setting from backup.drive import DriveRequests from backup.exceptions import CredRefreshMyError, GoogleCredentialsExpired, CredRefreshGoogleError from backup.tracing_session import TracingSession from yarl import URL @pytest.mark.asyncio async def test_correct_host(time: Time, session: TracingSession, config: Config, server: SimulationServer, drive_requests: DriveRequests, server_url, interceptor: RequestInterceptor): # Verify the correct endpoitns get called for a successful request session.record = True await drive_requests.exchanger.refresh(drive_requests.creds) assert interceptor.urlWasCalled("/drive/refresh") session._records[0]['url'] == server_url.with_path("/drive/refresh") @pytest.mark.asyncio async def test_some_bad_hosts(time: Time, session: TracingSession, config: Config, server: SimulationServer, drive_requests: DriveRequests, server_url, interceptor: RequestInterceptor): session.record = True config.override(Setting.EXCHANGER_TIMEOUT_SECONDS, 1) config.override(Setting.TOKEN_SERVER_HOSTS, "https://this.goes.nowhere.info," + str(server_url)) await drive_requests.exchanger.refresh(drive_requests.creds) assert interceptor.urlWasCalled("/drive/refresh") # Verify both hosts were checked session._records[0]['url'] == URL("https://this.goes.nowhere.info").with_path("/drive/refresh") session._records[1]['url'] == server_url.with_path("/drive/refresh") @pytest.mark.asyncio async def test_all_bad_hosts(time: Time, session: TracingSession, config: Config, server: SimulationServer, drive_requests: DriveRequests, interceptor: RequestInterceptor): session.record = True config.override(Setting.EXCHANGER_TIMEOUT_SECONDS, 1) config.override(Setting.TOKEN_SERVER_HOSTS, "https://this.goes.nowhere.info,http://also.a.bad.host") with pytest.raises(CredRefreshMyError) as e: await drive_requests.exchanger.refresh(drive_requests.creds) # Error should be about the last host name assert e.value.reason.index("also.a.bad.host") >= 0 # Verify both hosts were checked session._records[0]['url'] == URL("https://this.goes.nowhere.info").with_path("/drive/refresh") session._records[1]['url'] == URL("http://also.a.bad.host").with_path("/drive/refresh") @pytest.mark.asyncio async def test_exchange_timeout(time: Time, session: TracingSession, config: Config, server: SimulationServer, drive_requests: DriveRequests, interceptor: RequestInterceptor, server_url: URL): session.record = True interceptor.setSleep("/drive/refresh", sleep=10) config.override(Setting.EXCHANGER_TIMEOUT_SECONDS, 0.1) with pytest.raises(CredRefreshMyError) as e: await drive_requests.exchanger.refresh(drive_requests.creds) # Error should be about the last host name assert e.value.reason == "Timed out communicating with localhost" # Verify both hosts were checked session._records[0]['url'] == server_url.with_path("/drive/refresh") @pytest.mark.asyncio async def test_exchange_invalid_creds(time: Time, session: TracingSession, config: Config, server: SimulationServer, drive_requests: DriveRequests, interceptor: RequestInterceptor, server_url: URL): session.record = True drive_requests.creds._refresh_token = "fail" with pytest.raises(GoogleCredentialsExpired): await drive_requests.exchanger.refresh(drive_requests.creds) # Verify both hosts were checked session._records[0]['url'] == server_url.with_path("/drive/refresh") @pytest.mark.asyncio async def test_fail_503_with_error(time: Time, session: TracingSession, config: Config, server: SimulationServer, drive_requests: DriveRequests, interceptor: RequestInterceptor, server_url: URL): session.record = True interceptor.setError("^/drive/refresh$", 503, response={'error': 'test_value'}) with pytest.raises(CredRefreshGoogleError) as e: await drive_requests.exchanger.refresh(drive_requests.creds) assert e.value.message() == "Couldn't refresh your credentials with Google because: 'test_value'" # Verify both hosts were checked session._records[0]['url'] == server_url.with_path("/drive/refresh") @pytest.mark.asyncio async def test_fail_503_invalid_grant(time: Time, session: TracingSession, config: Config, server: SimulationServer, drive_requests: DriveRequests, interceptor: RequestInterceptor, server_url: URL): session.record = True interceptor.setError("^/drive/refresh$", 503, response={'error': 'invalid_grant'}) with pytest.raises(GoogleCredentialsExpired): await drive_requests.exchanger.refresh(drive_requests.creds) # Verify both hosts were checked session._records[0]['url'] == server_url.with_path("/drive/refresh") @pytest.mark.asyncio async def test_fail_503_with_invalid_json(time: Time, session: TracingSession, config: Config, server: SimulationServer, drive_requests: DriveRequests, interceptor: RequestInterceptor, server_url: URL): session.record = True interceptor.setError("^/drive/refresh$", 503, response={'ignored': 'nothing'}) with pytest.raises(CredRefreshMyError) as e: await drive_requests.exchanger.refresh(drive_requests.creds) assert e.value.message() == "Couldn't refresh Google Drive credentials because: HTTP 503 from localhost" # Verify both hosts were checked session._records[0]['url'] == server_url.with_path("/drive/refresh") @pytest.mark.asyncio async def test_fail_503_with_no_data(time: Time, session: TracingSession, config: Config, server: SimulationServer, drive_requests: DriveRequests, interceptor: RequestInterceptor, server_url: URL): session.record = True interceptor.setError("^/drive/refresh$", 503) with pytest.raises(CredRefreshMyError) as e: await drive_requests.exchanger.refresh(drive_requests.creds) assert e.value.message() == "Couldn't refresh Google Drive credentials because: HTTP 503 from localhost" # Verify both hosts were checked session._records[0]['url'] == server_url.with_path("/drive/refresh") @pytest.mark.asyncio async def test_fail_401(time: Time, session: TracingSession, config: Config, server: SimulationServer, drive_requests: DriveRequests, interceptor: RequestInterceptor, server_url: URL): session.record = True interceptor.setError("^/drive/refresh$", 401) with pytest.raises(GoogleCredentialsExpired): await drive_requests.exchanger.refresh(drive_requests.creds) # Verify both hosts were checked session._records[0]['url'] == server_url.with_path("/drive/refresh") @pytest.mark.asyncio async def test_fail_401_no_fall_through(time: Time, session: TracingSession, config: Config, server: SimulationServer, drive_requests: DriveRequests, interceptor: RequestInterceptor, server_url: URL): session.record = True config.override(Setting.TOKEN_SERVER_HOSTS, str(server_url) + "," + str(server_url)) interceptor.setError("^/drive/refresh$", 401) with pytest.raises(GoogleCredentialsExpired): await drive_requests.exchanger.refresh(drive_requests.creds) # Verify both hosts were checked session._records[0]['url'] == server_url.with_path("/drive/refresh") assert len(session._records) == 1 @pytest.mark.asyncio async def test_invalid_grant_no_fall_through(time: Time, session: TracingSession, config: Config, server: SimulationServer, drive_requests: DriveRequests, interceptor: RequestInterceptor, server_url: URL): session.record = True config.override(Setting.TOKEN_SERVER_HOSTS, str(server_url) + "," + str(server_url)) interceptor.setError("^/drive/refresh$", 503, response={'error': 'invalid_grant'}) with pytest.raises(GoogleCredentialsExpired): await drive_requests.exchanger.refresh(drive_requests.creds) # Verify both hosts were checked session._records[0]['url'] == server_url.with_path("/drive/refresh") assert len(session._records) == 1 @pytest.mark.asyncio async def test_timeout_fall_through(time: Time, session: TracingSession, config: Config, server: SimulationServer, drive_requests: DriveRequests, interceptor: RequestInterceptor, server_url: URL): session.record = True config.override(Setting.EXCHANGER_TIMEOUT_SECONDS, 0.1) config.override(Setting.TOKEN_SERVER_HOSTS, str(server_url) + "," + str(server_url)) interceptor.setSleep("^/drive/refresh$", sleep=10, wait_for=1) await drive_requests.exchanger.refresh(drive_requests.creds) # Verify both hosts were checked session._records[0]['url'] == server_url.with_path("/drive/refresh") session._records[1]['url'] == server_url.with_path("/drive/refresh") @pytest.mark.asyncio async def test_anything_else_through(time: Time, session: TracingSession, config: Config, server: SimulationServer, drive_requests: DriveRequests, interceptor: RequestInterceptor, server_url: URL): session.record = True config.override(Setting.TOKEN_SERVER_HOSTS, str(server_url) + "," + str(server_url)) interceptor.setError("^/drive/refresh$", status=500, fail_for=1) await drive_requests.exchanger.refresh(drive_requests.creds) # Verify both hosts were checked session._records[0]['url'] == server_url.with_path("/drive/refresh") session._records[1]['url'] == server_url.with_path("/drive/refresh")