| # Copyright 2020 Google Inc. |
| # |
| # 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. |
| # |
| ################################################################################ |
| """Utility functions for testing cloud functions.""" |
| import datetime |
| import os |
| import subprocess |
| import threading |
| |
| import requests |
| |
| DATASTORE_READY_INDICATOR = b'is now running' |
| DATASTORE_EMULATOR_PORT = 8432 |
| EMULATOR_TIMEOUT = 20 |
| |
| FUNCTIONS_DIR = os.path.dirname(__file__) |
| OSS_FUZZ_DIR = os.path.dirname(os.path.dirname(os.path.dirname(FUNCTIONS_DIR))) |
| PROJECTS_DIR = os.path.join(OSS_FUZZ_DIR, 'projects') |
| |
| FAKE_DATETIME = datetime.datetime(2020, 1, 1, 0, 0, 0) |
| IMAGE_PROJECT = 'oss-fuzz' |
| BASE_IMAGES_PROJECT = 'oss-fuzz-base' |
| PROJECT = 'test-project' |
| PROJECT_DIR = os.path.join(PROJECTS_DIR, PROJECT) |
| |
| |
| def create_project_data(project, |
| project_yaml_contents, |
| dockerfile_contents='test line'): |
| """Creates a project.yaml with |project_yaml_contents| and a Dockerfile with |
| |dockerfile_contents| for |project|.""" |
| project_dir = os.path.join(PROJECTS_DIR, project) |
| project_yaml_path = os.path.join(project_dir, 'project.yaml') |
| with open(project_yaml_path, 'w') as project_yaml_handle: |
| project_yaml_handle.write(project_yaml_contents) |
| |
| dockerfile_path = os.path.join(project_dir, 'Dockerfile') |
| with open(dockerfile_path, 'w') as dockerfile_handle: |
| dockerfile_handle.write(dockerfile_contents) |
| |
| |
| def start_datastore_emulator(): |
| """Start Datastore emulator.""" |
| return subprocess.Popen([ |
| 'gcloud', |
| 'beta', |
| 'emulators', |
| 'datastore', |
| 'start', |
| '--consistency=1.0', |
| '--host-port=localhost:' + str(DATASTORE_EMULATOR_PORT), |
| '--project=' + PROJECT, |
| '--no-store-on-disk', |
| ], |
| stdout=subprocess.PIPE, |
| stderr=subprocess.STDOUT) |
| |
| |
| def wait_for_emulator_ready(proc, |
| emulator, |
| indicator, |
| timeout=EMULATOR_TIMEOUT): |
| """Wait for emulator to be ready.""" |
| |
| def _read_thread(proc, ready_event): |
| """Thread to continuously read from the process stdout.""" |
| ready = False |
| while True: |
| line = proc.stdout.readline() |
| if not line: |
| break |
| if not ready and indicator in line: |
| ready = True |
| ready_event.set() |
| |
| # Wait for process to become ready. |
| ready_event = threading.Event() |
| thread = threading.Thread(target=_read_thread, args=(proc, ready_event)) |
| thread.daemon = True |
| thread.start() |
| if not ready_event.wait(timeout): |
| raise RuntimeError(f'{emulator} emulator did not get ready in time.') |
| return thread |
| |
| |
| def reset_ds_emulator(): |
| """Reset ds emulator/clean all entities.""" |
| req = requests.post(f'http://localhost:{DATASTORE_EMULATOR_PORT}/reset') |
| req.raise_for_status() |
| |
| |
| def cleanup_emulator(ds_emulator): |
| """Cleanup the system processes made by ds emulator.""" |
| del ds_emulator #To do, find a better way to cleanup emulator |
| os.system('pkill -f datastore') |
| |
| |
| def set_gcp_environment(): |
| """Set environment variables for simulating in google cloud platform.""" |
| os.environ['DATASTORE_EMULATOR_HOST'] = 'localhost:' + str( |
| DATASTORE_EMULATOR_PORT) |
| os.environ['GOOGLE_CLOUD_PROJECT'] = PROJECT |
| os.environ['DATASTORE_DATASET'] = PROJECT |
| os.environ['GCP_PROJECT'] = PROJECT |
| os.environ['FUNCTION_REGION'] = 'us-central1' |
| |
| |
| def get_test_data_file_path(filename): |
| """Returns the path to a test data file with name |filename|.""" |
| return os.path.join(os.path.dirname(__file__), 'test_data', filename) |