From 1bd5c963ce0226dee958b83a01c9c5bf8f023c75 Mon Sep 17 00:00:00 2001 From: Jimmy Mkude Date: Wed, 3 Jul 2019 10:43:07 -0700 Subject: [PATCH 01/11] Adds VPC SC integration tests for Video Intelligence API --- ...deo_intelligence_service_grpc_transport.py | 16 +- .../video_intelligence_service_client.py | 31 ++-- videointelligence/tests/system.py | 159 ++++++++++++++++++ 3 files changed, 189 insertions(+), 17 deletions(-) create mode 100644 videointelligence/tests/system.py diff --git a/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py b/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py index 0c3a472179cf..9bf9f3bd5024 100644 --- a/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py +++ b/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py @@ -19,6 +19,7 @@ import google.api_core.operations_v1 from google.cloud.videointelligence_v1.proto import video_intelligence_pb2_grpc +from google.longrunning import operations_pb2 class VideoIntelligenceServiceGrpcTransport(object): @@ -71,7 +72,8 @@ def __init__( self._stubs = { "video_intelligence_service_stub": video_intelligence_pb2_grpc.VideoIntelligenceServiceStub( channel - ) + ), + "operations_stub": operations_pb2.OperationsStub(channel) } # Because this API includes a method that returns a @@ -113,6 +115,18 @@ def channel(self): """ return self._channel + @property + def get_operation(self): + return self._operations_client.get_operation + + @property + def delete_operation(self): + return self._operations_client.delete_operation + + @property + def cancel_operation(self): + return self._operations_client.cancel_operation + @property def annotate_video(self): """Return the gRPC stub for :meth:`VideoIntelligenceServiceClient.annotate_video`. diff --git a/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py b/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py index 890992f9fb65..ff5fdec70e21 100644 --- a/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py +++ b/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py @@ -20,7 +20,6 @@ import warnings from google.oauth2 import service_account -import google.api_core.client_options import google.api_core.gapic_v1.client_info import google.api_core.gapic_v1.config import google.api_core.gapic_v1.method @@ -83,7 +82,6 @@ def __init__( credentials=None, client_config=None, client_info=None, - client_options=None, ): """Constructor. @@ -114,9 +112,6 @@ def __init__( API requests. If ``None``, then default info will be used. Generally, you only need to set this if you're developing your own client library. - client_options (Union[dict, google.api_core.client_options.ClientOptions]): - Client options used to set user options on the client. API Endpoint - should be set through client_options. """ # Raise deprecation warnings for things we want to go away. if client_config is not None: @@ -135,15 +130,6 @@ def __init__( stacklevel=2, ) - api_endpoint = self.SERVICE_ADDRESS - if client_options: - if type(client_options) == dict: - client_options = google.api_core.client_options.from_dict( - client_options - ) - if client_options.api_endpoint: - api_endpoint = client_options.api_endpoint - # Instantiate the transport. # The transport is responsible for handling serialization and # deserialization and actually sending data to the service. @@ -152,7 +138,6 @@ def __init__( self.transport = transport( credentials=credentials, default_class=video_intelligence_service_grpc_transport.VideoIntelligenceServiceGrpcTransport, - address=api_endpoint, ) else: if credentials: @@ -163,7 +148,7 @@ def __init__( self.transport = transport else: self.transport = video_intelligence_service_grpc_transport.VideoIntelligenceServiceGrpcTransport( - address=api_endpoint, channel=channel, credentials=credentials + address=self.SERVICE_ADDRESS, channel=channel, credentials=credentials ) if client_info is None: @@ -187,7 +172,19 @@ def __init__( # transport methods, wrapped with `wrap_method` to add retry, # timeout, and the like. self._inner_api_calls = {} + + def channel(self): + return self.transport.channel + def get_operation(self, name=None): + return self.transport.get_operation(name) + + def delete_operation(self, name=None): + return self.transport.delete_operation(name) + + def cancel_operation(self, name=None): + return self.transport.cancel_operation(name) + # Service calls def annotate_video( self, @@ -304,3 +301,5 @@ def annotate_video( video_intelligence_pb2.AnnotateVideoResponse, metadata_type=video_intelligence_pb2.AnnotateVideoProgress, ) + + diff --git a/videointelligence/tests/system.py b/videointelligence/tests/system.py new file mode 100644 index 000000000000..ea58a97286bb --- /dev/null +++ b/videointelligence/tests/system.py @@ -0,0 +1,159 @@ +# Copyright 2017, Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""System tests for VideoIntelligence API.""" + +import grpc +import io +import json +import os +import requests +import time +import unittest + +import google.api_core.exceptions +from google.cloud import exceptions +from google.cloud import videointelligence +from google.cloud.videointelligence_v1 import enums + +PROJECT_NUMBER = os.environ.get("PROJECT_NUMBER") +PROJECT_OUTSIDE = os.environ.get("GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_PROJECT") +BUCKET_OUTSIDE = os.environ.get("GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_BUCKET") +OUTSIDE_PROJECT_API_KEY = os.environ.get("GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_PROJECT_API_KEY") +OUTSIDE_IP = os.environ.get("GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_IP") +INSIDE_IP = os.environ.get("GOOGLE_CLOUD_TESTS_VPCSC_INSIDE_IP") + +class VideoIntelligenceSystemTestBase(unittest.TestCase): + client = None + + def setUp(self): + self.to_delete_by_case = [] + self.input_uri = "gs://cloud-samples-data/video/cat.mp4" + + def tearDown(self): + for value in self.to_delete_by_case: + value.delete() + + +def setUpModule(): + VideoIntelligenceSystemTestBase.client = videointelligence.VideoIntelligenceServiceClient() + + +class TestVideoIntelligenceClient(VideoIntelligenceSystemTestBase): + def test_annotate_video(self): + features_element = enums.Feature.LABEL_DETECTION + features = [features_element] + response = self.client.annotate_video(input_uri=self.input_uri, features=features) + + # Wait for the operation to complete. + lro_timeout_seconds = 60 + start_time = time.time() + cnt = 0 + while not response.done() and (time.time() - start_time) < lro_timeout_seconds: + time.sleep(1) + cnt += 1 + if not response.done(): + self.fail( + "wait for operation timed out after {lro_timeout_seconds} seconds".format( + lro_timeout_seconds=lro_timeout_seconds + ) + ) + + result = response.result() + annotations = result.annotation_results[0] + assert len(annotations.segment_label_annotations) > 0 + + + +@unittest.skipUnless( + OUTSIDE_PROJECT_API_KEY, + "GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_PROJECT_API_KEY not set in environment.", +) +class TestVideoIntelligenceClientVpcSc(VideoIntelligenceSystemTestBase): + # Tests to verify VideoIntelligence service requests blocked when trying to access resources outside of a secure perimeter. + def setUp(self): + VideoIntelligenceSystemTestBase.setUp(self) + # api-endpoint + self.url = "https://videointelligence.googleapis.com/v1/videos:annotate?key={}".format(OUTSIDE_PROJECT_API_KEY) + self.body = {"input_uri": self.input_uri, "features": ["LABEL_DETECTION"], "location_id": "us-west1"} + + def test_get_operation_from_different_project(self): + # sending request and saving the response as response object + r = requests.post(url=self.url, data=self.body) + outside_project_operation = json.loads(r.text) + + # Uses inside perimeter project to access operation resource created owned by outside project + with self.assertRaises(google.api_core.exceptions.NotFound) as cm: + self.client.get_operation(outside_project_operation["name"]) + + # Assert it returns not found. + self.assertEqual(cm.exception.code, 404) + self.assertEqual(cm.exception.message, "Operation not found: {}".format(outside_project_operation["name"])) + + def test_delete_operation_from_different_project(self): + # sending request and saving the response as response object + r = requests.post(url=self.url, data=self.body) + outside_project_operation = json.loads(r.text) + + # Uses inside perimeter project to access operation resource created owned by outside project + with self.assertRaises(Exception) as cm: + self.client.delete_operation(outside_project_operation["name"]) + + # Assert it returns not found. + self.assertEqual(cm.exception.code, 404) + self.assertEqual(cm.exception.message, "Operation not found: {}".format(outside_project_operation["name"])) + + def test_cancel_operation_from_different_project(self): + # sending request and saving the response as response object + r = requests.post(url=self.url, data=self.body) + outside_project_operation = json.loads(r.text) + + # Uses inside perimeter project to access operation resource created owned by outside project + with self.assertRaises(Exception) as cm: + self.client.cancel_operation(outside_project_operation["name"]) + + # Assert it returns not found. + self.assertEqual(cm.exception.code, 404) + self.assertEqual(cm.exception.message, "Operation not found: {}".format(outside_project_operation["name"])) + + @unittest.skipUnless(PROJECT_NUMBER, "PROJECT_NUMBER not set in environment.") + @unittest.skipUnless(OUTSIDE_IP, "GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_IP not set in environment.") + def test_outside_ip_address_blocked(self): + headers = { + "Content-Type": "application/json", + "X-User-IP": OUTSIDE_IP, + "X-Google-GFE-Cloud-Client-Network-Project-Number": PROJECT_NUMBER, + } + r = requests.post(url=self.url, data=json.dumps(self.body), headers=headers) + outside_project_operation = json.loads(r.text) + print(outside_project_operation) + # Assert it returns permission denied from VPC SC + self.assertEqual(outside_project_operation["error"]["code"], 403) + self.assertEqual(outside_project_operation["error"]["status"], "PERMISSION_DENIED") + self.assertEqual(outside_project_operation["error"]["details"][0]["violations"][0]["type"], "VPC_SERVICE_CONTROLS") + self.assertEqual(outside_project_operation["error"]["message"], "Request is prohibited by organization's policy") + + @unittest.skipUnless(PROJECT_NUMBER, "PROJECT_NUMBER not set in environment.") + @unittest.skipUnless(INSIDE_IP, "GOOGLE_CLOUD_TESTS_VPCSC_INSIDE_IP not set in environment.") + def test_inside_ip_address_allowed(self): + headers = { + "Content-Type": "application/json", + "X-User-IP": INSIDE_IP, + "X-Google-GFE-Cloud-Client-Network-Project-Number": PROJECT_NUMBER, + } + r = requests.post(url=self.url, data=json.dumps(self.body), headers=headers) + operation = json.loads(r.text) + # Assert it returns non-empty operation name. + self.assertNotEqual(operation["name"], "") + From 9a49e5407df17660e91f47f250df974f853589dd Mon Sep 17 00:00:00 2001 From: Jimmy Mkude Date: Mon, 8 Jul 2019 09:21:03 -0700 Subject: [PATCH 02/11] Addressing comments --- .../video_intelligence_service_grpc_transport.py | 4 +--- .../gapic/video_intelligence_service_client.py | 7 +------ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py b/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py index 9bf9f3bd5024..7dc775491d11 100644 --- a/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py +++ b/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py @@ -19,7 +19,6 @@ import google.api_core.operations_v1 from google.cloud.videointelligence_v1.proto import video_intelligence_pb2_grpc -from google.longrunning import operations_pb2 class VideoIntelligenceServiceGrpcTransport(object): @@ -72,8 +71,7 @@ def __init__( self._stubs = { "video_intelligence_service_stub": video_intelligence_pb2_grpc.VideoIntelligenceServiceStub( channel - ), - "operations_stub": operations_pb2.OperationsStub(channel) + ) } # Because this API includes a method that returns a diff --git a/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py b/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py index ff5fdec70e21..611e45fc6ed7 100644 --- a/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py +++ b/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py @@ -172,9 +172,6 @@ def __init__( # transport methods, wrapped with `wrap_method` to add retry, # timeout, and the like. self._inner_api_calls = {} - - def channel(self): - return self.transport.channel def get_operation(self, name=None): return self.transport.get_operation(name) @@ -300,6 +297,4 @@ def annotate_video( self.transport._operations_client, video_intelligence_pb2.AnnotateVideoResponse, metadata_type=video_intelligence_pb2.AnnotateVideoProgress, - ) - - + ) From 133b008871466672017d863af9af95dfc92228df Mon Sep 17 00:00:00 2001 From: Jimmy Mkude Date: Wed, 3 Jul 2019 10:43:07 -0700 Subject: [PATCH 03/11] Adds VPC SC integration tests for Video Intelligence API --- ...deo_intelligence_service_grpc_transport.py | 16 +- .../video_intelligence_service_client.py | 31 ++-- videointelligence/tests/system.py | 159 ++++++++++++++++++ 3 files changed, 189 insertions(+), 17 deletions(-) create mode 100644 videointelligence/tests/system.py diff --git a/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py b/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py index 0c3a472179cf..9bf9f3bd5024 100644 --- a/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py +++ b/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py @@ -19,6 +19,7 @@ import google.api_core.operations_v1 from google.cloud.videointelligence_v1.proto import video_intelligence_pb2_grpc +from google.longrunning import operations_pb2 class VideoIntelligenceServiceGrpcTransport(object): @@ -71,7 +72,8 @@ def __init__( self._stubs = { "video_intelligence_service_stub": video_intelligence_pb2_grpc.VideoIntelligenceServiceStub( channel - ) + ), + "operations_stub": operations_pb2.OperationsStub(channel) } # Because this API includes a method that returns a @@ -113,6 +115,18 @@ def channel(self): """ return self._channel + @property + def get_operation(self): + return self._operations_client.get_operation + + @property + def delete_operation(self): + return self._operations_client.delete_operation + + @property + def cancel_operation(self): + return self._operations_client.cancel_operation + @property def annotate_video(self): """Return the gRPC stub for :meth:`VideoIntelligenceServiceClient.annotate_video`. diff --git a/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py b/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py index 890992f9fb65..ff5fdec70e21 100644 --- a/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py +++ b/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py @@ -20,7 +20,6 @@ import warnings from google.oauth2 import service_account -import google.api_core.client_options import google.api_core.gapic_v1.client_info import google.api_core.gapic_v1.config import google.api_core.gapic_v1.method @@ -83,7 +82,6 @@ def __init__( credentials=None, client_config=None, client_info=None, - client_options=None, ): """Constructor. @@ -114,9 +112,6 @@ def __init__( API requests. If ``None``, then default info will be used. Generally, you only need to set this if you're developing your own client library. - client_options (Union[dict, google.api_core.client_options.ClientOptions]): - Client options used to set user options on the client. API Endpoint - should be set through client_options. """ # Raise deprecation warnings for things we want to go away. if client_config is not None: @@ -135,15 +130,6 @@ def __init__( stacklevel=2, ) - api_endpoint = self.SERVICE_ADDRESS - if client_options: - if type(client_options) == dict: - client_options = google.api_core.client_options.from_dict( - client_options - ) - if client_options.api_endpoint: - api_endpoint = client_options.api_endpoint - # Instantiate the transport. # The transport is responsible for handling serialization and # deserialization and actually sending data to the service. @@ -152,7 +138,6 @@ def __init__( self.transport = transport( credentials=credentials, default_class=video_intelligence_service_grpc_transport.VideoIntelligenceServiceGrpcTransport, - address=api_endpoint, ) else: if credentials: @@ -163,7 +148,7 @@ def __init__( self.transport = transport else: self.transport = video_intelligence_service_grpc_transport.VideoIntelligenceServiceGrpcTransport( - address=api_endpoint, channel=channel, credentials=credentials + address=self.SERVICE_ADDRESS, channel=channel, credentials=credentials ) if client_info is None: @@ -187,7 +172,19 @@ def __init__( # transport methods, wrapped with `wrap_method` to add retry, # timeout, and the like. self._inner_api_calls = {} + + def channel(self): + return self.transport.channel + def get_operation(self, name=None): + return self.transport.get_operation(name) + + def delete_operation(self, name=None): + return self.transport.delete_operation(name) + + def cancel_operation(self, name=None): + return self.transport.cancel_operation(name) + # Service calls def annotate_video( self, @@ -304,3 +301,5 @@ def annotate_video( video_intelligence_pb2.AnnotateVideoResponse, metadata_type=video_intelligence_pb2.AnnotateVideoProgress, ) + + diff --git a/videointelligence/tests/system.py b/videointelligence/tests/system.py new file mode 100644 index 000000000000..ea58a97286bb --- /dev/null +++ b/videointelligence/tests/system.py @@ -0,0 +1,159 @@ +# Copyright 2017, Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""System tests for VideoIntelligence API.""" + +import grpc +import io +import json +import os +import requests +import time +import unittest + +import google.api_core.exceptions +from google.cloud import exceptions +from google.cloud import videointelligence +from google.cloud.videointelligence_v1 import enums + +PROJECT_NUMBER = os.environ.get("PROJECT_NUMBER") +PROJECT_OUTSIDE = os.environ.get("GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_PROJECT") +BUCKET_OUTSIDE = os.environ.get("GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_BUCKET") +OUTSIDE_PROJECT_API_KEY = os.environ.get("GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_PROJECT_API_KEY") +OUTSIDE_IP = os.environ.get("GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_IP") +INSIDE_IP = os.environ.get("GOOGLE_CLOUD_TESTS_VPCSC_INSIDE_IP") + +class VideoIntelligenceSystemTestBase(unittest.TestCase): + client = None + + def setUp(self): + self.to_delete_by_case = [] + self.input_uri = "gs://cloud-samples-data/video/cat.mp4" + + def tearDown(self): + for value in self.to_delete_by_case: + value.delete() + + +def setUpModule(): + VideoIntelligenceSystemTestBase.client = videointelligence.VideoIntelligenceServiceClient() + + +class TestVideoIntelligenceClient(VideoIntelligenceSystemTestBase): + def test_annotate_video(self): + features_element = enums.Feature.LABEL_DETECTION + features = [features_element] + response = self.client.annotate_video(input_uri=self.input_uri, features=features) + + # Wait for the operation to complete. + lro_timeout_seconds = 60 + start_time = time.time() + cnt = 0 + while not response.done() and (time.time() - start_time) < lro_timeout_seconds: + time.sleep(1) + cnt += 1 + if not response.done(): + self.fail( + "wait for operation timed out after {lro_timeout_seconds} seconds".format( + lro_timeout_seconds=lro_timeout_seconds + ) + ) + + result = response.result() + annotations = result.annotation_results[0] + assert len(annotations.segment_label_annotations) > 0 + + + +@unittest.skipUnless( + OUTSIDE_PROJECT_API_KEY, + "GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_PROJECT_API_KEY not set in environment.", +) +class TestVideoIntelligenceClientVpcSc(VideoIntelligenceSystemTestBase): + # Tests to verify VideoIntelligence service requests blocked when trying to access resources outside of a secure perimeter. + def setUp(self): + VideoIntelligenceSystemTestBase.setUp(self) + # api-endpoint + self.url = "https://videointelligence.googleapis.com/v1/videos:annotate?key={}".format(OUTSIDE_PROJECT_API_KEY) + self.body = {"input_uri": self.input_uri, "features": ["LABEL_DETECTION"], "location_id": "us-west1"} + + def test_get_operation_from_different_project(self): + # sending request and saving the response as response object + r = requests.post(url=self.url, data=self.body) + outside_project_operation = json.loads(r.text) + + # Uses inside perimeter project to access operation resource created owned by outside project + with self.assertRaises(google.api_core.exceptions.NotFound) as cm: + self.client.get_operation(outside_project_operation["name"]) + + # Assert it returns not found. + self.assertEqual(cm.exception.code, 404) + self.assertEqual(cm.exception.message, "Operation not found: {}".format(outside_project_operation["name"])) + + def test_delete_operation_from_different_project(self): + # sending request and saving the response as response object + r = requests.post(url=self.url, data=self.body) + outside_project_operation = json.loads(r.text) + + # Uses inside perimeter project to access operation resource created owned by outside project + with self.assertRaises(Exception) as cm: + self.client.delete_operation(outside_project_operation["name"]) + + # Assert it returns not found. + self.assertEqual(cm.exception.code, 404) + self.assertEqual(cm.exception.message, "Operation not found: {}".format(outside_project_operation["name"])) + + def test_cancel_operation_from_different_project(self): + # sending request and saving the response as response object + r = requests.post(url=self.url, data=self.body) + outside_project_operation = json.loads(r.text) + + # Uses inside perimeter project to access operation resource created owned by outside project + with self.assertRaises(Exception) as cm: + self.client.cancel_operation(outside_project_operation["name"]) + + # Assert it returns not found. + self.assertEqual(cm.exception.code, 404) + self.assertEqual(cm.exception.message, "Operation not found: {}".format(outside_project_operation["name"])) + + @unittest.skipUnless(PROJECT_NUMBER, "PROJECT_NUMBER not set in environment.") + @unittest.skipUnless(OUTSIDE_IP, "GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_IP not set in environment.") + def test_outside_ip_address_blocked(self): + headers = { + "Content-Type": "application/json", + "X-User-IP": OUTSIDE_IP, + "X-Google-GFE-Cloud-Client-Network-Project-Number": PROJECT_NUMBER, + } + r = requests.post(url=self.url, data=json.dumps(self.body), headers=headers) + outside_project_operation = json.loads(r.text) + print(outside_project_operation) + # Assert it returns permission denied from VPC SC + self.assertEqual(outside_project_operation["error"]["code"], 403) + self.assertEqual(outside_project_operation["error"]["status"], "PERMISSION_DENIED") + self.assertEqual(outside_project_operation["error"]["details"][0]["violations"][0]["type"], "VPC_SERVICE_CONTROLS") + self.assertEqual(outside_project_operation["error"]["message"], "Request is prohibited by organization's policy") + + @unittest.skipUnless(PROJECT_NUMBER, "PROJECT_NUMBER not set in environment.") + @unittest.skipUnless(INSIDE_IP, "GOOGLE_CLOUD_TESTS_VPCSC_INSIDE_IP not set in environment.") + def test_inside_ip_address_allowed(self): + headers = { + "Content-Type": "application/json", + "X-User-IP": INSIDE_IP, + "X-Google-GFE-Cloud-Client-Network-Project-Number": PROJECT_NUMBER, + } + r = requests.post(url=self.url, data=json.dumps(self.body), headers=headers) + operation = json.loads(r.text) + # Assert it returns non-empty operation name. + self.assertNotEqual(operation["name"], "") + From 34e9c2b0178303b93a27de8d638bc005b5ec8dca Mon Sep 17 00:00:00 2001 From: Jimmy Mkude Date: Mon, 8 Jul 2019 09:21:03 -0700 Subject: [PATCH 04/11] Addressing comments --- .../video_intelligence_service_grpc_transport.py | 4 +--- .../gapic/video_intelligence_service_client.py | 7 +------ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py b/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py index 9bf9f3bd5024..7dc775491d11 100644 --- a/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py +++ b/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py @@ -19,7 +19,6 @@ import google.api_core.operations_v1 from google.cloud.videointelligence_v1.proto import video_intelligence_pb2_grpc -from google.longrunning import operations_pb2 class VideoIntelligenceServiceGrpcTransport(object): @@ -72,8 +71,7 @@ def __init__( self._stubs = { "video_intelligence_service_stub": video_intelligence_pb2_grpc.VideoIntelligenceServiceStub( channel - ), - "operations_stub": operations_pb2.OperationsStub(channel) + ) } # Because this API includes a method that returns a diff --git a/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py b/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py index ff5fdec70e21..611e45fc6ed7 100644 --- a/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py +++ b/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py @@ -172,9 +172,6 @@ def __init__( # transport methods, wrapped with `wrap_method` to add retry, # timeout, and the like. self._inner_api_calls = {} - - def channel(self): - return self.transport.channel def get_operation(self, name=None): return self.transport.get_operation(name) @@ -300,6 +297,4 @@ def annotate_video( self.transport._operations_client, video_intelligence_pb2.AnnotateVideoResponse, metadata_type=video_intelligence_pb2.AnnotateVideoProgress, - ) - - + ) From 625ffa03972131b537ba1ef02216115d8368c778 Mon Sep 17 00:00:00 2001 From: Jimmy Mkude Date: Tue, 9 Jul 2019 10:52:27 -0700 Subject: [PATCH 05/11] Removed changes in generated code. --- ...deo_intelligence_service_grpc_transport.py | 12 -- .../video_intelligence_service_client.py | 28 +++-- videointelligence/tests/system.py | 113 +++++++----------- 3 files changed, 63 insertions(+), 90 deletions(-) diff --git a/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py b/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py index 7dc775491d11..0c3a472179cf 100644 --- a/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py +++ b/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py @@ -113,18 +113,6 @@ def channel(self): """ return self._channel - @property - def get_operation(self): - return self._operations_client.get_operation - - @property - def delete_operation(self): - return self._operations_client.delete_operation - - @property - def cancel_operation(self): - return self._operations_client.cancel_operation - @property def annotate_video(self): """Return the gRPC stub for :meth:`VideoIntelligenceServiceClient.annotate_video`. diff --git a/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py b/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py index 611e45fc6ed7..890992f9fb65 100644 --- a/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py +++ b/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py @@ -20,6 +20,7 @@ import warnings from google.oauth2 import service_account +import google.api_core.client_options import google.api_core.gapic_v1.client_info import google.api_core.gapic_v1.config import google.api_core.gapic_v1.method @@ -82,6 +83,7 @@ def __init__( credentials=None, client_config=None, client_info=None, + client_options=None, ): """Constructor. @@ -112,6 +114,9 @@ def __init__( API requests. If ``None``, then default info will be used. Generally, you only need to set this if you're developing your own client library. + client_options (Union[dict, google.api_core.client_options.ClientOptions]): + Client options used to set user options on the client. API Endpoint + should be set through client_options. """ # Raise deprecation warnings for things we want to go away. if client_config is not None: @@ -130,6 +135,15 @@ def __init__( stacklevel=2, ) + api_endpoint = self.SERVICE_ADDRESS + if client_options: + if type(client_options) == dict: + client_options = google.api_core.client_options.from_dict( + client_options + ) + if client_options.api_endpoint: + api_endpoint = client_options.api_endpoint + # Instantiate the transport. # The transport is responsible for handling serialization and # deserialization and actually sending data to the service. @@ -138,6 +152,7 @@ def __init__( self.transport = transport( credentials=credentials, default_class=video_intelligence_service_grpc_transport.VideoIntelligenceServiceGrpcTransport, + address=api_endpoint, ) else: if credentials: @@ -148,7 +163,7 @@ def __init__( self.transport = transport else: self.transport = video_intelligence_service_grpc_transport.VideoIntelligenceServiceGrpcTransport( - address=self.SERVICE_ADDRESS, channel=channel, credentials=credentials + address=api_endpoint, channel=channel, credentials=credentials ) if client_info is None: @@ -173,15 +188,6 @@ def __init__( # timeout, and the like. self._inner_api_calls = {} - def get_operation(self, name=None): - return self.transport.get_operation(name) - - def delete_operation(self, name=None): - return self.transport.delete_operation(name) - - def cancel_operation(self, name=None): - return self.transport.cancel_operation(name) - # Service calls def annotate_video( self, @@ -297,4 +303,4 @@ def annotate_video( self.transport._operations_client, video_intelligence_pb2.AnnotateVideoResponse, metadata_type=video_intelligence_pb2.AnnotateVideoProgress, - ) + ) diff --git a/videointelligence/tests/system.py b/videointelligence/tests/system.py index ea58a97286bb..bf4d5cdfc278 100644 --- a/videointelligence/tests/system.py +++ b/videointelligence/tests/system.py @@ -30,32 +30,34 @@ PROJECT_NUMBER = os.environ.get("PROJECT_NUMBER") PROJECT_OUTSIDE = os.environ.get("GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_PROJECT") BUCKET_OUTSIDE = os.environ.get("GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_BUCKET") -OUTSIDE_PROJECT_API_KEY = os.environ.get("GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_PROJECT_API_KEY") +OUTSIDE_PROJECT_API_KEY = os.environ.get( + "GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_PROJECT_API_KEY" +) OUTSIDE_IP = os.environ.get("GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_IP") INSIDE_IP = os.environ.get("GOOGLE_CLOUD_TESTS_VPCSC_INSIDE_IP") + class VideoIntelligenceSystemTestBase(unittest.TestCase): client = None def setUp(self): - self.to_delete_by_case = [] self.input_uri = "gs://cloud-samples-data/video/cat.mp4" - def tearDown(self): - for value in self.to_delete_by_case: - value.delete() - def setUpModule(): - VideoIntelligenceSystemTestBase.client = videointelligence.VideoIntelligenceServiceClient() + VideoIntelligenceSystemTestBase.client = ( + videointelligence.VideoIntelligenceServiceClient() + ) class TestVideoIntelligenceClient(VideoIntelligenceSystemTestBase): def test_annotate_video(self): features_element = enums.Feature.LABEL_DETECTION features = [features_element] - response = self.client.annotate_video(input_uri=self.input_uri, features=features) - + response = self.client.annotate_video( + input_uri=self.input_uri, features=features + ) + # Wait for the operation to complete. lro_timeout_seconds = 60 start_time = time.time() @@ -69,13 +71,12 @@ def test_annotate_video(self): lro_timeout_seconds=lro_timeout_seconds ) ) - + result = response.result() annotations = result.annotation_results[0] assert len(annotations.segment_label_annotations) > 0 - @unittest.skipUnless( OUTSIDE_PROJECT_API_KEY, "GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_PROJECT_API_KEY not set in environment.", @@ -84,76 +85,54 @@ class TestVideoIntelligenceClientVpcSc(VideoIntelligenceSystemTestBase): # Tests to verify VideoIntelligence service requests blocked when trying to access resources outside of a secure perimeter. def setUp(self): VideoIntelligenceSystemTestBase.setUp(self) - # api-endpoint - self.url = "https://videointelligence.googleapis.com/v1/videos:annotate?key={}".format(OUTSIDE_PROJECT_API_KEY) - self.body = {"input_uri": self.input_uri, "features": ["LABEL_DETECTION"], "location_id": "us-west1"} - - def test_get_operation_from_different_project(self): - # sending request and saving the response as response object - r = requests.post(url=self.url, data=self.body) - outside_project_operation = json.loads(r.text) - - # Uses inside perimeter project to access operation resource created owned by outside project - with self.assertRaises(google.api_core.exceptions.NotFound) as cm: - self.client.get_operation(outside_project_operation["name"]) - - # Assert it returns not found. - self.assertEqual(cm.exception.code, 404) - self.assertEqual(cm.exception.message, "Operation not found: {}".format(outside_project_operation["name"])) - - def test_delete_operation_from_different_project(self): - # sending request and saving the response as response object - r = requests.post(url=self.url, data=self.body) - outside_project_operation = json.loads(r.text) - - # Uses inside perimeter project to access operation resource created owned by outside project - with self.assertRaises(Exception) as cm: - self.client.delete_operation(outside_project_operation["name"]) - - # Assert it returns not found. - self.assertEqual(cm.exception.code, 404) - self.assertEqual(cm.exception.message, "Operation not found: {}".format(outside_project_operation["name"])) - - def test_cancel_operation_from_different_project(self): - # sending request and saving the response as response object - r = requests.post(url=self.url, data=self.body) - outside_project_operation = json.loads(r.text) - - # Uses inside perimeter project to access operation resource created owned by outside project - with self.assertRaises(Exception) as cm: - self.client.cancel_operation(outside_project_operation["name"]) - - # Assert it returns not found. - self.assertEqual(cm.exception.code, 404) - self.assertEqual(cm.exception.message, "Operation not found: {}".format(outside_project_operation["name"])) - + # api-endpoint + self.url = "https://videointelligence.googleapis.com/v1/videos:annotate?key={}".format( + OUTSIDE_PROJECT_API_KEY + ) + self.body = { + "input_uri": self.input_uri, + "features": ["LABEL_DETECTION"], + "location_id": "us-west1", + } + @unittest.skipUnless(PROJECT_NUMBER, "PROJECT_NUMBER not set in environment.") - @unittest.skipUnless(OUTSIDE_IP, "GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_IP not set in environment.") + @unittest.skipUnless( + OUTSIDE_IP, "GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_IP not set in environment." + ) def test_outside_ip_address_blocked(self): headers = { - "Content-Type": "application/json", - "X-User-IP": OUTSIDE_IP, - "X-Google-GFE-Cloud-Client-Network-Project-Number": PROJECT_NUMBER, + "Content-Type": "application/json", + "X-User-IP": OUTSIDE_IP, + "X-Google-GFE-Cloud-Client-Network-Project-Number": PROJECT_NUMBER, } r = requests.post(url=self.url, data=json.dumps(self.body), headers=headers) outside_project_operation = json.loads(r.text) print(outside_project_operation) # Assert it returns permission denied from VPC SC self.assertEqual(outside_project_operation["error"]["code"], 403) - self.assertEqual(outside_project_operation["error"]["status"], "PERMISSION_DENIED") - self.assertEqual(outside_project_operation["error"]["details"][0]["violations"][0]["type"], "VPC_SERVICE_CONTROLS") - self.assertEqual(outside_project_operation["error"]["message"], "Request is prohibited by organization's policy") - + self.assertEqual( + outside_project_operation["error"]["status"], "PERMISSION_DENIED" + ) + self.assertEqual( + outside_project_operation["error"]["details"][0]["violations"][0]["type"], + "VPC_SERVICE_CONTROLS", + ) + self.assertEqual( + outside_project_operation["error"]["message"], + "Request is prohibited by organization's policy", + ) + @unittest.skipUnless(PROJECT_NUMBER, "PROJECT_NUMBER not set in environment.") - @unittest.skipUnless(INSIDE_IP, "GOOGLE_CLOUD_TESTS_VPCSC_INSIDE_IP not set in environment.") + @unittest.skipUnless( + INSIDE_IP, "GOOGLE_CLOUD_TESTS_VPCSC_INSIDE_IP not set in environment." + ) def test_inside_ip_address_allowed(self): headers = { - "Content-Type": "application/json", - "X-User-IP": INSIDE_IP, - "X-Google-GFE-Cloud-Client-Network-Project-Number": PROJECT_NUMBER, + "Content-Type": "application/json", + "X-User-IP": INSIDE_IP, + "X-Google-GFE-Cloud-Client-Network-Project-Number": PROJECT_NUMBER, } r = requests.post(url=self.url, data=json.dumps(self.body), headers=headers) operation = json.loads(r.text) # Assert it returns non-empty operation name. self.assertNotEqual(operation["name"], "") - From d6707d3b568ac536025bd11c83a40832d1a67dfa Mon Sep 17 00:00:00 2001 From: Jimmy Mkude Date: Tue, 9 Jul 2019 11:02:54 -0700 Subject: [PATCH 06/11] Reverting generated code changes. --- ...deo_intelligence_service_grpc_transport.py | 12 -------- .../video_intelligence_service_client.py | 28 +++++++++++-------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py b/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py index 7dc775491d11..0c3a472179cf 100644 --- a/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py +++ b/videointelligence/google/cloud/videointelligence_v1/gapic/transports/video_intelligence_service_grpc_transport.py @@ -113,18 +113,6 @@ def channel(self): """ return self._channel - @property - def get_operation(self): - return self._operations_client.get_operation - - @property - def delete_operation(self): - return self._operations_client.delete_operation - - @property - def cancel_operation(self): - return self._operations_client.cancel_operation - @property def annotate_video(self): """Return the gRPC stub for :meth:`VideoIntelligenceServiceClient.annotate_video`. diff --git a/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py b/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py index 611e45fc6ed7..890992f9fb65 100644 --- a/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py +++ b/videointelligence/google/cloud/videointelligence_v1/gapic/video_intelligence_service_client.py @@ -20,6 +20,7 @@ import warnings from google.oauth2 import service_account +import google.api_core.client_options import google.api_core.gapic_v1.client_info import google.api_core.gapic_v1.config import google.api_core.gapic_v1.method @@ -82,6 +83,7 @@ def __init__( credentials=None, client_config=None, client_info=None, + client_options=None, ): """Constructor. @@ -112,6 +114,9 @@ def __init__( API requests. If ``None``, then default info will be used. Generally, you only need to set this if you're developing your own client library. + client_options (Union[dict, google.api_core.client_options.ClientOptions]): + Client options used to set user options on the client. API Endpoint + should be set through client_options. """ # Raise deprecation warnings for things we want to go away. if client_config is not None: @@ -130,6 +135,15 @@ def __init__( stacklevel=2, ) + api_endpoint = self.SERVICE_ADDRESS + if client_options: + if type(client_options) == dict: + client_options = google.api_core.client_options.from_dict( + client_options + ) + if client_options.api_endpoint: + api_endpoint = client_options.api_endpoint + # Instantiate the transport. # The transport is responsible for handling serialization and # deserialization and actually sending data to the service. @@ -138,6 +152,7 @@ def __init__( self.transport = transport( credentials=credentials, default_class=video_intelligence_service_grpc_transport.VideoIntelligenceServiceGrpcTransport, + address=api_endpoint, ) else: if credentials: @@ -148,7 +163,7 @@ def __init__( self.transport = transport else: self.transport = video_intelligence_service_grpc_transport.VideoIntelligenceServiceGrpcTransport( - address=self.SERVICE_ADDRESS, channel=channel, credentials=credentials + address=api_endpoint, channel=channel, credentials=credentials ) if client_info is None: @@ -173,15 +188,6 @@ def __init__( # timeout, and the like. self._inner_api_calls = {} - def get_operation(self, name=None): - return self.transport.get_operation(name) - - def delete_operation(self, name=None): - return self.transport.delete_operation(name) - - def cancel_operation(self, name=None): - return self.transport.cancel_operation(name) - # Service calls def annotate_video( self, @@ -297,4 +303,4 @@ def annotate_video( self.transport._operations_client, video_intelligence_pb2.AnnotateVideoResponse, metadata_type=video_intelligence_pb2.AnnotateVideoProgress, - ) + ) From f88ce4f6be8dc386194fc7a21429d5cdca5785ad Mon Sep 17 00:00:00 2001 From: Jimmy Mkude Date: Wed, 10 Jul 2019 00:45:45 -0700 Subject: [PATCH 07/11] Set VPS SC environment variables. --- videointelligence/noxfile.py | 11 +++++++++-- videointelligence/tests/system.py | 2 -- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/videointelligence/noxfile.py b/videointelligence/noxfile.py index a2eefbb6765f..386bf4c64552 100644 --- a/videointelligence/noxfile.py +++ b/videointelligence/noxfile.py @@ -118,11 +118,18 @@ def system(session): session.install("-e", "../test_utils/") session.install("-e", ".") + # Additional set up for VPC SC. + env = { + "GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_PROJECT_API_KEY": "AIzaSyCgRxOwpqt-lO6FD4sIqko23wwwexA4YsM", + "PROJECT_NUMBER": "570941833855", + "GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_IP": "10.1.1.1", + "GOOGLE_CLOUD_TESTS_VPCSC_INSIDE_IP": "55.55.0.0", + } # Run py.test against the system tests. if system_test_exists: - session.run("py.test", "--quiet", system_test_path, *session.posargs) + session.run("py.test", "--quiet", system_test_path, env=env, *session.posargs) if system_test_folder_exists: - session.run("py.test", "--quiet", system_test_folder_path, *session.posargs) + session.run("py.test", "--quiet", system_test_folder_path, env=env *session.posargs) @nox.session(python="3.7") diff --git a/videointelligence/tests/system.py b/videointelligence/tests/system.py index bf4d5cdfc278..59c29dc97139 100644 --- a/videointelligence/tests/system.py +++ b/videointelligence/tests/system.py @@ -28,8 +28,6 @@ from google.cloud.videointelligence_v1 import enums PROJECT_NUMBER = os.environ.get("PROJECT_NUMBER") -PROJECT_OUTSIDE = os.environ.get("GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_PROJECT") -BUCKET_OUTSIDE = os.environ.get("GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_BUCKET") OUTSIDE_PROJECT_API_KEY = os.environ.get( "GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_PROJECT_API_KEY" ) From e9271daf7d4387d5b92d16be7bc2e9a3b5490015 Mon Sep 17 00:00:00 2001 From: Jimmy Mkude Date: Wed, 10 Jul 2019 01:00:25 -0700 Subject: [PATCH 08/11] Remove Api key from code (sensitive data) will have to be set through kokoro. --- videointelligence/noxfile.py | 1 - 1 file changed, 1 deletion(-) diff --git a/videointelligence/noxfile.py b/videointelligence/noxfile.py index 386bf4c64552..81cc32d7bc15 100644 --- a/videointelligence/noxfile.py +++ b/videointelligence/noxfile.py @@ -120,7 +120,6 @@ def system(session): # Additional set up for VPC SC. env = { - "GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_PERIMETER_PROJECT_API_KEY": "AIzaSyCgRxOwpqt-lO6FD4sIqko23wwwexA4YsM", "PROJECT_NUMBER": "570941833855", "GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_IP": "10.1.1.1", "GOOGLE_CLOUD_TESTS_VPCSC_INSIDE_IP": "55.55.0.0", From c14396a22f1ecbdd07a3765d99d7af0db100bcb7 Mon Sep 17 00:00:00 2001 From: Jimmy Mkude Date: Wed, 10 Jul 2019 16:19:46 -0700 Subject: [PATCH 09/11] Fix lint error. --- videointelligence/noxfile.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/videointelligence/noxfile.py b/videointelligence/noxfile.py index 81cc32d7bc15..9a0e46e83078 100644 --- a/videointelligence/noxfile.py +++ b/videointelligence/noxfile.py @@ -120,15 +120,17 @@ def system(session): # Additional set up for VPC SC. env = { - "PROJECT_NUMBER": "570941833855", - "GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_IP": "10.1.1.1", - "GOOGLE_CLOUD_TESTS_VPCSC_INSIDE_IP": "55.55.0.0", + "PROJECT_NUMBER": "570941833855", + "GOOGLE_CLOUD_TESTS_VPCSC_OUTSIDE_IP": "10.1.1.1", + "GOOGLE_CLOUD_TESTS_VPCSC_INSIDE_IP": "55.55.0.0", } # Run py.test against the system tests. if system_test_exists: session.run("py.test", "--quiet", system_test_path, env=env, *session.posargs) if system_test_folder_exists: - session.run("py.test", "--quiet", system_test_folder_path, env=env *session.posargs) + session.run( + "py.test", "--quiet", system_test_folder_path, env=env * session.posargs + ) @nox.session(python="3.7") From f885db70f155fb70f43dec7d404a9018e2f437e0 Mon Sep 17 00:00:00 2001 From: Jimmy Mkude Date: Wed, 10 Jul 2019 17:48:47 -0700 Subject: [PATCH 10/11] Remove unused imports. --- videointelligence/tests/system.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/videointelligence/tests/system.py b/videointelligence/tests/system.py index 59c29dc97139..eb1c4bd5547d 100644 --- a/videointelligence/tests/system.py +++ b/videointelligence/tests/system.py @@ -14,16 +14,12 @@ """System tests for VideoIntelligence API.""" -import grpc -import io import json import os import requests import time import unittest -import google.api_core.exceptions -from google.cloud import exceptions from google.cloud import videointelligence from google.cloud.videointelligence_v1 import enums From e23764d41beafd321259c5da25116dd6fdf4a775 Mon Sep 17 00:00:00 2001 From: Jimmy Mkude Date: Thu, 11 Jul 2019 12:33:11 -0700 Subject: [PATCH 11/11] Increase lro timeout to 180s. --- videointelligence/tests/system.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/videointelligence/tests/system.py b/videointelligence/tests/system.py index eb1c4bd5547d..a8ad0a9b29bf 100644 --- a/videointelligence/tests/system.py +++ b/videointelligence/tests/system.py @@ -53,7 +53,8 @@ def test_annotate_video(self): ) # Wait for the operation to complete. - lro_timeout_seconds = 60 + # Long timeout value warranted due to https://github.com/grpc/grpc/issues/19173 + lro_timeout_seconds = 180 start_time = time.time() cnt = 0 while not response.done() and (time.time() - start_time) < lro_timeout_seconds: