Skip to content

Commit 0c85f7b

Browse files
authored
Fix: Retry CLI launch if needed (#8221)
* Fix: add region tags * Fix: region tag typos * Fix: urlpatterns moved to end * Fix: typo * Fix: cli retries to fix flakiness * Fix: remove duplicate tags * Fix: use backoff for retries * Fix: lint import order error
1 parent 2afd6c9 commit 0c85f7b

File tree

18 files changed

+331
-200
lines changed

18 files changed

+331
-200
lines changed

appengine/standard_python3/bundled-services/blobstore/django/main_test.py

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,38 +17,55 @@
1717
import subprocess
1818
import uuid
1919

20+
import backoff
2021
import pytest
2122
import requests
2223

2324

24-
@pytest.fixture
25-
def version():
26-
"""Launch a new version of the app for testing, and yield the
27-
project and version number so tests can invoke it, then delete it.
25+
@backoff.on_exception(backoff.expo, Exception, max_tries=3)
26+
def gcloud_cli(command):
2827
"""
28+
Runs the gcloud CLI with given options, parses the json formatted output
29+
and returns the resulting Python object.
30+
31+
Usage: gcloud_cli(options)
32+
options: command line options
33+
34+
Example:
35+
result = gcloud_cli("app deploy --no-promote")
36+
print(f"Deployed version {result['versions'][0]['id']}")
2937
38+
Raises Exception with the stderr output of the last attempt on failure.
39+
"""
3040
output = subprocess.run(
31-
f"gcloud app deploy --no-promote --quiet --format=json --version={uuid.uuid4().hex}",
41+
f"gcloud {command} --quiet --format=json",
3242
capture_output=True,
3343
shell=True,
44+
check=True,
3445
)
35-
3646
try:
37-
result = json.loads(output.stdout)
38-
version_id = result["versions"][0]["id"]
39-
project_id = result["versions"][0]["project"]
40-
except Exception as e:
41-
print(f"New version deployment output not usable: {e}")
42-
print(f"Command stderr is '{output.stderr}'")
43-
raise ValueError
47+
entries = json.loads(output.stdout)
48+
return entries
49+
except Exception:
50+
print("Failed to read log")
51+
print(f"gcloud stderr was {output.stderr}")
52+
53+
raise Exception(output.stderr)
54+
55+
56+
@pytest.fixture
57+
def version():
58+
"""Launch a new version of the app for testing, and yield the
59+
project and version number so tests can invoke it, then delete it.
60+
"""
61+
62+
result = gcloud_cli(f"app deploy --no-promote --version={uuid.uuid4().hex}")
63+
version_id = result["versions"][0]["id"]
64+
project_id = result["versions"][0]["project"]
4465

4566
yield project_id, version_id
4667

47-
output = subprocess.run(
48-
f"gcloud app versions delete {version_id}",
49-
capture_output=True,
50-
shell=True,
51-
)
68+
gcloud_cli(f"app versions delete {version_id}")
5269

5370

5471
def test_upload_and_view(version):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
backoff==2.1.2
12
pytest==7.1.2
23
requests==2.28.1

appengine/standard_python3/bundled-services/blobstore/flask/main_test.py

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,42 +17,55 @@
1717
import subprocess
1818
import uuid
1919

20+
import backoff
2021
import pytest
2122
import requests
2223

2324

24-
@pytest.fixture
25-
def version():
26-
"""Launch a new version of the app for testing, and yield the
27-
project and version number so tests can invoke it, then delete it.
25+
@backoff.on_exception(backoff.expo, Exception, max_tries=3)
26+
def gcloud_cli(command):
2827
"""
28+
Runs the gcloud CLI with given options, parses the json formatted output
29+
and returns the resulting Python object.
30+
31+
Usage: gcloud_cli(options)
32+
options: command line options
2933
30-
debug_output = subprocess.run("gcloud config list", capture_output=True, shell=True)
31-
print(f"Debug stdout of list is {debug_output.stdout}")
32-
print(f"Debug stderr of list is {debug_output.stderr}")
34+
Example:
35+
result = gcloud_cli("app deploy --no-promote")
36+
print(f"Deployed version {result['versions'][0]['id']}")
3337
38+
Raises Exception with the stderr output of the last attempt on failure.
39+
"""
3440
output = subprocess.run(
35-
f"gcloud app deploy --no-promote --quiet --format=json --version={uuid.uuid4().hex}",
41+
f"gcloud {command} --quiet --format=json",
3642
capture_output=True,
3743
shell=True,
44+
check=True,
3845
)
39-
4046
try:
41-
result = json.loads(output.stdout)
42-
version_id = result["versions"][0]["id"]
43-
project_id = result["versions"][0]["project"]
44-
except Exception as e:
45-
print(f"New version deployment output not usable: {e}")
46-
print(f"Command stderr is '{output.stderr}'")
47-
raise ValueError
47+
entries = json.loads(output.stdout)
48+
return entries
49+
except Exception:
50+
print("Failed to read log")
51+
print(f"gcloud stderr was {output.stderr}")
52+
53+
raise Exception(output.stderr)
54+
55+
56+
@pytest.fixture
57+
def version():
58+
"""Launch a new version of the app for testing, and yield the
59+
project and version number so tests can invoke it, then delete it.
60+
"""
61+
62+
result = gcloud_cli(f"app deploy --no-promote --version={uuid.uuid4().hex}")
63+
version_id = result["versions"][0]["id"]
64+
project_id = result["versions"][0]["project"]
4865

4966
yield project_id, version_id
5067

51-
output = subprocess.run(
52-
f"gcloud app versions delete {version_id}",
53-
capture_output=True,
54-
shell=True,
55-
)
68+
gcloud_cli(f"app versions delete {version_id}")
5669

5770

5871
def test_upload_and_view(version):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
backoff==2.1.2
12
pytest==7.1.2
23
requests==2.28.1

appengine/standard_python3/bundled-services/blobstore/wsgi/main_test.py

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,38 +17,55 @@
1717
import subprocess
1818
import uuid
1919

20+
import backoff
2021
import pytest
2122
import requests
2223

2324

24-
@pytest.fixture
25-
def version():
26-
"""Launch a new version of the app for testing, and yield the
27-
project and version number so tests can invoke it, then delete it.
25+
@backoff.on_exception(backoff.expo, Exception, max_tries=3)
26+
def gcloud_cli(command):
2827
"""
28+
Runs the gcloud CLI with given options, parses the json formatted output
29+
and returns the resulting Python object.
30+
31+
Usage: gcloud_cli(options)
32+
options: command line options
33+
34+
Example:
35+
result = gcloud_cli("app deploy --no-promote")
36+
print(f"Deployed version {result['versions'][0]['id']}")
2937
38+
Raises Exception with the stderr output of the last attempt on failure.
39+
"""
3040
output = subprocess.run(
31-
f"gcloud app deploy --no-promote --quiet --format=json --version={uuid.uuid4().hex}",
41+
f"gcloud {command} --quiet --format=json",
3242
capture_output=True,
3343
shell=True,
44+
check=True,
3445
)
35-
3646
try:
37-
result = json.loads(output.stdout)
38-
version_id = result["versions"][0]["id"]
39-
project_id = result["versions"][0]["project"]
40-
except Exception as e:
41-
print(f"New version deployment output not usable: {e}")
42-
print(f"Command stderr is '{output.stderr}'")
43-
raise ValueError
47+
entries = json.loads(output.stdout)
48+
return entries
49+
except Exception:
50+
print("Failed to read log")
51+
print(f"gcloud stderr was {output.stderr}")
52+
53+
raise Exception(output.stderr)
54+
55+
56+
@pytest.fixture
57+
def version():
58+
"""Launch a new version of the app for testing, and yield the
59+
project and version number so tests can invoke it, then delete it.
60+
"""
61+
62+
result = gcloud_cli(f"app deploy --no-promote --version={uuid.uuid4().hex}")
63+
version_id = result["versions"][0]["id"]
64+
project_id = result["versions"][0]["project"]
4465

4566
yield project_id, version_id
4667

47-
output = subprocess.run(
48-
f"gcloud app versions delete {version_id}",
49-
capture_output=True,
50-
shell=True,
51-
)
68+
gcloud_cli(f"app versions delete {version_id}")
5269

5370

5471
def test_upload_and_view(version):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
backoff==2.1.2
12
pytest==7.1.2
23
requests==2.28.1

appengine/standard_python3/bundled-services/deferred/django/main_test.py

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,38 +17,55 @@
1717
import time
1818
import uuid
1919

20+
import backoff
2021
import pytest
2122
import requests
2223

2324

24-
@pytest.fixture
25-
def version():
26-
"""Launch a new version of the app for testing, and yield the
27-
project and version number so tests can invoke it, then delete it.
25+
@backoff.on_exception(backoff.expo, Exception, max_tries=3)
26+
def gcloud_cli(command):
2827
"""
28+
Runs the gcloud CLI with given options, parses the json formatted output
29+
and returns the resulting Python object.
30+
31+
Usage: gcloud_cli(options)
32+
options: command line options
33+
34+
Example:
35+
result = gcloud_cli("app deploy --no-promote")
36+
print(f"Deployed version {result['versions'][0]['id']}")
2937
38+
Raises Exception with the stderr output of the last attempt on failure.
39+
"""
3040
output = subprocess.run(
31-
f"gcloud app deploy --no-promote --quiet --format=json --version={uuid.uuid4().hex}",
41+
f"gcloud {command} --quiet --format=json",
3242
capture_output=True,
3343
shell=True,
44+
check=True,
3445
)
35-
3646
try:
37-
result = json.loads(output.stdout)
38-
version_id = result["versions"][0]["id"]
39-
project_id = result["versions"][0]["project"]
40-
except Exception as e:
41-
print(f"New version deployment output not usable: {e}")
42-
print(f"Command stderr is '{output.stderr}'")
43-
raise ValueError
47+
entries = json.loads(output.stdout)
48+
return entries
49+
except Exception:
50+
print("Failed to read log")
51+
print(f"gcloud stderr was {output.stderr}")
52+
53+
raise Exception(output.stderr)
54+
55+
56+
@pytest.fixture
57+
def version():
58+
"""Launch a new version of the app for testing, and yield the
59+
project and version number so tests can invoke it, then delete it.
60+
"""
61+
62+
result = gcloud_cli(f"app deploy --no-promote --version={uuid.uuid4().hex}")
63+
version_id = result["versions"][0]["id"]
64+
project_id = result["versions"][0]["project"]
4465

4566
yield project_id, version_id
4667

47-
output = subprocess.run(
48-
f"gcloud app versions delete {version_id}",
49-
capture_output=True,
50-
shell=True,
51-
)
68+
gcloud_cli(f"app versions delete {version_id}")
5269

5370

5471
def test_upload_and_view(version):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
backoff==2.1.2
12
pytest==7.1.2
23
requests==2.28.1

appengine/standard_python3/bundled-services/deferred/flask/main_test.py

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,38 +17,55 @@
1717
import time
1818
import uuid
1919

20+
import backoff
2021
import pytest
2122
import requests
2223

2324

24-
@pytest.fixture
25-
def version():
26-
"""Launch a new version of the app for testing, and yield the
27-
project and version number so tests can invoke it, then delete it.
25+
@backoff.on_exception(backoff.expo, Exception, max_tries=3)
26+
def gcloud_cli(command):
2827
"""
28+
Runs the gcloud CLI with given options, parses the json formatted output
29+
and returns the resulting Python object.
30+
31+
Usage: gcloud_cli(options)
32+
options: command line options
33+
34+
Example:
35+
result = gcloud_cli("app deploy --no-promote")
36+
print(f"Deployed version {result['versions'][0]['id']}")
2937
38+
Raises Exception with the stderr output of the last attempt on failure.
39+
"""
3040
output = subprocess.run(
31-
f"gcloud app deploy --no-promote --quiet --format=json --version={uuid.uuid4().hex}",
41+
f"gcloud {command} --quiet --format=json",
3242
capture_output=True,
3343
shell=True,
44+
check=True,
3445
)
35-
3646
try:
37-
result = json.loads(output.stdout)
38-
version_id = result["versions"][0]["id"]
39-
project_id = result["versions"][0]["project"]
40-
except Exception as e:
41-
print(f"New version deployment output not usable: {e}")
42-
print(f"Command stderr is '{output.stderr}'")
43-
raise ValueError
47+
entries = json.loads(output.stdout)
48+
return entries
49+
except Exception:
50+
print("Failed to read log")
51+
print(f"gcloud stderr was {output.stderr}")
52+
53+
raise Exception(output.stderr)
54+
55+
56+
@pytest.fixture
57+
def version():
58+
"""Launch a new version of the app for testing, and yield the
59+
project and version number so tests can invoke it, then delete it.
60+
"""
61+
62+
result = gcloud_cli(f"app deploy --no-promote --version={uuid.uuid4().hex}")
63+
version_id = result["versions"][0]["id"]
64+
project_id = result["versions"][0]["project"]
4465

4566
yield project_id, version_id
4667

47-
output = subprocess.run(
48-
f"gcloud app versions delete {version_id}",
49-
capture_output=True,
50-
shell=True,
51-
)
68+
gcloud_cli(f"app versions delete {version_id}")
5269

5370

5471
def test_upload_and_view(version):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
backoff==2.1.2
12
pytest==7.1.2
23
requests==2.28.1

0 commit comments

Comments
 (0)