예제 #1
0
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)
예제 #2
0
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   Branch modified\n"
            "-------------------------  ------  ----------------")
        self.watch._execute()
        self.assertEqual(self.watch._widget.text, response)
예제 #3
0
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 = (
            "Info: 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."
        )
        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)
예제 #4
0
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()
예제 #5
0
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)
예제 #6
0
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"])