def test_exception_on_failed_make_install(self, mock_isdir, mock_makedirs,
                                              mock_cwd, mock_chdir, mock_popen,
                                              mock_open):
        mock_isdir.side_effect = [
            True,  # Global package cache first access
            False,  # Local package cache first access
            True,  # Global package cache second access
            True,  # Local package cache second access
            True,  # Global package cache third access
            True  # Local package cache third access
        ]
        mock_popen.side_effect = [
            MockProcess("CMAKE_OUT", "ERR", 0),
            MockProcess("MAKE_OUT", "ERR", 0),
            MockProcess("MAKE_INSTALL_OUT", "ERR", 1)
        ]
        self.assertRaises(PackageInstallerException,
                          self.installer.install_packages, self.package_list)

        popen_calls = [
            call([
                "cmake", ".",
                "-DCMAKE_INSTALL_PREFIX=" + self.conf["LocalPackageCache"]
            ],
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE),
            call(["make"], stdout=subprocess.PIPE, stderr=subprocess.PIPE),
            call(["make", "install"],
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE)
        ]
        mock_popen.assert_has_calls(popen_calls, any_order=False)
Esempio n. 2
0
    def test_build_happy_case(self, mock_makedirs, mock_popen, mock_isdir,
                              mock_chdir, mock_getcwd):
        # Mock popen calls
        p_cmake = MockProcess("OUT", "ERR", TestCppCmake.EXIT_SUCCESS)
        p_make = MockProcess("OUT", "ERR", TestCppCmake.EXIT_SUCCESS)

        # Argument captors
        makedirs_calls = [call(self.config_obj["BuildDir"])]
        isdir_calls = [call(self.config_obj["BuildDir"])]
        chdir_calls = [
            call(self.config_obj["BuildDir"]),
            call(self.config_obj["ProjectRoot"])
        ]
        popen_calls = [
            call([
                "cmake", self.config_obj["ProjectRoot"],
                "-DPACKAGE_CACHE=" + self.config_obj["LocalPackageCache"]
            ],
                 stdout=subprocess.PIPE),
            call(["make"])
        ]
        mock_popen.side_effect = [p_cmake, p_make]

        self.builder.build()
        mock_isdir.assert_has_calls(isdir_calls, any_order=False)
        mock_makedirs.assert_has_calls(makedirs_calls, any_order=False)
        mock_chdir.assert_has_calls(chdir_calls, any_order=False)
        mock_popen.assert_has_calls(popen_calls, any_order=False)
 def test_exception_on_failed_wget(self, mock_file, mock_tarfile,
                                   mock_popen, mock_makedirs, mock_isdir,
                                   mock_isfile):
     wget_1 = MockProcess("ERR", "ERROR occured",
                          TestPackageDownloader.EXIT_FAILURE)
     wget_2 = MockProcess("ERR", "OUT", TestPackageDownloader.EXIT_SUCCESS)
     mock_popen.side_effect = [wget_1, wget_2]
     self.assertRaises(PackageDownloaderException,
                       self.downloader.download_and_extract,
                       self.package_list)
    def test_exception_on_extract_fail(self, mock_file, mock_tarfile,
                                       mock_popen, mock_makedirs, mock_isdir,
                                       mock_isfile):
        wget_1 = MockProcess("ERR", "OUT", TestPackageDownloader.EXIT_SUCCESS)
        wget_2 = MockProcess("ERR", "OUT", TestPackageDownloader.EXIT_SUCCESS)
        mock_popen.side_effect = [wget_1, wget_2]

        tarfile_pointer = MockTarfilePointer()
        mock_tarfile.side_effect = [tarfile_pointer]
        tarfile_pointer.set_exception()
        self.assertRaises(PackageDownloaderException,
                          self.downloader.download_and_extract,
                          self.package_list)
