Skip to content

Commit 77dd1f7

Browse files
authored
Merge pull request #1 from aknrdureegaesr/test_port
Test for the improved "nikola serve" error handling.
2 parents b962cab + 0c41ab9 commit 77dd1f7

File tree

2 files changed

+44
-64
lines changed

2 files changed

+44
-64
lines changed

nikola/plugins/command/serve.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,8 @@ def _execute(self, options, args):
151151
except OSError as e:
152152
if e.errno == errno.EADDRINUSE:
153153
self.logger.error(f"Port address {options['port']} already in use, please use "
154-
"the `-p <port>` option to select a different one.")
155-
sys.exit(1)
154+
"the `-p <port>` option to select a different one.")
155+
return 3
156156
else:
157157
raise
158158

tests/integration/test_dev_server_serve.py

Lines changed: 42 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import logging
2+
import re
3+
import socket
4+
from io import StringIO
15
from time import sleep
26
from typing import Tuple
37
import requests
@@ -8,77 +12,53 @@
812
from nikola.utils import base_path_from_siteuri
913
from .dev_server_test_helper import MyFakeSite, SERVER_ADDRESS, find_unused_port, LOGGER, OUTPUT_FOLDER
1014

11-
def test_two_serves_with_different_port( site_and_base_path: Tuple[MyFakeSite, str], expected_text: str
12-
):
13-
site, base_path = site_and_base_path
14-
command_serveA = serve.CommandServe()
15-
command_serveA.set_site(site)
16-
command_serveB = serve.CommandServe()
17-
command_serveB.set_site(site)
18-
with ThreadPoolExecutor(max_workers=2) as executor:
19-
options = {
20-
"address": SERVER_ADDRESS,
21-
"port": find_unused_port(),
22-
"browser": False,
23-
"detach": False,
24-
"ipv6": False,
25-
}
26-
future_to_run_web_serverA = executor.submit(lambda: command_serveA.execute(options=options))
27-
options = {
28-
"address": SERVER_ADDRESS,
29-
"port": find_unused_port(),
30-
"browser": False,
31-
"detach": False,
32-
"ipv6": False,
33-
}
34-
future_to_run_web_serverB = executor.submit(lambda: command_serveB.execute(options=options))
35-
sleep(0.1)
36-
try:
37-
command_serveA.shutdown()
38-
future_to_run_web_serverA.result()
39-
except SystemExit as e:
40-
assert e.code == 0
41-
try:
42-
command_serveB.shutdown()
43-
future_to_run_web_serverB.result()
44-
except SystemExit as e:
45-
assert e.code == 0
4615

47-
def test_two_serves_with_same_port( site_and_base_path: Tuple[MyFakeSite, str], expected_text: str
48-
):
16+
def test_server_on_used_port(site_and_base_path: Tuple[MyFakeSite, str]):
4917
site, base_path = site_and_base_path
50-
command_serveA = serve.CommandServe()
51-
command_serveA.set_site(site)
52-
command_serveB = serve.CommandServe()
53-
command_serveB.set_site(site)
54-
port = find_unused_port()
55-
with ThreadPoolExecutor(max_workers=2) as executor:
56-
options = {
57-
"address": SERVER_ADDRESS,
58-
"port": port,
59-
"browser": False,
60-
"detach": False,
61-
"ipv6": False,
62-
}
63-
future_to_run_web_serverA = executor.submit(lambda: command_serveA.execute(options=options))
64-
future_to_run_web_serverB = executor.submit(lambda: command_serveB.execute(options=options))
65-
sleep(0.1)
66-
try:
67-
command_serveA.shutdown()
68-
future_to_run_web_serverA.result()
69-
except SystemExit as e:
70-
assert e.code == 0
18+
command_serve = serve.CommandServe()
19+
command_serve.set_site(site)
20+
command_serve.serve_pidfile = "there is no file with this name we hope"
21+
command_serve.logger = logging.getLogger("dev_server_test")
22+
catch_log = StringIO()
23+
catch_log_handler = logging.StreamHandler(catch_log)
24+
logging.getLogger().addHandler(catch_log_handler)
25+
try:
26+
s = socket.socket()
7127
try:
72-
command_serveB.shutdown()
73-
future_to_run_web_serverB.result()
74-
except SystemExit as e:
75-
assert e.code == 1
28+
ANY_PORT = 0
29+
s.bind((SERVER_ADDRESS, ANY_PORT))
30+
address, port = s.getsockname()
31+
with ThreadPoolExecutor(max_workers=2) as executor:
32+
options = {
33+
"address": SERVER_ADDRESS,
34+
"port": port,
35+
"browser": False,
36+
"detach": False,
37+
"ipv6": False,
38+
}
39+
future_to_run_web_server = executor.submit(lambda: command_serve.execute(options=options))
40+
command_serve.shutdown()
41+
result = future_to_run_web_server.result()
42+
assert 3 == result
43+
assert re.match(
44+
r"Port address \d+ already in use, "
45+
r"please use the `\-p \<port\>` option to select a different one\.",
46+
catch_log.getvalue()
47+
)
48+
assert "OSError" not in catch_log.getvalue()
49+
finally:
50+
s.close()
51+
finally:
52+
logging.getLogger().removeHandler(catch_log_handler)
53+
7654

7755
def test_serves_root_dir(
7856
site_and_base_path: Tuple[MyFakeSite, str], expected_text: str
7957
) -> None:
8058
site, base_path = site_and_base_path
8159
command_serve = serve.CommandServe()
60+
command_serve.serve_pidfile = "there is no file with this name we hope"
61+
command_serve.logger = logging.getLogger("dev_server_test")
8262
command_serve.set_site(site)
8363
options = {
8464
"address": SERVER_ADDRESS,

0 commit comments

Comments
 (0)