def test_copy_minimal_subset_of_repository(self):
     controller = CallbacksAdapter()
     repo1 = generator.gen_repository(name="repo1")
     repo2 = generator.gen_repository(name="repo2")
     repo3 = generator.gen_repository(name="repo3")
     mirror1 = generator.gen_repository(name="mirror1")
     mirror2 = generator.gen_repository(name="mirror2")
     pkg_group1 = [
         generator.gen_package(
             idx=1, requires=None, repository=repo1
         ),
         generator.gen_package(
             idx=1, version=2, requires=None, repository=repo1
         ),
         generator.gen_package(
             idx=2, requires=None, repository=repo1
         )
     ]
     pkg_group2 = [
         generator.gen_package(
             idx=4,
             requires=[generator.gen_relation("package1")],
             repository=repo2,
             mandatory=True,
         )
     ]
     pkg_group3 = [
         generator.gen_package(
             idx=3, requires=None, repository=repo1
         )
     ]
     controller.load_repositories.side_effect = [[repo1, repo2], repo3]
     controller.load_packages.side_effect = [
         pkg_group1 + pkg_group2 + pkg_group3,
         generator.gen_package(
             idx=6,
             repository=repo3,
             requires=[generator.gen_relation("package2")]
         )
     ]
     controller.clone_repositories.return_value = {
         repo1: mirror1, repo2: mirror2
     }
     controller.copy_packages.return_value = 1
     api = RepositoryApi(controller)
     api.clone_repositories(
         ["file:///repo1", "file:///repo2"], "/mirror",
         ["file:///repo3"],
         keep_existing=True
     )
     controller.copy_packages.assert_any_call(
         mirror1, set(pkg_group1), True
     )
     controller.copy_packages.assert_any_call(
         mirror2, set(pkg_group2), True
     )
     self.assertEqual(2, controller.copy_packages.call_count)
 def test_get_packages_as_is(self):
     controller = CallbacksAdapter()
     pkg = generator.gen_package(name="test")
     controller.load_packages.side_effect = [
         pkg
     ]
     api = RepositoryApi(controller)
     packages = api.get_packages("file:///repo1")
     self.assertEqual(1, len(packages))
     package = packages.pop()
     self.assertIs(pkg, package)
Exemple #3
0
 def test_create_with_config(self, connection_mock, controller_mock,
                             jsonschema_mock):
     config = Configuration(http_proxy="http://localhost",
                            https_proxy="https://localhost",
                            retries_num=10,
                            retry_interval=1,
                            threads_num=8,
                            ignore_errors_num=6)
     RepositoryApi.create(config, "deb", "x86_64")
     connection_mock.assert_called_once_with(
         proxy="http://localhost",
         secure_proxy="https://localhost",
         retries_num=10,
         retry_interval=1)
     controller_mock.load.assert_called_once_with(mock.ANY, "deb", "x86_64")
