Skip to content

Commit e7763c3

Browse files
author
Takashi Matsuo
authored
[storage] testing: use multiple projects (#4048)
* [storage] testing: use multiple projects We still need to use the old project for some tests. fixes #4033 fixes #4029 * remove print * use uuid instead of time.time() * lint fix
1 parent 5f7b982 commit e7763c3

File tree

6 files changed

+173
-16
lines changed

6 files changed

+173
-16
lines changed

storage/cloud-client/acl_test.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import os
1516
import uuid
1617

1718
from google.cloud import storage
@@ -39,13 +40,20 @@
3940
@pytest.fixture(scope="module")
4041
def test_bucket():
4142
"""Yields a bucket that is deleted after the test completes."""
43+
44+
# The new projects have uniform bucket-level access and our tests don't
45+
# pass with those buckets. We need to use the old main project for now.
46+
original_value = os.environ['GOOGLE_CLOUD_PROJECT']
47+
os.environ['GOOGLE_CLOUD_PROJECT'] = os.environ['MAIN_GOOGLE_CLOUD_PROJECT']
4248
bucket = None
4349
while bucket is None or bucket.exists():
4450
bucket_name = "acl-test-{}".format(uuid.uuid4())
4551
bucket = storage.Client().bucket(bucket_name)
4652
bucket.create()
4753
yield bucket
4854
bucket.delete(force=True)
55+
# Set the value back.
56+
os.environ['GOOGLE_CLOUD_PROJECT'] = original_value
4957

5058

5159
@pytest.fixture

storage/cloud-client/hmac_samples_test.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,14 @@
3131
import storage_get_hmac_key
3232
import storage_list_hmac_keys
3333

34-
35-
PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"]
34+
# We are reaching maximum number of HMAC keys on the service account.
35+
# We change the service account based on the value of
36+
# RUN_TESTS_SESSION in noxfile_config.py.
37+
# The reason we can not use multiple project is that our new projects
38+
# are enforced to have
39+
# 'constraints/iam.disableServiceAccountKeyCreation' policy.
40+
41+
PROJECT_ID = os.environ["MAIN_GOOGLE_CLOUD_PROJECT"]
3642
SERVICE_ACCOUNT_EMAIL = os.environ["HMAC_KEY_TEST_SERVICE_ACCOUNT"]
3743
STORAGE_CLIENT = storage.Client(project=PROJECT_ID)
3844

storage/cloud-client/iam_test.py

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import os
1516
import re
1617
import time
1718
import uuid
@@ -36,7 +37,7 @@
3637
)
3738

3839

39-
@pytest.fixture
40+
@pytest.fixture(scope="module")
4041
def bucket():
4142
bucket = None
4243
while bucket is None or bucket.exists():
@@ -50,6 +51,26 @@ def bucket():
5051
bucket.delete(force=True)
5152

5253

54+
@pytest.fixture(scope="function")
55+
def public_bucket():
56+
# The new projects don't allow to make a bucket available to public, so
57+
# we need to use the old main project for now.
58+
original_value = os.environ['GOOGLE_CLOUD_PROJECT']
59+
os.environ['GOOGLE_CLOUD_PROJECT'] = os.environ['MAIN_GOOGLE_CLOUD_PROJECT']
60+
bucket = None
61+
while bucket is None or bucket.exists():
62+
storage_client = storage.Client()
63+
bucket_name = "test-iam-{}".format(uuid.uuid4())
64+
bucket = storage_client.bucket(bucket_name)
65+
bucket.iam_configuration.uniform_bucket_level_access_enabled = True
66+
storage_client.create_bucket(bucket)
67+
yield bucket
68+
time.sleep(3)
69+
bucket.delete(force=True)
70+
# Set the value back.
71+
os.environ['GOOGLE_CLOUD_PROJECT'] = original_value
72+
73+
5374
def test_view_bucket_iam_members(capsys, bucket):
5475
storage_view_bucket_iam_members.view_bucket_iam_members(bucket.name)
5576
assert re.match("Role: .*, Members: .*", capsys.readouterr().out)
@@ -87,10 +108,11 @@ def test_add_bucket_conditional_iam_binding(bucket):
87108
)
88109

89110

90-
def test_remove_bucket_iam_member(bucket):
91-
storage_remove_bucket_iam_member.remove_bucket_iam_member(bucket.name, ROLE, MEMBER)
111+
def test_remove_bucket_iam_member(public_bucket):
112+
storage_remove_bucket_iam_member.remove_bucket_iam_member(
113+
public_bucket.name, ROLE, MEMBER)
92114

