Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/external/curl/tests/http/test_20_websockets.py
2654 views
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
#***************************************************************************
4
# _ _ ____ _
5
# Project ___| | | | _ \| |
6
# / __| | | | |_) | |
7
# | (__| |_| | _ <| |___
8
# \___|\___/|_| \_\_____|
9
#
10
# Copyright (C) Daniel Stenberg, <[email protected]>, et al.
11
#
12
# This software is licensed as described in the file COPYING, which
13
# you should have received as part of this distribution. The terms
14
# are also available at https://curl.se/docs/copyright.html.
15
#
16
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
17
# copies of the Software, and permit persons to whom the Software is
18
# furnished to do so, under the terms of the COPYING file.
19
#
20
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21
# KIND, either express or implied.
22
#
23
# SPDX-License-Identifier: curl
24
#
25
###########################################################################
26
#
27
import logging
28
import os
29
import shutil
30
import socket
31
import subprocess
32
import time
33
from datetime import datetime, timedelta
34
from typing import Dict
35
import pytest
36
37
from testenv import Env, CurlClient, LocalClient
38
from testenv.ports import alloc_ports_and_do
39
40
41
log = logging.getLogger(__name__)
42
43
44
@pytest.mark.skipif(condition=not Env.curl_has_protocol('ws'),
45
reason='curl lacks ws protocol support')
46
class TestWebsockets:
47
48
PORT_SPECS = {
49
'ws': socket.SOCK_STREAM,
50
}
51
52
def check_alive(self, env, port, timeout=Env.SERVER_TIMEOUT):
53
curl = CurlClient(env=env)
54
url = f'http://localhost:{port}/'
55
end = datetime.now() + timedelta(seconds=timeout)
56
while datetime.now() < end:
57
r = curl.http_download(urls=[url])
58
if r.exit_code == 0:
59
return True
60
time.sleep(.1)
61
return False
62
63
def _mkpath(self, path):
64
if not os.path.exists(path):
65
return os.makedirs(path)
66
67
def _rmrf(self, path):
68
if os.path.exists(path):
69
return shutil.rmtree(path)
70
71
@pytest.fixture(autouse=True, scope='class')
72
def ws_echo(self, env):
73
self.run_dir = os.path.join(env.gen_dir, 'ws_echo_server')
74
err_file = os.path.join(self.run_dir, 'stderr')
75
self._rmrf(self.run_dir)
76
self._mkpath(self.run_dir)
77
self.cmd = os.path.join(env.project_dir,
78
'tests/http/testenv/ws_echo_server.py')
79
self.wsproc = None
80
self.cerr = None
81
82
def startup(ports: Dict[str, int]) -> bool:
83
wargs = [self.cmd, '--port', str(ports['ws'])]
84
log.info(f'start_ {wargs}')
85
self.wsproc = subprocess.Popen(args=wargs,
86
cwd=self.run_dir,
87
stderr=self.cerr,
88
stdout=self.cerr)
89
if self.check_alive(env, ports['ws']):
90
env.update_ports(ports)
91
return True
92
log.error(f'not alive {wargs}')
93
self.wsproc.terminate()
94
self.wsproc = None
95
return False
96
97
with open(err_file, 'w') as self.cerr:
98
assert alloc_ports_and_do(TestWebsockets.PORT_SPECS, startup,
99
env.gen_root, max_tries=3)
100
assert self.wsproc
101
yield
102
self.wsproc.terminate()
103
104
def test_20_01_basic(self, env: Env, ws_echo):
105
curl = CurlClient(env=env)
106
url = f'http://localhost:{env.ws_port}/'
107
r = curl.http_download(urls=[url])
108
r.check_response(http_status=426)
109
110
def test_20_02_pingpong_small(self, env: Env, ws_echo):
111
payload = 125 * "x"
112
client = LocalClient(env=env, name='cli_ws_pingpong')
113
if not client.exists():
114
pytest.skip(f'example client not built: {client.name}')
115
url = f'ws://localhost:{env.ws_port}/'
116
r = client.run(args=[url, payload])
117
r.check_exit_code(0)
118
119
# the python websocket server does not like 'large' control frames
120
def test_20_03_pingpong_too_large(self, env: Env, ws_echo):
121
payload = 127 * "x"
122
client = LocalClient(env=env, name='cli_ws_pingpong')
123
if not client.exists():
124
pytest.skip(f'example client not built: {client.name}')
125
url = f'ws://localhost:{env.ws_port}/'
126
r = client.run(args=[url, payload])
127
r.check_exit_code(100) # CURLE_TOO_LARGE
128
129
@pytest.mark.parametrize("model", [
130
pytest.param(1, id='multi_perform'),
131
pytest.param(2, id='curl_ws_send+recv'),
132
])
133
def test_20_04_data_small(self, env: Env, ws_echo, model):
134
client = LocalClient(env=env, name='cli_ws_data')
135
if not client.exists():
136
pytest.skip(f'example client not built: {client.name}')
137
url = f'ws://localhost:{env.ws_port}/'
138
r = client.run(args=[f'-{model}', '-m', str(1), '-M', str(10), url])
139
r.check_exit_code(0)
140
141
@pytest.mark.parametrize("model", [
142
pytest.param(1, id='multi_perform'),
143
pytest.param(2, id='curl_ws_send+recv'),
144
])
145
def test_20_05_data_med(self, env: Env, ws_echo, model):
146
client = LocalClient(env=env, name='cli_ws_data')
147
if not client.exists():
148
pytest.skip(f'example client not built: {client.name}')
149
url = f'ws://localhost:{env.ws_port}/'
150
r = client.run(args=[f'-{model}', '-m', str(120), '-M', str(130), url])
151
r.check_exit_code(0)
152
153
@pytest.mark.parametrize("model", [
154
pytest.param(1, id='multi_perform'),
155
pytest.param(2, id='curl_ws_send+recv'),
156
])
157
def test_20_06_data_large(self, env: Env, ws_echo, model):
158
client = LocalClient(env=env, name='cli_ws_data')
159
if not client.exists():
160
pytest.skip(f'example client not built: {client.name}')
161
url = f'ws://localhost:{env.ws_port}/'
162
r = client.run(args=[f'-{model}', '-m', str(65535 - 5), '-M', str(65535 + 5), url])
163
r.check_exit_code(0)
164
165
@pytest.mark.parametrize("model", [
166
pytest.param(1, id='multi_perform'),
167
pytest.param(2, id='curl_ws_send+recv'),
168
])
169
def test_20_07_data_large_small_recv(self, env: Env, ws_echo, model):
170
run_env = os.environ.copy()
171
run_env['CURL_WS_CHUNK_SIZE'] = '1024'
172
client = LocalClient(env=env, name='cli_ws_data', run_env=run_env)
173
if not client.exists():
174
pytest.skip(f'example client not built: {client.name}')
175
url = f'ws://localhost:{env.ws_port}/'
176
r = client.run(args=[f'-{model}', '-m', str(65535 - 5), '-M', str(65535 + 5), url])
177
r.check_exit_code(0)
178
179
# Send large frames and simulate send blocking on 8192 bytes chunks
180
# Simlates error reported in #15865
181
@pytest.mark.parametrize("model", [
182
pytest.param(1, id='multi_perform'),
183
pytest.param(2, id='curl_ws_send+recv'),
184
])
185
def test_20_08_data_very_large(self, env: Env, ws_echo, model):
186
run_env = os.environ.copy()
187
run_env['CURL_WS_CHUNK_EAGAIN'] = '8192'
188
client = LocalClient(env=env, name='cli_ws_data', run_env=run_env)
189
if not client.exists():
190
pytest.skip(f'example client not built: {client.name}')
191
url = f'ws://localhost:{env.ws_port}/'
192
count = 10
193
large = 20000
194
r = client.run(args=[f'-{model}', '-c', str(count), '-m', str(large), url])
195
r.check_exit_code(0)
196
197
@pytest.mark.parametrize("model", [
198
pytest.param(1, id='multi_perform'),
199
pytest.param(2, id='curl_ws_send+recv'),
200
])
201
def test_20_09_data_empty(self, env: Env, ws_echo, model):
202
client = LocalClient(env=env, name='cli_ws_data')
203
if not client.exists():
204
pytest.skip(f'example client not built: {client.name}')
205
url = f'ws://localhost:{env.ws_port}/'
206
count = 10
207
large = 0
208
r = client.run(args=[f'-{model}', '-c', str(count), '-m', str(large), url])
209
r.check_exit_code(0)
210
211