Exemple #4
0
 def setUp(self):
     self.controller = CallbacksAdapter()
     self.api = RepositoryApi(self.controller)
     self.repo_data = {"name": "repo1", "uri": "file:///repo1"}
     self.requirements_data = [{
         "name": "test1"
     }, {
         "name": "test2",
         "versions": ["< 3", "> 1"]
     }]
     self.schema = {}
     self.repo = generator.gen_repository(**self.repo_data)
     self.controller.load_repositories.return_value = [self.repo]
     self.controller.get_repository_data_schema.return_value = self.schema
     self._generate_packages()
 def test_get_unresolved(self):
     controller = CallbacksAdapter()
     pkg = generator.gen_package(
         name="test", requires=[generator.gen_relation("test2")]
     )
     controller.load_packages.side_effect = [
         pkg
     ]
     api = RepositoryApi(controller)
     r = api.get_unresolved_dependencies("file:///repo1")
     controller.load_repositories.assert_called_once_with("file:///repo1")
     self.assertItemsEqual(
         ["test2"],
         (x.name for x in r)
     )
 def test_create_with_config(self, connection_mock, controller_mock,
                             jsonschema_mock):
     config = Configuration(
         http_proxy="http://localhost", https_proxy="https://localhost",
         retries_num=10, retry_interval=1, threads_num=8,
         ignore_errors_num=6
     )
     RepositoryApi.create(config, "deb", "x86_64")
     connection_mock.assert_called_once_with(
         proxy="http://localhost",
         secure_proxy="https://localhost",
         retries_num=10,
         retry_interval=1
     )
     controller_mock.load.assert_called_once_with(
         mock.ANY, "deb", "x86_64"
     )
 def setUp(self):
     self.controller = CallbacksAdapter()
     self.api = RepositoryApi(self.controller)
     self.repo_data = {"name": "repo1", "uri": "file:///repo1"}
     self.requirements_data = [
         {"name": "test1"}, {"name": "test2", "versions": ["< 3", "> 1"]}
     ]
     self.schema = {}
     self.repo = generator.gen_repository(**self.repo_data)
     self.controller.load_repositories.return_value = [self.repo]
     self.controller.get_repository_data_schema.return_value = self.schema
     self._generate_packages()
 def test_clone_repositories_as_is(self):
     controller = CallbacksAdapter()
     repo = generator.gen_repository(name="repo1")
     packages = [
         generator.gen_package(name="test1", repository=repo),
         generator.gen_package(name="test2", repository=repo)
     ]
     mirror = generator.gen_repository(name="mirror")
     controller.load_repositories.return_value = repo
     controller.load_packages.return_value = packages
     controller.clone_repositories.return_value = {repo: mirror}
     controller.copy_packages.return_value = [0, 1]
     api = RepositoryApi(controller)
     stats = api.clone_repositories(
         ["file:///repo1"], "/mirror", keep_existing=True
     )
     self.assertEqual(2, stats.total)
     self.assertEqual(1, stats.copied)
     controller.copy_packages.assert_called_once_with(
         mirror, set(packages), True
     )
 def test_get_unresolved_with_main(self):
     controller = CallbacksAdapter()
     pkg1 = generator.gen_package(
         name="test1", requires=[
             generator.gen_relation("test2"),
             generator.gen_relation("test3")
         ]
     )
     pkg2 = generator.gen_package(
         name="test2", requires=[generator.gen_relation("test4")]
     )
     controller.load_packages.side_effect = [
         pkg1, pkg2
     ]
     api = RepositoryApi(controller)
     r = api.get_unresolved_dependencies("file:///repo1", "file:///repo2")
     controller.load_repositories.assert_any_call("file:///repo1")
     controller.load_repositories.assert_any_call("file:///repo2")
     self.assertItemsEqual(
         ["test3"],
         (x.name for x in r)
     )
    def test_get_packages_with_depends_resolving(self):
        controller = CallbacksAdapter()
        controller.load_packages.side_effect = [
            [
                generator.gen_package(idx=1, requires=None),
                generator.gen_package(
                    idx=2, requires=[generator.gen_relation("package1")]
                ),
                generator.gen_package(
                    idx=3, requires=[generator.gen_relation("package1")]
                ),
                generator.gen_package(idx=4, requires=None),
                generator.gen_package(idx=5, requires=None),
            ],
            generator.gen_package(
                idx=6, requires=[generator.gen_relation("package2")]
            ),
        ]

        api = RepositoryApi(controller)
        packages = api.get_packages([
            "file:///repo1", "file:///repo2"
        ],
            "file:///repo3", ["package4"]
        )

        self.assertEqual(3, len(packages))
        self.assertItemsEqual(
            ["package1", "package4", "package2"],
            (x.name for x in packages)
        )
        controller.load_repositories.assert_any_call(
            ["file:///repo1", "file:///repo2"]
        )
        controller.load_repositories.assert_any_call(
            "file:///repo3"
        )
    def test_parse_requirements(self):
        requirements = RepositoryApi._parse_requirements(
            ["p1 le 2 | p2 | p3 ge 2"]
        )

        expected = generator.gen_relation(
            "p1",
            ["le", '2'],
            generator.gen_relation(
                "p2",
                None,
                generator.gen_relation(
                    "p3",
                    ["ge", '2']
                )
            )
        )
        self.assertEqual(1, len(requirements))
        self.assertEqual(
            list(expected),
            list(requirements.pop())
        )
