예제 #1
0
def test_invalid_jdk_archive(test_command, tmp_path):
    "If the JDK download isn't a valid archive, raise an error"
    # Mock Linux as the host
    test_command.host_os = 'Linux'

    # Mock the cached download path
    # Consider to remove if block when we drop py3.7 support, only keep statements from else.
    # MagicMock below py3.8 doesn't has __fspath__ attribute.
    if sys.version_info < (3, 8):
        archive = FsPathMock("/path/to/download.zip")
    else:
        archive = mock.MagicMock()
        archive.__fspath__.return_value = "/path/to/download.zip"
    test_command.download_url.return_value = archive

    # Mock an unpack failure due to an invalid archive
    test_command.shutil.unpack_archive.side_effect = shutil.ReadError

    with pytest.raises(BriefcaseCommandError):
        JDK.verify(command=test_command)

    # The download occurred
    test_command.download_url.assert_called_with(
        url=
        "https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/"
        "jdk8u242-b08/OpenJDK8U-jdk_x64_linux_hotspot_8u242b08.tar.gz",
        download_path=tmp_path / "tools",
    )
    # An attempt was made to unpack the archive.
    # TODO: Py3.6 compatibility; os.fsdecode not required in Py3.7
    test_command.shutil.unpack_archive.assert_called_with(
        "/path/to/download.zip", extract_dir=os.fsdecode(tmp_path / "tools"))
    # The original archive was not deleted
    assert archive.unlink.call_count == 0
예제 #2
0
def test_default_name(mock_sdk, tmp_path):
    "A new emulator can be created with the default name."
    # This test doesn't validate most of the test process;
    # it only checks that the emulator is created with the default name.

    # User provides no input; default name will be used
    mock_sdk.command.input.return_value = ''

    # Mock the initial output of an AVD config file.
    avd_config_path = tmp_path / ".android" / "avd" / 'beePhone.avd' / 'config.ini'
    avd_config_path.parent.mkdir(parents=True)
    with avd_config_path.open('w') as f:
        f.write('hw.device.name=pixel\n')

    # Consider to remove if block when we drop py3.7 support.
    # MagicMock below py3.8 doesn't has __fspath__ attribute.
    if sys.version_info < (3, 8):
        skin_tgz_path = FsPathMock("")
        mock_sdk.command.download_url.return_value = skin_tgz_path

    # Create the emulator
    avd = mock_sdk.create_emulator()

    # The expected device AVD was created.
    assert avd == 'beePhone'
예제 #3
0
def test_default_name_with_collisions(mock_sdk, tmp_path):
    """The default name will avoid collisions with existing emulators."""
    # This test doesn't validate most of the test process;
    # it only checks that the emulator is created with the default name.

    # Create some existing emulators that will collide with the default name.
    mock_sdk.emulators = MagicMock(return_value=[
        "beePhone2",
        "runningEmulator",
        "beePhone",
    ])
    # User provides no input; default name will be used
    mock_sdk.command.input.return_value = ""

    # Mock the initial output of an AVD config file.
    avd_config_path = tmp_path / ".android" / "avd" / "beePhone3.avd" / "config.ini"
    avd_config_path.parent.mkdir(parents=True)
    with avd_config_path.open("w") as f:
        f.write("hw.device.name=pixel\n")

    # Consider to remove if block when we drop py3.7 support.
    # MagicMock below py3.8 doesn't has __fspath__ attribute.
    if sys.version_info < (3, 8):
        skin_tgz_path = FsPathMock("")
        mock_sdk.command.download_url.return_value = skin_tgz_path

    # Create the emulator
    avd = mock_sdk.create_emulator()

    # The expected device AVD was created.
    assert avd == "beePhone3"
