#!/usr/bin/env python # coding=utf-8 from __future__ import absolute_import import unittest import mock from octoprint_tailscale_funnel.tailscale_interface import TailscaleInterface, TailscaleError class TestTailscaleInterface(unittest.TestCase): def setUp(self): self.tailscale_interface = TailscaleInterface() @mock.patch('octoprint_tailscale_funnel.tailscale_interface.subprocess.run') def test_run_command_success(self, mock_run): # Setup mock mock_result = mock.Mock() mock_result.returncode = 0 mock_result.stdout = "command output" mock_result.stderr = "" mock_run.return_value = mock_result # Execute result = self.tailscale_interface._run_command("test command") # Assert self.assertTrue(result["success"]) self.assertEqual(result["output"], "command output") self.assertIsNone(result["error"]) mock_run.assert_called_once_with("test command", shell=True, capture_output=True, text=True, timeout=30) @mock.patch('octoprint_tailscale_funnel.tailscale_interface.subprocess.run') def test_run_command_failure(self, mock_run): # Setup mock mock_result = mock.Mock() mock_result.returncode = 1 mock_result.stdout = "" mock_result.stderr = "error message" mock_run.return_value = mock_result # Execute result = self.tailscale_interface._run_command("test command") # Assert self.assertFalse(result["success"]) self.assertIsNone(result["output"]) self.assertEqual(result["error"], "error message") @mock.patch('octoprint_tailscale_funnel.tailscale_interface.subprocess.run') def test_is_tailscale_installed_true(self, mock_run): # Setup mock mock_result = mock.Mock() mock_result.returncode = 0 mock_result.stdout = "/usr/bin/tailscale" mock_result.stderr = "" mock_run.return_value = mock_result # Execute result = self.tailscale_interface.is_tailscale_installed() # Assert self.assertTrue(result) @mock.patch('octoprint_tailscale_funnel.tailscale_interface.subprocess.run') def test_is_tailscale_installed_false(self, mock_run): # Setup mock mock_result = mock.Mock() mock_result.returncode = 1 mock_result.stdout = "" mock_result.stderr = "which: no tailscale in (/usr/bin:/bin)" mock_run.return_value = mock_result # Execute result = self.tailscale_interface.is_tailscale_installed() # Assert self.assertFalse(result) @mock.patch('octoprint_tailscale_funnel.tailscale_interface.TailscaleInterface.is_tailscale_installed') @mock.patch('octoprint_tailscale_funnel.tailscale_interface.subprocess.run') def test_is_tailscale_running_true(self, mock_run, mock_installed): # Setup mocks mock_installed.return_value = True mock_result = mock.Mock() mock_result.returncode = 0 mock_result.stdout = '{"Status": "running"}' mock_result.stderr = "" mock_run.return_value = mock_result # Execute result = self.tailscale_interface.is_tailscale_running() # Assert self.assertTrue(result) @mock.patch('octoprint_tailscale_funnel.tailscale_interface.TailscaleInterface.is_tailscale_installed') @mock.patch('octoprint_tailscale_funnel.tailscale_interface.subprocess.run') def test_is_tailscale_running_false(self, mock_run, mock_installed): # Setup mocks mock_installed.return_value = True mock_result = mock.Mock() mock_result.returncode = 1 mock_result.stdout = "" mock_result.stderr = "not running" mock_run.return_value = mock_result # Execute result = self.tailscale_interface.is_tailscale_running() # Assert self.assertFalse(result) @mock.patch('octoprint_tailscale_funnel.tailscale_interface.TailscaleInterface.is_tailscale_installed') @mock.patch('octoprint_tailscale_funnel.tailscale_interface.subprocess.run') def test_enable_funnel_success(self, mock_run, mock_installed): # Setup mocks mock_installed.return_value = True mock_result = mock.Mock() mock_result.returncode = 0 mock_result.stdout = "" mock_result.stderr = "" mock_run.return_value = mock_result # Execute result = self.tailscale_interface.enable_funnel(80) # Assert self.assertTrue(result) mock_run.assert_called_once_with("tailscale funnel 80 on", shell=True, capture_output=True, text=True, timeout=30) @mock.patch('octoprint_tailscale_funnel.tailscale_interface.TailscaleInterface.is_tailscale_installed') @mock.patch('octoprint_tailscale_funnel.tailscale_interface.subprocess.run') def test_disable_funnel_success(self, mock_run, mock_installed): # Setup mocks mock_installed.return_value = True mock_result = mock.Mock() mock_result.returncode = 0 mock_result.stdout = "" mock_result.stderr = "" mock_run.return_value = mock_result # Execute result = self.tailscale_interface.disable_funnel(80) # Assert self.assertTrue(result) mock_run.assert_called_once_with("tailscale funnel 80 off", shell=True, capture_output=True, text=True, timeout=30) if __name__ == '__main__': unittest.main()