summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorBruce Ashfield <bruce.ashfield@gmail.com>2026-01-08 04:56:39 +0000
committerBruce Ashfield <bruce.ashfield@gmail.com>2026-01-21 18:00:26 -0500
commitc55674f76684a18eb6ddc714c4e91440600aea1a (patch)
tree6283722847d95aa4fd922abdfc9fce2195853e92 /tests
parent63b5365a7c66459bf2f79613bcd380b67055d011 (diff)
downloadmeta-virtualization-c55674f76684a18eb6ddc714c4e91440600aea1a.tar.gz
tests: add tests for auto-start and dynamic port forwarding
Add test coverage for new vmemres features: TestAutoStartDaemon: - test_auto_start_on_first_command: Verify daemon auto-starts - test_no_daemon_flag: Verify --no-daemon uses ephemeral mode - test_vconfig_auto_daemon: Test auto-daemon config setting - test_vconfig_idle_timeout: Test idle-timeout config setting TestDynamicPortForwarding: - test_dynamic_port_forward_run: Run -d -p adds forward dynamically - test_port_forward_cleanup_on_stop: Forwards removed on stop - test_port_forward_cleanup_on_rm: Forwards removed on rm - test_multiple_dynamic_port_forwards: Multiple containers work TestPortForwardRegistry: - test_port_forward_cleared_on_memres_stop: Registry cleared Also add ensure_busybox() helper to both VdkrRunner and VpdmnRunner. Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/conftest.py14
-rw-r--r--tests/test_vdkr.py236
2 files changed, 250 insertions, 0 deletions
diff --git a/tests/conftest.py b/tests/conftest.py
index b35f190c..71b86430 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -400,6 +400,13 @@ class VdkrRunner:
400 if not self.has_image("alpine"): 400 if not self.has_image("alpine"):
401 self.pull("alpine:latest", timeout=timeout) 401 self.pull("alpine:latest", timeout=timeout)
402 402
403 def ensure_busybox(self, timeout=300):
404 """Ensure busybox:latest is available, pulling if necessary."""
405 # Ensure memres is running first (in case a previous test stopped it)
406 self.ensure_memres()
407 if not self.has_image("busybox"):
408 self.pull("busybox:latest", timeout=timeout)
409
403 410
404@pytest.fixture(scope="session") 411@pytest.fixture(scope="session")
405def vdkr(vdkr_bin, vdkr_env, arch, test_state_dir): 412def vdkr(vdkr_bin, vdkr_env, arch, test_state_dir):
@@ -611,6 +618,13 @@ class VpdmnRunner:
611 if not self.has_image("alpine"): 618 if not self.has_image("alpine"):
612 self.pull("alpine:latest", timeout=timeout) 619 self.pull("alpine:latest", timeout=timeout)
613 620
621 def ensure_busybox(self, timeout=300):
622 """Ensure busybox:latest is available, pulling if necessary."""
623 # Ensure memres is running first (in case a previous test stopped it)
624 self.ensure_memres()
625 if not self.has_image("busybox"):
626 self.pull("busybox:latest", timeout=timeout)
627
614 628
615@pytest.fixture(scope="session") 629@pytest.fixture(scope="session")
616def vpdmn(vpdmn_bin, vdkr_env, arch, vpdmn_test_state_dir): 630def vpdmn(vpdmn_bin, vdkr_env, arch, vpdmn_test_state_dir):
diff --git a/tests/test_vdkr.py b/tests/test_vdkr.py
index d7701057..81715d16 100644
--- a/tests/test_vdkr.py
+++ b/tests/test_vdkr.py
@@ -784,3 +784,239 @@ class TestRemoteFetchAndCrossInstall:
784 784
785 result = vdkr.vrun("alpine:latest", "/bin/echo", "alpine_ok") 785 result = vdkr.vrun("alpine:latest", "/bin/echo", "alpine_ok")
786 assert "alpine_ok" in result.stdout 786 assert "alpine_ok" in result.stdout
787
788
789class TestAutoStartDaemon:
790 """Test auto-start daemon behavior.
791
792 When auto-daemon is enabled (default), vmemres starts automatically
793 on the first command and stops after idle timeout.
794 """
795
796 def test_auto_start_on_first_command(self, vdkr):
797 """Test that daemon auto-starts on first command."""
798 # Stop daemon if running
799 vdkr.memres_stop()
800 assert not vdkr.is_memres_running(), "Daemon should be stopped"
801
802 # Run a command - daemon should auto-start
803 result = vdkr.images(timeout=180)
804 assert result.returncode == 0
805
806 # Verify daemon is now running
807 assert vdkr.is_memres_running(), "Daemon should have auto-started"
808
809 def test_no_daemon_flag(self, vdkr):
810 """Test --no-daemon runs without starting daemon."""
811 # Stop daemon if running
812 vdkr.memres_stop()
813 assert not vdkr.is_memres_running(), "Daemon should be stopped"
814
815 # Run with --no-daemon - should use ephemeral mode
816 result = vdkr.run("--no-daemon", "images", timeout=180)
817 assert result.returncode == 0
818
819 # Daemon should NOT be running
820 assert not vdkr.is_memres_running(), "Daemon should not have started with --no-daemon"
821
822 def test_vconfig_auto_daemon(self, vdkr):
823 """Test vconfig auto-daemon setting."""
824 # Check current value
825 result = vdkr.run("vconfig", "auto-daemon")
826 assert result.returncode == 0
827 assert "true" in result.stdout.lower() or "auto-daemon" in result.stdout
828
829 # Test setting to false
830 result = vdkr.run("vconfig", "auto-daemon", "false")
831 assert result.returncode == 0
832
833 # Reset to default
834 result = vdkr.run("vconfig", "auto-daemon", "--reset")
835 assert result.returncode == 0
836
837 def test_vconfig_idle_timeout(self, vdkr):
838 """Test vconfig idle-timeout setting."""
839 # Check current value
840 result = vdkr.run("vconfig", "idle-timeout")
841 assert result.returncode == 0
842
843 # Test setting value
844 result = vdkr.run("vconfig", "idle-timeout", "3600")
845 assert result.returncode == 0
846
847 # Reset to default
848 result = vdkr.run("vconfig", "idle-timeout", "--reset")
849 assert result.returncode == 0
850
851
852class TestDynamicPortForwarding:
853 """Test dynamic port forwarding via QMP.
854
855 Port forwards can be added dynamically when running detached containers,
856 without needing to specify them at vmemres start time.
857 """
858
859 @pytest.mark.network
860 @pytest.mark.slow
861 def test_dynamic_port_forward_run(self, vdkr):
862 """Test that run -d -p adds port forward dynamically."""
863 import subprocess
864 import time
865
866 # Ensure memres is running (without static port forwards)
867 vdkr.memres_stop()
868 vdkr.memres_start(timeout=180)
869 assert vdkr.is_memres_running()
870
871 try:
872 # Pull nginx:alpine if not present
873 vdkr.run("pull", "nginx:alpine", timeout=300)
874
875 # Run with dynamic port forward
876 result = vdkr.run("run", "-d", "--name", "nginx-test", "-p", "8888:80",
877 "nginx:alpine", timeout=60)
878 assert result.returncode == 0, f"nginx run failed: {result.stderr}"
879
880 # Give nginx time to start
881 time.sleep(3)
882
883 # Test access from host
884 curl_result = subprocess.run(
885 ["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}",
886 "http://localhost:8888"],
887 capture_output=True,
888 text=True,
889 timeout=10
890 )
891 assert curl_result.stdout == "200", \
892 f"Expected HTTP 200, got {curl_result.stdout}"
893
894 # Check ps shows port forwards
895 ps_result = vdkr.run("ps")
896 assert ps_result.returncode == 0
897 assert "8888" in ps_result.stdout or "Port Forwards" in ps_result.stdout
898
899 finally:
900 # Clean up
901 vdkr.run("stop", "nginx-test", timeout=10, check=False)
902 vdkr.run("rm", "-f", "nginx-test", check=False)
903
904 def test_port_forward_cleanup_on_stop(self, memres_session):
905 """Test that port forwards are cleaned up when container stops."""
906 vdkr = memres_session
907 vdkr.ensure_memres()
908
909 # Ensure we have busybox
910 vdkr.ensure_busybox()
911
912 # Run a container with port forward
913 result = vdkr.run("run", "-d", "--name", "port-test", "-p", "9999:80",
914 "busybox:latest", "sleep", "300", timeout=60, check=False)
915
916 if result.returncode == 0:
917 # Stop the container
918 vdkr.run("stop", "port-test", timeout=10, check=False)
919
920 # Check ps - port forward should be removed
921 ps_result = vdkr.run("ps")
922 assert "9999" not in ps_result.stdout or "port-test" not in ps_result.stdout
923
924 # Clean up
925 vdkr.run("rm", "-f", "port-test", check=False)
926
927 def test_port_forward_cleanup_on_rm(self, memres_session):
928 """Test that port forwards are cleaned up when container is removed."""
929 vdkr = memres_session
930 vdkr.ensure_memres()
931
932 # Ensure we have busybox
933 vdkr.ensure_busybox()
934
935 # Run a container with port forward
936 result = vdkr.run("run", "-d", "--name", "rm-test", "-p", "7777:80",
937 "busybox:latest", "sleep", "300", timeout=60, check=False)
938
939 if result.returncode == 0:
940 # Force remove the container
941 vdkr.run("rm", "-f", "rm-test", timeout=10, check=False)
942
943 # Check ps - port forward should be removed
944 ps_result = vdkr.run("ps")
945 assert "7777" not in ps_result.stdout or "rm-test" not in ps_result.stdout
946
947 @pytest.mark.network
948 @pytest.mark.slow
949 def test_multiple_dynamic_port_forwards(self, vdkr):
950 """Test multiple containers with different dynamic port forwards."""
951 import time
952
953 vdkr.memres_stop()
954 vdkr.memres_start(timeout=180)
955 assert vdkr.is_memres_running()
956
957 try:
958 # Pull busybox
959 vdkr.run("pull", "busybox:latest", timeout=300, check=False)
960
961 # Run first container with port forward
962 result1 = vdkr.run("run", "-d", "--name", "http1", "-p", "8001:80",
963 "busybox:latest", "httpd", "-f", "-p", "80",
964 timeout=60, check=False)
965
966 # Run second container with different port forward
967 result2 = vdkr.run("run", "-d", "--name", "http2", "-p", "8002:80",
968 "busybox:latest", "httpd", "-f", "-p", "80",
969 timeout=60, check=False)
970
971 time.sleep(2)
972
973 # Check ps shows both port forwards
974 ps_result = vdkr.run("ps")
975 # Note: May show in port forwards section, not PORTS column
976 assert ps_result.returncode == 0
977
978 # Stop first - second should still work
979 vdkr.run("stop", "http1", timeout=10, check=False)
980
981 # Check ps - only second port forward should remain
982 ps_result = vdkr.run("ps")
983 # http1's port should be cleaned up, http2 should remain
984
985 finally:
986 vdkr.run("stop", "http1", timeout=10, check=False)
987 vdkr.run("stop", "http2", timeout=10, check=False)
988 vdkr.run("rm", "-f", "http1", check=False)
989 vdkr.run("rm", "-f", "http2", check=False)
990
991
992class TestPortForwardRegistry:
993 """Test port forward registry cleanup."""
994
995 def test_port_forward_cleared_on_memres_stop(self, vdkr):
996 """Test that port forward registry is cleared when memres stops."""
997 import os
998
999 # Start memres
1000 vdkr.memres_stop()
1001 vdkr.memres_start(timeout=180)
1002 assert vdkr.is_memres_running()
1003
1004 # Get state dir path
1005 result = vdkr.run("vstorage", "path")
1006 if result.returncode == 0:
1007 state_dir = result.stdout.strip()
1008 pf_file = os.path.join(state_dir, "port-forwards.txt")
1009
1010 # Run a container with port forward to create registry entry
1011 vdkr.ensure_busybox()
1012 vdkr.run("run", "-d", "--name", "pf-test", "-p", "6666:80",
1013 "busybox:latest", "sleep", "60", timeout=60, check=False)
1014
1015 # Stop memres - should clear port forward file
1016 vdkr.memres_stop()
1017
1018 # Port forward file should not exist or be empty
1019 if os.path.exists(pf_file):
1020 with open(pf_file, 'r') as f:
1021 content = f.read()
1022 assert content.strip() == "", "Port forward file should be empty"