예제 #4
0
def test_unpack_failure(mock_sdk, tmp_path):
    """If the download is corrupted and unpacking fails, an error is raised."""
    # Mock a valid user response.
    mock_sdk.command.input.return_value = "new-emulator"

    # Mock the result of the download of a skin
    # Consider to remove if block when we drop py3.7 support, only keep statements from else.
    # MagicMock below py3.8 doesn't has __fspath__ attribute.
    if sys.version_info < (3, 8):
        skin_tgz_path = FsPathMock("/path/to/skin.tgz")
    else:
        skin_tgz_path = MagicMock()
        skin_tgz_path.__fspath__.return_value = "/path/to/skin.tgz"
    mock_sdk.command.download_url.return_value = skin_tgz_path

    # Mock a failure unpacking the skin
    mock_sdk.command.shutil.unpack_archive.side_effect = EOFError

    # Create the emulator
    with pytest.raises(BriefcaseCommandError):
        mock_sdk.create_emulator()

    # avdmanager was invoked
    mock_sdk.command.subprocess.check_output.assert_called_once_with(
        [
            os.fsdecode(mock_sdk.avdmanager_path),
            "--verbose",
            "create",
            "avd",
            "--name",
            "new-emulator",
            "--abi",
            "x86_64",
            "--package",
            "system-images;android-31;default;x86_64",
            "--device",
            "pixel",
        ],
        env=mock_sdk.env,
        stderr=subprocess.STDOUT,
    )

    # Skin was downloaded
    mock_sdk.command.download_url.assert_called_once_with(
        url="https://android.googlesource.com/platform/tools/adt/idea/"
        "+archive/refs/heads/mirror-goog-studio-master-dev/"
        "artwork/resources/device-art-resources/pixel_3a.tar.gz",
        download_path=mock_sdk.root_path,
    )

    # An attempt to unpack the skin was made.
    mock_sdk.command.shutil.unpack_archive.assert_called_once_with(
        skin_tgz_path, extract_dir=mock_sdk.root_path / "skins" / "pixel_3a")

    # Original file wasn't deleted.
    assert skin_tgz_path.unlink.call_count == 0
예제 #5
0
def test_macOS_existing_install(test_command, tmp_path):
    """If there's an existing managed macOS JDK install, it is deleted and
    redownloaded."""
    # Force mocking on macOS
    test_command.host_os = "Darwin"

    # Create a mock of a previously installed Java version.
    java_home = tmp_path / "tools" / "java" / "Contents" / "Home"
    (java_home / "bin").mkdir(parents=True)

    # We actually need to delete the original java install
    def rmtree(path):
        shutil.rmtree(path)

    test_command.shutil.rmtree.side_effect = rmtree

    # Mock the cached download path.
    # Consider to remove if block when we drop py3.7 support, only keep statements from else.
    # MagicMock below py3.8 doesn't has __fspath__ attribute.
    if sys.version_info < (3, 8):
        archive = FsPathMock("/path/to/download.zip")
    else:
        archive = MagicMock()
        archive.__fspath__.return_value = "/path/to/download.zip"
    test_command.download_url.return_value = archive

    # Create a directory to make it look like Java was downloaded and unpacked.
    (tmp_path / "tools" / "jdk8u242-b08").mkdir(parents=True)

    # Create an SDK wrapper
    jdk = JDK(test_command, java_home=java_home)

    # Attempt an upgrade.
    jdk.upgrade()

    # The old version has been deleted
    test_command.shutil.rmtree.assert_called_with(tmp_path / "tools" / "java")

    # A download was initiated
    test_command.download_url.assert_called_with(
        url=
        "https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/"
        "jdk8u242-b08/OpenJDK8U-jdk_x64_mac_hotspot_8u242b08.tar.gz",
        download_path=tmp_path / "tools",
    )

    # The archive was unpacked.
    # TODO: Py3.6 compatibility; os.fsdecode not required in Py3.7
    test_command.shutil.unpack_archive.assert_called_with(
        "/path/to/download.zip", extract_dir=os.fsdecode(tmp_path / "tools"))
    # The original archive was deleted
    archive.unlink.assert_called_once_with()
