TUN-4851: Component tests to sanity check that Proxy DNS and Tunnel are only run when expected
This commit is contained in:
parent
cd4af5696d
commit
1e8dea9112
|
@ -3,7 +3,7 @@ import copy
|
||||||
|
|
||||||
from dataclasses import dataclass, InitVar
|
from dataclasses import dataclass, InitVar
|
||||||
|
|
||||||
from constants import METRICS_PORT
|
from constants import METRICS_PORT, PROXY_DNS_PORT
|
||||||
|
|
||||||
# frozen=True raises exception when assigning to fields. This emulates immutability
|
# frozen=True raises exception when assigning to fields. This emulates immutability
|
||||||
|
|
||||||
|
@ -93,3 +93,12 @@ class ClassicTunnelConfig(ClassicTunnelBaseConfig):
|
||||||
|
|
||||||
def get_url(self):
|
def get_url(self):
|
||||||
return "https://" + self.hostname
|
return "https://" + self.hostname
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class ProxyDnsConfig(BaseConfig):
|
||||||
|
full_config = {
|
||||||
|
"port": PROXY_DNS_PORT,
|
||||||
|
"no-autoupdate": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,21 @@
|
||||||
import os
|
import os
|
||||||
|
from enum import Enum, auto
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from time import sleep
|
from config import NamedTunnelConfig, ClassicTunnelConfig, ProxyDnsConfig
|
||||||
|
from constants import BACKOFF_SECS, PROXY_DNS_PORT
|
||||||
from config import NamedTunnelConfig, ClassicTunnelConfig
|
|
||||||
from constants import BACKOFF_SECS
|
|
||||||
from util import LOGGER
|
from util import LOGGER
|
||||||
|
|
||||||
|
|
||||||
|
class CfdModes(Enum):
|
||||||
|
NAMED = auto()
|
||||||
|
CLASSIC = auto()
|
||||||
|
PROXY_DNS = auto()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session")
|
@pytest.fixture(scope="session")
|
||||||
def component_tests_config():
|
def component_tests_config():
|
||||||
config_file = os.getenv("COMPONENT_TESTS_CONFIG")
|
config_file = os.getenv("COMPONENT_TESTS_CONFIG")
|
||||||
|
@ -19,22 +26,30 @@ def component_tests_config():
|
||||||
config = yaml.safe_load(stream)
|
config = yaml.safe_load(stream)
|
||||||
LOGGER.info(f"component tests base config {config}")
|
LOGGER.info(f"component tests base config {config}")
|
||||||
|
|
||||||
def _component_tests_config(additional_config={}, named_tunnel=True):
|
def _component_tests_config(additional_config={}, cfd_mode=CfdModes.NAMED, run_proxy_dns=True):
|
||||||
|
if run_proxy_dns:
|
||||||
|
# Regression test for TUN-4177, running with proxy-dns should not prevent tunnels from running.
|
||||||
|
# So we run all tests with it.
|
||||||
|
additional_config["proxy-dns"] = True
|
||||||
|
additional_config["proxy-dns-port"] = PROXY_DNS_PORT
|
||||||
|
else:
|
||||||
|
additional_config.pop("proxy-dns", None)
|
||||||
|
additional_config.pop("proxy-dns-port", None)
|
||||||
|
|
||||||
# Regression test for TUN-4177, running with proxy-dns should not prevent tunnels from running
|
if cfd_mode is CfdModes.NAMED:
|
||||||
additional_config["proxy-dns"] = True
|
|
||||||
additional_config["proxy-dns-port"] = 9053
|
|
||||||
|
|
||||||
if named_tunnel:
|
|
||||||
return NamedTunnelConfig(additional_config=additional_config,
|
return NamedTunnelConfig(additional_config=additional_config,
|
||||||
cloudflared_binary=config['cloudflared_binary'],
|
cloudflared_binary=config['cloudflared_binary'],
|
||||||
tunnel=config['tunnel'],
|
tunnel=config['tunnel'],
|
||||||
credentials_file=config['credentials_file'],
|
credentials_file=config['credentials_file'],
|
||||||
ingress=config['ingress'])
|
ingress=config['ingress'])
|
||||||
|
elif cfd_mode is CfdModes.CLASSIC:
|
||||||
return ClassicTunnelConfig(
|
return ClassicTunnelConfig(
|
||||||
additional_config=additional_config, cloudflared_binary=config['cloudflared_binary'],
|
additional_config=additional_config, cloudflared_binary=config['cloudflared_binary'],
|
||||||
hostname=config['classic_hostname'], origincert=config['origincert'])
|
hostname=config['classic_hostname'], origincert=config['origincert'])
|
||||||
|
elif cfd_mode is CfdModes.PROXY_DNS:
|
||||||
|
return ProxyDnsConfig(cloudflared_binary=config['cloudflared_binary'])
|
||||||
|
else:
|
||||||
|
raise Exception(f"Unknown cloudflared mode {cfd_mode}")
|
||||||
|
|
||||||
return _component_tests_config
|
return _component_tests_config
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
METRICS_PORT = 51000
|
METRICS_PORT = 51000
|
||||||
MAX_RETRIES = 5
|
MAX_RETRIES = 5
|
||||||
BACKOFF_SECS = 7
|
BACKOFF_SECS = 7
|
||||||
|
|
||||||
|
PROXY_DNS_PORT = 9053
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import socket
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
import constants
|
||||||
|
from conftest import CfdModes
|
||||||
|
from util import start_cloudflared, wait_tunnel_ready, check_tunnel_not_connected
|
||||||
|
|
||||||
|
|
||||||
|
# Sanity checks that test that we only run Proxy DNS and Tunnel when we really expect them to be there.
|
||||||
|
class TestProxyDns:
|
||||||
|
def test_proxy_dns_with_named_tunnel(self, tmp_path, component_tests_config):
|
||||||
|
run_test_scenario(tmp_path, component_tests_config, CfdModes.NAMED, run_proxy_dns=True)
|
||||||
|
|
||||||
|
def test_proxy_dns_with_classic_tunnel(self, tmp_path, component_tests_config):
|
||||||
|
run_test_scenario(tmp_path, component_tests_config, CfdModes.CLASSIC, run_proxy_dns=True)
|
||||||
|
|
||||||
|
def test_proxy_dns_alone(self, tmp_path, component_tests_config):
|
||||||
|
run_test_scenario(tmp_path, component_tests_config, CfdModes.PROXY_DNS, run_proxy_dns=True)
|
||||||
|
|
||||||
|
def test_named_tunnel_alone(self, tmp_path, component_tests_config):
|
||||||
|
run_test_scenario(tmp_path, component_tests_config, CfdModes.NAMED, run_proxy_dns=False)
|
||||||
|
|
||||||
|
def test_classic_tunnel_alone(self, tmp_path, component_tests_config):
|
||||||
|
run_test_scenario(tmp_path, component_tests_config, CfdModes.CLASSIC, run_proxy_dns=False)
|
||||||
|
|
||||||
|
|
||||||
|
def run_test_scenario(tmp_path, component_tests_config, cfd_mode, run_proxy_dns):
|
||||||
|
expect_proxy_dns = run_proxy_dns
|
||||||
|
expect_tunnel = False
|
||||||
|
|
||||||
|
if cfd_mode == CfdModes.NAMED:
|
||||||
|
expect_tunnel = True
|
||||||
|
pre_args = ["tunnel"]
|
||||||
|
args = ["run"]
|
||||||
|
elif cfd_mode == CfdModes.CLASSIC:
|
||||||
|
expect_tunnel = True
|
||||||
|
pre_args = []
|
||||||
|
args = []
|
||||||
|
elif cfd_mode == CfdModes.PROXY_DNS:
|
||||||
|
expect_proxy_dns = True
|
||||||
|
pre_args = []
|
||||||
|
args = ["proxy-dns", "--port", str(constants.PROXY_DNS_PORT)]
|
||||||
|
else:
|
||||||
|
assert False, f"Unknown cfd_mode {cfd_mode}"
|
||||||
|
|
||||||
|
config = component_tests_config(cfd_mode=cfd_mode, run_proxy_dns=run_proxy_dns)
|
||||||
|
with start_cloudflared(tmp_path, config, cfd_pre_args=pre_args, cfd_args=args, new_process=True, capture_output=False):
|
||||||
|
if expect_tunnel:
|
||||||
|
wait_tunnel_ready()
|
||||||
|
else:
|
||||||
|
check_tunnel_not_connected()
|
||||||
|
verify_proxy_dns(expect_proxy_dns)
|
||||||
|
|
||||||
|
|
||||||
|
def verify_proxy_dns(should_be_running):
|
||||||
|
# Wait for the Proxy DNS listener to come up.
|
||||||
|
sleep(constants.BACKOFF_SECS)
|
||||||
|
had_failure = False
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
try:
|
||||||
|
sock.connect(('localhost', constants.PROXY_DNS_PORT))
|
||||||
|
sock.send(b"anything")
|
||||||
|
except:
|
||||||
|
if should_be_running:
|
||||||
|
assert False, "Expected Proxy DNS to be running, but it was not."
|
||||||
|
had_failure = True
|
||||||
|
finally:
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
if not should_be_running and not had_failure:
|
||||||
|
assert False, "Proxy DNS should not have been running, but it was."
|
|
@ -6,6 +6,7 @@ from time import sleep
|
||||||
import pytest
|
import pytest
|
||||||
from flaky import flaky
|
from flaky import flaky
|
||||||
|
|
||||||
|
from conftest import CfdModes
|
||||||
from util import start_cloudflared, wait_tunnel_ready, check_tunnel_not_connected
|
from util import start_cloudflared, wait_tunnel_ready, check_tunnel_not_connected
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,8 +28,7 @@ class TestReconnect:
|
||||||
def test_classic_reconnect(self, tmp_path, component_tests_config):
|
def test_classic_reconnect(self, tmp_path, component_tests_config):
|
||||||
extra_config = copy.copy(self.extra_config)
|
extra_config = copy.copy(self.extra_config)
|
||||||
extra_config["hello-world"] = True
|
extra_config["hello-world"] = True
|
||||||
config = component_tests_config(
|
config = component_tests_config(additional_config=extra_config, cfd_mode=CfdModes.CLASSIC)
|
||||||
additional_config=extra_config, named_tunnel=False)
|
|
||||||
with start_cloudflared(tmp_path, config, cfd_args=[], new_process=True, allow_input=True, capture_output=False) as cloudflared:
|
with start_cloudflared(tmp_path, config, cfd_args=[], new_process=True, allow_input=True, capture_output=False) as cloudflared:
|
||||||
self.assert_reconnect(config, cloudflared, 1)
|
self.assert_reconnect(config, cloudflared, 1)
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ from pathlib import Path
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import test_logging
|
import test_logging
|
||||||
|
from conftest import CfdModes
|
||||||
from util import start_cloudflared, wait_tunnel_ready
|
from util import start_cloudflared, wait_tunnel_ready
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ class TestServiceMode:
|
||||||
"hello-world": True,
|
"hello-world": True,
|
||||||
"logfile": str(log_file),
|
"logfile": str(log_file),
|
||||||
}
|
}
|
||||||
config = component_tests_config(additional_config=additional_config, named_tunnel=False)
|
config = component_tests_config(additional_config=additional_config, cfd_mode=CfdModes.CLASSIC)
|
||||||
|
|
||||||
def assert_log_file():
|
def assert_log_file():
|
||||||
test_logging.assert_log_in_file(log_file)
|
test_logging.assert_log_in_file(log_file)
|
||||||
|
@ -52,7 +53,7 @@ class TestServiceMode:
|
||||||
"loglevel": "debug",
|
"loglevel": "debug",
|
||||||
"log-directory": str(log_dir),
|
"log-directory": str(log_dir),
|
||||||
}
|
}
|
||||||
config = component_tests_config(additional_config=additional_config, named_tunnel=False)
|
config = component_tests_config(additional_config=additional_config, cfd_mode=CfdModes.CLASSIC)
|
||||||
|
|
||||||
def assert_rotating_log():
|
def assert_rotating_log():
|
||||||
test_logging.assert_log_to_dir(config, log_dir)
|
test_logging.assert_log_to_dir(config, log_dir)
|
||||||
|
|
Loading…
Reference in New Issue