Esempio n. 5
0
    def test_exception_on_failed_snapcraft_command(self, mock_temp_dir,
                                                   mock_makedirs, mock_open,
                                                   mock_getcwd, mock_chdir,
                                                   mock_subprocess,
                                                   mock_listdir, mock_copyfile,
                                                   mock_isfile):
        # Set up mocks
        mock_temp_dir.side_effect = [
            MockTemporaryDirectory("MY_TEMPORARY_DIRECTORY")
        ]
        snap_yaml_fp = MockFilePointer()
        mock_open.side_effect = [snap_yaml_fp]

        snap_process = MockProcess("OUT", "ERR", 1)
        mock_subprocess.side_effect = [snap_process]

        dirs = ["papaya.snap"]
        mock_listdir.side_effect = [dirs]

        # Make the package call
        conf = copy.deepcopy(self.conf)
        for key in self.package_step:
            conf[key] = self.package_step[key]
        snapper = SnapCMake(conf)
        self.assertRaises(SnapCMakeException, snapper.package)
Esempio n. 6
0
    def test_happy_case(self, mock_temp_dir, mock_makedirs, mock_open,
                        mock_getcwd, mock_chdir, mock_subprocess, mock_listdir,
                        mock_copyfile, mock_isfile):
        # Set up mocks
        mock_temp_dir.side_effect = [
            MockTemporaryDirectory("MY_TEMPORARY_DIRECTORY")
        ]
        snap_yaml_fp = MockFilePointer()
        print()
        mock_open.side_effect = [snap_yaml_fp]

        snap_process = MockProcess("OUT", "ERR", 0)
        mock_subprocess.side_effect = [snap_process]

        dirs = ["papaya.snap"]
        mock_listdir.side_effect = [dirs]

        # Make the package call
        conf = copy.deepcopy(self.conf)
        for key in self.package_step:
            conf[key] = self.package_step[key]
        snapper = SnapCMake(conf)
        snapper.package()

        # Validate chdir to temp dir and back
        mock_chdir_calls = [call("MY_TEMPORARY_DIRECTORY"), call("CWD")]
        mock_chdir.assert_has_calls(mock_chdir_calls)

        # Validate creation of snapcraft.yaml file
        yaml_contents = yaml.load(snap_yaml_fp.invocations["write"][0])
        for key in self.package_step:
            # Skip checking the Apps section here
            if key != "Apps":
                self.assertEquals(self.package_step[key],
                                  yaml_contents[key.lower()])
        self.assertEquals(self.package_step["Apps"][0]["Command"],
                          yaml_contents["apps"]["MY_APP_1"]["command"])
        self.assertEquals(self.package_step["Apps"][1]["Command"],
                          yaml_contents["apps"]["MY_APP_2"]["command"])

        self.assertEquals("A", list(yaml_contents["parts"].keys())[0])
        self.assertEquals("cmake", yaml_contents["parts"]["A"]["plugin"])
        source = os.path.join(self.conf["GlobalPackageCache"],
                              self.conf["Dependencies"][0]["Name"],
                              self.conf["Dependencies"][0]["Version"],
                              self.conf["Dependencies"][0]["Name"] + ".tar")
        self.assertEquals(source, yaml_contents["parts"]["A"]["source"])
        self.assertEquals(1, len(snap_yaml_fp.invocations["write"]))

        # Validate it called snapcraft command
        popen_calls = [call(["snapcraft"])]
        mock_subprocess.assert_has_calls(popen_calls)

        # Validate it copied the snap back to the build folder
        mock_copyfile_calls = [
            call(os.path.join("MY_TEMPORARY_DIRECTORY", "papaya.snap"),
                 os.path.join(self.conf["BuildFolder"], "papaya.snap"))
        ]
        mock_copyfile.assert_has_calls(mock_copyfile_calls)