예제 #6
0
def test_unpack_fail(test_command, tmp_path):
    """If there's an existing managed JDK install, it is deleted and
    redownloaded."""
    # Create a mock of a previously installed Java version.
    java_home = tmp_path / "tools" / "java"
    (java_home / "bin").mkdir(parents=True)

    # We actually need to delete the original java install
    def rmtree(path):
        shutil.rmtree(path)

    test_command.shutil.rmtree.side_effect = rmtree

    # Mock the cached download path
    # Consider to remove if block when we drop py3.7 support, only keep statements from else.
    # MagicMock below py3.8 doesn't has __fspath__ attribute.
    if sys.version_info < (3, 8):
        archive = FsPathMock("/path/to/download.zip")
    else:
        archive = MagicMock()
        archive.__fspath__.return_value = "/path/to/download.zip"
    test_command.download_url.return_value = archive

    # Mock an unpack failure due to an invalid archive
    test_command.shutil.unpack_archive.side_effect = shutil.ReadError

    # Create an SDK wrapper
    jdk = JDK(test_command, java_home=java_home)

    # Attempt an upgrade. This will fail.
    with pytest.raises(BriefcaseCommandError):
        jdk.upgrade()

    # The old version has been deleted
    test_command.shutil.rmtree.assert_called_with(java_home)

    # A download was initiated
    test_command.download_url.assert_called_with(
        url=
        "https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/"
        "jdk8u242-b08/OpenJDK8U-jdk_x64_linux_hotspot_8u242b08.tar.gz",
        download_path=tmp_path / "tools",
    )

    # The archive was unpacked.
    # TODO: Py3.6 compatibility; os.fsdecode not required in Py3.7
    test_command.shutil.unpack_archive.assert_called_with(
        "/path/to/download.zip", extract_dir=os.fsdecode(tmp_path / "tools"))
    # The original archive was not deleted
    assert archive.unlink.call_count == 0
예제 #7
0
def test_existing_wix_install(mock_command, tmp_path):
    "If there's an existing managed WiX install, it is deleted and redownloaded"
    # Create a mock of a previously installed WiX version.
    wix_path = tmp_path / 'tools' / 'wix'
    wix_path.mkdir(parents=True)
    (wix_path / 'heat.exe').touch()
    (wix_path / 'light.exe').touch()
    (wix_path / 'candle.exe').touch()

    # Mock the download
    wix_path = tmp_path / 'tools' / 'wix'

    wix_zip_path = os.fsdecode(tmp_path / 'tools' / 'wix.zip')
    # Consider to remove if block when we drop py3.7 support, only keep statements from else.
    # MagicMock below py3.8 doesn't has __fspath__ attribute.
    if sys.version_info < (3, 8):
        wix_zip = FsPathMock(wix_zip_path)
    else:
        wix_zip = MagicMock()
        wix_zip.__fspath__.return_value = wix_zip_path

    mock_command.download_url.return_value = wix_zip

    # Create an SDK wrapper
    wix = WiX(mock_command, wix_home=wix_path, bin_install=True)

    # Attempt an upgrade.
    wix.upgrade()

    # The old version has been deleted
    mock_command.shutil.rmtree.assert_called_with(wix_path)

    # A download was initiated
    mock_command.download_url.assert_called_with(
        url=WIX_DOWNLOAD_URL,
        download_path=tmp_path / 'tools',
    )

    # The download was unpacked
    # TODO: Py3.6 compatibility; os.fsdecode not required in Py3.7
    mock_command.shutil.unpack_archive.assert_called_with(
        os.fsdecode(wix_zip_path),
        extract_dir=os.fsdecode(wix_path)
    )

    # The zip file was removed
    wix_zip.unlink.assert_called_with()
예제 #8
0
def test_unpack_fail(mock_command, tmp_path):
    "If the download archive is corrupted, the validator fails"
    # Create a mock of a previously installed WiX version.
    wix_path = tmp_path / 'tools' / 'wix'
    wix_path.mkdir(parents=True)
    (wix_path / 'heat.exe').touch()
    (wix_path / 'light.exe').touch()
    (wix_path / 'candle.exe').touch()

    # Mock the download
    wix_zip_path = os.fsdecode(tmp_path / 'tools' / 'wix.zip')
    # Consider to remove if block when we drop py3.7 support, only keep statements from else.
    # MagicMock below py3.8 doesn't has __fspath__ attribute.
    if sys.version_info < (3, 8):
        wix_zip = FsPathMock(wix_zip_path)
    else:
        wix_zip = MagicMock()
        wix_zip.__fspath__.return_value = wix_zip_path

    mock_command.download_url.return_value = wix_zip

    # Mock an unpack failure
    mock_command.shutil.unpack_archive.side_effect = EOFError

    # Create an SDK wrapper
    wix = WiX(mock_command, wix_home=wix_path, bin_install=True)

    # Upgrade the install. This will trigger a download,
    # but the unpack will fail.
    with pytest.raises(BriefcaseCommandError):
        wix.upgrade()

    # A download was initiated
    mock_command.download_url.assert_called_with(
        url=WIX_DOWNLOAD_URL,
        download_path=tmp_path / 'tools',
    )

    # The download was unpacked.
    # TODO: Py3.6 compatibility; os.fsdecode not required in Py3.7
    mock_command.shutil.unpack_archive.assert_called_with(
        os.fsdecode(wix_zip_path),
        extract_dir=os.fsdecode(wix_path)
    )

    # The zip file was not removed
    assert wix_zip.unlink.call_count == 0
