1313# limitations under the License.
1414
1515from __future__ import absolute_import
16+ from concurrent .futures import ThreadPoolExecutor
1617from pathlib import Path
1718import os
1819import sys
2930ADS_TEMPLATES = path .join (path .dirname (__file__ ), "gapic" , "ads-templates" )
3031
3132
32- @nox .session (python = ["3.6" , "3.7" , "3.8" , "3.9" , "3.10" ])
33+ ALL_PYTHON = (
34+ "3.6" ,
35+ "3.7" ,
36+ "3.8" ,
37+ "3.9" ,
38+ )
39+
40+ NEWEST_PYTHON = "3.9"
41+
42+
43+ @nox .session (python = ALL_PYTHON )
3344def unit (session ):
3445 """Run the unit test suite."""
3546
@@ -50,11 +61,89 @@ def unit(session):
5061 "--cov-report=term" ,
5162 "--cov-fail-under=100" ,
5263 path .join ("tests" , "unit" ),
53- ]
64+ ]
5465 ),
5566 )
5667
5768
69+ FRAG_DIR = Path ("tests" ) / "fragments"
70+ FRAGMENT_FILES = tuple (
71+ Path (dirname ).relative_to (FRAG_DIR ) / f
72+ for dirname , _ , files in os .walk (FRAG_DIR )
73+ for f in files
74+ if os .path .splitext (f )[1 ] == ".proto" and f .startswith ("test_" )
75+ )
76+
77+ # Note: this class lives outside 'fragment'
78+ # so that, if necessary, it can be pickled for a ProcessPoolExecutor
79+ # A callable class is necessary so that the session can be closed over
80+ # instead of passed in, which simplifies the invocation via map.
81+ class FragTester :
82+ def __init__ (self , session ):
83+ self .session = session
84+
85+ def __call__ (self , frag ):
86+ with tempfile .TemporaryDirectory () as tmp_dir :
87+ # Generate the fragment GAPIC.
88+ outputs = []
89+ outputs .append (
90+ self .session .run (
91+ "python" ,
92+ "-m" ,
93+ "grpc_tools.protoc" ,
94+ f"--proto_path={ str (FRAG_DIR )} " ,
95+ f"--python_gapic_out={ tmp_dir } " ,
96+ "--python_gapic_opt=transport=grpc+rest" ,
97+ str (frag ),
98+ external = True ,
99+ silent = True ,
100+ )
101+ )
102+
103+ # Install the generated fragment library.
104+ # Note: install into the tempdir to prevent issues
105+ # with running pip concurrently.
106+ self .session .install (tmp_dir , "-e" , "." , "-t" , tmp_dir , "-qqq" )
107+
108+ # Run the fragment's generated unit tests.
109+ # Don't bother parallelizing them: we already parallelize
110+ # the fragments, and there usually aren't too many tests per fragment.
111+ outputs .append (
112+ self .session .run (
113+ "py.test" ,
114+ "--quiet" ,
115+ f"--cov-config={ str (Path (tmp_dir ) / '.coveragerc' )} " ,
116+ "--cov-report=term" ,
117+ "--cov-fail-under=100" ,
118+ str (Path (tmp_dir ) / "tests" / "unit" ),
119+ silent = True ,
120+ )
121+ )
122+
123+ return "" .join (outputs )
124+
125+
126+ # TODO(dovs): ads templates
127+ @nox .session (python = ALL_PYTHON )
128+ def fragment (session ):
129+ session .install (
130+ "coverage" ,
131+ "pytest" ,
132+ "pytest-cov" ,
133+ "pytest-xdist" ,
134+ "asyncmock" ,
135+ "pytest-asyncio" ,
136+ "grpcio-tools" ,
137+ )
138+ session .install ("-e" , "." )
139+
140+ with ThreadPoolExecutor () as p :
141+ all_outs = p .map (FragTester (session ), FRAGMENT_FILES )
142+
143+ output = "" .join (all_outs )
144+ session .log (output )
145+
146+
58147# TODO(yon-mg): -add compute context manager that includes rest transport
59148# -add compute unit tests
60149# (to test against temporarily while rest transport is incomplete)
@@ -114,8 +203,7 @@ def showcase_library(
114203 f"google/showcase/v1beta1/messaging.proto" ,
115204 )
116205 session .run (
117- * cmd_tup ,
118- external = True ,
206+ * cmd_tup , external = True ,
119207 )
120208
121209 # Install the library.
@@ -124,7 +212,7 @@ def showcase_library(
124212 yield tmp_dir
125213
126214
127- @nox .session (python = "3.9" )
215+ @nox .session (python = NEWEST_PYTHON )
128216def showcase (
129217 session ,
130218 templates = "DEFAULT" ,
@@ -136,12 +224,14 @@ def showcase(
136224 with showcase_library (session , templates = templates , other_opts = other_opts ):
137225 session .install ("mock" , "pytest" , "pytest-asyncio" )
138226 session .run (
139- "py.test" , "--quiet" , * (session .posargs or [path .join ("tests" , "system" )]),
227+ "py.test" ,
228+ "--quiet" ,
229+ * (session .posargs or [path .join ("tests" , "system" )]),
140230 env = env ,
141231 )
142232
143233
144- @nox .session (python = "3.9" )
234+ @nox .session (python = NEWEST_PYTHON )
145235def showcase_mtls (
146236 session ,
147237 templates = "DEFAULT" ,
@@ -161,7 +251,7 @@ def showcase_mtls(
161251 )
162252
163253
164- @nox .session (python = "3.9" )
254+ @nox .session (python = NEWEST_PYTHON )
165255def showcase_alternative_templates (session ):
166256 templates = path .join (path .dirname (__file__ ), "gapic" , "ads-templates" )
167257 showcase (
@@ -172,7 +262,7 @@ def showcase_alternative_templates(session):
172262 )
173263
174264
175- @nox .session (python = "3.9" )
265+ @nox .session (python = NEWEST_PYTHON )
176266def showcase_mtls_alternative_templates (session ):
177267 templates = path .join (path .dirname (__file__ ), "gapic" , "ads-templates" )
178268 showcase_mtls (
@@ -200,12 +290,12 @@ def run_showcase_unit_tests(session, fail_under=100):
200290 "--quiet" ,
201291 "--cov=google" ,
202292 "--cov-append" ,
203- f"--cov-fail-under={ str (fail_under )} " ,
293+ f"--cov-fail-under={ str (fail_under )} " ,
204294 * (session .posargs or [path .join ("tests" , "unit" )]),
205295 )
206296
207297
208- @nox .session (python = [ "3.6" , "3.7" , "3.8" , "3.9" ] )
298+ @nox .session (python = ALL_PYTHON )
209299def showcase_unit (
210300 session , templates = "DEFAULT" , other_opts : typing .Iterable [str ] = (),
211301):
@@ -233,14 +323,16 @@ def showcase_unit(
233323 run_showcase_unit_tests (session , fail_under = 100 )
234324
235325
236- @nox .session (python = [ "3.7" , "3.8" , "3.9" ])
326+ @nox .session (python = ALL_PYTHON [ 1 :]) # Do not test 3.6
237327def showcase_unit_alternative_templates (session ):
238- with showcase_library (session , templates = ADS_TEMPLATES , other_opts = ("old-naming" ,)) as lib :
328+ with showcase_library (
329+ session , templates = ADS_TEMPLATES , other_opts = ("old-naming" ,)
330+ ) as lib :
239331 session .chdir (lib )
240332 run_showcase_unit_tests (session )
241333
242334
243- @nox .session (python = [ "3.9" ] )
335+ @nox .session (python = NEWEST_PYTHON )
244336def showcase_unit_add_iam_methods (session ):
245337 with showcase_library (session , other_opts = ("add-iam-methods" ,)) as lib :
246338 session .chdir (lib )
@@ -257,7 +349,7 @@ def showcase_unit_add_iam_methods(session):
257349 run_showcase_unit_tests (session , fail_under = 100 )
258350
259351
260- @nox .session (python = "3.9" )
352+ @nox .session (python = NEWEST_PYTHON )
261353def showcase_mypy (
262354 session , templates = "DEFAULT" , other_opts : typing .Iterable [str ] = (),
263355):
@@ -273,12 +365,12 @@ def showcase_mypy(
273365 session .run ("mypy" , "--explicit-package-bases" , "google" )
274366
275367
276- @nox .session (python = "3.9" )
368+ @nox .session (python = NEWEST_PYTHON )
277369def showcase_mypy_alternative_templates (session ):
278370 showcase_mypy (session , templates = ADS_TEMPLATES , other_opts = ("old-naming" ,))
279371
280372
281- @nox .session (python = "3.9" )
373+ @nox .session (python = NEWEST_PYTHON )
282374def snippetgen (session ):
283375 # Clone googleapis/api-common-protos which are referenced by the snippet
284376 # protos
@@ -299,14 +391,10 @@ def snippetgen(session):
299391
300392 session .install ("grpcio-tools" , "mock" , "pytest" , "pytest-asyncio" )
301393
302- session .run (
303- "py.test" ,
304- "-vv" ,
305- "tests/snippetgen"
306- )
394+ session .run ("py.test" , "-vv" , "tests/snippetgen" )
307395
308396
309- @nox .session (python = "3.9" )
397+ @nox .session (python = NEWEST_PYTHON )
310398def docs (session ):
311399 """Build the docs."""
312400
@@ -327,15 +415,10 @@ def docs(session):
327415 )
328416
329417
330- @nox .session (python = [ "3.7" , "3.8" , "3.9" ] )
418+ @nox .session (python = NEWEST_PYTHON )
331419def mypy (session ):
332420 """Perform typecheck analysis."""
333421
334- session .install (
335- "mypy" ,
336- "types-protobuf" ,
337- "types-PyYAML" ,
338- "types-dataclasses"
339- )
422+ session .install ("mypy" , "types-protobuf" , "types-PyYAML" , "types-dataclasses" )
340423 session .install ("." )
341424 session .run ("mypy" , "gapic" )
0 commit comments