1# Copyright 2016 gRPC authors. 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"""HTTP2 Test Server""" 16 17import argparse 18import logging 19import sys 20import twisted 21import twisted.internet 22import twisted.internet.endpoints 23import twisted.internet.reactor 24 25import http2_base_server 26import test_goaway 27import test_max_streams 28import test_ping 29import test_rst_after_data 30import test_rst_after_header 31import test_rst_during_data 32import test_data_frame_padding 33 34_TEST_CASE_MAPPING = { 35 'rst_after_header': test_rst_after_header.TestcaseRstStreamAfterHeader, 36 'rst_after_data': test_rst_after_data.TestcaseRstStreamAfterData, 37 'rst_during_data': test_rst_during_data.TestcaseRstStreamDuringData, 38 'goaway': test_goaway.TestcaseGoaway, 39 'ping': test_ping.TestcasePing, 40 'max_streams': test_max_streams.TestcaseSettingsMaxStreams, 41 42 # Positive tests below: 43 'data_frame_padding': test_data_frame_padding.TestDataFramePadding, 44 'no_df_padding_sanity_test': test_data_frame_padding.TestDataFramePadding, 45} 46 47_exit_code = 0 48 49class H2Factory(twisted.internet.protocol.Factory): 50 def __init__(self, testcase): 51 logging.info('Creating H2Factory for new connection (%s)', testcase) 52 self._num_streams = 0 53 self._testcase = testcase 54 55 def buildProtocol(self, addr): 56 self._num_streams += 1 57 logging.info('New Connection: %d' % self._num_streams) 58 if not _TEST_CASE_MAPPING.has_key(self._testcase): 59 logging.error('Unknown test case: %s' % self._testcase) 60 assert(0) 61 else: 62 t = _TEST_CASE_MAPPING[self._testcase] 63 64 if self._testcase == 'goaway': 65 return t(self._num_streams).get_base_server() 66 elif self._testcase == 'no_df_padding_sanity_test': 67 return t(use_padding=False).get_base_server() 68 else: 69 return t().get_base_server() 70 71def parse_arguments(): 72 parser = argparse.ArgumentParser() 73 parser.add_argument('--base_port', type=int, default=8080, 74 help='base port to run the servers (default: 8080). One test server is ' 75 'started on each incrementing port, beginning with base_port, in the ' 76 'following order: data_frame_padding,goaway,max_streams,' 77 'no_df_padding_sanity_test,ping,rst_after_data,rst_after_header,' 78 'rst_during_data' 79 ) 80 return parser.parse_args() 81 82def listen(endpoint, test_case): 83 deferred = endpoint.listen(H2Factory(test_case)) 84 def listen_error(reason): 85 # If listening fails, we stop the reactor and exit the program 86 # with exit code 1. 87 global _exit_code 88 _exit_code = 1 89 logging.error('Listening failed: %s' % reason.value) 90 twisted.internet.reactor.stop() 91 deferred.addErrback(listen_error) 92 93def start_test_servers(base_port): 94 """ Start one server per test case on incrementing port numbers 95 beginning with base_port """ 96 index = 0 97 for test_case in sorted(_TEST_CASE_MAPPING.keys()): 98 portnum = base_port + index 99 logging.warning('serving on port %d : %s'%(portnum, test_case)) 100 endpoint = twisted.internet.endpoints.TCP4ServerEndpoint( 101 twisted.internet.reactor, portnum, backlog=128) 102 # Wait until the reactor is running before calling endpoint.listen(). 103 twisted.internet.reactor.callWhenRunning(listen, endpoint, test_case) 104 105 index += 1 106 107if __name__ == '__main__': 108 logging.basicConfig( 109 format='%(levelname) -10s %(asctime)s %(module)s:%(lineno)s | %(message)s', 110 level=logging.INFO) 111 args = parse_arguments() 112 start_test_servers(args.base_port) 113 twisted.internet.reactor.run() 114 sys.exit(_exit_code) 115