1# Copyright 2020 Google Inc. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# 15################################################################################ 16"""Utility functions for testing cloud functions.""" 17import datetime 18import os 19import subprocess 20import threading 21 22import requests 23 24DATASTORE_READY_INDICATOR = b'is now running' 25DATASTORE_EMULATOR_PORT = 8432 26EMULATOR_TIMEOUT = 20 27 28FUNCTIONS_DIR = os.path.dirname(__file__) 29OSS_FUZZ_DIR = os.path.dirname(os.path.dirname(os.path.dirname(FUNCTIONS_DIR))) 30PROJECTS_DIR = os.path.join(OSS_FUZZ_DIR, 'projects') 31 32FAKE_DATETIME = datetime.datetime(2020, 1, 1, 0, 0, 0) 33IMAGE_PROJECT = 'oss-fuzz' 34BASE_IMAGES_PROJECT = 'oss-fuzz-base' 35PROJECT = 'test-project' 36PROJECT_DIR = os.path.join(PROJECTS_DIR, PROJECT) 37 38 39def create_project_data(project, 40 project_yaml_contents, 41 dockerfile_contents='test line'): 42 """Creates a project.yaml with |project_yaml_contents| and a Dockerfile with 43 |dockerfile_contents| for |project|.""" 44 project_dir = os.path.join(PROJECTS_DIR, project) 45 project_yaml_path = os.path.join(project_dir, 'project.yaml') 46 with open(project_yaml_path, 'w') as project_yaml_handle: 47 project_yaml_handle.write(project_yaml_contents) 48 49 dockerfile_path = os.path.join(project_dir, 'Dockerfile') 50 with open(dockerfile_path, 'w') as dockerfile_handle: 51 dockerfile_handle.write(dockerfile_contents) 52 53 54def start_datastore_emulator(): 55 """Start Datastore emulator.""" 56 return subprocess.Popen([ 57 'gcloud', 58 'beta', 59 'emulators', 60 'datastore', 61 'start', 62 '--consistency=1.0', 63 '--host-port=localhost:' + str(DATASTORE_EMULATOR_PORT), 64 '--project=' + PROJECT, 65 '--no-store-on-disk', 66 ], 67 stdout=subprocess.PIPE, 68 stderr=subprocess.STDOUT) 69 70 71def wait_for_emulator_ready(proc, 72 emulator, 73 indicator, 74 timeout=EMULATOR_TIMEOUT): 75 """Wait for emulator to be ready.""" 76 77 def _read_thread(proc, ready_event): 78 """Thread to continuously read from the process stdout.""" 79 ready = False 80 while True: 81 line = proc.stdout.readline() 82 if not line: 83 break 84 if not ready and indicator in line: 85 ready = True 86 ready_event.set() 87 88 # Wait for process to become ready. 89 ready_event = threading.Event() 90 thread = threading.Thread(target=_read_thread, args=(proc, ready_event)) 91 thread.daemon = True 92 thread.start() 93 if not ready_event.wait(timeout): 94 raise RuntimeError(f'{emulator} emulator did not get ready in time.') 95 return thread 96 97 98def reset_ds_emulator(): 99 """Reset ds emulator/clean all entities.""" 100 req = requests.post(f'http://localhost:{DATASTORE_EMULATOR_PORT}/reset') 101 req.raise_for_status() 102 103 104def cleanup_emulator(ds_emulator): 105 """Cleanup the system processes made by ds emulator.""" 106 del ds_emulator #To do, find a better way to cleanup emulator 107 os.system('pkill -f datastore') 108 109 110def set_gcp_environment(): 111 """Set environment variables for simulating in google cloud platform.""" 112 os.environ['DATASTORE_EMULATOR_HOST'] = 'localhost:' + str( 113 DATASTORE_EMULATOR_PORT) 114 os.environ['GOOGLE_CLOUD_PROJECT'] = PROJECT 115 os.environ['DATASTORE_DATASET'] = PROJECT 116 os.environ['GCP_PROJECT'] = PROJECT 117 os.environ['FUNCTION_REGION'] = 'us-central1' 118 119 120def get_test_data_file_path(filename): 121 """Returns the path to a test data file with name |filename|.""" 122 return os.path.join(os.path.dirname(__file__), 'test_data', filename) 123