Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit605022a

Browse files
authored
gh-131178: Add tests forhttp.server command-line interface (#132540)
1 parent986c367 commit605022a

File tree

2 files changed

+260
-2
lines changed

2 files changed

+260
-2
lines changed

‎Lib/http/server.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,7 +1000,7 @@ def test(HandlerClass=BaseHTTPRequestHandler,
10001000
sys.exit(0)
10011001

10021002

1003-
if__name__=='__main__':
1003+
def_main(args=None):
10041004
importargparse
10051005
importcontextlib
10061006

@@ -1024,7 +1024,7 @@ def test(HandlerClass=BaseHTTPRequestHandler,
10241024
parser.add_argument('port',default=8000,type=int,nargs='?',
10251025
help='bind to this port '
10261026
'(default: %(default)s)')
1027-
args=parser.parse_args()
1027+
args=parser.parse_args(args)
10281028

10291029
ifnotargs.tls_certandargs.tls_key:
10301030
parser.error("--tls-key requires --tls-cert to be set")
@@ -1064,3 +1064,7 @@ def finish_request(self, request, client_address):
10641064
tls_key=args.tls_key,
10651065
tls_password=tls_key_password,
10661066
)
1067+
1068+
1069+
if__name__=='__main__':
1070+
_main()

‎Lib/test/test_httpservers.py

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
SimpleHTTPRequestHandler
99
fromhttpimportserver,HTTPStatus
1010

11+
importcontextlib
1112
importos
1213
importsocket
1314
importsys
@@ -20,6 +21,7 @@
2021
importhtml
2122
importhttp,http.client
2223
importurllib.parse
24+
importurllib.request
2325
importtempfile
2426
importtime
2527
importdatetime
@@ -32,6 +34,8 @@
3234
fromtest.supportimport (
3335
is_apple,import_helper,os_helper,threading_helper
3436
)
37+
fromtest.support.script_helperimportkill_python,spawn_python
38+
fromtest.support.socket_helperimportfind_unused_port
3539

3640
try:
3741
importssl
@@ -1281,6 +1285,256 @@ def test_server_test_ipv4(self, _):
12811285
self.assertEqual(mock_server.address_family,socket.AF_INET)
12821286

12831287

1288+
classCommandLineTestCase(unittest.TestCase):
1289+
default_port=8000
1290+
default_bind=None
1291+
default_protocol='HTTP/1.0'
1292+
default_handler=SimpleHTTPRequestHandler
1293+
default_server=unittest.mock.ANY
1294+
tls_cert=certdata_file('ssl_cert.pem')
1295+
tls_key=certdata_file('ssl_key.pem')
1296+
tls_password='somepass'
1297+
tls_cert_options= ['--tls-cert']
1298+
tls_key_options= ['--tls-key']
1299+
tls_password_options= ['--tls-password-file']
1300+
args= {
1301+
'HandlerClass':default_handler,
1302+
'ServerClass':default_server,
1303+
'protocol':default_protocol,
1304+
'port':default_port,
1305+
'bind':default_bind,
1306+
'tls_cert':None,
1307+
'tls_key':None,
1308+
'tls_password':None,
1309+
}
1310+
1311+
defsetUp(self):
1312+
super().setUp()
1313+
self.tls_password_file=tempfile.mktemp()
1314+
withopen(self.tls_password_file,'wb')asf:
1315+
f.write(self.tls_password.encode())
1316+
self.addCleanup(os_helper.unlink,self.tls_password_file)
1317+
1318+
definvoke_httpd(self,*args,stdout=None,stderr=None):
1319+
stdout=StringIO()ifstdoutisNoneelsestdout
1320+
stderr=StringIO()ifstderrisNoneelsestderr
1321+
withcontextlib.redirect_stdout(stdout), \
1322+
contextlib.redirect_stderr(stderr):
1323+
server._main(args)
1324+
returnstdout.getvalue(),stderr.getvalue()
1325+
1326+
@mock.patch('http.server.test')
1327+
deftest_port_flag(self,mock_func):
1328+
ports= [8000,65535]
1329+
forportinports:
1330+
withself.subTest(port=port):
1331+
self.invoke_httpd(str(port))
1332+
call_args=self.args|dict(port=port)
1333+
mock_func.assert_called_once_with(**call_args)
1334+
mock_func.reset_mock()
1335+
1336+
@mock.patch('http.server.test')
1337+
deftest_directory_flag(self,mock_func):
1338+
options= ['-d','--directory']
1339+
directories= ['.','/foo','\\bar','/',
1340+
'C:\\','C:\\foo','C:\\bar',
1341+
'/home/user','./foo/foo2','D:\\foo\\bar']
1342+
forflaginoptions:
1343+
fordirectoryindirectories:
1344+
withself.subTest(flag=flag,directory=directory):
1345+
self.invoke_httpd(flag,directory)
1346+
mock_func.assert_called_once_with(**self.args)
1347+
mock_func.reset_mock()
1348+
1349+
@mock.patch('http.server.test')
1350+
deftest_bind_flag(self,mock_func):
1351+
options= ['-b','--bind']
1352+
bind_addresses= ['localhost','127.0.0.1','::1',
1353+
'0.0.0.0','8.8.8.8']
1354+
forflaginoptions:
1355+
forbind_addressinbind_addresses:
1356+
withself.subTest(flag=flag,bind_address=bind_address):
1357+
self.invoke_httpd(flag,bind_address)
1358+
call_args=self.args|dict(bind=bind_address)
1359+
mock_func.assert_called_once_with(**call_args)
1360+
mock_func.reset_mock()
1361+
1362+
@mock.patch('http.server.test')
1363+
deftest_protocol_flag(self,mock_func):
1364+
options= ['-p','--protocol']
1365+
protocols= ['HTTP/1.0','HTTP/1.1','HTTP/2.0','HTTP/3.0']
1366+
forflaginoptions:
1367+
forprotocolinprotocols:
1368+
withself.subTest(flag=flag,protocol=protocol):
1369+
self.invoke_httpd(flag,protocol)
1370+
call_args=self.args|dict(protocol=protocol)
1371+
mock_func.assert_called_once_with(**call_args)
1372+
mock_func.reset_mock()
1373+
1374+
@unittest.skipIf(sslisNone,"requires ssl")
1375+
@mock.patch('http.server.test')
1376+
deftest_tls_cert_and_key_flags(self,mock_func):
1377+
fortls_cert_optioninself.tls_cert_options:
1378+
fortls_key_optioninself.tls_key_options:
1379+
self.invoke_httpd(tls_cert_option,self.tls_cert,
1380+
tls_key_option,self.tls_key)
1381+
call_args=self.args| {
1382+
'tls_cert':self.tls_cert,
1383+
'tls_key':self.tls_key,
1384+
}
1385+
mock_func.assert_called_once_with(**call_args)
1386+
mock_func.reset_mock()
1387+
1388+
@unittest.skipIf(sslisNone,"requires ssl")
1389+
@mock.patch('http.server.test')
1390+
deftest_tls_cert_and_key_and_password_flags(self,mock_func):
1391+
fortls_cert_optioninself.tls_cert_options:
1392+
fortls_key_optioninself.tls_key_options:
1393+
fortls_password_optioninself.tls_password_options:
1394+
self.invoke_httpd(tls_cert_option,
1395+
self.tls_cert,
1396+
tls_key_option,
1397+
self.tls_key,
1398+
tls_password_option,
1399+
self.tls_password_file)
1400+
call_args=self.args| {
1401+
'tls_cert':self.tls_cert,
1402+
'tls_key':self.tls_key,
1403+
'tls_password':self.tls_password,
1404+
}
1405+
mock_func.assert_called_once_with(**call_args)
1406+
mock_func.reset_mock()
1407+
1408+
@unittest.skipIf(sslisNone,"requires ssl")
1409+
@mock.patch('http.server.test')
1410+
deftest_missing_tls_cert_flag(self,mock_func):
1411+
fortls_key_optioninself.tls_key_options:
1412+
withself.assertRaises(SystemExit):
1413+
self.invoke_httpd(tls_key_option,self.tls_key)
1414+
mock_func.reset_mock()
1415+
1416+
fortls_password_optioninself.tls_password_options:
1417+
withself.assertRaises(SystemExit):
1418+
self.invoke_httpd(tls_password_option,self.tls_password)
1419+
mock_func.reset_mock()
1420+
1421+
@unittest.skipIf(sslisNone,"requires ssl")
1422+
@mock.patch('http.server.test')
1423+
deftest_invalid_password_file(self,mock_func):
1424+
non_existent_file='non_existent_file'
1425+
fortls_password_optioninself.tls_password_options:
1426+
fortls_cert_optioninself.tls_cert_options:
1427+
withself.assertRaises(SystemExit):
1428+
self.invoke_httpd(tls_cert_option,
1429+
self.tls_cert,
1430+
tls_password_option,
1431+
non_existent_file)
1432+
1433+
@mock.patch('http.server.test')
1434+
deftest_no_arguments(self,mock_func):
1435+
self.invoke_httpd()
1436+
mock_func.assert_called_once_with(**self.args)
1437+
mock_func.reset_mock()
1438+
1439+
@mock.patch('http.server.test')
1440+
deftest_help_flag(self,_):
1441+
options= ['-h','--help']
1442+
foroptioninoptions:
1443+
stdout,stderr=StringIO(),StringIO()
1444+
withself.assertRaises(SystemExit):
1445+
self.invoke_httpd(option,stdout=stdout,stderr=stderr)
1446+
self.assertIn('usage',stdout.getvalue())
1447+
self.assertEqual(stderr.getvalue(),'')
1448+
1449+
@mock.patch('http.server.test')
1450+
deftest_unknown_flag(self,_):
1451+
stdout,stderr=StringIO(),StringIO()
1452+
withself.assertRaises(SystemExit):
1453+
self.invoke_httpd('--unknown-flag',stdout=stdout,stderr=stderr)
1454+
self.assertEqual(stdout.getvalue(),'')
1455+
self.assertIn('error',stderr.getvalue())
1456+
1457+
1458+
classCommandLineRunTimeTestCase(unittest.TestCase):
1459+
served_data=os.urandom(32)
1460+
served_file_name='served_filename'
1461+
tls_cert=certdata_file('ssl_cert.pem')
1462+
tls_key=certdata_file('ssl_key.pem')
1463+
tls_password='somepass'
1464+
1465+
defsetUp(self):
1466+
super().setUp()
1467+
withopen(self.served_file_name,'wb')asf:
1468+
f.write(self.served_data)
1469+
self.addCleanup(os_helper.unlink,self.served_file_name)
1470+
self.tls_password_file=tempfile.mktemp()
1471+
withopen(self.tls_password_file,'wb')asf:
1472+
f.write(self.tls_password.encode())
1473+
self.addCleanup(os_helper.unlink,self.tls_password_file)
1474+
1475+
deffetch_file(self,path):
1476+
context=ssl.create_default_context()
1477+
# allow self-signed certificates
1478+
context.check_hostname=False
1479+
context.verify_mode=ssl.CERT_NONE
1480+
req=urllib.request.Request(path,method='GET')
1481+
withurllib.request.urlopen(req,context=context)asres:
1482+
returnres.read()
1483+
1484+
defparse_cli_output(self,output):
1485+
matches=re.search(r'\((https?)://([^/:]+):(\d+)/?\)',output)
1486+
ifmatchesisNone:
1487+
returnNone,None,None
1488+
returnmatches.group(1),matches.group(2),int(matches.group(3))
1489+
1490+
defwait_for_server(self,proc,protocol,port,bind,timeout=50):
1491+
"""Check the server process output.
1492+
1493+
Return True if the server was successfully started
1494+
and is listening on the given port and bind address.
1495+
"""
1496+
whiletimeout>0:
1497+
line=proc.stdout.readline()
1498+
ifnotline:
1499+
time.sleep(0.1)
1500+
timeout-=1
1501+
continue
1502+
protocol_,host_,port_=self.parse_cli_output(line)
1503+
ifnotprotocol_ornothost_ornotport_:
1504+
time.sleep(0.1)
1505+
timeout-=1
1506+
continue
1507+
ifprotocol_==protocolandhost_==bindandport_==port:
1508+
returnTrue
1509+
break
1510+
returnFalse
1511+
1512+
deftest_http_client(self):
1513+
port=find_unused_port()
1514+
bind='127.0.0.1'
1515+
proc=spawn_python('-u','-m','http.server',str(port),'-b',bind,
1516+
bufsize=1,text=True)
1517+
self.addCleanup(kill_python,proc)
1518+
self.addCleanup(proc.terminate)
1519+
self.assertTrue(self.wait_for_server(proc,'http',port,bind))
1520+
res=self.fetch_file(f'http://{bind}:{port}/{self.served_file_name}')
1521+
self.assertEqual(res,self.served_data)
1522+
1523+
deftest_https_client(self):
1524+
port=find_unused_port()
1525+
bind='127.0.0.1'
1526+
proc=spawn_python('-u','-m','http.server',str(port),'-b',bind,
1527+
'--tls-cert',self.tls_cert,
1528+
'--tls-key',self.tls_key,
1529+
'--tls-password-file',self.tls_password_file,
1530+
bufsize=1,text=True)
1531+
self.addCleanup(kill_python,proc)
1532+
self.addCleanup(proc.terminate)
1533+
self.assertTrue(self.wait_for_server(proc,'https',port,bind))
1534+
res=self.fetch_file(f'https://{bind}:{port}/{self.served_file_name}')
1535+
self.assertEqual(res,self.served_data)
1536+
1537+
12841538
defsetUpModule():
12851539
unittest.addModuleCleanup(os.chdir,os.getcwd())
12861540

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp