1#!/usr/bin/env python2.7
2# Copyright 2015 gRPC authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16
17"""Generates the appropriate build.json data for all the end2end tests."""
18
19
20import yaml
21import collections
22import hashlib
23
24
25FixtureOptions = collections.namedtuple(
26    'FixtureOptions',
27    'fullstack includes_proxy dns_resolver name_resolution secure platforms ci_mac tracing exclude_configs exclude_iomgrs large_writes enables_compression supports_compression is_inproc is_http2 supports_proxy_auth supports_write_buffering client_channel')
28default_unsecure_fixture_options = FixtureOptions(
29    True, False, True, True, False, ['windows', 'linux', 'mac', 'posix'],
30    True, False, [], [], True, False, True, False, True, False, True, True)
31socketpair_unsecure_fixture_options = default_unsecure_fixture_options._replace(
32    fullstack=False, dns_resolver=False, client_channel=False)
33default_secure_fixture_options = default_unsecure_fixture_options._replace(
34    secure=True)
35uds_fixture_options = default_unsecure_fixture_options._replace(
36    dns_resolver=False, platforms=['linux', 'mac', 'posix'],
37    exclude_iomgrs=['uv'])
38local_fixture_options = default_secure_fixture_options._replace(
39    dns_resolver=False, platforms=['linux', 'mac', 'posix'],
40    exclude_iomgrs=['uv'])
41fd_unsecure_fixture_options = default_unsecure_fixture_options._replace(
42    dns_resolver=False, fullstack=False, platforms=['linux', 'mac', 'posix'],
43    exclude_iomgrs=['uv'], client_channel=False)
44inproc_fixture_options = default_unsecure_fixture_options._replace(
45    dns_resolver=False, fullstack=False, name_resolution=False,
46    supports_compression=False, is_inproc=True, is_http2=False,
47    supports_write_buffering=False, client_channel=False)
48
49# maps fixture name to whether it requires the security library
50END2END_FIXTURES = {
51    'h2_compress': default_unsecure_fixture_options._replace(enables_compression=True),
52    'h2_census': default_unsecure_fixture_options,
53     # This cmake target is disabled for now because it depends on OpenCensus,
54     # which is Bazel-only.
55     # 'h2_load_reporting': default_unsecure_fixture_options,
56    'h2_fakesec': default_secure_fixture_options._replace(ci_mac=False),
57    'h2_fd': fd_unsecure_fixture_options,
58    'h2_full': default_unsecure_fixture_options,
59    'h2_full+pipe': default_unsecure_fixture_options._replace(
60        platforms=['linux'], exclude_iomgrs=['uv']),
61    'h2_full+trace': default_unsecure_fixture_options._replace(tracing=True),
62    'h2_full+workarounds': default_unsecure_fixture_options,
63    'h2_http_proxy': default_unsecure_fixture_options._replace(
64        ci_mac=False, exclude_iomgrs=['uv'], supports_proxy_auth=True),
65    'h2_oauth2': default_secure_fixture_options._replace(
66        ci_mac=False, exclude_iomgrs=['uv']),
67    'h2_proxy': default_unsecure_fixture_options._replace(
68        includes_proxy=True, ci_mac=False, exclude_iomgrs=['uv']),
69    'h2_sockpair_1byte': socketpair_unsecure_fixture_options._replace(
70        ci_mac=False, exclude_configs=['msan'], large_writes=False,
71        exclude_iomgrs=['uv']),
72    'h2_sockpair': socketpair_unsecure_fixture_options._replace(
73        ci_mac=False, exclude_iomgrs=['uv']),
74    'h2_sockpair+trace': socketpair_unsecure_fixture_options._replace(
75        ci_mac=False, tracing=True, large_writes=False, exclude_iomgrs=['uv']),
76    'h2_ssl': default_secure_fixture_options,
77    'h2_local': local_fixture_options,
78    'h2_ssl_proxy': default_secure_fixture_options._replace(
79        includes_proxy=True, ci_mac=False, exclude_iomgrs=['uv']),
80    'h2_uds': uds_fixture_options,
81    'inproc': inproc_fixture_options
82}
83
84TestOptions = collections.namedtuple(
85    'TestOptions',
86    'needs_fullstack needs_dns needs_names proxyable secure traceable cpu_cost exclude_iomgrs large_writes flaky allows_compression needs_compression exclude_inproc needs_http2 needs_proxy_auth needs_write_buffering needs_client_channel')
87default_test_options = TestOptions(
88    False, False, False, True, False, True, 1.0, [], False, False, True,
89    False, False, False, False, False, False)
90connectivity_test_options = default_test_options._replace(
91    needs_fullstack=True)
92
93LOWCPU = 0.1
94
95# maps test names to options
96END2END_TESTS = {
97    'authority_not_supported': default_test_options,
98    'bad_hostname': default_test_options._replace(needs_names=True),
99    'bad_ping': connectivity_test_options._replace(proxyable=False),
100    'binary_metadata': default_test_options._replace(cpu_cost=LOWCPU),
101    'resource_quota_server': default_test_options._replace(
102        large_writes=True, proxyable=False, allows_compression=False),
103    'call_creds': default_test_options._replace(secure=True),
104    'cancel_after_accept': default_test_options._replace(cpu_cost=LOWCPU),
105    'cancel_after_client_done': default_test_options._replace(cpu_cost=LOWCPU),
106    'cancel_after_invoke': default_test_options._replace(cpu_cost=LOWCPU),
107    'cancel_after_round_trip': default_test_options._replace(cpu_cost=LOWCPU),
108    'cancel_before_invoke': default_test_options._replace(cpu_cost=LOWCPU),
109    'cancel_in_a_vacuum': default_test_options._replace(cpu_cost=LOWCPU),
110    'cancel_with_status': default_test_options._replace(cpu_cost=LOWCPU),
111    'compressed_payload': default_test_options._replace(proxyable=False,
112                                                        needs_compression=True),
113    'connectivity': connectivity_test_options._replace(needs_names=True,
114        proxyable=False, cpu_cost=LOWCPU, exclude_iomgrs=['uv']),
115    'channelz': default_test_options,
116    'default_host': default_test_options._replace(
117        needs_fullstack=True, needs_dns=True, needs_names=True),
118    'call_host_override': default_test_options._replace(
119        needs_fullstack=True, needs_dns=True, needs_names=True),
120    'disappearing_server': connectivity_test_options._replace(flaky=True,
121                                                              needs_names=True),
122    'empty_batch': default_test_options._replace(cpu_cost=LOWCPU),
123    'filter_causes_close': default_test_options._replace(cpu_cost=LOWCPU),
124    'filter_call_init_fails': default_test_options,
125    'filter_latency': default_test_options._replace(cpu_cost=LOWCPU),
126    'filter_status_code': default_test_options._replace(cpu_cost=LOWCPU),
127    'graceful_server_shutdown': default_test_options._replace(
128        cpu_cost=LOWCPU, exclude_inproc=True),
129    'hpack_size': default_test_options._replace(proxyable=False,
130                                                traceable=False,
131                                                cpu_cost=LOWCPU),
132    'high_initial_seqno': default_test_options._replace(cpu_cost=LOWCPU),
133    'idempotent_request': default_test_options,
134    'invoke_large_request': default_test_options,
135    'keepalive_timeout': default_test_options._replace(proxyable=False,
136                                                       cpu_cost=LOWCPU,
137                                                       needs_http2=True),
138    'large_metadata': default_test_options,
139    'max_concurrent_streams': default_test_options._replace(
140        proxyable=False, cpu_cost=LOWCPU, exclude_inproc=True),
141    'max_connection_age': default_test_options._replace(cpu_cost=LOWCPU,
142                                                        exclude_inproc=True),
143    'max_connection_idle': connectivity_test_options._replace(
144        proxyable=False, exclude_iomgrs=['uv'], cpu_cost=LOWCPU),
145    'max_message_length': default_test_options._replace(cpu_cost=LOWCPU),
146    'negative_deadline': default_test_options,
147    'network_status_change': default_test_options._replace(cpu_cost=LOWCPU),
148    'no_error_on_hotpath': default_test_options._replace(proxyable=False),
149    'no_logging': default_test_options._replace(traceable=False),
150    'no_op': default_test_options,
151    'payload': default_test_options,
152    # This cmake target is disabled for now because it depends on OpenCensus,
153    # which is Bazel-only.
154    # 'load_reporting_hook': default_test_options,
155    'ping_pong_streaming': default_test_options._replace(cpu_cost=LOWCPU),
156    'ping': connectivity_test_options._replace(proxyable=False,
157                                               cpu_cost=LOWCPU),
158    'proxy_auth': default_test_options._replace(needs_proxy_auth=True),
159    'registered_call': default_test_options,
160    'request_with_flags': default_test_options._replace(
161        proxyable=False, cpu_cost=LOWCPU),
162    'request_with_payload': default_test_options._replace(cpu_cost=LOWCPU),
163    # TODO(roth): Remove proxyable=False for all retry tests once we
164    # have a way for the proxy to propagate the fact that trailing
165    # metadata is available when initial metadata is returned.
166    # See https://github.com/grpc/grpc/issues/14467 for context.
167    'retry': default_test_options._replace(cpu_cost=LOWCPU,
168                                           needs_client_channel=True,
169                                           proxyable=False),
170    'retry_cancellation': default_test_options._replace(
171        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
172    'retry_disabled': default_test_options._replace(cpu_cost=LOWCPU,
173                                                    needs_client_channel=True,
174                                                    proxyable=False),
175    'retry_exceeds_buffer_size_in_initial_batch': default_test_options._replace(
176        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
177    'retry_exceeds_buffer_size_in_subsequent_batch':
178        default_test_options._replace(cpu_cost=LOWCPU,
179                                      needs_client_channel=True,
180                                      proxyable=False),
181    'retry_non_retriable_status': default_test_options._replace(
182        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
183    'retry_non_retriable_status_before_recv_trailing_metadata_started':
184        default_test_options._replace(
185            cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
186    'retry_recv_initial_metadata': default_test_options._replace(
187        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
188    'retry_recv_message': default_test_options._replace(
189        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
190    'retry_server_pushback_delay': default_test_options._replace(
191        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
192    'retry_server_pushback_disabled': default_test_options._replace(
193        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
194    'retry_streaming': default_test_options._replace(cpu_cost=LOWCPU,
195                                                     needs_client_channel=True,
196                                                     proxyable=False),
197    'retry_streaming_after_commit': default_test_options._replace(
198        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
199    'retry_streaming_succeeds_before_replay_finished':
200        default_test_options._replace(cpu_cost=LOWCPU,
201                                      needs_client_channel=True,
202                                      proxyable=False),
203    'retry_throttled': default_test_options._replace(cpu_cost=LOWCPU,
204                                                     needs_client_channel=True,
205                                                     proxyable=False),
206    'retry_too_many_attempts': default_test_options._replace(
207        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
208    'server_finishes_request': default_test_options._replace(cpu_cost=LOWCPU),
209    'shutdown_finishes_calls': default_test_options._replace(cpu_cost=LOWCPU),
210    'shutdown_finishes_tags': default_test_options._replace(cpu_cost=LOWCPU),
211    'simple_cacheable_request': default_test_options._replace(cpu_cost=LOWCPU),
212    'stream_compression_compressed_payload': default_test_options._replace(
213        proxyable=False, exclude_inproc=True),
214    'stream_compression_payload': default_test_options._replace(
215        exclude_inproc=True),
216    'stream_compression_ping_pong_streaming': default_test_options._replace(
217        exclude_inproc=True),
218    'simple_delayed_request': connectivity_test_options,
219    'simple_metadata': default_test_options,
220    'simple_request': default_test_options,
221    'streaming_error_response': default_test_options._replace(cpu_cost=LOWCPU),
222    'trailing_metadata': default_test_options,
223    'workaround_cronet_compression': default_test_options,
224    'write_buffering': default_test_options._replace(
225        cpu_cost=LOWCPU, needs_write_buffering=True),
226    'write_buffering_at_end': default_test_options._replace(
227        cpu_cost=LOWCPU, needs_write_buffering=True),
228}
229
230
231def compatible(f, t):
232  if END2END_TESTS[t].needs_fullstack:
233    if not END2END_FIXTURES[f].fullstack:
234      return False
235  if END2END_TESTS[t].needs_dns:
236    if not END2END_FIXTURES[f].dns_resolver:
237      return False
238  if END2END_TESTS[t].needs_names:
239    if not END2END_FIXTURES[f].name_resolution:
240      return False
241  if not END2END_TESTS[t].proxyable:
242    if END2END_FIXTURES[f].includes_proxy:
243      return False
244  if not END2END_TESTS[t].traceable:
245    if END2END_FIXTURES[f].tracing:
246      return False
247  if END2END_TESTS[t].large_writes:
248    if not END2END_FIXTURES[f].large_writes:
249      return False
250  if not END2END_TESTS[t].allows_compression:
251    if END2END_FIXTURES[f].enables_compression:
252      return False
253  if END2END_TESTS[t].needs_compression:
254    if not END2END_FIXTURES[f].supports_compression:
255      return False
256  if END2END_TESTS[t].exclude_inproc:
257    if END2END_FIXTURES[f].is_inproc:
258      return False
259  if END2END_TESTS[t].needs_http2:
260    if not END2END_FIXTURES[f].is_http2:
261      return False
262  if END2END_TESTS[t].needs_proxy_auth:
263    if not END2END_FIXTURES[f].supports_proxy_auth:
264      return False
265  if END2END_TESTS[t].needs_write_buffering:
266    if not END2END_FIXTURES[f].supports_write_buffering:
267      return False
268  if END2END_TESTS[t].needs_client_channel:
269    if not END2END_FIXTURES[f].client_channel:
270      return False
271  return True
272
273
274def without(l, e):
275  l = l[:]
276  l.remove(e)
277  return l
278
279
280def main():
281  sec_deps = [
282    'grpc_test_util',
283    'grpc',
284    'gpr_test_util',
285    'gpr'
286  ]
287  unsec_deps = [
288    'grpc_test_util_unsecure',
289    'grpc_unsecure',
290    'gpr_test_util',
291    'gpr'
292  ]
293  json = {
294      '#': 'generated with test/end2end/gen_build_json.py',
295      'libs': [
296          {
297              'name': 'end2end_tests',
298              'build': 'private',
299              'language': 'c',
300              'secure': True,
301              'src': ['test/core/end2end/end2end_tests.cc',
302                      'test/core/end2end/end2end_test_utils.cc'] + [
303                  'test/core/end2end/tests/%s.cc' % t
304                  for t in sorted(END2END_TESTS.keys())],
305              'headers': ['test/core/end2end/tests/cancel_test_helpers.h',
306                          'test/core/end2end/end2end_tests.h'],
307              'deps': sec_deps,
308              'vs_proj_dir': 'test/end2end/tests',
309          }
310      ] + [
311          {
312              'name': 'end2end_nosec_tests',
313              'build': 'private',
314              'language': 'c',
315              'secure': False,
316              'src': ['test/core/end2end/end2end_nosec_tests.cc',
317                      'test/core/end2end/end2end_test_utils.cc'] + [
318                  'test/core/end2end/tests/%s.cc' % t
319                  for t in sorted(END2END_TESTS.keys())
320                  if not END2END_TESTS[t].secure],
321              'headers': ['test/core/end2end/tests/cancel_test_helpers.h',
322                          'test/core/end2end/end2end_tests.h'],
323              'deps': unsec_deps,
324              'vs_proj_dir': 'test/end2end/tests',
325          }
326      ],
327      'targets': [
328          {
329              'name': '%s_test' % f,
330              'build': 'test',
331              'language': 'c',
332              'run': False,
333              'src': ['test/core/end2end/fixtures/%s.cc' % f],
334              'platforms': END2END_FIXTURES[f].platforms,
335              'ci_platforms': (END2END_FIXTURES[f].platforms
336                               if END2END_FIXTURES[f].ci_mac else without(
337                                   END2END_FIXTURES[f].platforms, 'mac')),
338              'deps': [
339                  'end2end_tests'
340              ] + sec_deps,
341              'vs_proj_dir': 'test/end2end/fixtures',
342          }
343          for f in sorted(END2END_FIXTURES.keys())
344      ] + [
345          {
346              'name': '%s_nosec_test' % f,
347              'build': 'test',
348              'language': 'c',
349              'secure': False,
350              'src': ['test/core/end2end/fixtures/%s.cc' % f],
351              'run': False,
352              'platforms': END2END_FIXTURES[f].platforms,
353              'ci_platforms': (END2END_FIXTURES[f].platforms
354                               if END2END_FIXTURES[f].ci_mac else without(
355                                   END2END_FIXTURES[f].platforms, 'mac')),
356              'deps': [
357                  'end2end_nosec_tests'
358              ] + unsec_deps,
359              'vs_proj_dir': 'test/end2end/fixtures',
360          }
361          for f in sorted(END2END_FIXTURES.keys())
362          if not END2END_FIXTURES[f].secure
363      ],
364      'tests': [
365          {
366              'name': '%s_test' % f,
367              'args': [t],
368              'exclude_configs': END2END_FIXTURES[f].exclude_configs,
369              'exclude_iomgrs': list(set(END2END_FIXTURES[f].exclude_iomgrs) |
370                                     set(END2END_TESTS[t].exclude_iomgrs)),
371              'platforms': END2END_FIXTURES[f].platforms,
372              'ci_platforms': (END2END_FIXTURES[f].platforms
373                               if END2END_FIXTURES[f].ci_mac else without(
374                                   END2END_FIXTURES[f].platforms, 'mac')),
375              'flaky': END2END_TESTS[t].flaky,
376              'language': 'c',
377              'cpu_cost': END2END_TESTS[t].cpu_cost,
378          }
379          for f in sorted(END2END_FIXTURES.keys())
380          for t in sorted(END2END_TESTS.keys()) if compatible(f, t)
381      ] + [
382          {
383              'name': '%s_nosec_test' % f,
384              'args': [t],
385              'exclude_configs': END2END_FIXTURES[f].exclude_configs,
386              'exclude_iomgrs': list(set(END2END_FIXTURES[f].exclude_iomgrs) |
387                                     set(END2END_TESTS[t].exclude_iomgrs)),
388              'platforms': END2END_FIXTURES[f].platforms,
389              'ci_platforms': (END2END_FIXTURES[f].platforms
390                               if END2END_FIXTURES[f].ci_mac else without(
391                                   END2END_FIXTURES[f].platforms, 'mac')),
392              'flaky': END2END_TESTS[t].flaky,
393              'language': 'c',
394              'cpu_cost': END2END_TESTS[t].cpu_cost,
395          }
396          for f in sorted(END2END_FIXTURES.keys())
397          if not END2END_FIXTURES[f].secure
398          for t in sorted(END2END_TESTS.keys())
399          if compatible(f, t) and not END2END_TESTS[t].secure
400      ],
401      'core_end2end_tests': dict(
402          (t, END2END_TESTS[t].secure)
403          for t in END2END_TESTS.keys()
404      )
405  }
406  print yaml.dump(json)
407
408
409if __name__ == '__main__':
410  main()
411