blob: 67f99004d99a18597fcc3cf2989b6fdc061fb20d [file] [log] [blame]
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -07001# Copyright 2016 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"""Noxfile for automating system tests.
16
17This file handles setting up environments needed by the system tests. This
18separates the tests from their environment configuration.
19
20See the `nox docs`_ for details on how this file works:
21
22.. _nox docs: http://nox.readthedocs.io/en/latest/
23"""
24
25import os
26
27from nox.command import which
28import py.path
29
30
31HERE = os.path.dirname(__file__)
32DATA_DIR = os.path.join(HERE, 'data')
33SERVICE_ACCOUNT_FILE = os.path.join(DATA_DIR, 'service_account.json')
34AUTHORIZED_USER_FILE = os.path.join(DATA_DIR, 'authorized_user.json')
35EXPLICIT_CREDENTIALS_ENV = 'GOOGLE_APPLICATION_CREDENTIALS'
36EXPLICIT_PROJECT_ENV = 'GOOGLE_CLOUD_PROJECT'
37EXPECT_PROJECT_ENV = 'EXPECT_PROJECT_ID'
38
39# The download location for the Cloud SDK
40CLOUD_SDK_DIST_FILENAME = 'google-cloud-sdk.tar.gz'
41CLOUD_SDK_DOWNLOAD_URL = (
42 'https://dl.google.com/dl/cloudsdk/release/{}'.format(
43 CLOUD_SDK_DIST_FILENAME))
44
45# This environment variable is recognized by the Cloud SDK and overrides
46# the location of the SDK's configuration files (which is usually at
47# ${HOME}/.config).
48CLOUD_SDK_CONFIG_ENV = 'CLOUDSDK_CONFIG'
49
50# If set, this is where the environment setup will install the Cloud SDK.
51# If unset, it will download the SDK to a temporary directory.
52CLOUD_SDK_ROOT = os.environ.get('CLOUD_SDK_ROOT')
53
54if CLOUD_SDK_ROOT is not None:
55 CLOUD_SDK_ROOT = py.path.local(CLOUD_SDK_ROOT)
56 CLOUD_SDK_ROOT.ensure(dir=True) # Makes sure the directory exists.
57else:
58 CLOUD_SDK_ROOT = py.path.local.mkdtemp()
59
60# The full path the cloud sdk install directory
61CLOUD_SDK_INSTALL_DIR = CLOUD_SDK_ROOT.join('google-cloud-sdk')
62
63# The full path to the gcloud cli executable.
64GCLOUD = str(CLOUD_SDK_INSTALL_DIR.join('bin', 'gcloud'))
65
66# gcloud requires Python 2 and doesn't work on 3, so we need to tell it
67# where to find 2 when we're running in a 3 environment.
68CLOUD_SDK_PYTHON_ENV = 'CLOUDSDK_PYTHON'
69CLOUD_SDK_PYTHON = which('python2', None)
70
71# Cloud SDK helpers
72
73
74def install_cloud_sdk(session):
75 """Downloads and installs the Google Cloud SDK."""
76 # Configure environment variables needed by the SDK.
77 # This sets the config root to the tests' config root. This prevents
78 # our tests from clobbering a developer's configuration when running
79 # these tests locally.
80 session.env[CLOUD_SDK_CONFIG_ENV] = str(CLOUD_SDK_ROOT)
81 # This tells gcloud which Python interpreter to use (always use 2.7)
82 session.env[CLOUD_SDK_PYTHON_ENV] = CLOUD_SDK_PYTHON
83
84 # If the glcoud already exists, we don't need to do anything else.
85 # Note that because of this we do not attempt to update the sdk -
86 # if the CLOUD_SDK_ROOT is cached, it will need to be periodically cleared.
87 if py.path.local(GCLOUD).exists():
88 return
89
90 tar_path = CLOUD_SDK_ROOT.join(CLOUD_SDK_DIST_FILENAME)
91
92 # Download the release.
93 session.run(
94 'wget', CLOUD_SDK_DOWNLOAD_URL, '-O', str(tar_path), silent=True)
95
96 # Extract the release.
97 session.run(
98 'tar', 'xzf', str(tar_path), '-C', str(CLOUD_SDK_ROOT))
99 session.run(tar_path.remove)
100
101 # Run the install script.
102 session.run(
103 str(CLOUD_SDK_INSTALL_DIR.join('install.sh')),
104 '--usage-reporting', 'false',
105 '--path-update', 'false',
106 '--command-completion', 'false',
107 silent=True)
108
109
110def copy_credentials(credentials_path):
111 """Copies credentials into the SDK root as the application default
112 credentials."""
113 dest = CLOUD_SDK_ROOT.join('application_default_credentials.json')
114 if dest.exists():
115 dest.remove()
116 py.path.local(credentials_path).copy(dest)
117
118
119def configure_cloud_sdk(
120 session, application_default_credentials, project=False):
121 """Installs and configures the Cloud SDK with the given application default
122 credentials.
123
124 If project is True, then a project will be set in the active config.
125 If it is false, this will ensure no project is set.
126 """
127 install_cloud_sdk(session)
128
129 if project:
130 session.run(GCLOUD, 'config', 'set', 'project', 'example-project')
131 else:
132 session.run(GCLOUD, 'config', 'unset', 'project')
133
134 # Copy the credentials file to the config root. This is needed because
135 # unfortunately gcloud doesn't provide a clean way to tell it to use
136 # a particular set of credentials. However, this does verify that gcloud
137 # also considers the credentials valid by calling application-default
138 # print-access-token
139 session.run(copy_credentials, application_default_credentials)
140
141 # Calling this forces the Cloud SDK to read the credentials we just wrote
142 # and obtain a new access token with those credentials. This validates
143 # that our credentials matches the format expected by gcloud.
144 # Silent is set to True to prevent leaking secrets in test logs.
145 session.run(
146 GCLOUD, 'auth', 'application-default', 'print-access-token',
147 silent=True)
148
149
150# Test sesssions
151
152
153def session_service_account(session):
154 session.virtualenv = False
155 session.run('pytest', 'test_service_account.py')
156
157
158def session_oauth2_credentials(session):
159 session.virtualenv = False
160 session.run('pytest', 'test_oauth2_credentials.py')
161
162
163def session_default_explicit_service_account(session):
164 session.virtualenv = False
165 session.env[EXPLICIT_CREDENTIALS_ENV] = SERVICE_ACCOUNT_FILE
166 session.env[EXPECT_PROJECT_ENV] = '1'
167 session.run('pytest', 'test_default.py')
168
169
170def session_default_explicit_authorized_user(session):
171 session.virtualenv = False
172 session.env[EXPLICIT_CREDENTIALS_ENV] = AUTHORIZED_USER_FILE
173 session.run('pytest', 'test_default.py')
174
175
176def session_default_explicit_authorized_user_explicit_project(session):
177 session.virtualenv = False
178 session.env[EXPLICIT_CREDENTIALS_ENV] = AUTHORIZED_USER_FILE
179 session.env[EXPLICIT_PROJECT_ENV] = 'example-project'
180 session.env[EXPECT_PROJECT_ENV] = '1'
181 session.run('pytest', 'test_default.py')
182
183
184def session_default_cloud_sdk_service_account(session):
185 session.virtualenv = False
186 configure_cloud_sdk(session, SERVICE_ACCOUNT_FILE)
187 session.env[EXPECT_PROJECT_ENV] = '1'
188 session.run('pytest', 'test_default.py')
189
190
191def session_default_cloud_sdk_authorized_user(session):
192 session.virtualenv = False
193 configure_cloud_sdk(session, AUTHORIZED_USER_FILE)
194 session.run('pytest', 'test_default.py')
195
196
197def session_default_cloud_sdk_authorized_user_configured_project(session):
198 session.virtualenv = False
199 configure_cloud_sdk(session, AUTHORIZED_USER_FILE, project=True)
200 session.env[EXPECT_PROJECT_ENV] = '1'
201 session.run('pytest', 'test_default.py')
202
203
204def session_compute_engine(session):
205 session.virtualenv = False
206 session.run('pytest', 'test_compute_engine.py')
207
208
209def session_app_engine(session):
210 session.virtualenv = False
211 session.run('pytest', 'app_engine/test_app_engine.py')