blob: 864a5be327043ed28cda21243d824b4970a8f5b3 [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
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"]
173PYTHON_VERSIONS=['2.7', '3.7']
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700174
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700175@nox.session(python=PYTHON_VERSIONS)
176def service_account(session):
177 session.install(*TEST_DEPENDENCIES)
178 session.install(LIBRARY_DIR)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700179 session.run("pytest", "test_service_account.py")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700180
181
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700182@nox.session(python=PYTHON_VERSIONS)
183def oauth2_credentials(session):
184 session.install(*TEST_DEPENDENCIES)
185 session.install(LIBRARY_DIR)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700186 session.run("pytest", "test_oauth2_credentials.py")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700187
188
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700189@nox.session(python=PYTHON_VERSIONS)
190def default_explicit_service_account(session):
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700191 session.env[EXPLICIT_CREDENTIALS_ENV] = SERVICE_ACCOUNT_FILE
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700192 session.env[EXPECT_PROJECT_ENV] = "1"
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700193 session.install(*TEST_DEPENDENCIES)
194 session.install(LIBRARY_DIR)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700195 session.run("pytest", "test_default.py")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700196
197
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700198@nox.session(python=PYTHON_VERSIONS)
199def default_explicit_authorized_user(session):
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700200 session.env[EXPLICIT_CREDENTIALS_ENV] = AUTHORIZED_USER_FILE
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_explicit_project(session):
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700208 session.env[EXPLICIT_CREDENTIALS_ENV] = AUTHORIZED_USER_FILE
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700209 session.env[EXPLICIT_PROJECT_ENV] = "example-project"
210 session.env[EXPECT_PROJECT_ENV] = "1"
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700211 session.install(*TEST_DEPENDENCIES)
212 session.install(LIBRARY_DIR)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700213 session.run("pytest", "test_default.py")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700214
215
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700216@nox.session(python=PYTHON_VERSIONS)
217def default_cloud_sdk_service_account(session):
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700218 configure_cloud_sdk(session, SERVICE_ACCOUNT_FILE)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700219 session.env[EXPECT_PROJECT_ENV] = "1"
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700220 session.install(*TEST_DEPENDENCIES)
221 session.install(LIBRARY_DIR)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700222 session.run("pytest", "test_default.py")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700223
224
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700225@nox.session(python=PYTHON_VERSIONS)
226def default_cloud_sdk_authorized_user(session):
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700227 configure_cloud_sdk(session, AUTHORIZED_USER_FILE)
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_configured_project(session):
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700235 configure_cloud_sdk(session, AUTHORIZED_USER_FILE, project=True)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700236 session.env[EXPECT_PROJECT_ENV] = "1"
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700237 session.install(*TEST_DEPENDENCIES)
238 session.install(LIBRARY_DIR)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700239 session.run("pytest", "test_default.py")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700240
241
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700242@nox.session(python=PYTHON_VERSIONS)
243def compute_engine(session):
244 session.install(*TEST_DEPENDENCIES)
245 # unset Application Default Credentials so
246 # credentials are detected from environment
247 del session.virtualenv.env["GOOGLE_APPLICATION_CREDENTIALS"]
248 session.install(LIBRARY_DIR)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700249 session.run("pytest", "test_compute_engine.py")
Jon Wayne Parrottbbc39432016-10-27 23:12:39 -0700250
251
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700252@nox.session(python=["2.7"])
253def app_engine(session):
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700254 if SKIP_GAE_TEST_ENV in os.environ:
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700255 session.log("Skipping App Engine tests.")
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700256 return
257
258 # Unlike the default tests above, the App Engine system test require a
259 # 'real' gcloud sdk installation that is configured to deploy to an
260 # app engine project.
261 # Grab the project ID from the cloud sdk.
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700262 project_id = (
263 subprocess.check_output(
264 ["gcloud", "config", "list", "project", "--format", "value(core.project)"]
265 )
266 .decode("utf-8")
267 .strip()
268 )
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700269
270 if not project_id:
271 session.error(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700272 "The Cloud SDK must be installed and configured to deploy to App " "Engine."
273 )
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700274
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700275 application_url = GAE_APP_URL_TMPL.format(GAE_TEST_APP_SERVICE, project_id)
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700276
277 # Vendor in the test application's dependencies
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700278 session.chdir(os.path.join(HERE, "app_engine_test_app"))
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700279 session.install(*TEST_DEPENDENCIES)
280 session.install(LIBRARY_DIR)
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700281 session.run(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700282 "pip", "install", "--target", "lib", "-r", "requirements.txt", silent=True
283 )
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700284
285 # Deploy the application.
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700286 session.run("gcloud", "app", "deploy", "-q", "app.yaml")
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700287
288 # Run the tests
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700289 session.env["TEST_APP_URL"] = application_url
Jon Wayne Parrottb551ef22016-10-28 12:35:15 -0700290 session.chdir(HERE)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700291 session.run("pytest", "test_app_engine.py")
Jon Wayne Parrottb9897dc2016-11-02 20:31:14 -0700292
293
Bu Sun Kim65e33c02019-10-25 10:45:00 -0700294@nox.session(python=PYTHON_VERSIONS)
295def grpc(session):
296 session.install(LIBRARY_DIR)
297 session.install(*TEST_DEPENDENCIES, "google-cloud-pubsub==1.0.0")
Jon Wayne Parrottb9897dc2016-11-02 20:31:14 -0700298 session.env[EXPLICIT_CREDENTIALS_ENV] = SERVICE_ACCOUNT_FILE
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700299 session.run("pytest", "test_grpc.py")