Exemple #12
0
class TestRepositoryApi(base.TestCase):
    def setUp(self):
        self.controller = CallbacksAdapter()
        self.api = RepositoryApi(self.controller)
        self.repo_data = {"name": "repo1", "uri": "file:///repo1"}
        self.requirements_data = [{
            "name": "test1"
        }, {
            "name": "test2",
            "versions": ["< 3", "> 1"]
        }]
        self.schema = {}
        self.repo = generator.gen_repository(**self.repo_data)
        self.controller.load_repositories.return_value = [self.repo]
        self.controller.get_repository_data_schema.return_value = self.schema
        self._generate_packages()

    def _generate_packages(self):
        self.packages = [
            generator.gen_package(idx=1, repository=self.repo, requires=None),
            generator.gen_package(idx=2, repository=self.repo, requires=None),
            generator.gen_package(
                idx=3,
                repository=self.repo,
                mandatory=True,
                requires=[generator.gen_relation("package2")]),
            generator.gen_package(
                idx=4,
                repository=self.repo,
                mandatory=False,
                requires=[generator.gen_relation("package1")]),
            generator.gen_package(
                idx=5,
                repository=self.repo,
                requires=[generator.gen_relation("package6")])
        ]
        self.controller.load_packages.return_value = self.packages

    @mock.patch("packetary.api.RepositoryController")
    @mock.patch("packetary.api.ConnectionsManager")
    def test_create_with_config(self, connection_mock, controller_mock,
                                jsonschema_mock):
        config = Configuration(http_proxy="http://localhost",
                               https_proxy="https://localhost",
                               retries_num=10,
                               retry_interval=1,
                               threads_num=8,
                               ignore_errors_num=6)
        RepositoryApi.create(config, "deb", "x86_64")
        connection_mock.assert_called_once_with(
            proxy="http://localhost",
            secure_proxy="https://localhost",
            retries_num=10,
            retry_interval=1)
        controller_mock.load.assert_called_once_with(mock.ANY, "deb", "x86_64")

    @mock.patch("packetary.api.RepositoryController")
    @mock.patch("packetary.api.ConnectionsManager")
    def test_create_with_context(self, connection_mock, controller_mock,
                                 jsonschema_mock):
        config = Configuration(http_proxy="http://localhost",
                               https_proxy="https://localhost",
                               retries_num=10,
                               retry_interval=1,
                               threads_num=8,
                               ignore_errors_num=6)
        context = Context(config)
        RepositoryApi.create(context, "deb", "x86_64")
        connection_mock.assert_called_once_with(
            proxy="http://localhost",
            secure_proxy="https://localhost",
            retries_num=10,
            retry_interval=1)
        controller_mock.load.assert_called_once_with(context, "deb", "x86_64")

    def test_create_repository(self, jsonschema_mock):
        file_urls = ["file://test1.pkg"]
        self.api.create_repository(self.repo_data, file_urls)
        self.controller.create_repository.assert_called_once_with(
            self.repo_data, file_urls)
        jsonschema_mock.validate.assert_has_calls([
            mock.call(self.repo_data, self.schema),
            mock.call(file_urls, PACKAGE_FILES_SCHEMA),
        ])

    def test_get_packages_as_is(self, jsonschema_mock):
        packages = self.api.get_packages([self.repo_data], None, False, None)
        self.assertEqual(5, len(packages))
        self.assertItemsEqual(self.packages, packages)
        jsonschema_mock.validate.assert_called_once_with(
            self.repo_data, self.schema)

    def test_get_packages_by_requirements_with_mandatory(
            self, jsonschema_mock):
        requirements = [{"name": "package1"}]
        packages = self.api.get_packages([self.repo_data], requirements, True,
                                         None)
        self.assertEqual(3, len(packages))
        self.assertItemsEqual(["package1", "package2", "package3"],
                              (x.name for x in packages))
        jsonschema_mock.validate.assert_has_calls([
            mock.call(self.repo_data, self.schema),
            mock.call(requirements, PACKAGES_SCHEMA),
        ])

    def test_get_packages_by_requirements_without_mandatory(
            self, jsonschema_mock):
        requirements = [{"name": "package4"}]
        packages = self.api.get_packages([self.repo_data], requirements, False,
                                         None)
        self.assertEqual(2, len(packages))
        self.assertItemsEqual(["package1", "package4"],
                              (x.name for x in packages))
        jsonschema_mock.validate.assert_has_calls([
            mock.call(self.repo_data, self.schema),
            mock.call(requirements, PACKAGES_SCHEMA),
        ])

    def test_clone_repositories_as_is(self, jsonschema_mock):
        # return value is used as statistics
        mirror = copy.copy(self.repo)
        mirror.url = "file:///mirror/repo"
        self.controller.fork_repository.return_value = mirror
        self.controller.assign_packages.return_value = [0, 1, 1, 1, 0, 6]
        stats = self.api.clone_repositories([self.repo_data], None, "/mirror")
        self.controller.fork_repository.assert_called_once_with(
            self.repo, '/mirror', False, False)
        self.controller.assign_packages.assert_called_once_with(
            mirror, set(self.packages))
        self.assertEqual(6, stats.total)
        self.assertEqual(4, stats.copied)
        jsonschema_mock.validate.assert_called_once_with(
            self.repo_data, self.schema)

    def test_clone_by_requirements_with_mandatory(self, jsonschema_mock):
        # return value is used as statistics
        mirror = copy.copy(self.repo)
        mirror.url = "file:///mirror/repo"
        requirements = [{"name": "package1"}]
        self.controller.fork_repository.return_value = mirror
        self.controller.assign_packages.return_value = [0, 1, 1]
        stats = self.api.clone_repositories([self.repo_data],
                                            requirements,
                                            "/mirror",
                                            include_mandatory=True)
        packages = {self.packages[0], self.packages[1], self.packages[2]}
        self.controller.fork_repository.assert_called_once_with(
            self.repo, '/mirror', False, False)
        self.controller.assign_packages.assert_called_once_with(
            mirror, packages)
        self.assertEqual(3, stats.total)
        self.assertEqual(2, stats.copied)
        jsonschema_mock.validate.assert_has_calls([
            mock.call(self.repo_data, self.schema),
            mock.call(requirements, PACKAGES_SCHEMA),
        ])

    def test_clone_by_requirements_without_mandatory(self, jsonschema_mock):
        # return value is used as statistics
        mirror = copy.copy(self.repo)
        mirror.url = "file:///mirror/repo"
        requirements = [{"name": "package4"}]
        self.controller.fork_repository.return_value = mirror
        self.controller.assign_packages.return_value = [0, 4]
        stats = self.api.clone_repositories([self.repo_data],
                                            requirements,
                                            "/mirror",
                                            include_mandatory=False)
        packages = {self.packages[0], self.packages[3]}
        self.controller.fork_repository.assert_called_once_with(
            self.repo, '/mirror', False, False)
        self.controller.assign_packages.assert_called_once_with(
            mirror, packages)
        self.assertEqual(2, stats.total)
        self.assertEqual(1, stats.copied)
        jsonschema_mock.validate.assert_has_calls([
            mock.call(self.repo_data, self.schema),
            mock.call(requirements, PACKAGES_SCHEMA),
        ])

    def test_clone_with_filter(self, jsonschema_mock):
        repos_data = "repos_data"
        requirements_data = "requirements_data"
        filter_data = "filter_data"
        repos = "repos"
        requirements = "requirements"
        exclude_filter = "exclude_filter"

        self.api._load_repositories = mock.Mock(return_value=repos)
        self.api._load_requirements = mock.Mock(return_value=requirements)
        self.api._load_filter = mock.Mock(return_value=exclude_filter)
        self.api._get_packages = mock.Mock(return_value=set())
        self.api.controller = mock.Mock()

        self.api.clone_repositories(repos_data,
                                    requirements_data,
                                    "destination",
                                    filter_data=filter_data)

        self.api._load_repositories.assert_called_once_with(repos_data)
        self.api._load_requirements.assert_called_once_with(requirements_data)
        self.api._load_filter.assert_called_once_with(filter_data)
        self.api._get_packages.assert_called_once_with(repos, requirements,
                                                       False, exclude_filter)

    def test_get_packages_with_exclude_filter(self, jsonschema_mock):
        exclude_filter = lambda p: any([p == "p1", p == "p3"])
        self.api._load_packages = CallbacksAdapter()
        self.api._load_packages.return_value = ["p1", "p2", "p3", "p4"]
        packages = self.api._get_packages("repos", None, False, exclude_filter)
        self.assertSetEqual(packages, set(["p2", "p4"]))

    def test_get_packages_without_exclude_filter(self, jsonschema_mock):
        self.api._load_packages = CallbacksAdapter()
        self.api._load_packages.return_value = ["p1", "p2"]
        packages = self.api._get_packages("repos", None, False, None)
        self.assertSetEqual(packages, set(["p1", "p2"]))

    def test_get_unresolved(self, jsonschema_mock):
        unresolved = self.api.get_unresolved_dependencies([self.repo_data])
        self.assertItemsEqual(["package6"], (x.name for x in unresolved))
        jsonschema_mock.validate.assert_called_once_with(
            self.repo_data, self.schema)

    def test_load_filter_with_none(self, jsonschema_mock):
        self.assertIsNone(self.api._load_filter(None))

    def test_load_filter(self, jsonschema_mock):
        self.api._validate_filter_data = mock.Mock()
        filter_data = [
            {
                "name": "p1",
                "group": "g1"
            },
            {
                "name": "p2"
            },
            {
                "group": "g3"
            },
            {
                "name": "/^.5/",
                "group": "/^.*3/"
            },
            {
                "group": "/^.*4/"
            },
        ]
        exclude_filter = self.api._load_filter(filter_data)

        p1 = generator.gen_package(name="p1", group="g1")
        p2 = generator.gen_package(name="p2", group="g1")
        p3 = generator.gen_package(name="p3", group="g2")
        p4 = generator.gen_package(name="p4", group="g3")
        p5 = generator.gen_package(name="p5", group="g3")
        p6 = generator.gen_package(name="p6", group="g4")

        cases = [
            (True, (p1, )),
            (True, (p2, )),
            (False, (p3, )),
            (True, (p4, )),
            (True, (p5, )),
            (True, (p6, )),
        ]
        self._check_cases(self.assertEqual, cases, exclude_filter)

    def test_validate_filter_data(self, jsonschema_mock):
        self.api._validate_data = mock.Mock()
        self.api._validate_filter_data("filter_data")
        self.api._validate_data.assert_called_once_with(
            "filter_data", PACKAGE_FILTER_SCHEMA)

    def test_load_requirements(self, jsonschema_mock):
        expected = {
            generator.gen_relation("test1"),
            generator.gen_relation("test2", ["<", "3"]),
            generator.gen_relation("test2", [">", "1"]),
        }
        actual = set(self.api._load_requirements(self.requirements_data))
        self.assertEqual(expected, actual)
        self.assertIsNone(self.api._load_requirements(None))
        jsonschema_mock.validate.assert_called_once_with(
            self.requirements_data, PACKAGES_SCHEMA)

    def test_validate_data(self, jsonschema_mock):
        self.api._validate_data(self.repo_data, self.schema)
        jsonschema_mock.validate.assert_called_once_with(
            self.repo_data, self.schema)

    def test_validate_invalid_data(self, jschema_m):
        jschema_m.ValidationError = jsonschema.ValidationError
        jschema_m.SchemaError = jsonschema.SchemaError
        paths = [(("a", 0), "\['a'\]\[0\]"), ((), "")]
        for path, details in paths:
            msg = "Invalid data: error."
            if details:
                msg += "\nField: {0}".format(details)
            with self.assertRaisesRegexp(ValueError, msg):
                jschema_m.validate.side_effect = jsonschema.ValidationError(
                    "error", path=path)
                self.api._validate_data([], {})
            jschema_m.validate.assert_called_with([], {})
            jschema_m.validate.reset_mock()

            msg = "Invalid schema: error."
            if details:
                msg += "\nField: {0}".format(details)
            with self.assertRaisesRegexp(ValueError, msg):
                jschema_m.validate.side_effect = jsonschema.SchemaError(
                    "error", schema_path=path)
                self.api._validate_data([], {})
            jschema_m.validate.assert_called_with([], {})
