From f135ffdc2123149724ef67a934cf412c79eed2fd Mon Sep 17 00:00:00 2001 From: Shantanu Dhiman Date: Fri, 28 Aug 2020 18:14:53 +0530 Subject: [PATCH 01/10] Changes: 1) Changed test_gcp.py file to include unit tests instead of automation tests. 2) Modified tox.ini as per above changes. --- tests/integrations/gcp/test_gcp.py | 318 ++++++----------------------- tox.ini | 9 +- 2 files changed, 59 insertions(+), 268 deletions(-) diff --git a/tests/integrations/gcp/test_gcp.py b/tests/integrations/gcp/test_gcp.py index a185a721f0..3347d25f01 100644 --- a/tests/integrations/gcp/test_gcp.py +++ b/tests/integrations/gcp/test_gcp.py @@ -1,36 +1,37 @@ """ -# GCP Cloud Functions system tests +# GCP Cloud Functions unit tests """ import json -import time from textwrap import dedent -import uuid import tempfile -import shutil import sys import subprocess -import pickle import pytest import os.path import os -requests = pytest.importorskip("requests") -google_cloud_sdk = pytest.importorskip("google-cloud-sdk") -build = pytest.importorskip("googleapiclient.discovery.build") -InstalledAppFlow = pytest.importorskip("google_auth_oauthlib.flow.InstalledAppFlow") -Request = pytest.importorskip("google.auth.transport.requests.Request") - -SCOPES = [ - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/cloud-platform.read-only", - "https://www.googleapis.com/auth/cloudfunctions", - "https://www.googleapis.com/auth/logging.read", - "https://www.googleapis.com/auth/logging.admin", -] FUNCTIONS_PRELUDE = """ +from unittest.mock import Mock +import __main__ as gcp_functions +import os + +# Initializing all the necessary environment variables +os.environ["FUNCTION_TIMEOUT_SEC"] = "3" +os.environ["FUNCTION_NAME"] = "Google Cloud function" +os.environ["ENTRY_POINT"] = "cloud_function" +os.environ["FUNCTION_IDENTITY"] = "func_ID" +os.environ["FUNCTION_REGION"] = "us-central1" +os.environ["GCP_PROJECT"] = "serverless_project" + +gcp_functions.worker_v1 = Mock() +gcp_functions.worker_v1.FunctionHandler = Mock() +gcp_functions.worker_v1.FunctionHandler.invoke_user_function = cloud_function +function = gcp_functions.worker_v1.FunctionHandler.invoke_user_function + + import sentry_sdk from sentry_sdk.integrations.gcp import GcpIntegration import json @@ -50,7 +51,7 @@ def _send_event(self, event): # therefore cannot be interleaved with other threads. This is why we # explicitly add a newline at the end even though `print` would provide # us one. - print("\\nEVENTS: {}\\n".format(json.dumps(event))) + print("EVENTS: {}".format(json.dumps(event))) def init_sdk(timeout_warning=False, **extra_init_args): sentry_sdk.init( @@ -60,63 +61,15 @@ def init_sdk(timeout_warning=False, **extra_init_args): shutdown_timeout=10, **extra_init_args ) + """ @pytest.fixture -def authorized_credentials(): - credentials = None - - # Skipping tests if environment variables not set. - if "SENTRY_PYTHON_TEST_GCP_CREDENTIALS_JSON" not in os.environ: - pytest.skip("GCP environ vars not set") - - # The file token.pickle stores the user's access and refresh tokens, and is - # created automatically when the authorization flow completes for the first - # time. - with open( - os.environ.get("SENTRY_PYTHON_TEST_GCP_CREDENTIALS_JSON"), "rb" - ) as creds_file: - for line in creds_file.readlines(): - creds_json = json.loads(line) - project_id = creds_json.get("installed", {}).get("project_id") - if not project_id: - pytest.skip("Credentials json file is not valid") - - if os.path.exists("token.pickle"): - with open("token.pickle", "rb") as token: - credentials = pickle.load(token) - # If there are no (valid) credentials available, let the user log in. - if not credentials or not credentials.valid: - if credentials and credentials.expired and credentials.refresh_token: - credentials.refresh(Request()) - else: - credential_json = os.environ.get("SENTRY_PYTHON_TEST_GCP_CREDENTIALS_JSON") - flow = InstalledAppFlow.from_client_secrets_file(credential_json, SCOPES) - credentials = flow.run_local_server(port=0) - # Save the credentials for the next run - with open("token.pickle", "wb") as token: - pickle.dump(credentials, token) - return credentials, project_id - - -@pytest.fixture(params=["python37"]) -def functions_runtime(request): - return request.param +def run_cloud_function(): + def inner(code, subprocess_kwargs=()): - -@pytest.fixture -def run_cloud_function(request, authorized_credentials, functions_runtime): - def inner(code, timeout="10s", subprocess_kwargs=()): - - events = [] - creds, project_id = authorized_credentials - functions_service = build("cloudfunctions", "v1", credentials=creds) - location_id = "us-central1" - function_name = "test_function_{}".format(uuid.uuid4()) - name = "projects/{}/locations/{}/functions/{}".format( - project_id, location_id, function_name - ) + event = [] # STEP : Create a zip of cloud function @@ -143,177 +96,32 @@ def inner(code, timeout="10s", subprocess_kwargs=()): shell=True, **subprocess_kwargs ) - shutil.make_archive(os.path.join(tmpdir, "ball"), "zip", tmpdir) - - # STEP : Generate a signed url - parent = "projects/{}/locations/{}".format(project_id, location_id) - - api_request = ( - functions_service.projects() - .locations() - .functions() - .generateUploadUrl(parent=parent) - ) - upload_url_response = api_request.execute() - - upload_url = upload_url_response.get("uploadUrl") - - # STEP : Upload zip file of cloud function to generated signed url - with open(os.path.join(tmpdir, "ball.zip"), "rb") as data: - requests.put( - upload_url, - data=data, - headers={ - "x-goog-content-length-range": "0,104857600", - "content-type": "application/zip", - }, - ) - - # STEP : Create a new cloud function - location = "projects/{}/locations/{}".format(project_id, location_id) - - function_url = "https://{}-{}.cloudfunctions.net/{}".format( - location_id, project_id, function_name - ) - - body = { - "name": name, - "description": "Created as part of testsuite for getsentry/sentry-python", - "entryPoint": "cloud_handler", - "runtime": functions_runtime, - "timeout": timeout, - "availableMemoryMb": 128, - "sourceUploadUrl": upload_url, - "httpsTrigger": {"url": function_url}, - } - - api_request = ( - functions_service.projects() - .locations() - .functions() - .create(location=location, body=body) - ) - api_request.execute() - # STEP : Invoke the cloud function - # Adding delay of 60 seconds for new created function to get deployed. - time.sleep(60) - api_request = ( - functions_service.projects().locations().functions().call(name=name) - ) - function_call_response = api_request.execute() - - # STEP : Fetch logs of invoked function - log_name = "projects/{}/logs/cloudfunctions.googleapis.com%2Fcloud-functions".format( - project_id - ) - project_name = "projects/{}".format(project_id) - body = {"resourceNames": [project_name], "filter": log_name} + stream = os.popen("python {}/main.py".format(tmpdir)) + event = stream.read() + event = json.loads(event[len("EVENT: ") :]) - log_service = build("logging", "v2", credentials=creds) - - api_request = log_service.entries().list(body=body) - log_response = api_request.execute() - - for entry in log_response.get("entries", []): - entry_log_name = entry.get("logName") - entry_function_name = ( - entry.get("resource", {}).get("labels", {}).get("function_name") - ) - entry_text_payload = entry.get("textPayload", "") - if ( - entry_log_name == log_name - and entry_function_name == function_name - and "EVENTS: " in entry_text_payload - ): - event = entry_text_payload[len("EVENTS: ") :] - events.append(json.loads(event)) - - log_flag = True - - # Looping so that appropriate event can be fetched from logs - while log_response.get("nextPageToken") and log_flag: - body = { - "resourceNames": [project_name], - "pageToken": log_response["nextPageToken"], - "filter": log_name, - } - - api_request = log_service.entries().list(body=body) - log_response = api_request.execute() - - for entry in log_response.get("entries", []): - entry_log_name = entry.get("logName") - entry_function_name = ( - entry.get("resource", {}).get("labels", {}).get("function_name") - ) - entry_text_payload = entry.get("textPayload", "") - if ( - entry_log_name == log_name - and entry_function_name == function_name - and "EVENTS: " in entry_text_payload - ): - log_flag = False - event = entry_text_payload[len("EVENTS: ") :] - events.append(json.loads(event)) - - # STEP : Delete the cloud function - @request.addfinalizer - def delete_function(): - api_request = ( - functions_service.projects().locations().functions().delete(name=name) - ) - api_request.execute() - - return events, function_call_response + return event return inner def test_handled_exception(run_cloud_function): - events, response = run_cloud_function( - FUNCTIONS_PRELUDE - + dedent( + event = run_cloud_function( + dedent( """ - init_sdk() - - - def cloud_handler(request): + def cloud_function(): raise Exception("something went wrong") """ ) - ) - - assert ( - response["error"] - == "Error: function terminated. Recommended action: inspect logs for termination reason. Details:\nsomething went wrong" - ) - (event,) = events - assert event["level"] == "error" - (exception,) = event["exception"]["values"] - - assert exception["type"] == "Exception" - assert exception["value"] == "something went wrong" - assert exception["mechanism"] == {"type": "gcp", "handled": False} - - -def test_initialization_order(run_cloud_function): - events, response = run_cloud_function( - FUNCTIONS_PRELUDE + + FUNCTIONS_PRELUDE + dedent( """ - def cloud_handler(request): - init_sdk() - raise Exception("something went wrong") + init_sdk(timeout_warning=False) + gcp_functions.worker_v1.FunctionHandler.invoke_user_function() """ ) ) - - assert ( - response["error"] - == "Error: function terminated. Recommended action: inspect logs for termination reason. Details:\nsomething went wrong" - ) - (event,) = events assert event["level"] == "error" (exception,) = event["exception"]["values"] @@ -323,57 +131,47 @@ def cloud_handler(request): def test_unhandled_exception(run_cloud_function): - events, response = run_cloud_function( - FUNCTIONS_PRELUDE - + dedent( + event = run_cloud_function( + dedent( """ - init_sdk() - - - def cloud_handler(request): + def cloud_function(): x = 3/0 - return "str" + return "3" + """ + ) + + FUNCTIONS_PRELUDE + + dedent( + """ + init_sdk(timeout_warning=False) + gcp_functions.worker_v1.FunctionHandler.invoke_user_function() """ ) ) - - assert ( - response["error"] - == "Error: function terminated. Recommended action: inspect logs for termination reason. Details:\ndivision by zero" - ) - (event,) = events assert event["level"] == "error" (exception,) = event["exception"]["values"] - assert exception["type"] == "Exception" - assert exception["value"] == "something went wrong" + assert exception["type"] == "ZeroDivisionError" + assert exception["value"] == "division by zero" assert exception["mechanism"] == {"type": "gcp", "handled": False} def test_timeout_error(run_cloud_function): - events, response = run_cloud_function( - FUNCTIONS_PRELUDE + event = run_cloud_function( + dedent( + """ + def cloud_function(): + time.sleep(10) + return "3" + """ + ) + + FUNCTIONS_PRELUDE + dedent( """ - def event_processor(event): - return event - init_sdk(timeout_warning=True) - - - def cloud_handler(request): - time.sleep(10) - return "str" + gcp_functions.worker_v1.FunctionHandler.invoke_user_function() """ - ), - timeout=3, - ) - - assert ( - response["error"] - == "Error: function execution attempt timed out. Instance restarted." + ) ) - (event,) = events assert event["level"] == "error" (exception,) = event["exception"]["values"] diff --git a/tox.ini b/tox.ini index 96e10cfda1..fb789f02b0 100644 --- a/tox.ini +++ b/tox.ini @@ -45,7 +45,7 @@ envlist = py3.7-aws_lambda # The gcp deploy to the real GCP and have their own matrix of Python versions. - # py3.7-gcp + py3.7-gcp {pypy,py2.7,py3.5,py3.6,py3.7,py3.8}-pyramid-{1.6,1.7,1.8,1.9,1.10} @@ -135,12 +135,6 @@ deps = aws_lambda: boto3 - gcp: google-api-python-client==1.10.0 - gcp: google-auth-httplib2==0.0.4 - gcp: google-auth-oauthlib==0.4.1 - gcp: oauth2client==3.0.0 - gcp: requests==2.24.0 - pyramid-1.6: pyramid>=1.6,<1.7 pyramid-1.7: pyramid>=1.7,<1.8 pyramid-1.8: pyramid>=1.8,<1.9 @@ -231,7 +225,6 @@ passenv = SENTRY_PYTHON_TEST_AWS_IAM_ROLE SENTRY_PYTHON_TEST_POSTGRES_USER SENTRY_PYTHON_TEST_POSTGRES_NAME - SENTRY_PYTHON_TEST_GCP_CREDENTIALS_JSON usedevelop = True extras = flask: flask From 9a3c3b9f86494ff18bb05b5963176c24ed1120f8 Mon Sep 17 00:00:00 2001 From: Shantanu Dhiman Date: Mon, 31 Aug 2020 18:13:21 +0530 Subject: [PATCH 02/10] Changes: 1) Modified local time to utc time in google cloud logs url. 2) Converted log range to include log values from after the completion of execution. --- sentry_sdk/integrations/gcp.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sentry_sdk/integrations/gcp.py b/sentry_sdk/integrations/gcp.py index a2572896a9..bb3b0615e2 100644 --- a/sentry_sdk/integrations/gcp.py +++ b/sentry_sdk/integrations/gcp.py @@ -51,7 +51,7 @@ def sentry_func(*args, **kwargs): configured_time = int(configured_time) - initial_time = datetime.now() + initial_time = datetime.utcnow() with hub.push_scope() as scope: with capture_internal_exceptions(): @@ -119,7 +119,7 @@ def _make_request_event_processor(configured_timeout, initial_time): def event_processor(event, hint): # type: (Event, Hint) -> Optional[Event] - final_time = datetime.now() + final_time = datetime.utcnow() time_diff = final_time - initial_time execution_duration_in_millis = time_diff.microseconds / MILLIS_TO_SECONDS @@ -136,7 +136,7 @@ def event_processor(event, hint): } extra["google cloud logs"] = { - "url": _get_google_cloud_logs_url(initial_time), + "url": _get_google_cloud_logs_url(final_time), } request = event.get("request", {}) @@ -150,7 +150,7 @@ def event_processor(event, hint): return event_processor -def _get_google_cloud_logs_url(initial_time): +def _get_google_cloud_logs_url(final_time): # type: (datetime) -> str """ Generates a Google Cloud Logs console URL based on the environment variables @@ -159,22 +159,22 @@ def _get_google_cloud_logs_url(initial_time): Returns: str -- Google Cloud Logs Console URL to logs. """ - hour_ago = initial_time - timedelta(hours=1) + hour_ago = final_time - timedelta(hours=1) url = ( "https://console.cloud.google.com/logs/viewer?project={project}&resource=cloud_function" "%2Ffunction_name%2F{function_name}%2Fregion%2F{region}&minLogLevel=0&expandAll=false" - "×tamp={initial_time}&customFacets=&limitCustomFacetWidth=true" - "&dateRangeStart={timestamp_start}&dateRangeEnd={timestamp_end}" - "&interval=PT1H&scrollTimestamp={timestamp_current}" + "×tamp={initial_time}Z&customFacets=&limitCustomFacetWidth=true" + "&dateRangeStart={timestamp_start}Z&dateRangeEnd={timestamp_end}Z" + "&interval=PT1H&scrollTimestamp={timestamp_current}Z" ).format( project=environ.get("GCP_PROJECT"), function_name=environ.get("FUNCTION_NAME"), region=environ.get("FUNCTION_REGION"), - initial_time=initial_time, + initial_time=final_time, timestamp_start=hour_ago, - timestamp_end=initial_time, - timestamp_current=initial_time, + timestamp_end=final_time, + timestamp_current=final_time, ) return url From 88745d782cab7e608a81284ae6d09215ae3c0e98 Mon Sep 17 00:00:00 2001 From: Shantanu Dhiman Date: Tue, 1 Sep 2020 11:33:19 +0530 Subject: [PATCH 03/10] Changes: 1) Modified test_gcp.py file to skip tests python versions 2.7 & pypy for GCP integration unit test cases. --- tests/integrations/gcp/test_gcp.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/integrations/gcp/test_gcp.py b/tests/integrations/gcp/test_gcp.py index 3347d25f01..bb4fad6d94 100644 --- a/tests/integrations/gcp/test_gcp.py +++ b/tests/integrations/gcp/test_gcp.py @@ -12,6 +12,8 @@ import os.path import os +pytest.importorskip("tempfile.TemporaryDirectory") + FUNCTIONS_PRELUDE = """ from unittest.mock import Mock From 16cf50af1f93ce631a99437b7690da3aa9ff8ef0 Mon Sep 17 00:00:00 2001 From: Shantanu Dhiman Date: Tue, 1 Sep 2020 14:49:00 +0530 Subject: [PATCH 04/10] Modified tox.ini file to resolve build fail for python3.7 environment --- tox.ini | 3 --- 1 file changed, 3 deletions(-) diff --git a/tox.ini b/tox.ini index fb789f02b0..f313a0e902 100644 --- a/tox.ini +++ b/tox.ini @@ -44,9 +44,6 @@ envlist = # The aws_lambda tests deploy to the real AWS and have their own matrix of Python versions. py3.7-aws_lambda - # The gcp deploy to the real GCP and have their own matrix of Python versions. - py3.7-gcp - {pypy,py2.7,py3.5,py3.6,py3.7,py3.8}-pyramid-{1.6,1.7,1.8,1.9,1.10} {pypy,py2.7,py3.5,py3.6}-rq-{0.6,0.7,0.8,0.9,0.10,0.11} From 3bd76d4dbb4e84b5075e65bb12f9e0dbd6d5b126 Mon Sep 17 00:00:00 2001 From: Shantanu Dhiman Date: Tue, 1 Sep 2020 16:57:38 +0530 Subject: [PATCH 05/10] Changes: 1) Modified log url to include standard format for timestamp to construct log url. 2) Added code in tox.ini file to run test suite for GCP unit test cases. --- sentry_sdk/integrations/gcp.py | 15 ++++++++------- tox.ini | 2 ++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/sentry_sdk/integrations/gcp.py b/sentry_sdk/integrations/gcp.py index bb3b0615e2..a282ba61ef 100644 --- a/sentry_sdk/integrations/gcp.py +++ b/sentry_sdk/integrations/gcp.py @@ -160,21 +160,22 @@ def _get_google_cloud_logs_url(final_time): str -- Google Cloud Logs Console URL to logs. """ hour_ago = final_time - timedelta(hours=1) + formatstring = "%Y-%m-%dT%H:%M:%SZ" url = ( "https://console.cloud.google.com/logs/viewer?project={project}&resource=cloud_function" "%2Ffunction_name%2F{function_name}%2Fregion%2F{region}&minLogLevel=0&expandAll=false" - "×tamp={initial_time}Z&customFacets=&limitCustomFacetWidth=true" - "&dateRangeStart={timestamp_start}Z&dateRangeEnd={timestamp_end}Z" - "&interval=PT1H&scrollTimestamp={timestamp_current}Z" + "×tamp={initial_time}&customFacets=&limitCustomFacetWidth=true" + "&dateRangeStart={timestamp_start}&dateRangeEnd={timestamp_end}" + "&interval=PT1H&scrollTimestamp={timestamp_current}" ).format( project=environ.get("GCP_PROJECT"), function_name=environ.get("FUNCTION_NAME"), region=environ.get("FUNCTION_REGION"), - initial_time=final_time, - timestamp_start=hour_ago, - timestamp_end=final_time, - timestamp_current=final_time, + initial_time=final_time.strftime(formatstring), + timestamp_start=hour_ago.strftime(formatstring), + timestamp_end=final_time.strftime(formatstring), + timestamp_current=final_time.strftime(formatstring), ) return url diff --git a/tox.ini b/tox.ini index f313a0e902..d1fe8b9d6e 100644 --- a/tox.ini +++ b/tox.ini @@ -44,6 +44,8 @@ envlist = # The aws_lambda tests deploy to the real AWS and have their own matrix of Python versions. py3.7-aws_lambda + py3.7-gcp + {pypy,py2.7,py3.5,py3.6,py3.7,py3.8}-pyramid-{1.6,1.7,1.8,1.9,1.10} {pypy,py2.7,py3.5,py3.6}-rq-{0.6,0.7,0.8,0.9,0.10,0.11} From 890996e4b752ec3f4158ff559fd8b71138897c2d Mon Sep 17 00:00:00 2001 From: Shantanu Dhiman Date: Tue, 1 Sep 2020 17:06:38 +0530 Subject: [PATCH 06/10] Fixed variable names for log url to appropriate values. --- sentry_sdk/integrations/gcp.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sentry_sdk/integrations/gcp.py b/sentry_sdk/integrations/gcp.py index a282ba61ef..02e5933029 100644 --- a/sentry_sdk/integrations/gcp.py +++ b/sentry_sdk/integrations/gcp.py @@ -155,7 +155,7 @@ def _get_google_cloud_logs_url(final_time): """ Generates a Google Cloud Logs console URL based on the environment variables Arguments: - initial_time {datetime} -- Initial time + final_time {datetime} -- Final time Returns: str -- Google Cloud Logs Console URL to logs. """ @@ -165,14 +165,14 @@ def _get_google_cloud_logs_url(final_time): url = ( "https://console.cloud.google.com/logs/viewer?project={project}&resource=cloud_function" "%2Ffunction_name%2F{function_name}%2Fregion%2F{region}&minLogLevel=0&expandAll=false" - "×tamp={initial_time}&customFacets=&limitCustomFacetWidth=true" + "×tamp={final_time}&customFacets=&limitCustomFacetWidth=true" "&dateRangeStart={timestamp_start}&dateRangeEnd={timestamp_end}" "&interval=PT1H&scrollTimestamp={timestamp_current}" ).format( project=environ.get("GCP_PROJECT"), function_name=environ.get("FUNCTION_NAME"), region=environ.get("FUNCTION_REGION"), - initial_time=final_time.strftime(formatstring), + final_time=final_time.strftime(formatstring), timestamp_start=hour_ago.strftime(formatstring), timestamp_end=final_time.strftime(formatstring), timestamp_current=final_time.strftime(formatstring), From fd632247d8c7d07ed4a6751ce92eca65ac8784a8 Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Tue, 1 Sep 2020 13:47:11 +0200 Subject: [PATCH 07/10] fix importorskip --- tests/integrations/gcp/test_gcp.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/integrations/gcp/test_gcp.py b/tests/integrations/gcp/test_gcp.py index bb4fad6d94..848e7d8396 100644 --- a/tests/integrations/gcp/test_gcp.py +++ b/tests/integrations/gcp/test_gcp.py @@ -12,7 +12,8 @@ import os.path import os -pytest.importorskip("tempfile.TemporaryDirectory") +if not hasattr(tempfile, "TemporaryDirectory"): + pytest.skip("Not running on Python 3.2+") FUNCTIONS_PRELUDE = """ From adf68ccb0969648a49d466eb13a1b04773b95731 Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Tue, 1 Sep 2020 13:48:22 +0200 Subject: [PATCH 08/10] Revert "fix importorskip" This reverts commit fd632247d8c7d07ed4a6751ce92eca65ac8784a8. --- tests/integrations/gcp/test_gcp.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/integrations/gcp/test_gcp.py b/tests/integrations/gcp/test_gcp.py index 848e7d8396..bb4fad6d94 100644 --- a/tests/integrations/gcp/test_gcp.py +++ b/tests/integrations/gcp/test_gcp.py @@ -12,8 +12,7 @@ import os.path import os -if not hasattr(tempfile, "TemporaryDirectory"): - pytest.skip("Not running on Python 3.2+") +pytest.importorskip("tempfile.TemporaryDirectory") FUNCTIONS_PRELUDE = """ From ee443a9d31d18bcc4722dec74466a0f48a63b75f Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Tue, 1 Sep 2020 13:50:41 +0200 Subject: [PATCH 09/10] attempt skipif fix again --- tests/integrations/gcp/test_gcp.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/integrations/gcp/test_gcp.py b/tests/integrations/gcp/test_gcp.py index bb4fad6d94..6fe5b5967b 100644 --- a/tests/integrations/gcp/test_gcp.py +++ b/tests/integrations/gcp/test_gcp.py @@ -12,7 +12,9 @@ import os.path import os -pytest.importorskip("tempfile.TemporaryDirectory") +pytestmark = pytest.mark.skipif( + not hasattr(tempfile, "TemporaryDirectory"), reason="need Python 3.2+" +) FUNCTIONS_PRELUDE = """ From 0a9f28ee29d3d9774c39f6859a7e59349f8a832e Mon Sep 17 00:00:00 2001 From: Shantanu Dhiman Date: Tue, 1 Sep 2020 17:39:19 +0530 Subject: [PATCH 10/10] Made changes as per review comments related to variable naming and usage for timestamp. --- sentry_sdk/integrations/gcp.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sentry_sdk/integrations/gcp.py b/sentry_sdk/integrations/gcp.py index 02e5933029..8935a5d932 100644 --- a/sentry_sdk/integrations/gcp.py +++ b/sentry_sdk/integrations/gcp.py @@ -165,17 +165,15 @@ def _get_google_cloud_logs_url(final_time): url = ( "https://console.cloud.google.com/logs/viewer?project={project}&resource=cloud_function" "%2Ffunction_name%2F{function_name}%2Fregion%2F{region}&minLogLevel=0&expandAll=false" - "×tamp={final_time}&customFacets=&limitCustomFacetWidth=true" + "×tamp={timestamp_end}&customFacets=&limitCustomFacetWidth=true" "&dateRangeStart={timestamp_start}&dateRangeEnd={timestamp_end}" - "&interval=PT1H&scrollTimestamp={timestamp_current}" + "&interval=PT1H&scrollTimestamp={timestamp_end}" ).format( project=environ.get("GCP_PROJECT"), function_name=environ.get("FUNCTION_NAME"), region=environ.get("FUNCTION_REGION"), - final_time=final_time.strftime(formatstring), - timestamp_start=hour_ago.strftime(formatstring), timestamp_end=final_time.strftime(formatstring), - timestamp_current=final_time.strftime(formatstring), + timestamp_start=hour_ago.strftime(formatstring), ) return url