Skip to content

Commit 1e8dea9

Browse files
committed
TUN-4851: Component tests to sanity check that Proxy DNS and Tunnel are only run when expected
1 parent cd4af56 commit 1e8dea9

File tree

6 files changed

+119
-20
lines changed

6 files changed

+119
-20
lines changed

component-tests/config.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from dataclasses import dataclass, InitVar
55

6-
from constants import METRICS_PORT
6+
from constants import METRICS_PORT, PROXY_DNS_PORT
77

88
# frozen=True raises exception when assigning to fields. This emulates immutability
99

@@ -93,3 +93,12 @@ def __post_init__(self, additional_config):
9393

9494
def get_url(self):
9595
return "https://" + self.hostname
96+
97+
98+
@dataclass(frozen=True)
99+
class ProxyDnsConfig(BaseConfig):
100+
full_config = {
101+
"port": PROXY_DNS_PORT,
102+
"no-autoupdate": True,
103+
}
104+

component-tests/conftest.py

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
import os
2+
from enum import Enum, auto
3+
from time import sleep
4+
25
import pytest
36
import yaml
47

5-
from time import sleep
6-
7-
from config import NamedTunnelConfig, ClassicTunnelConfig
8-
from constants import BACKOFF_SECS
8+
from config import NamedTunnelConfig, ClassicTunnelConfig, ProxyDnsConfig
9+
from constants import BACKOFF_SECS, PROXY_DNS_PORT
910
from util import LOGGER
1011

1112

13+
class CfdModes(Enum):
14+
NAMED = auto()
15+
CLASSIC = auto()
16+
PROXY_DNS = auto()
17+
18+
1219
@pytest.fixture(scope="session")
1320
def component_tests_config():
1421
config_file = os.getenv("COMPONENT_TESTS_CONFIG")
@@ -19,22 +26,30 @@ def component_tests_config():
1926
config = yaml.safe_load(stream)
2027
LOGGER.info(f"component tests base config {config}")
2128

22-
def _component_tests_config(additional_config={}, named_tunnel=True):
23-
24-
# Regression test for TUN-4177, running with proxy-dns should not prevent tunnels from running
25-
additional_config["proxy-dns"] = True
26-
additional_config["proxy-dns-port"] = 9053
27-
28-
if named_tunnel:
29+
def _component_tests_config(additional_config={}, cfd_mode=CfdModes.NAMED, run_proxy_dns=True):
30+
if run_proxy_dns:
31+
# Regression test for TUN-4177, running with proxy-dns should not prevent tunnels from running.
32+
# So we run all tests with it.
33+
additional_config["proxy-dns"] = True
34+
additional_config["proxy-dns-port"] = PROXY_DNS_PORT
35+
else:
36+
additional_config.pop("proxy-dns", None)
37+
additional_config.pop("proxy-dns-port", None)
38+
39+
if cfd_mode is CfdModes.NAMED:
2940
return NamedTunnelConfig(additional_config=additional_config,
3041
cloudflared_binary=config['cloudflared_binary'],
3142
tunnel=config['tunnel'],
3243
credentials_file=config['credentials_file'],
3344
ingress=config['ingress'])
34-
35-
return ClassicTunnelConfig(
36-
additional_config=additional_config, cloudflared_binary=config['cloudflared_binary'],
37-
hostname=config['classic_hostname'], origincert=config['origincert'])
45+
elif cfd_mode is CfdModes.CLASSIC:
46+
return ClassicTunnelConfig(
47+
additional_config=additional_config, cloudflared_binary=config['cloudflared_binary'],
48+
hostname=config['classic_hostname'], origincert=config['origincert'])
49+
elif cfd_mode is CfdModes.PROXY_DNS:
50+
return ProxyDnsConfig(cloudflared_binary=config['cloudflared_binary'])
51+
else:
52+
raise Exception(f"Unknown cloudflared mode {cfd_mode}")
3853

3954
return _component_tests_config
4055

component-tests/constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
METRICS_PORT = 51000
22
MAX_RETRIES = 5
33
BACKOFF_SECS = 7
4+
5+
PROXY_DNS_PORT = 9053