Esempio n. 7
0
 def test_exception_on_make_error_during_build(self, mock_makedirs,
                                               mock_popen, mock_isdir,
                                               mock_chdir, mock_getcwd):
     mock_popen.side_effect = [
         MockProcess("OUT", "ERR", TestCppCmake.EXIT_SUCCESS),
         OSError("No such file")
     ]
     self.assertRaises(BuildException, self.builder.build)
    def test_exception_on_failure_to_extract(self, mock_file, mock_tarfile,
                                             mock_popen, mock_makedirs,
                                             mock_isdir):
        # Mocks
        wget_1 = MockProcess("ERR", "OUT", TestPackageDownloader.EXIT_FAILURE)
        wget_2 = MockProcess("ERR", "OUT", TestPackageDownloader.EXIT_SUCCESS)
        tarfile_open = MockTarfilePointer()
        tarfile_open.set_exception()
        file_open = MockFilePointer()

        mock_tarfile.side_effect = [tarfile_open, tarfile_open, tarfile_open]
        mock_file.side_effect = [file_open]
        mock_popen.side_effect = [wget_1, wget_2]

        self.assertRaises(PackageDownloaderException,
                          self.downloader.download_and_extract,
                          self.package_list)
    def test_exception_on_failed_s3_download(self, mock_s3, mock_file,
                                             mock_tarfile, mock_popen,
                                             mock_makedirs, mock_isdir,
                                             mock_isfile):
        # Mocks
        mock_isfile.side_effect = [True, False, True]
        wget_1 = MockProcess("ERR", "OUT", TestPackageDownloader.EXIT_FAILURE)
        wget_2 = MockProcess("ERR", "OUT", TestPackageDownloader.EXIT_SUCCESS)
        tarfile_open = MockTarfilePointer()
        file_open = MockFilePointer()

        mock_tarfile.side_effect = [tarfile_open, tarfile_open, tarfile_open]
        mock_file.side_effect = [file_open]
        mock_popen.side_effect = [wget_1, wget_2]

        downloader = PackageDownloader(self.config_obj)

        downloader.s3_client.set_up_client_error()
        self.assertRaises(PackageDownloaderException,
                          downloader.download_and_extract, self.package_list)
Esempio n. 10
0
    def test_run_test_happy_case(self, mock_popen, mock_isdir, mock_chdir,
                                 mock_getcwd):
        # Mock popen calls
        p_make = MockProcess("OUT", "ERR", TestCppCmake.EXIT_SUCCESS)
        # Argument captors
        isdir_calls = [call(self.config_obj["BuildDir"])]
        chdir_calls = [
            call(self.config_obj["BuildDir"]),
            call(self.config_obj["ProjectRoot"])
        ]
        popen_calls = [call(["make", "test"])]
        mock_popen.side_effect = [p_make]

        self.builder.run_tests()
        mock_isdir.assert_has_calls(isdir_calls, any_order=False)
        mock_chdir.assert_has_calls(chdir_calls, any_order=False)
        mock_popen.assert_has_calls(popen_calls, any_order=False)
