1#!/usr/bin/env python
2#
3# Copyright 2018 Espressif Systems (Shanghai) PTE LTD
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17from __future__ import division, print_function, unicode_literals
18
19import os
20import re
21
22import ttfw_idf
23from idf_http_server_test import test as client
24from tiny_test_fw import Utility
25
26# When running on local machine execute the following before running this script
27# > make app bootloader
28# > make print_flash_cmd | tail -n 1 > build/download.config
29
30# Due to connectivity issues (between runner host and DUT) in the runner environment,
31# some of the `advanced_tests` are ignored. These tests are intended for verifying
32# the expected limits of the http_server capabilities, and implement sending and receiving
33# of large HTTP packets and malformed requests, running multiple parallel sessions, etc.
34# It is advised that all these tests be run locally, when making changes or adding new
35# features to this component.
36
37
38@ttfw_idf.idf_example_test(env_tag='Example_WIFI')
39def test_examples_protocol_http_server_advanced(env, extra_data):
40    # Acquire DUT
41    dut1 = env.get_dut('http_server', 'examples/protocols/http_server/advanced_tests', dut_class=ttfw_idf.ESP32DUT)
42
43    # Get binary file
44    binary_file = os.path.join(dut1.app.binary_path, 'tests.bin')
45    bin_size = os.path.getsize(binary_file)
46    ttfw_idf.log_performance('http_server_bin_size', '{}KB'.format(bin_size // 1024))
47
48    # Upload binary and start testing
49    Utility.console_log('Starting http_server advanced test app')
50    dut1.start_app()
51
52    # Parse IP address of STA
53    Utility.console_log('Waiting to connect with AP')
54    got_ip = dut1.expect(re.compile(r'(?:[\s\S]*)IPv4 address: (\d+.\d+.\d+.\d+)'), timeout=30)[0]
55
56    got_port = dut1.expect(re.compile(r"(?:[\s\S]*)Started HTTP server on port: '(\d+)'"), timeout=15)[0]
57    result = dut1.expect(re.compile(r"(?:[\s\S]*)Max URI handlers: '(\d+)'(?:[\s\S]*)Max Open Sessions: "  # noqa: W605
58                                    r"'(\d+)'(?:[\s\S]*)Max Header Length: '(\d+)'(?:[\s\S]*)Max URI Length: "
59                                    r"'(\d+)'(?:[\s\S]*)Max Stack Size: '(\d+)'"), timeout=15)
60    # max_uri_handlers = int(result[0])
61    max_sessions = int(result[1])
62    max_hdr_len = int(result[2])
63    max_uri_len = int(result[3])
64    max_stack_size = int(result[4])
65
66    Utility.console_log('Got IP   : ' + got_ip)
67    Utility.console_log('Got Port : ' + got_port)
68
69    # Run test script
70    # If failed raise appropriate exception
71    failed = False
72
73    Utility.console_log('Sessions and Context Tests...')
74    if not client.spillover_session(got_ip, got_port, max_sessions):
75        Utility.console_log('Ignoring failure')
76    if not client.parallel_sessions_adder(got_ip, got_port, max_sessions):
77        Utility.console_log('Ignoring failure')
78    if not client.leftover_data_test(got_ip, got_port):
79        failed = True
80    if not client.async_response_test(got_ip, got_port):
81        failed = True
82    if not client.recv_timeout_test(got_ip, got_port):
83        failed = True
84    if not client.arbitrary_termination_test(got_ip, got_port):
85        failed = True
86
87    # This test fails a lot! Enable when connection is stable
88    # test_size = 50*1024 # 50KB
89    # if not client.packet_size_limit_test(got_ip, got_port, test_size):
90    #    Utility.console_log("Ignoring failure")
91
92    Utility.console_log('Getting initial stack usage...')
93    if not client.get_hello(got_ip, got_port):
94        failed = True
95
96    inital_stack = int(dut1.expect(re.compile(r"(?:[\s\S]*)Free Stack for server task: '(\d+)'"), timeout=15)[0])
97
98    if inital_stack < 0.1 * max_stack_size:
99        Utility.console_log('More than 90% of stack being used on server start')
100        failed = True
101
102    Utility.console_log('Basic HTTP Client Tests...')
103    if not client.get_hello(got_ip, got_port):
104        failed = True
105    if not client.post_hello(got_ip, got_port):
106        failed = True
107    if not client.put_hello(got_ip, got_port):
108        failed = True
109    if not client.post_echo(got_ip, got_port):
110        failed = True
111    if not client.get_echo(got_ip, got_port):
112        failed = True
113    if not client.put_echo(got_ip, got_port):
114        failed = True
115    if not client.get_hello_type(got_ip, got_port):
116        failed = True
117    if not client.get_hello_status(got_ip, got_port):
118        failed = True
119    if not client.get_false_uri(got_ip, got_port):
120        failed = True
121    if not client.get_test_headers(got_ip, got_port):
122        failed = True
123
124    Utility.console_log('Error code tests...')
125    if not client.code_500_server_error_test(got_ip, got_port):
126        failed = True
127    if not client.code_501_method_not_impl(got_ip, got_port):
128        failed = True
129    if not client.code_505_version_not_supported(got_ip, got_port):
130        failed = True
131    if not client.code_400_bad_request(got_ip, got_port):
132        failed = True
133    if not client.code_404_not_found(got_ip, got_port):
134        failed = True
135    if not client.code_405_method_not_allowed(got_ip, got_port):
136        failed = True
137    if not client.code_408_req_timeout(got_ip, got_port):
138        failed = True
139    if not client.code_414_uri_too_long(got_ip, got_port, max_uri_len):
140        Utility.console_log('Ignoring failure')
141    if not client.code_431_hdr_too_long(got_ip, got_port, max_hdr_len):
142        Utility.console_log('Ignoring failure')
143    if not client.test_upgrade_not_supported(got_ip, got_port):
144        failed = True
145
146    Utility.console_log('Getting final stack usage...')
147    if not client.get_hello(got_ip, got_port):
148        failed = True
149
150    final_stack = int(dut1.expect(re.compile(r"(?:[\s\S]*)Free Stack for server task: '(\d+)'"), timeout=15)[0])
151
152    if final_stack < 0.05 * max_stack_size:
153        Utility.console_log('More than 95% of stack got used during tests')
154        failed = True
155
156    if failed:
157        raise RuntimeError
158
159
160if __name__ == '__main__':
161    test_examples_protocol_http_server_advanced()
162