class TestDockerComposeWatch(TestCase): def setUp(self): inspector = MagicMock() inspector.get_git_revision_from_path.return_value = "master" self.config = Config() self.config.add_path(LATEST_CONFIG_PATH) self.config.load_file_data() self.watch = DockerComposeWatch( config=self.config, version=self.config.version, git=inspector, docker=inspector, ) def test__execute(self): response = ( "------------------------- ------ ----------------\n" "docker-compose (override) master [36m [22m[37m[2m[33mBranch modified[22m[22m\n" "------------------------- ------ ----------------") self.watch._execute() self.assertEqual(self.watch._widget.text, response)
class TestConfigTemplate(TestCase): def setUp(self): self.maxDiff = None self._generate_config() def _generate_config(self): self.config = Config() self.config.add_path(LATEST_CONFIG_PATH) self.config.load_file_data() self.assertTrue(self.config.is_valid) def test_load_not_found_file_data(self): self.config.list_path = [("/tmp/bad/path", "")] with self.assertRaises(SystemExit) as cm: self.config.load_file_data() self.assertEqual(cm.exception.code, 127) def test_load_bad_file_data(self): bad_content = """ BAD: - CONTENT """ with tempfile.NamedTemporaryFile("w") as temp: temp.write(bad_content) temp.flush() temp_path = os.path.join(tempfile.gettempdir(), temp.name) self.config.list_path = [(temp_path, "")] with self.assertRaises(SystemExit) as cm: self.config.load_file_data() self.assertEqual(cm.exception.code, 1)
class TestDashboard(TestCase): def setUp(self): self.dummyWatch = Box() self.config = Config() self.config.add_path(LATEST_CONFIG_PATH) self.config.load_file_data() self.assertTrue(self.config.is_valid) self.dashboard = Dashboard(self.config) self.dashboard.compose_watch = self.dummyWatch self.dashboard.user_watches = self.dummyWatch self.dashboard.system_watch = self.dummyWatch self._create_box() def _create_box(self): inspect_mock = Mock() inspect_mock.interval = 6 self.box = Box(docker=inspect_mock, git=inspect_mock) self.box.data = {"interval": 15, "name": "Test Box"} self.box._services = ["Test App1", "TestApp2"] def test_all_boxes(self): self.assertListEqual( self.dashboard.all_boxes, [self.dummyWatch, self.dummyWatch, self.dummyWatch], ) def test__log_box(self): temporary_stdout = StringIO() response = ( "[36mInfo: Box 'Test Box' added. Inspecting docker containers each 6 seconds. " "Inspecting git repositories each 6 seconds. Refreshing data each 15.0 seconds. " "Services: Test App1, TestApp2.[22m" ) with contextlib.redirect_stdout(temporary_stdout): self.dashboard._log_box(self.box) output = temporary_stdout.getvalue().strip() self.assertEqual(output, response) @mock.patch("cabrita.components.dashboard.Terminal") @mock.patch("cabrita.components.dashboard.Dashboard._get_layout") @mock.patch( "cabrita.components.dashboard.Dashboard._update_boxes", side_effect=KeyboardInterrupt(), ) def test_run(self, *mocks): with self.assertRaises(SystemExit) as assert_exit: self.dashboard.run() self.assertEqual(assert_exit.exception.code, 0) def test_add_box(self): self.dashboard.add_box(self.box) self.assertTrue(len(self.dashboard.large_boxes), 1) @mock.patch("cabrita.components.dashboard.Pool", autospec=True) def test__update_boxes(self, *mocks): self.dashboard._update_boxes() self.assertIsInstance(self.dashboard.user_watches.widget, MagicMock) @mock.patch("blessed.Terminal") def test__get_layout(self, mock_terminal): self.assertIsInstance(self.dashboard._get_layout(mock_terminal), Split)
class CabritaCommand: """Cabrita Command class.""" def __init__( self, cabrita_path: str, compose_path: tuple, background_color: Optional[str] = "black", version: str = "dev", ) -> None: """Init class.""" self.version = version self.cabrita_path = cabrita_path self.config = Config() self.config.add_path(self.cabrita_path) self.config.load_file_data() self.config.manual_compose_paths = list(compose_path) self.compose = None # type: Compose self.dashboard = None # type: Dashboard self._background_color = background_color @property def background_color(self): """Return Background Color enum. :return: BoxColor instance """ return (getattr(BoxColor, self._background_color) if self._background_color else self.config.background_color) @property def has_a_valid_config(self) -> bool: """Return if Config data is valid. :return: bool """ return self.config.is_valid @property def has_a_valid_compose(self) -> bool: """Return if Compose data is valid. :return: bool """ return self.compose.is_valid def read_compose_files(self) -> None: """Read docker compose files data. :return: None """ self.compose = Compose() for compose in self.config.compose_files: base_compose_path = os.path.dirname(compose) if "." in base_compose_path: base_compose_path = self.config.base_path self.compose.add_path(compose, base_path=base_compose_path) if not self.compose.is_valid: sys.exit(1) self.compose.load_file_data() if self.config.version == 0: self.config.generate_boxes(self.compose.services) def _add_watchers(self) -> None: """Configure and add watchers to dashboard. :return: None """ git = GitInspect(target_branch="", interval=30, compose=self.compose) self.dashboard.compose_watch = DockerComposeWatch( background_color=self.background_color, git=git, config=self.config, version=self.version, ) self.dashboard.system_watch = SystemWatch( background_color=self.background_color) self.dashboard.user_watches = UserWatch( background_color=self.background_color, git=git, config=self.config) def _add_services_in_boxes(self) -> None: """Configure and add docker services to dashboard boxes. The 'main' box are the last to be processed, because this box will include any non-ignored service which aren't included in any box before. :return: None """ included_services = [] # type: List[str] main_box = None for name in self.config.boxes: box_data = self.config.boxes[name] docker = DockerInspect( compose=self.compose, interval=box_data.get("interval", 0), port_view=box_data.get("port_view", PortView.hidden), port_detail=box_data.get("port_detail", PortDetail.external), files_to_watch=box_data.get("watch_for_build_using_files", []), services_to_check_git=box_data.get("watch_for_build_using_git", []), ) git = GitInspect( target_branch=box_data.get("watch_branch", ""), interval=box_data.get("git_fetch_interval", 30), compose=self.compose, ) services_in_box = [] for service in self.compose.services: if (service not in included_services and service not in self.config.ignore_services): services_list = set([ s.lower() for s in box_data.get("includes", []) + box_data.get("categories", []) ]) for service_name in services_list: if service_name.lower() in service.lower(): services_in_box.append(service) included_services.append(service) box = Box( compose=self.compose, docker=docker, git=git, background_color=self.background_color, ) box.services = services_in_box box.load_data(box_data) if box.main: main_box = box else: self.dashboard.add_box(box) if main_box: for service in self.compose.services: if (service not in included_services and service not in self.config.ignore_services): main_box.add_service(service) self.dashboard.add_box(main_box) def prepare_dashboard(self) -> None: """Prepare the dashboard. :return: None """ self.dashboard = Dashboard(config=self.config) self._add_watchers() self._add_services_in_boxes() def execute(self) -> None: """Execute dashboard to show data in terminal. :return: None """ self.dashboard.run()
class TestConfig(TestCase): def setUp(self): self.maxDiff = None self._generate_config() def _generate_config(self): self.config = Config() self.config.add_path(LATEST_CONFIG_PATH) self.config.load_file_data() self.assertTrue(self.config.is_valid) def test_ignore_services(self): self.assertEqual(self.config.ignore_services, ["portainer"]) def test_compose_files(self): self.assertEqual( self.config.compose_files, [ "$TEST_PROJECT_PATH/docker-compose.yml", "$TEST_PROJECT_PATH/docker-compose.override.yml", ], ) def test_layout(self): self.assertEqual(self.config.layout, "horizontal") def test_boxes(self): self.assertEqual(len(self.config.boxes.keys()), 3) for box_name in self.config.boxes.keys(): self.assertTrue(box_name in ["all", "workers", "devops"]) def test_title(self): self.assertEqual(self.config.title, "My Docker Project") def test_background_color(self): from cabrita.components import BoxColor self.assertEqual(self.config.background_color, BoxColor.grey) def test_background_color_value(self): self.assertEqual(self.config.background_color_value, 0) def test_watchers(self): pass def test_get_compose_path(self): current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = str(Path(current_dir).parent.parent) os.environ["TEST_PROJECT_PATH"] = os.path.join(parent_dir, "sheep") self.assertEqual( Path( self.config.get_compose_path( "$TEST_PROJECT_PATH/docker-compose.yml", parent_dir ) ), Path(os.path.join(parent_dir, "sheep/docker-compose.yml")).resolve(), ) def test_generate_boxes(self): services_list = {"django": {}, "django-worker": {}, "flask": {}} expected_box = { "box_0": { "includes": ["django", "django-worker", "flask"], "name": "Docker Services", "port_view": "column", "show_revision": True, "size": "small", } } self.config.generate_boxes(services_list) self.assertListEqual( self.config.boxes["box_0"]["includes"], expected_box["box_0"]["includes"] ) self.assertEqual( self.config.boxes["box_0"]["name"], expected_box["box_0"]["name"] ) self.assertEqual( self.config.boxes["box_0"]["port_view"], expected_box["box_0"]["port_view"] ) self.assertEqual( self.config.boxes["box_0"]["show_revision"], expected_box["box_0"]["show_revision"], ) self.assertEqual( self.config.boxes["box_0"]["size"], expected_box["box_0"]["size"] ) def test_bad_config(self): self.config = Config() self.config.add_path("./sheep/config/cabrita-v2.yml") self.config.load_file_data() self.config.data["layout"] = "triangular" self.config.data["background_color"] = "no_color" self.config.data["compose_files"] = {} self.config.data["boxes"] = { "wrong_box": { "size": "ultra_large", "port_view": "wrong_option", "port_detail": "wrong_option", "watch_for_build_using_files": {}, "watch_for_build_using_git": {}, "includes": {}, "categories": {}, } } self.config.data["ignore_services"] = {} self.assertFalse(self.config.is_valid)
class TestConfig(TestCase): def setUp(self): self.maxDiff = None self._generate_config() def _generate_config(self): self.config = Config() self.config.add_path("./sheep/config/cabrita-v1.yml") self.config.load_file_data() self.assertTrue(self.config.is_valid) def test_ignore_services(self): self.assertListEqual(self.config.ignore_services, ["portainer"]) def test_compose_files(self): self.assertListEqual(self.config.compose_files, ["$TEST_PROJECT_PATH/docker-compose.yml"]) def test_layout(self): self.assertEqual(self.config.layout, "horizontal") def test_boxes(self): self.assertEqual(len(self.config.boxes.keys()), 3) for box_name in self.config.boxes.keys(): self.assertTrue(box_name in ["all", "workers", "devops"]) def test_title(self): self.assertEqual(self.config.title, "Docker-Compose") def test_background_color(self): from cabrita.components import BoxColor self.assertEqual(self.config.background_color, BoxColor.black) def test_background_color_value(self): self.assertEqual(self.config.background_color_value, 16) def test_watchers(self): pass def test_get_compose_path(self): current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = str(Path(current_dir).parent.parent) os.environ["TEST_PROJECT_PATH"] = os.path.join(parent_dir, "sheep") self.assertEqual( Path( self.config.get_compose_path( "$TEST_PROJECT_PATH/docker-compose.yml", parent_dir)), Path(os.path.join(parent_dir, "sheep/docker-compose.yml")).resolve(), ) def test_generate_boxes(self): services_list = {"django": {}, "django-worker": {}, "flask": {}} expected_box = { "box_0": { "includes": ["django", "django-worker", "flask"], "name": "Docker Services", "port_view": "column", "show_revision": True, "size": "small", } } self.config.generate_boxes(services_list) self.assertListEqual(self.config.boxes["box_0"]["includes"], expected_box["box_0"]["includes"]) self.assertEqual(self.config.boxes["box_0"]["name"], expected_box["box_0"]["name"]) self.assertEqual(self.config.boxes["box_0"]["port_view"], expected_box["box_0"]["port_view"]) self.assertEqual( self.config.boxes["box_0"]["show_revision"], expected_box["box_0"]["show_revision"], ) self.assertEqual(self.config.boxes["box_0"]["size"], expected_box["box_0"]["size"])
class TestConfig(TestCase): def setUp(self): self.maxDiff = None self.manual_files = [ "./sheep/docker-compose.yml", "./sheep/docker-compose.override.yml", ] self._generate_config() def _generate_config(self): self.config = Config() self.config.manual_compose_paths = self.manual_files self.config.load_file_data() self.assertTrue(self.config.is_valid) def test_ignore_services(self): self.assertEqual(self.config.ignore_services, []) def test_compose_files(self): self.assertEqual(self.config.compose_files, self.manual_files) def test_layout(self): self.assertEqual(self.config.layout, "horizontal") def test_title(self): self.assertEqual(self.config.title, "Docker-Compose") def test_background_color(self): from cabrita.components import BoxColor self.assertEqual(self.config.background_color, BoxColor.black) def test_background_color_value(self): self.assertEqual(self.config.background_color_value, 16) def test_get_compose_path(self): current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = Path(current_dir).parent.parent self.assertEqual( Path( self.config.get_compose_path(self.manual_files[0], str(parent_dir))), Path(os.path.join(str(parent_dir), self.manual_files[0])).resolve(), ) def test_generate_boxes(self): services_list = {"django": {}, "django-worker": {}, "flask": {}} expected_box = { "box_0": { "includes": ["django", "django-worker", "flask"], "name": "Docker Services", "port_view": "column", "show_revision": True, "size": "small", } } self.config.generate_boxes(services_list) self.assertListEqual(self.config.boxes["box_0"]["includes"], expected_box["box_0"]["includes"]) self.assertEqual(self.config.boxes["box_0"]["name"], expected_box["box_0"]["name"]) self.assertEqual(self.config.boxes["box_0"]["port_view"], expected_box["box_0"]["port_view"]) self.assertEqual( self.config.boxes["box_0"]["show_revision"], expected_box["box_0"]["show_revision"], ) self.assertEqual(self.config.boxes["box_0"]["size"], expected_box["box_0"]["size"])