class TestPackageInstaller(unittest.TestCase):
    def setUp(self):
        self.conf = {
            "GlobalPackageCache": "GLOBAL_CACHE",
            "LocalPackageCache": "LOCAL_CACHE",
            "Logger": MockLog()
        }
        self.package_list = [{
            "Name": "A",
            "Version": "1.0"
        }, {
            "Name": "B",
            "Version": "2.0"
        }]
        self.md = {
            "A": {
                "Dependencies": [{
                    "Name": "C",
                    "Version": "3.0"
                }],
                "TestDeps": [{
                    "Name": "B",
                    "Version": "2.0"
                }]
            },
            "B": {
                "BuildDeps": [{
                    "Name": "Z",
                    "Version": "1.0"
                }],
                "RuntimeDeps": [{
                    "Name": "X",
                    "Version": "0.0"
                }]
            }
        }
        self.installer = PackageInstaller(self.conf)

    @patch("builtins.open", autospec=True)
    @patch("subprocess.Popen", return_value=MockProcess("OUT", "ERR", 0))
    @patch("os.chdir", return_value=None)
    @patch("os.getcwd", return_value="CWD")
    @patch("os.makedirs", return_value=None)
    @patch("os.path.isdir", autospec=True)
    def test_package_installer_happy_case(self, mock_isdir, mock_makedirs,
                                          mock_cwd, mock_chdir, mock_popen,
                                          mock_open):
        mock_isdir.side_effect = [
            True,  # Global package cache first access
            False,  # Local package cache first access
            True,  # Global package cache second access
            True,  # Local package cache second access
            True,  # Global package cache third access
            True  # Local package cache third access
        ]
        md_file_A = MockFilePointer(read_text=json.dumps(self.md["A"]))
        md_file_B = MockFilePointer(read_text=json.dumps(self.md["B"]))
        mock_open.side_effect = [md_file_A, md_file_B]

        actual_deps = self.installer.install_packages(self.package_list)
        expexted_deps = {}
        for dep in self.md["A"]["Dependencies"] + self.md["A"][
                "TestDeps"] + self.md["B"]["RuntimeDeps"] + self.md["B"][
                    "BuildDeps"]:
            expexted_deps[dep["Name"]] = dep
        self.assertEqual(expexted_deps, actual_deps)

        isdir_calls = [
            call(
                os.path.join(self.conf["GlobalPackageCache"],
                             self.package_list[0]["Name"],
                             self.package_list[0]["Version"])),
            call(self.conf["LocalPackageCache"]),
            call(
                os.path.join(self.conf["GlobalPackageCache"],
                             self.package_list[1]["Name"],
                             self.package_list[1]["Version"])),
            call(self.conf["LocalPackageCache"])
        ]
        mock_isdir.assert_has_calls(isdir_calls, any_order=False)

        makedirs_calls = [call(self.conf["LocalPackageCache"])]
        mock_makedirs.assert_has_calls(makedirs_calls, any_order=False)

        def get_chdir_call(i):
            return [
                call(
                    os.path.join(self.conf["GlobalPackageCache"],
                                 self.package_list[i]["Name"],
                                 self.package_list[i]["Version"])),
                call("CWD")
            ] * 3

        chdir_calls = get_chdir_call(0) + get_chdir_call(1)
        mock_chdir.assert_has_calls(chdir_calls, any_order=False)

        popen_calls = [
            call([
                "cmake", ".",
                "-DCMAKE_INSTALL_PREFIX=" + self.conf["LocalPackageCache"]
            ],
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE),
            call(["make"], stdout=subprocess.PIPE, stderr=subprocess.PIPE),
            call(["make", "install"],
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE)
        ] * 2
        mock_popen.assert_has_calls(popen_calls, any_order=False)

    @patch("builtins.open", autospec=True)
    @patch("subprocess.Popen", autospec=True)
    @patch("os.chdir", return_value=None)
    @patch("os.getcwd", return_value="CWD")
    @patch("os.makedirs", return_value=None)
    @patch("os.path.isdir", autospec=True)
    def test_exception_on_absent_package(self, mock_isdir, mock_makedirs,
                                         mock_cwd, mock_chdir, mock_popen,
                                         mock_open):
        mock_isdir.side_effect = [
            False,  # Global package cache first access
            False,  # Local package cache first access
            True,  # Global package cache second access
            True,  # Local package cache second access
            True,  # Global package cache third access
            True  # Local package cache third access
        ]
        md_file_A = MockFilePointer(read_text=json.dumps(self.md["A"]))
        md_file_B = MockFilePointer(read_text=json.dumps(self.md["B"]))
        mock_open.side_effect = [md_file_A, md_file_B]

        self.assertRaises(PackageInstallerException,
                          self.installer.install_packages, self.package_list)

    @patch("builtins.open", autospec=True)
    @patch("subprocess.Popen", return_value=MockProcess("OUT", "ERR", 0))
    @patch("os.chdir", return_value=None)
    @patch("os.getcwd", return_value="CWD")
    @patch("os.makedirs", return_value=None)
    @patch("os.path.isdir", autospec=True)
    def test_exception_on_absent_cmake(self, mock_isdir, mock_makedirs,
                                       mock_cwd, mock_chdir, mock_popen,
                                       mock_open):
        mock_isdir.side_effect = [
            True,  # Global package cache first access
            False,  # Local package cache first access
            True,  # Global package cache second access
            True,  # Local package cache second access
            True,  # Global package cache third access
            True  # Local package cache third access
        ]
        mock_popen.side_effect = OSError()

        self.assertRaises(PackageInstallerException,
                          self.installer.install_packages, self.package_list)

        popen_calls = [
            call([
                "cmake", ".",
                "-DCMAKE_INSTALL_PREFIX=" + self.conf["LocalPackageCache"]
            ],
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE)
        ]
        mock_popen.assert_has_calls(popen_calls, any_order=False)

    @patch("builtins.open", autospec=True)
    @patch("subprocess.Popen", return_value=MockProcess("OUT", "ERR", 0))
    @patch("os.chdir", return_value=None)
    @patch("os.getcwd", return_value="CWD")
    @patch("os.makedirs", return_value=None)
    @patch("os.path.isdir", autospec=True)
    def test_exception_on_absent_make(self, mock_isdir, mock_makedirs,
                                      mock_cwd, mock_chdir, mock_popen,
                                      mock_open):
        mock_isdir.side_effect = [
            True,  # Global package cache first access
            False,  # Local package cache first access
            True,  # Global package cache second access
            True,  # Local package cache second access
            True,  # Global package cache third access
            True  # Local package cache third access
        ]
        mock_popen.side_effect = [MockProcess("OUT", "ERR", 0), OSError()]
        self.assertRaises(PackageInstallerException,
                          self.installer.install_packages, self.package_list)

        popen_calls = [
            call([
                "cmake", ".",
                "-DCMAKE_INSTALL_PREFIX=" + self.conf["LocalPackageCache"]
            ],
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE),
            call(["make"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        ]
        mock_popen.assert_has_calls(popen_calls, any_order=False)

    @patch("builtins.open", autospec=True)
    @patch("subprocess.Popen", return_value=MockProcess("OUT", "ERR", 0))
    @patch("os.chdir", return_value=None)
    @patch("os.getcwd", return_value="CWD")
    @patch("os.makedirs", return_value=None)
    @patch("os.path.isdir", autospec=True)
    def test_exception_on_failed_cmake(self, mock_isdir, mock_makedirs,
                                       mock_cwd, mock_chdir, mock_popen,
                                       mock_open):
        mock_isdir.side_effect = [
            True,  # Global package cache first access
            False,  # Local package cache first access
            True,  # Global package cache second access
            True,  # Local package cache second access
            True,  # Global package cache third access
            True  # Local package cache third access
        ]
        mock_popen.side_effect = [MockProcess("CMAKE_OUT", "ERR", 1)]
        self.assertRaises(PackageInstallerException,
                          self.installer.install_packages, self.package_list)

        popen_calls = [
            call([
                "cmake", ".",
                "-DCMAKE_INSTALL_PREFIX=" + self.conf["LocalPackageCache"]
            ],
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE),
        ]
        mock_popen.assert_has_calls(popen_calls, any_order=False)

    @patch("builtins.open", autospec=True)
    @patch("subprocess.Popen", return_value=MockProcess("OUT", "ERR", 0))
    @patch("os.chdir", return_value=None)
    @patch("os.getcwd", return_value="CWD")
    @patch("os.makedirs", return_value=None)
    @patch("os.path.isdir", autospec=True)
    def test_exception_on_failed_make(self, mock_isdir, mock_makedirs,
                                      mock_cwd, mock_chdir, mock_popen,
                                      mock_open):
        mock_isdir.side_effect = [
            True,  # Global package cache first access
            False,  # Local package cache first access
            True,  # Global package cache second access
            True,  # Local package cache second access
            True,  # Global package cache third access
            True  # Local package cache third access
        ]
        mock_popen.side_effect = [
            MockProcess("CMAKE_OUT", "ERR", 0),
            MockProcess("MAKE_OUT", "ERR", 1)
        ]
        self.assertRaises(PackageInstallerException,
                          self.installer.install_packages, self.package_list)

        popen_calls = [
            call([
                "cmake", ".",
                "-DCMAKE_INSTALL_PREFIX=" + self.conf["LocalPackageCache"]
            ],
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE),
            call(["make"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        ]
        mock_popen.assert_has_calls(popen_calls, any_order=False)

    @patch("builtins.open", autospec=True)
    @patch("subprocess.Popen", return_value=MockProcess("OUT", "ERR", 0))
    @patch("os.chdir", return_value=None)
    @patch("os.getcwd", return_value="CWD")
    @patch("os.makedirs", return_value=None)
    @patch("os.path.isdir", autospec=True)
    def test_exception_on_failed_make_install(self, mock_isdir, mock_makedirs,
                                              mock_cwd, mock_chdir, mock_popen,
                                              mock_open):
        mock_isdir.side_effect = [
            True,  # Global package cache first access
            False,  # Local package cache first access
            True,  # Global package cache second access
            True,  # Local package cache second access
            True,  # Global package cache third access
            True  # Local package cache third access
        ]
        mock_popen.side_effect = [
            MockProcess("CMAKE_OUT", "ERR", 0),
            MockProcess("MAKE_OUT", "ERR", 0),
            MockProcess("MAKE_INSTALL_OUT", "ERR", 1)
        ]
        self.assertRaises(PackageInstallerException,
                          self.installer.install_packages, self.package_list)

        popen_calls = [
            call([
                "cmake", ".",
                "-DCMAKE_INSTALL_PREFIX=" + self.conf["LocalPackageCache"]
            ],
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE),
            call(["make"], stdout=subprocess.PIPE, stderr=subprocess.PIPE),
            call(["make", "install"],
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE)
        ]
        mock_popen.assert_has_calls(popen_calls, any_order=False)

    @patch("builtins.open", autospec=True)
    @patch("subprocess.Popen", return_value=MockProcess("OUT", "ERR", 0))
    @patch("os.chdir", return_value=None)
    @patch("os.getcwd", return_value="CWD")
    @patch("os.makedirs", return_value=None)
    @patch("os.path.isdir", autospec=True)
    def test_exception_on_invalid_metadata_file(self, mock_isdir,
                                                mock_makedirs, mock_cwd,
                                                mock_chdir, mock_popen,
                                                mock_open):
        mock_isdir.side_effect = [
            True,  # Global package cache first access
            False,  # Local package cache first access
            True,  # Global package cache second access
            True,  # Local package cache second access
            True,  # Global package cache third access
            True  # Local package cache third access
        ]
        md_file_A = MockFilePointer(read_text="Bad json")
        md_file_B = MockFilePointer(read_text=json.dumps(self.md["B"]))
        mock_open.side_effect = [md_file_A, md_file_B]

        self.assertRaises(PackageInstallerException,
                          self.installer.install_packages, self.package_list)

    @patch("builtins.open", autospec=True)
    @patch("subprocess.Popen", return_value=MockProcess("OUT", "ERR", 0))
    @patch("os.chdir", return_value=None)
    @patch("os.getcwd", return_value="CWD")
    @patch("os.makedirs", return_value=None)
    @patch("os.path.isdir", autospec=True)
    def test_exception_on_invalid_absent_file(self, mock_isdir, mock_makedirs,
                                              mock_cwd, mock_chdir, mock_popen,
                                              mock_open):
        mock_isdir.side_effect = [
            True,  # Global package cache first access
            False,  # Local package cache first access
            True,  # Global package cache second access
            True,  # Local package cache second access
            True,  # Global package cache third access
            True  # Local package cache third access
        ]
        md_file_A = OSError()
        md_file_B = MockFilePointer(read_text=json.dumps(self.md["B"]))
        mock_open.side_effect = [md_file_A, md_file_B]

        self.assertRaises(PackageInstallerException,
                          self.installer.install_packages, self.package_list)

    def test_init_errors(self):
        self.assertRaises(PackageInstallerException, PackageInstaller, {})
        self.assertRaises(PackageInstallerException, PackageInstaller, 10)
    def test_packages_downloaded_happy_case(self, mock_file, mock_tarfile,
                                            mock_popen, mock_makedirs,
                                            mock_isdir, mock_isfile):
        # Mocks
        wget_1 = MockProcess("ERR", "OUT", TestPackageDownloader.EXIT_SUCCESS)
        wget_2 = MockProcess("ERR", "OUT", TestPackageDownloader.EXIT_SUCCESS)
        tarfile_open = MockTarfilePointer()
        file_open = MockFilePointer()

        # Argument captors
        isdir_calls = [
            call(self.config_obj["GlobalPackageCache"]),
            call(
                os.path.join(self.config_obj["GlobalPackageCache"], "A",
                             "1.0")),
            call(self.config_obj["GlobalPackageCache"]),
            call(
                os.path.join(self.config_obj["GlobalPackageCache"], "B",
                             "2.0")),
            call(self.config_obj["GlobalPackageCache"]),
            call(
                os.path.join(self.config_obj["GlobalPackageCache"], "C",
                             "3.0"))
        ]
        makedirs_calls = [
            call(self.config_obj["GlobalPackageCache"]),
            call(
                os.path.join(self.config_obj["GlobalPackageCache"],
                             self.package_list[0]["Name"],
                             self.package_list[0]["Version"])),
            call(
                os.path.join(self.config_obj["GlobalPackageCache"],
                             self.package_list[1]["Name"],
                             self.package_list[1]["Version"])),
            call(
                os.path.join(self.config_obj["GlobalPackageCache"],
                             self.package_list[2]["Name"],
                             self.package_list[2]["Version"]))
        ]
        wget_url_1 = "/".join([
            self.config_obj["PackageSource"]["Url"],
            self.package_list[0]["Name"], self.package_list[0]["Version"],
            self.package_list[0]["Name"] + ".tar"
        ])
        dest_1 = os.path.join(self.config_obj["GlobalPackageCache"],
                              self.package_list[0]["Name"],
                              self.package_list[0]["Version"],
                              self.package_list[0]["Name"] + ".tar")

        wget_url_2 = "/".join([
            self.package_list[2]["PackageSource"]["Url"],
            self.package_list[2]["Name"], self.package_list[2]["Version"],
            self.package_list[2]["Name"] + ".tar"
        ])
        dest_2 = os.path.join(self.config_obj["GlobalPackageCache"],
                              self.package_list[2]["Name"],
                              self.package_list[2]["Version"],
                              self.package_list[2]["Name"] + ".tar")
        popen_calls = [
            call(["wget", wget_url_1, "-O", dest_1],
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE),
            call(["wget", wget_url_2, "-O", dest_2],
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE)
        ]
        s3_key = os.path.join(self.package_list[1]["Name"],
                              self.package_list[1]["Version"],
                              self.package_list[1]["Name"] + ".tar")
        tarfile_opens = [
            os.path.join(self.config_obj["GlobalPackageCache"],
                         self.package_list[0]["Name"],
                         self.package_list[0]["Version"]),
            os.path.join(self.config_obj["GlobalPackageCache"],
                         self.package_list[1]["Name"],
                         self.package_list[1]["Version"]),
            os.path.join(self.config_obj["GlobalPackageCache"],
                         self.package_list[2]["Name"],
                         self.package_list[2]["Version"])
        ]

        mock_isdir.side_effect = [False, False, True, False, True, False]
        mock_tarfile.side_effect = [tarfile_open, tarfile_open, tarfile_open]
        mock_file.side_effect = [file_open]
        mock_popen.side_effect = [wget_1, wget_2]

        self.downloader.download_and_extract(self.package_list)

        mock_isdir.assert_has_calls(isdir_calls, any_order=False)
        mock_makedirs.assert_has_calls(makedirs_calls, any_order=False)
        mock_popen.assert_has_calls(popen_calls)
        self.assertEqual(1, len(self.downloader.s3_client.invocations))
        self.assertEqual((self.package_list[1]["PackageSource"]["Bucket"],
                          s3_key, file_open),
                         self.downloader.s3_client.invocations[0])
        self.assertEqual(tarfile_opens, tarfile_open.invocations["extractall"])