component-tests/test_proxy_dns.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#!/usr/bin/env python
2+
import socket
3+
from time import sleep
4+
5+
import constants
6+
from conftest import CfdModes
7+
from util import start_cloudflared, wait_tunnel_ready, check_tunnel_not_connected
8+
9+
10+
# Sanity checks that test that we only run Proxy DNS and Tunnel when we really expect them to be there.
11+
class TestProxyDns:
12+
def test_proxy_dns_with_named_tunnel(self, tmp_path, component_tests_config):
13+
run_test_scenario(tmp_path, component_tests_config, CfdModes.NAMED, run_proxy_dns=True)
14+
15+
def test_proxy_dns_with_classic_tunnel(self, tmp_path, component_tests_config):
16+
run_test_scenario(tmp_path, component_tests_config, CfdModes.CLASSIC, run_proxy_dns=True)
17+
18+
def test_proxy_dns_alone(self, tmp_path, component_tests_config):
19+
run_test_scenario(tmp_path, component_tests_config, CfdModes.PROXY_DNS, run_proxy_dns=True)
20+
21+
def test_named_tunnel_alone(self, tmp_path, component_tests_config):
22+
run_test_scenario(tmp_path, component_tests_config, CfdModes.NAMED, run_proxy_dns=False)
23+
24+
def test_classic_tunnel_alone(self, tmp_path, component_tests_config):
25+
run_test_scenario(tmp_path, component_tests_config, CfdModes.CLASSIC, run_proxy_dns=False)
26+
27+
28+
def run_test_scenario(tmp_path, component_tests_config, cfd_mode, run_proxy_dns):
29+
expect_proxy_dns = run_proxy_dns
30+
expect_tunnel = False
31+
32+
if cfd_mode == CfdModes.NAMED:
33+
expect_tunnel = True
34+
pre_args = ["tunnel"]
35+
args = ["run"]
36+
elif cfd_mode == CfdModes.CLASSIC:
37+
expect_tunnel = True
38+
pre_args = []
39+
args = []
40+
elif cfd_mode == CfdModes.PROXY_DNS:
41+
expect_proxy_dns = True
42+
pre_args = []
43+
args = ["proxy-dns", "--port", str(constants.PROXY_DNS_PORT)]
44+
else:
45+
assert False, f"Unknown cfd_mode {cfd_mode}"
46+
47+
config = component_tests_config(cfd_mode=cfd_mode, run_proxy_dns=run_proxy_dns)
48+
with start_cloudflared(tmp_path, config, cfd_pre_args=pre_args, cfd_args=args, new_process=True, capture_output=False):
49+
if expect_tunnel:
50+
wait_tunnel_ready()
51+
else:
52+
check_tunnel_not_connected()
53+
verify_proxy_dns(expect_proxy_dns)
54+
55+
56+
def verify_proxy_dns(should_be_running):
57+
# Wait for the Proxy DNS listener to come up.
58+
sleep(constants.BACKOFF_SECS)
59+
had_failure = False
60+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
61+
try:
62+
sock.connect(('localhost', constants.PROXY_DNS_PORT))
63+
sock.send(b"anything")
64+
except:
65+
if should_be_running:
66+
assert False, "Expected Proxy DNS to be running, but it was not."
67+
had_failure = True
68+
finally:
69+
sock.close()
70+
71+
if not should_be_running and not had_failure:
72+
assert False, "Proxy DNS should not have been running, but it was."

component-tests/test_reconnect.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import pytest
77
from flaky import flaky
88

9+
from conftest import CfdModes
910
from util import start_cloudflared, wait_tunnel_ready, check_tunnel_not_connected
1011

1112

@@ -27,8 +28,7 @@ def test_named_reconnect(self, tmp_path, component_tests_config):
2728
def test_classic_reconnect(self, tmp_path, component_tests_config):
2829
extra_config = copy.copy(self.extra_config)
2930
extra_config["hello-world"] = True
30-
config = component_tests_config(
31-
additional_config=extra_config, named_tunnel=False)
31+
config = component_tests_config(additional_config=extra_config, cfd_mode=CfdModes.CLASSIC)
3232
with start_cloudflared(tmp_path, config, cfd_args=[], new_process=True, allow_input=True, capture_output=False) as cloudflared:
3333
self.assert_reconnect(config, cloudflared, 1)
3434

component-tests/test_service.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import pytest
99

1010
import test_logging
11+
from conftest import CfdModes
1112
from util import start_cloudflared, wait_tunnel_ready
1213

1314

@@ -34,7 +35,7 @@ def test_launchd_service_log_to_file(self, tmp_path, component_tests_config):
3435
"hello-world": True,
3536
"logfile": str(log_file),
3637
}
37-
config = component_tests_config(additional_config=additional_config, named_tunnel=False)
38+
config = component_tests_config(additional_config=additional_config, cfd_mode=CfdModes.CLASSIC)
3839

3940
def assert_log_file():
4041
test_logging.assert_log_in_file(log_file)
@@ -52,7 +53,7 @@ def test_launchd_service_rotating_log(self, tmp_path, component_tests_config):
5253
"loglevel": "debug",
5354
"log-directory": str(log_dir),
5455
}
55-
config = component_tests_config(additional_config=additional_config, named_tunnel=False)
56+
config = component_tests_config(additional_config=additional_config, cfd_mode=CfdModes.CLASSIC)
5657

5758
def assert_rotating_log():
5859
test_logging.assert_log_to_dir(config, log_dir)

0 commit comments

Comments
 (0)