blob: 6e66eb4ed211766c515a17a93bf38bebc9fb7123 [file] [log] [blame]
C.J. Collier37141e42020-02-13 13:49:49 -08001# Copyright 2016 Google LLC
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -07002#
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
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -070026import subprocess
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -070027
28from nox.command import which
Bu Sun Kim65e33c02019-10-25 10:45:00 -070029import nox
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -070030import py.path
31
32
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -070033HERE = os.path.abspath(os.path.dirname(__file__))
Bu Sun Kim65e33c02019-10-25 10:45:00 -070034LIBRARY_DIR = os.path.join(HERE, "..")
Bu Sun Kim9eec0912019-10-21 17:04:21 -070035DATA_DIR = os.path.join(HERE, "data")
36SERVICE_ACCOUNT_FILE = os.path.join(DATA_DIR, "service_account.json")
37AUTHORIZED_USER_FILE = os.path.join(DATA_DIR, "authorized_user.json")
38EXPLICIT_CREDENTIALS_ENV = "GOOGLE_APPLICATION_CREDENTIALS"
39EXPLICIT_PROJECT_ENV = "GOOGLE_CLOUD_PROJECT"
40EXPECT_PROJECT_ENV = "EXPECT_PROJECT_ID"
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -070041
Bu Sun Kim9eec0912019-10-21 17:04:21 -070042SKIP_GAE_TEST_ENV = "SKIP_APP_ENGINE_SYSTEM_TEST"
43GAE_APP_URL_TMPL = "https://{}-dot-{}.appspot.com"
44GAE_TEST_APP_SERVICE = "google-auth-system-tests"
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -070045
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -070046# The download location for the Cloud SDK
Bu Sun Kim9eec0912019-10-21 17:04:21 -070047CLOUD_SDK_DIST_FILENAME = "google-cloud-sdk.tar.gz"
48CLOUD_SDK_DOWNLOAD_URL = "https://dl.google.com/dl/cloudsdk/release/{}".format(
49 CLOUD_SDK_DIST_FILENAME
50)
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -070051
52# This environment variable is recognized by the Cloud SDK and overrides
53# the location of the SDK's configuration files (which is usually at
54# ${HOME}/.config).
Bu Sun Kim9eec0912019-10-21 17:04:21 -070055CLOUD_SDK_CONFIG_ENV = "CLOUDSDK_CONFIG"
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -070056
57# If set, this is where the environment setup will install the Cloud SDK.
58# If unset, it will download the SDK to a temporary directory.
Bu Sun Kim9eec0912019-10-21 17:04:21 -070059CLOUD_SDK_ROOT = os.environ.get("CLOUD_SDK_ROOT")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -070060
61if CLOUD_SDK_ROOT is not None:
62 CLOUD_SDK_ROOT = py.path.local(CLOUD_SDK_ROOT)
63 CLOUD_SDK_ROOT.ensure(dir=True) # Makes sure the directory exists.
64else:
65 CLOUD_SDK_ROOT = py.path.local.mkdtemp()
66
67# The full path the cloud sdk install directory
Bu Sun Kim9eec0912019-10-21 17:04:21 -070068CLOUD_SDK_INSTALL_DIR = CLOUD_SDK_ROOT.join("google-cloud-sdk")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -070069
70# The full path to the gcloud cli executable.
Bu Sun Kim9eec0912019-10-21 17:04:21 -070071GCLOUD = str(CLOUD_SDK_INSTALL_DIR.join("bin", "gcloud"))
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -070072
73# gcloud requires Python 2 and doesn't work on 3, so we need to tell it
74# where to find 2 when we're running in a 3 environment.
Bu Sun Kim9eec0912019-10-21 17:04:21 -070075CLOUD_SDK_PYTHON_ENV = "CLOUDSDK_PYTHON"
76CLOUD_SDK_PYTHON = which("python2", None)
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -070077
78# Cloud SDK helpers
79
80
81def install_cloud_sdk(session):
82 """Downloads and installs the Google Cloud SDK."""
83 # Configure environment variables needed by the SDK.
84 # This sets the config root to the tests' config root. This prevents
85 # our tests from clobbering a developer's configuration when running
86 # these tests locally.
87 session.env[CLOUD_SDK_CONFIG_ENV] = str(CLOUD_SDK_ROOT)
88 # This tells gcloud which Python interpreter to use (always use 2.7)
89 session.env[CLOUD_SDK_PYTHON_ENV] = CLOUD_SDK_PYTHON
Jon Wayne Parrott0c09c732017-03-24 12:10:44 -070090 # This set the $PATH for the subprocesses so they can find the gcloud
91 # executable.
Bu Sun Kim9eec0912019-10-21 17:04:21 -070092 session.env["PATH"] = (
93 str(CLOUD_SDK_INSTALL_DIR.join("bin")) + os.pathsep + os.environ["PATH"]
94 )
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -070095
Jon Wayne Parrott87161412017-03-01 09:28:15 -080096 # If gcloud cli executable already exists, just update it.
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -070097 if py.path.local(GCLOUD).exists():
Bu Sun Kim9eec0912019-10-21 17:04:21 -070098 session.run(GCLOUD, "components", "update", "-q")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -070099 return
100
101 tar_path = CLOUD_SDK_ROOT.join(CLOUD_SDK_DIST_FILENAME)
102
103 # Download the release.
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700104 session.run("wget", CLOUD_SDK_DOWNLOAD_URL, "-O", str(tar_path), silent=True)
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700105
106 # Extract the release.
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700107 session.run("tar", "xzf", str(tar_path), "-C", str(CLOUD_SDK_ROOT))
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700108 session.run(tar_path.remove)
109
110 # Run the install script.
111 session.run(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700112 str(CLOUD_SDK_INSTALL_DIR.join("install.sh")),
113 "--usage-reporting",
114 "false",
115 "--path-update",
116 "false",
117 "--command-completion",
118 "false",
119 silent=True,
120 )
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700121
122
123def copy_credentials(credentials_path):
124 """Copies credentials into the SDK root as the application default
125 credentials."""
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700126 dest = CLOUD_SDK_ROOT.join("application_default_credentials.json")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700127 if dest.exists():
128 dest.remove()
129 py.path.local(credentials_path).copy(dest)
130
131
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700132def configure_cloud_sdk(session, application_default_credentials, project=False):
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700133 """Installs and configures the Cloud SDK with the given application default
134 credentials.
135
136 If project is True, then a project will be set in the active config.
137 If it is false, this will ensure no project is set.
138 """
139 install_cloud_sdk(session)
140
Jon Wayne Parrott0c09c732017-03-24 12:10:44 -0700141 # Setup the service account as the default user account. This is
142 # needed for the project ID detection to work. Note that this doesn't
143 # change the application default credentials file, which is user
144 # credentials instead of service account credentials sometimes.
145 session.run(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700146 GCLOUD, "auth", "activate-service-account", "--key-file", SERVICE_ACCOUNT_FILE
147 )
Jon Wayne Parrott0c09c732017-03-24 12:10:44 -0700148
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700149 if project:
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700150 session.run(GCLOUD, "config", "set", "project", "example-project")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700151 else:
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700152 session.run(GCLOUD, "config", "unset", "project")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700153
154 # Copy the credentials file to the config root. This is needed because
155 # unfortunately gcloud doesn't provide a clean way to tell it to use
156 # a particular set of credentials. However, this does verify that gcloud
157 # also considers the credentials valid by calling application-default
158 # print-access-token
159 session.run(copy_credentials, application_default_credentials)
160
161 # Calling this forces the Cloud SDK to read the credentials we just wrote
162 # and obtain a new access token with those credentials. This validates
163 # that our credentials matches the format expected by gcloud.
164 # Silent is set to True to prevent leaking secrets in test logs.
165 session.run(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700166 GCLOUD, "auth", "application-default", "print-access-token", silent=True
167 )
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700168
169
170# Test sesssions
171
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700172TEST_DEPENDENCIES = ["pytest", "requests"]
Bu Sun Kim82e224b2020-03-13 13:21:18 -0700173PYTHON_VERSIONS = ["2.7", "3.7"]
174
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700175
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700176@nox.session(python=PYTHON_VERSIONS)
177def service_account(session):
178 session.install(*TEST_DEPENDENCIES)
179 session.install(LIBRARY_DIR)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700180 session.run("pytest", "test_service_account.py")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700181
182
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700183@nox.session(python=PYTHON_VERSIONS)
184def oauth2_credentials(session):
185 session.install(*TEST_DEPENDENCIES)
186 session.install(LIBRARY_DIR)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700187 session.run("pytest", "test_oauth2_credentials.py")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700188
189
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700190@nox.session(python=PYTHON_VERSIONS)
Bu Sun Kim82e224b2020-03-13 13:21:18 -0700191def impersonated_credentials(session):
192 session.install(*TEST_DEPENDENCIES)
193 session.install(LIBRARY_DIR)
194 session.run("pytest", "test_impersonated_credentials.py")
195
196
197@nox.session(python=PYTHON_VERSIONS)
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700198def default_explicit_service_account(session):
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700199 session.env[EXPLICIT_CREDENTIALS_ENV] = SERVICE_ACCOUNT_FILE
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700200 session.env[EXPECT_PROJECT_ENV] = "1"
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700201 session.install(*TEST_DEPENDENCIES)
202 session.install(LIBRARY_DIR)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700203 session.run("pytest", "test_default.py")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700204
205
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700206@nox.session(python=PYTHON_VERSIONS)
207def default_explicit_authorized_user(session):
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700208 session.env[EXPLICIT_CREDENTIALS_ENV] = AUTHORIZED_USER_FILE
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700209 session.install(*TEST_DEPENDENCIES)
210 session.install(LIBRARY_DIR)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700211 session.run("pytest", "test_default.py")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700212
213
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700214@nox.session(python=PYTHON_VERSIONS)
215def default_explicit_authorized_user_explicit_project(session):
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700216 session.env[EXPLICIT_CREDENTIALS_ENV] = AUTHORIZED_USER_FILE
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700217 session.env[EXPLICIT_PROJECT_ENV] = "example-project"
218 session.env[EXPECT_PROJECT_ENV] = "1"
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700219 session.install(*TEST_DEPENDENCIES)
220 session.install(LIBRARY_DIR)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700221 session.run("pytest", "test_default.py")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700222
223
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700224@nox.session(python=PYTHON_VERSIONS)
225def default_cloud_sdk_service_account(session):
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700226 configure_cloud_sdk(session, SERVICE_ACCOUNT_FILE)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700227 session.env[EXPECT_PROJECT_ENV] = "1"
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700228 session.install(*TEST_DEPENDENCIES)
229 session.install(LIBRARY_DIR)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700230 session.run("pytest", "test_default.py")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700231
232
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700233@nox.session(python=PYTHON_VERSIONS)
234def default_cloud_sdk_authorized_user(session):
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700235 configure_cloud_sdk(session, AUTHORIZED_USER_FILE)
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700236 session.install(*TEST_DEPENDENCIES)
237 session.install(LIBRARY_DIR)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700238 session.run("pytest", "test_default.py")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700239
240
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700241@nox.session(python=PYTHON_VERSIONS)
242def default_cloud_sdk_authorized_user_configured_project(session):
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700243 configure_cloud_sdk(session, AUTHORIZED_USER_FILE, project=True)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700244 session.env[EXPECT_PROJECT_ENV] = "1"
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700245 session.install(*TEST_DEPENDENCIES)
246 session.install(LIBRARY_DIR)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700247 session.run("pytest", "test_default.py")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700248
249
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700250@nox.session(python=PYTHON_VERSIONS)
251def compute_engine(session):
252 session.install(*TEST_DEPENDENCIES)
253 # unset Application Default Credentials so
254 # credentials are detected from environment
255 del session.virtualenv.env["GOOGLE_APPLICATION_CREDENTIALS"]
256 session.install(LIBRARY_DIR)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700257 session.run("pytest", "test_compute_engine.py")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700258
259
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700260@nox.session(python=["2.7"])
261def app_engine(session):
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700262 if SKIP_GAE_TEST_ENV in os.environ:
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700263 session.log("Skipping App Engine tests.")
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700264 return
265
266 # Unlike the default tests above, the App Engine system test require a
267 # 'real' gcloud sdk installation that is configured to deploy to an
268 # app engine project.
269 # Grab the project ID from the cloud sdk.
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700270 project_id = (
271 subprocess.check_output(
272 ["gcloud", "config", "list", "project", "--format", "value(core.project)"]
273 )
274 .decode("utf-8")
275 .strip()
276 )
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700277
278 if not project_id:
279 session.error(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700280 "The Cloud SDK must be installed and configured to deploy to App " "Engine."
281 )
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700282
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700283 application_url = GAE_APP_URL_TMPL.format(GAE_TEST_APP_SERVICE, project_id)
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700284
285 # Vendor in the test application's dependencies
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700286 session.chdir(os.path.join(HERE, "app_engine_test_app"))
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700287 session.install(*TEST_DEPENDENCIES)
288 session.install(LIBRARY_DIR)
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700289 session.run(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700290 "pip", "install", "--target", "lib", "-r", "requirements.txt", silent=True
291 )
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700292
293 # Deploy the application.
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700294 session.run("gcloud", "app", "deploy", "-q", "app.yaml")
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700295
296 # Run the tests
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700297 session.env["TEST_APP_URL"] = application_url
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700298 session.chdir(HERE)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700299 session.run("pytest", "test_app_engine.py")
Jon Wayne Parrottb9897dc2016-11-02 20:31:14 -0700300
301
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700302@nox.session(python=PYTHON_VERSIONS)
303def grpc(session):
304 session.install(LIBRARY_DIR)
305 session.install(*TEST_DEPENDENCIES, "google-cloud-pubsub==1.0.0")
Jon Wayne Parrottb9897dc2016-11-02 20:31:14 -0700306 session.env[EXPLICIT_CREDENTIALS_ENV] = SERVICE_ACCOUNT_FILE
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700307 session.run("pytest", "test_grpc.py")
arithmetic1728bb9215a2020-03-20 09:49:44 -0700308
309
310@nox.session(python=PYTHON_VERSIONS)
311def mtls_http(session):
312 session.install(LIBRARY_DIR)
313 session.install(*TEST_DEPENDENCIES, "pyopenssl")
314 session.env[EXPLICIT_CREDENTIALS_ENV] = SERVICE_ACCOUNT_FILE
315 session.run("pytest", "test_mtls_http.py")