예제 #9
0
def test_successful_jdk_download(test_command, tmp_path, capsys, host_os,
                                 jdk_url, jhome):
    "If needed, a JDK can be downloaded."
    # Mock host OS
    test_command.host_os = host_os

    # Mock a JAVA_HOME that won't exist
    # This is only needed to make macOS *not* run /usr/libexec/java_home
    test_command.os.environ.get = mock.MagicMock(
        return_value='/does/not/exist')

    # Mock the cached download path
    # Consider to remove if block when we drop py3.7 support, only keep statements from else.
    # MagicMock below py3.8 doesn't has __fspath__ attribute.
    if sys.version_info < (3, 8):
        archive = FsPathMock("/path/to/download.zip")
    else:
        archive = mock.MagicMock()
        archive.__fspath__.return_value = "/path/to/download.zip"
    test_command.download_url.return_value = archive

    # Create a directory to make it look like Java was downloaded and unpacked.
    (tmp_path / 'tools' / 'jdk8u242-b08').mkdir(parents=True)

    # Invoke the verify call
    jdk = JDK.verify(command=test_command)

    assert jdk.java_home == tmp_path / 'tools' / jhome

    # Console output contains a warning about the bad JDK location
    output = capsys.readouterr()
    assert output.err == ''
    assert "** WARNING: JAVA_HOME does not point to a Java 8 JDK" in output.out

    # Download was invoked
    test_command.download_url.assert_called_with(
        url=jdk_url,
        download_path=tmp_path / "tools",
    )
    # The archive was unpacked
    # TODO: Py3.6 compatibility; os.fsdecode not required in Py3.7
    test_command.shutil.unpack_archive.assert_called_with(
        "/path/to/download.zip", extract_dir=os.fsdecode(tmp_path / "tools"))
    # The original archive was deleted
    archive.unlink.assert_called_once_with()
예제 #10
0
def test_download_wix(mock_command, tmp_path):
    "If there's no existing managed WiX install, it is downloaded and unpacked"
    # Mock the environment as if there is not WiX variable
    mock_command.os.environ.get.return_value = None

    # Mock the download
    wix_path = tmp_path / 'tools' / 'wix'

    wix_zip_path = os.fsdecode(tmp_path / 'tools' / 'wix.zip')
    # Consider to remove if block when we drop py3.7 support, only keep statements from else.
    # MagicMock below py3.8 doesn't has __fspath__ attribute.
    if sys.version_info < (3, 8):
        wix_zip = FsPathMock(wix_zip_path)
    else:
        wix_zip = MagicMock()
        wix_zip.__fspath__.return_value = wix_zip_path

    mock_command.download_url.return_value = wix_zip

    # Verify the install. This will trigger a download
    wix = WiX.verify(mock_command)

    # The environment was queried.
    mock_command.os.environ.get.assert_called_with('WIX')

    # A download was initiated
    mock_command.download_url.assert_called_with(
        url=WIX_DOWNLOAD_URL,
        download_path=tmp_path / 'tools',
    )

    # The download was unpacked.
    # TODO: Py3.6 compatibility; os.fsdecode not required in Py3.7
    mock_command.shutil.unpack_archive.assert_called_with(
        os.fsdecode(wix_zip_path),
        extract_dir=os.fsdecode(wix_path)
    )

    # The zip file was removed
    wix_zip.unlink.assert_called_with()

    # The returned paths are as expected
    assert wix.heat_exe == tmp_path / 'tools' / 'wix' / 'heat.exe'
    assert wix.light_exe == tmp_path / 'tools' / 'wix' / 'light.exe'
    assert wix.candle_exe == tmp_path / 'tools' / 'wix' / 'candle.exe'