class TestRepositoryApi(base.TestCase):
    def setUp(self):
        self.controller = CallbacksAdapter()
        self.api = RepositoryApi(self.controller)
        self.repo_data = {"name": "repo1", "uri": "file:///repo1"}
        self.requirements_data = [
            {"name": "test1"}, {"name": "test2", "versions": ["< 3", "> 1"]}
        ]
        self.schema = {}
        self.repo = generator.gen_repository(**self.repo_data)
        self.controller.load_repositories.return_value = [self.repo]
        self.controller.get_repository_data_schema.return_value = self.schema
        self._generate_packages()

    def _generate_packages(self):
        self.packages = [
            generator.gen_package(idx=1, repository=self.repo, requires=None),
            generator.gen_package(idx=2, repository=self.repo, requires=None),
            generator.gen_package(
                idx=3, repository=self.repo, mandatory=True,
                requires=[generator.gen_relation("package2")]
            ),
            generator.gen_package(
                idx=4, repository=self.repo, mandatory=False,
                requires=[generator.gen_relation("package1")]
            ),
            generator.gen_package(
                idx=5, repository=self.repo,
                requires=[generator.gen_relation("package6")])
        ]
        self.controller.load_packages.return_value = self.packages

    @mock.patch("packetary.api.RepositoryController")
    @mock.patch("packetary.api.ConnectionsManager")
    def test_create_with_config(self, connection_mock, controller_mock,
                                jsonschema_mock):
        config = Configuration(
            http_proxy="http://localhost", https_proxy="https://localhost",
            retries_num=10, retry_interval=1, threads_num=8,
            ignore_errors_num=6
        )
        RepositoryApi.create(config, "deb", "x86_64")
        connection_mock.assert_called_once_with(
            proxy="http://localhost",
            secure_proxy="https://localhost",
            retries_num=10,
            retry_interval=1
        )
        controller_mock.load.assert_called_once_with(
            mock.ANY, "deb", "x86_64"
        )

    @mock.patch("packetary.api.RepositoryController")
    @mock.patch("packetary.api.ConnectionsManager")
    def test_create_with_context(self, connection_mock, controller_mock,
                                 jsonschema_mock):
        config = Configuration(
            http_proxy="http://localhost", https_proxy="https://localhost",
            retries_num=10, retry_interval=1, threads_num=8,
            ignore_errors_num=6
        )
        context = Context(config)
        RepositoryApi.create(context, "deb", "x86_64")
        connection_mock.assert_called_once_with(
            proxy="http://localhost",
            secure_proxy="https://localhost",
            retries_num=10,
            retry_interval=1
        )
        controller_mock.load.assert_called_once_with(
            context, "deb", "x86_64"
        )

    def test_create_repository(self, jsonschema_mock):
        file_urls = ["file://test1.pkg"]
        self.api.create_repository(self.repo_data, file_urls)
        self.controller.create_repository.assert_called_once_with(
            self.repo_data, file_urls
        )
        jsonschema_mock.validate.assert_has_calls(
            [
                mock.call(self.repo_data, self.schema),
                mock.call(file_urls, PACKAGE_FILES_SCHEMA),
            ]
        )

    def test_get_packages_as_is(self, jsonschema_mock):
        packages = self.api.get_packages([self.repo_data], None, False, None)
        self.assertEqual(5, len(packages))
        self.assertItemsEqual(
            self.packages,
            packages
        )
        jsonschema_mock.validate.assert_called_once_with(
            self.repo_data, self.schema
        )

    def test_get_packages_by_requirements_with_mandatory(self,
                                                         jsonschema_mock):
        requirements = [{"name": "package1"}]
        packages = self.api.get_packages(
            [self.repo_data], requirements, True, None
        )
        self.assertEqual(3, len(packages))
        self.assertItemsEqual(
            ["package1", "package2", "package3"],
            (x.name for x in packages)
        )
        jsonschema_mock.validate.assert_has_calls(
            [
                mock.call(self.repo_data, self.schema),
                mock.call(requirements, PACKAGES_SCHEMA),
            ]
        )

    def test_get_packages_by_requirements_without_mandatory(self,
                                                            jsonschema_mock):
        requirements = [{"name": "package4"}]
        packages = self.api.get_packages(
            [self.repo_data], requirements, False, None
        )
        self.assertEqual(2, len(packages))
        self.assertItemsEqual(
            ["package1", "package4"],
            (x.name for x in packages)
        )
        jsonschema_mock.validate.assert_has_calls(
            [
                mock.call(self.repo_data, self.schema),
                mock.call(requirements, PACKAGES_SCHEMA),
            ]
        )

    def test_clone_repositories_as_is(self, jsonschema_mock):
        # return value is used as statistics
        mirror = copy.copy(self.repo)
        mirror.url = "file:///mirror/repo"
        self.controller.fork_repository.return_value = mirror
        self.controller.assign_packages.return_value = [0, 1, 1, 1, 0, 6]
        stats = self.api.clone_repositories([self.repo_data], None, "/mirror")
        self.controller.fork_repository.assert_called_once_with(
            self.repo, '/mirror', False, False
        )
        self.controller.assign_packages.assert_called_once_with(
            mirror, set(self.packages)
        )
        self.assertEqual(6, stats.total)
        self.assertEqual(4, stats.copied)
        jsonschema_mock.validate.assert_called_once_with(
            self.repo_data, self.schema
        )

    def test_clone_by_requirements_with_mandatory(self, jsonschema_mock):
        # return value is used as statistics
        mirror = copy.copy(self.repo)
        mirror.url = "file:///mirror/repo"
        requirements = [{"name": "package1"}]
        self.controller.fork_repository.return_value = mirror
        self.controller.assign_packages.return_value = [0, 1, 1]
        stats = self.api.clone_repositories(
            [self.repo_data], requirements,
            "/mirror", include_mandatory=True
        )
        packages = {self.packages[0], self.packages[1], self.packages[2]}
        self.controller.fork_repository.assert_called_once_with(
            self.repo, '/mirror', False, False
        )
        self.controller.assign_packages.assert_called_once_with(
            mirror, packages
        )
        self.assertEqual(3, stats.total)
        self.assertEqual(2, stats.copied)
        jsonschema_mock.validate.assert_has_calls(
            [
                mock.call(self.repo_data, self.schema),
                mock.call(requirements, PACKAGES_SCHEMA),
            ]
        )

    def test_clone_by_requirements_without_mandatory(self,
                                                     jsonschema_mock):
        # return value is used as statistics
        mirror = copy.copy(self.repo)
        mirror.url = "file:///mirror/repo"
        requirements = [{"name": "package4"}]
        self.controller.fork_repository.return_value = mirror
        self.controller.assign_packages.return_value = [0, 4]
        stats = self.api.clone_repositories(
            [self.repo_data], requirements,
            "/mirror", include_mandatory=False
        )
        packages = {self.packages[0], self.packages[3]}
        self.controller.fork_repository.assert_called_once_with(
            self.repo, '/mirror', False, False
        )
        self.controller.assign_packages.assert_called_once_with(
            mirror, packages
        )
        self.assertEqual(2, stats.total)
        self.assertEqual(1, stats.copied)
        jsonschema_mock.validate.assert_has_calls(
            [
                mock.call(self.repo_data, self.schema),
                mock.call(requirements, PACKAGES_SCHEMA),
            ]
        )

    def test_clone_with_filter(self, jsonschema_mock):
        repos_data = "repos_data"
        requirements_data = "requirements_data"
        filter_data = "filter_data"
        repos = "repos"
        requirements = "requirements"
        exclude_filter = "exclude_filter"

        self.api._load_repositories = mock.Mock(return_value=repos)
        self.api._load_requirements = mock.Mock(return_value=requirements)
        self.api._load_filter = mock.Mock(return_value=exclude_filter)
        self.api._get_packages = mock.Mock(return_value=set())
        self.api.controller = mock.Mock()

        self.api.clone_repositories(repos_data, requirements_data,
                                    "destination", filter_data=filter_data)

        self.api._load_repositories.assert_called_once_with(repos_data)
        self.api._load_requirements.assert_called_once_with(requirements_data)
        self.api._load_filter.assert_called_once_with(filter_data)
        self.api._get_packages.assert_called_once_with(
            repos, requirements, False, exclude_filter)

    def test_get_packages_with_exclude_filter(self, jsonschema_mock):
        exclude_filter = lambda p: any([p == "p1", p == "p3"])
        self.api._load_packages = CallbacksAdapter()
        self.api._load_packages.return_value = ["p1", "p2", "p3", "p4"]
        packages = self.api._get_packages("repos", None, False, exclude_filter)
        self.assertSetEqual(packages, set(["p2", "p4"]))

    def test_get_packages_without_exclude_filter(self, jsonschema_mock):
        self.api._load_packages = CallbacksAdapter()
        self.api._load_packages.return_value = ["p1", "p2"]
        packages = self.api._get_packages("repos", None, False, None)
        self.assertSetEqual(packages, set(["p1", "p2"]))

    def test_get_unresolved(self, jsonschema_mock):
        unresolved = self.api.get_unresolved_dependencies([self.repo_data])
        self.assertItemsEqual(["package6"], (x.name for x in unresolved))
        jsonschema_mock.validate.assert_called_once_with(
            self.repo_data, self.schema
        )

    def test_load_filter_with_none(self, jsonschema_mock):
        self.assertIsNone(self.api._load_filter(None))

    def test_load_filter(self, jsonschema_mock):
        self.api._validate_filter_data = mock.Mock()
        filter_data = [
            {"name": "p1", "group": "g1"},
            {"name": "p2"},
            {"group": "g3"},
            {"name": "/^.5/", "group": "/^.*3/"},
            {"group": "/^.*4/"},
        ]
        exclude_filter = self.api._load_filter(filter_data)

        p1 = generator.gen_package(name="p1", group="g1")
        p2 = generator.gen_package(name="p2", group="g1")
        p3 = generator.gen_package(name="p3", group="g2")
        p4 = generator.gen_package(name="p4", group="g3")
        p5 = generator.gen_package(name="p5", group="g3")
        p6 = generator.gen_package(name="p6", group="g4")

        cases = [
            (True, (p1,)),
            (True, (p2,)),
            (False, (p3,)),
            (True, (p4,)),
            (True, (p5,)),
            (True, (p6,)),
        ]
        self._check_cases(self.assertEqual, cases, exclude_filter)

    def test_validate_filter_data(self, jsonschema_mock):
        self.api._validate_data = mock.Mock()
        self.api._validate_filter_data("filter_data")
        self.api._validate_data.assert_called_once_with("filter_data",
                                                        PACKAGE_FILTER_SCHEMA)

    def test_load_requirements(self, jsonschema_mock):
        expected = {
            generator.gen_relation("test1"),
            generator.gen_relation("test2", ["<", "3"]),
            generator.gen_relation("test2", [">", "1"]),
        }
        actual = set(self.api._load_requirements(
            self.requirements_data
        ))
        self.assertEqual(expected, actual)
        self.assertIsNone(self.api._load_requirements(None))
        jsonschema_mock.validate.assert_called_once_with(
            self.requirements_data,
            PACKAGES_SCHEMA
        )

    def test_validate_data(self, jsonschema_mock):
        self.api._validate_data(self.repo_data, self.schema)
        jsonschema_mock.validate.assert_called_once_with(
            self.repo_data, self.schema
        )

    def test_validate_invalid_data(self, jschema_m):
        jschema_m.ValidationError = jsonschema.ValidationError
        jschema_m.SchemaError = jsonschema.SchemaError
        paths = [(("a", 0), "\['a'\]\[0\]"), ((), "")]
        for path, details in paths:
            msg = "Invalid data: error."
            if details:
                msg += "\nField: {0}".format(details)
            with self.assertRaisesRegexp(ValueError, msg):
                jschema_m.validate.side_effect = jsonschema.ValidationError(
                    "error", path=path
                )
                self.api._validate_data([], {})
            jschema_m.validate.assert_called_with([], {})
            jschema_m.validate.reset_mock()

            msg = "Invalid schema: error."
            if details:
                msg += "\nField: {0}".format(details)
            with self.assertRaisesRegexp(ValueError, msg):
                jschema_m.validate.side_effect = jsonschema.SchemaError(
                    "error", schema_path=path
                )
                self.api._validate_data([], {})
            jschema_m.validate.assert_called_with([], {})