93-
policy = bucket.get_iam_policy(requested_policy_version=3)
115+
policy = public_bucket.get_iam_policy(requested_policy_version=3)
94116
assert not any(
95117
binding["role"] == ROLE and MEMBER in binding["members"]
96118
for binding in policy.bindings
@@ -114,13 +136,13 @@ def test_remove_bucket_conditional_iam_binding(bucket):
114136
)
115137

116138

117-
def test_set_bucket_public_iam(bucket):
139+
def test_set_bucket_public_iam(public_bucket):
118140
role = "roles/storage.objectViewer"
119141
member = "allUsers"
120142
storage_set_bucket_public_iam.set_bucket_public_iam(
121-
bucket.name, role, member
143+
public_bucket.name, role, member
122144
)
123-
policy = bucket.get_iam_policy(requested_policy_version=3)
145+
policy = public_bucket.get_iam_policy(requested_policy_version=3)
124146
assert any(
125147
binding["role"] == role and member in binding["members"]
126148
for binding in policy.bindings
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Copyright 2020 Google LLC
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+
# Default TEST_CONFIG_OVERRIDE for python repos.
16+
17+
# You can copy this file into your directory, then it will be inported from
18+
# the noxfile.py.
19+
20+
# The source of truth:
21+
# https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/noxfile_config.py
22+
23+
import os
24+
25+
26+
# We are reaching maximum number of HMAC keys on the service account.
27+
# We change the service account based on the value of
28+
# RUN_TESTS_SESSION. The reason we can not use multiple project is
29+
# that our new projects are enforced to have
30+
# 'constraints/iam.disableServiceAccountKeyCreation' policy.
31+
def get_service_account_email():
32+
session = os.environ.get('RUN_TESTS_SESSION')
33+
if session == 'py-3.6':
34+
return ('py36-storage-test@'
35+
'python-docs-samples-tests.iam.gserviceaccount.com')
36+
if session == 'py-3.7':
37+
return ('py37-storage-test@'
38+
'python-docs-samples-tests.iam.gserviceaccount.com')
39+
if session == 'py-3.8':
40+
return ('py38-storage-test@'
41+
'python-docs-samples-tests.iam.gserviceaccount.com')
42+
return os.environ['HMAC_KEY_TEST_SERVICE_ACCOUNT']
43+
44+
45+
# We change the value of CLOUD_KMS_KEY based on the value of
46+
# RUN_TESTS_SESSION.
47+
def get_cloud_kms_key():
48+
session = os.environ.get('RUN_TESTS_SESSION')
49+
if session == 'py-3.6':
50+
return ('projects/python-docs-samples-tests-py36/locations/us/'
51+
'keyRings/gcs-kms-key-ring/cryptoKeys/gcs-kms-key')
52+
if session == 'py-3.7':
53+
return ('projects/python-docs-samples-tests-py37/locations/us/'
54+
'keyRings/gcs-kms-key-ring/cryptoKeys/gcs-kms-key')
55+
if session == 'py-3.8':
56+
return ('projects/python-docs-samples-tests-py38/locations/us/'
57+
'keyRings/gcs-kms-key-ring/cryptoKeys/gcs-kms-key')
58+
return os.environ['CLOUD_KMS_KEY']
59+
60+
61+
TEST_CONFIG_OVERRIDE = {
62+
# You can opt out from the test for specific Python versions.
63+
'ignored_versions': ["2.7"],
64+
65+
# An envvar key for determining the project id to use. Change it
66+
# to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a
67+
# build specific Cloud project. You can also use your own string
68+
# to use your own Cloud project.
69+
# 'gcloud_project_env': 'GOOGLE_CLOUD_PROJECT',
70+
'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT',
71+
72+
# A dictionary you want to inject into your test. Don't put any
73+
# secrets here. These values will override predefined values.
74+
'envs': {
75+
'HMAC_KEY_TEST_SERVICE_ACCOUNT': get_service_account_email(),
76+
'CLOUD_KMS_KEY': get_cloud_kms_key(),
77+
# Some tests can not use multiple projects because of several reasons:
78+
# 1. The new projects is enforced to have the
79+
# 'constraints/iam.disableServiceAccountKeyCreation' policy.
80+
# 2. The new projects buckets need to have universal permission model.
81+
# For those tests, we'll use the original project.
82+
'MAIN_GOOGLE_CLOUD_PROJECT': 'python-docs-samples-tests'
83+
},
84+
}

storage/cloud-client/snippets_test.py

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,24 @@ def test_bucket():
105105
bucket.delete(force=True)
106106

107107

108+
@pytest.fixture(scope="function")
109+
def test_public_bucket():
110+
# The new projects don't allow to make a bucket available to public, so
111+
# for some tests we need to use the old main project for now.
112+
original_value = os.environ['GOOGLE_CLOUD_PROJECT']
113+
os.environ['GOOGLE_CLOUD_PROJECT'] = os.environ['MAIN_GOOGLE_CLOUD_PROJECT']
114+
bucket = None
115+
while bucket is None or bucket.exists():
116+
storage_client = storage.Client()
117+
bucket_name = "storage-snippets-test-{}".format(uuid.uuid4())
118+
bucket = storage_client.bucket(bucket_name)
119+
storage_client.create_bucket(bucket)
120+
yield bucket
121+
bucket.delete(force=True)
122+
# Set the value back.
123+
os.environ['GOOGLE_CLOUD_PROJECT'] = original_value
124+
125+
108126
@pytest.fixture
109127
def test_blob(test_bucket):
110128
"""Yields a blob that is deleted after the test completes."""
@@ -114,6 +132,15 @@ def test_blob(test_bucket):
114132
yield blob
115133

116134

135+
@pytest.fixture(scope="function")
136+
def test_public_blob(test_public_bucket):
137+
"""Yields a blob that is deleted after the test completes."""
138+
bucket = test_public_bucket
139+
blob = bucket.blob("storage_snippets_test_sigil-{}".format(uuid.uuid4()))
140+
blob.upload_from_string("Hello, is it me you're looking for?")
141+
yield blob
142+
143+
117144
@pytest.fixture
118145
def test_bucket_create():
119146
"""Yields a bucket object that is deleted after the test completes."""
@@ -196,10 +223,11 @@ def test_delete_blob(test_blob):
196223
storage_delete_file.delete_blob(test_blob.bucket.name, test_blob.name)
197224

198225

199-
def test_make_blob_public(test_blob):
200-
storage_make_public.make_blob_public(test_blob.bucket.name, test_blob.name)
226+
def test_make_blob_public(test_public_blob):
227+
storage_make_public.make_blob_public(
228+
test_public_blob.bucket.name, test_public_blob.name)
201229

202-
r = requests.get(test_blob.public_url)
230+
r = requests.get(test_public_blob.public_url)
203231
assert r.text == "Hello, is it me you're looking for?"
204232

205233

@@ -342,11 +370,12 @@ def test_get_service_account(capsys):
342370
assert "@gs-project-accounts.iam.gserviceaccount.com" in out
343371

344372

345-
def test_download_public_file(test_blob):
346-
storage_make_public.make_blob_public(test_blob.bucket.name, test_blob.name)
373+
def test_download_public_file(test_public_blob):
374+
storage_make_public.make_blob_public(
375+
test_public_blob.bucket.name, test_public_blob.name)
347376
with tempfile.NamedTemporaryFile() as dest_file:
348377
storage_download_public_file.download_public_file(
349-
test_blob.bucket.name, test_blob.name, dest_file.name
378+
test_public_blob.bucket.name, test_public_blob.name, dest_file.name
350379
)
351380

352381
assert dest_file.read() == b"Hello, is it me you're looking for?"

storage/cloud-client/uniform_bucket_level_access_test.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import os
1516
import time
17+
import uuid
1618

1719
from google.cloud import storage
1820
import pytest
@@ -25,14 +27,20 @@
2527
@pytest.fixture()
2628
def bucket():
2729
"""Yields a bucket that is deleted after the test completes."""
30+
# The new projects enforces uniform bucket level access, so
31+
# we need to use the old main project for now.
32+
original_value = os.environ['GOOGLE_CLOUD_PROJECT']
33+
os.environ['GOOGLE_CLOUD_PROJECT'] = os.environ['MAIN_GOOGLE_CLOUD_PROJECT']
2834
bucket = None
2935
while bucket is None or bucket.exists():
30-
bucket_name = "uniform-bucket-level-access-{}".format(int(time.time()))
36+
bucket_name = "uniform-bucket-level-access-{}".format(uuid.uuid4().hex)
3137
bucket = storage.Client().bucket(bucket_name)
3238
bucket.create()
3339
yield bucket
3440
time.sleep(3)
3541
bucket.delete(force=True)
42+
# Set the value back.
43+
os.environ['GOOGLE_CLOUD_PROJECT'] = original_value
3644

3745

3846
def test_get_uniform_bucket_level_access(bucket, capsys):

0 commit comments

Comments
 (0)