예제 #11
0
def test_unpack_fail(mock_command, tmp_path):
    "If the download archive is corrupted, the validator fails"
    # Mock the environment as if there is not WiX variable
    mock_command.os.environ.get.return_value = None

    # Mock the download
    wix_path = tmp_path / 'tools' / 'wix'

    wix_zip_path = os.fsdecode(tmp_path / 'tools' / 'wix.zip')
    # Consider to remove if block when we drop py3.7 support, only keep statements from else.
    # MagicMock below py3.8 doesn't has __fspath__ attribute.
    if sys.version_info < (3, 8):
        wix_zip = FsPathMock(wix_zip_path)
    else:
        wix_zip = MagicMock()
        wix_zip.__fspath__.return_value = wix_zip_path

    mock_command.download_url.return_value = wix_zip

    # Mock an unpack failure
    mock_command.shutil.unpack_archive.side_effect = EOFError

    # Verify the install. This will trigger a download,
    # but the unpack will fail
    with pytest.raises(BriefcaseCommandError, match="interrupted or corrupted"):
        WiX.verify(mock_command)

    # The environment was queried.
    mock_command.os.environ.get.assert_called_with('WIX')

    # A download was initiated
    mock_command.download_url.assert_called_with(
        url=WIX_DOWNLOAD_URL,
        download_path=tmp_path / 'tools',
    )

    # The download was unpacked.
    # TODO: Py3.6 compatibility; os.fsdecode not required in Py3.7
    mock_command.shutil.unpack_archive.assert_called_with(
        os.fsdecode(wix_zip_path),
        extract_dir=os.fsdecode(wix_path)
    )

    # The zip file was not removed
    assert wix_zip.unlink.call_count == 0
예제 #12
0
def test_create_emulator(mock_sdk, tmp_path, host_os, host_arch, emulator_abi):
    """A new emulator can be created."""
    # This test validates everything going well on first run.
    # This means the skin will be downloaded and unpacked.

    # Mock the hardware and operating system to specific values
    mock_sdk.command.host_os = host_os
    mock_sdk.command.host_arch = host_arch

    # Mock the user providing several invalid names before getting it right.
    mock_sdk.command.input.side_effect = [
        "runningEmulator",
        "invalid name",
        "annoying!",
        "new-emulator",
    ]

    # Consider to remove if block when we drop py3.7 support, only keep statements from else.
    # MagicMock below py3.8 doesn't has __fspath__ attribute.
    if sys.version_info < (3, 8):
        skin_tgz_path = FsPathMock("/path/to/skin.tgz")
    else:
        skin_tgz_path = MagicMock()
        skin_tgz_path.__fspath__.return_value = "/path/to/skin.tgz"
    mock_sdk.command.download_url.return_value = skin_tgz_path

    # Mock the initial output of an AVD config file.
    avd_config_path = tmp_path / ".android" / "avd" / "new-emulator.avd" / "config.ini"
    avd_config_path.parent.mkdir(parents=True)
    with avd_config_path.open("w") as f:
        f.write("hw.device.name=pixel\n")

    # Create the emulator
    avd = mock_sdk.create_emulator()

    # The expected device AVD was created.
    assert avd == "new-emulator"

    # avdmanager was invoked
    mock_sdk.command.subprocess.check_output.assert_called_once_with(
        [
            os.fsdecode(mock_sdk.avdmanager_path),
            "--verbose",
            "create",
            "avd",
            "--name",
            "new-emulator",
            "--abi",
            emulator_abi,
            "--package",
            f"system-images;android-31;default;{emulator_abi}",
            "--device",
            "pixel",
        ],
        env=mock_sdk.env,
        stderr=subprocess.STDOUT,
    )

    # Skin was downloaded
    mock_sdk.command.download_url.assert_called_once_with(
        url="https://android.googlesource.com/platform/tools/adt/idea/"
        "+archive/refs/heads/mirror-goog-studio-master-dev/"
        "artwork/resources/device-art-resources/pixel_3a.tar.gz",
        download_path=mock_sdk.root_path,
    )

    # Skin is unpacked.
    mock_sdk.command.shutil.unpack_archive.assert_called_once_with(
        skin_tgz_path, extract_dir=mock_sdk.root_path / "skins" / "pixel_3a")

    # Original file was deleted.
    skin_tgz_path.unlink.assert_called_once_with()

    # Emulator configuration file has been appended.
    with avd_config_path.open() as f:
        config = f.read().split("\n")
    assert "hw.keyboard=yes" in config
    assert "skin.name=pixel_3a" in config