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
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 archive = mock.MagicMock() archive.__str__.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 test_command.shutil.unpack_archive.assert_called_with( '/path/to/download.zip', extract_dir=str(tmp_path / "tools")) # The original archive was not deleted assert archive.unlink.call_count == 0
def test_download_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(str(path)) test_command.shutil.rmtree.side_effect = rmtree # Mock a failure on download test_command.download_url.side_effect = requests_exceptions.ConnectionError # Create an SDK wrapper jdk = JDK(test_command, java_home=java_home) # Attempt an upgrade. This will fail along with the download with pytest.raises(NetworkFailure): 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', ) # No attempt was made to unpack the archive assert test_command.shutil.unpack_archive.call_count == 0
def test_non_existing_install(test_command, tmp_path): "If there's no existing managed JDK install, upgrading is an error" # Create an SDK wrapper around a non-existing managed install jdk = JDK(test_command, java_home=tmp_path / 'tools' / 'java') with pytest.raises(MissingToolError): jdk.upgrade() # No download was attempted assert test_command.download_url.call_count == 0
def test_not_installed(test_command, tmp_path): "If the JDK isn't installed, and install isn't requested, an error is raised." # Mock host OS test_command.host_os = 'Linux' # Invoke the verify call. Install is not requested, so this will fail. with pytest.raises(MissingToolError): JDK.verify(command=test_command, install=False) # Download was not invoked assert test_command.download_url.call_count == 0
def test_non_managed_install(test_command, tmp_path, capsys): "If the Java install points to a non-managed install, no upgrade is attempted" # Make the installation point to somewhere else. jdk = JDK(test_command, java_home=tmp_path / 'other-jdk') # Attempt an upgrade. This will fail because the install is non-managed with pytest.raises(NonManagedToolError): jdk.upgrade() # No download was attempted assert test_command.download_url.call_count == 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()
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
def test_macos_tool_java_home(test_command, capsys): """On macOS, the /usr/libexec/java_home utility is checked.""" # Mock being on macOS test_command.host_os = "Darwin" # Mock 2 calls to check_output. test_command.subprocess.check_output.side_effect = [ "/path/to/java", "javac 1.8.0_144\n", ] # Create a JDK wrapper by verification jdk = JDK.verify(command=test_command) # The JDK should have the path returned by the tool assert jdk.java_home == Path("/path/to/java") test_command.subprocess.check_output.assert_has_calls([ # First call is to /usr/lib/java_home mock.call( ["/usr/libexec/java_home"], stderr=subprocess.STDOUT, ), # Second is a call to verify a valid Java version mock.call( [os.fsdecode(Path("/path/to/java/bin/javac")), "-version"], stderr=subprocess.STDOUT, ), ]) # No console output output = capsys.readouterr() assert output.out == "" assert output.err == ""
def test_javac_error(test_command, tmp_path, capsys): """If javac can't be executed, the briefcase JDK is used.""" # Mock environ.get returning an explicit JAVA_HOME test_command.os.environ.get = mock.MagicMock(return_value="/path/to/java") # Mock return value from javac failing because executable doesn't exist test_command.subprocess.check_output.side_effect = subprocess.CalledProcessError( returncode=1, cmd="/path/to/java/bin/javac") # Create a directory to make it look like the Briefcase Java already exists. (tmp_path / "tools" / "java" / "bin").mkdir(parents=True) # Create a JDK wrapper by verification jdk = JDK.verify(command=test_command) # The JDK should have the briefcase JAVA_HOME assert jdk.java_home == tmp_path / "tools" / "java" # A single call was made to check javac test_command.subprocess.check_output.assert_called_once_with( [os.fsdecode(Path("/path/to/java/bin/javac")), "-version"], stderr=subprocess.STDOUT, ), # No console output (because Briefcase JDK exists) output = capsys.readouterr() assert output.out == "" assert output.err == ""
def test_invalid_jdk_version(test_command, tmp_path, capsys): """If the JDK pointed to by JAVA_HOME isn't a Java 8 JDK, the briefcase JDK is used.""" # Mock environ.get returning an explicit JAVA_HOME test_command.os.environ.get = mock.MagicMock(return_value="/path/to/java") # Mock return value from javac. test_command.subprocess.check_output.return_value = "javac 14\n" # Create a directory to make it look like the Briefcase Java already exists. (tmp_path / "tools" / "java" / "bin").mkdir(parents=True) # Create a JDK wrapper by verification jdk = JDK.verify(command=test_command) # The JDK should have the briefcase JAVA_HOME assert jdk.java_home == tmp_path / "tools" / "java" # A single call was made to check javac test_command.subprocess.check_output.assert_called_once_with( [os.fsdecode(Path("/path/to/java/bin/javac")), "-version"], stderr=subprocess.STDOUT, ), # No console output (because Briefcase JDK exists) output = capsys.readouterr() assert output.out == "" assert output.err == ""
def test_macos_provided_overrides_tool_java_home(test_command, capsys): "On macOS, an explicit JAVA_HOME overrides /usr/libexec/java_home" # Mock being on macOS test_command.host_os = 'Darwin' # Mock environ.get returning an explicit JAVA_HOME test_command.os.environ.get = mock.MagicMock(return_value='/path/to/java') # Mock return value from javac. libexec won't be invoked. test_command.subprocess.check_output.return_value = 'javac 1.8.0_144\n' # Create a JDK wrapper by verification jdk = JDK.verify(command=test_command) # The JDK should have the path returned by the tool assert jdk.java_home == Path('/path/to/java') # A single call to check output test_command.subprocess.check_output.assert_called_once_with( [os.fsdecode(Path('/path/to/java/bin/javac')), '-version'], universal_newlines=True, stderr=subprocess.STDOUT, ), # No console output output = capsys.readouterr() assert output.out == '' assert output.err == ''
def test_macos_tool_failure(test_command, tmp_path, capsys): "On macOS, if the libexec tool fails, the Briefcase JDK is used" # Mock being on macOS test_command.host_os = 'Darwin' # Mock a failed call on the libexec tool test_command.subprocess.check_output.side_effect = subprocess.CalledProcessError( returncode=1, cmd='/usr/libexec/java_home') # Create a directory to make it look like the Briefcase Java already exists. (tmp_path / 'tools' / 'java' / 'Contents' / 'Home' / 'bin').mkdir(parents=True) # Create a JDK wrapper by verification jdk = JDK.verify(command=test_command) # The JDK should have the briefcase JAVA_HOME assert jdk.java_home == tmp_path / 'tools' / 'java' / 'Contents' / 'Home' test_command.subprocess.check_output.assert_has_calls([ # First call is to /usr/lib/java_home mock.call( ['/usr/libexec/java_home'], universal_newlines=True, stderr=subprocess.STDOUT, ), ]) # No console output output = capsys.readouterr() assert output.out == '' assert output.err == ''
def test_macos_tool_java_home(test_command, capsys): "On macOS, the /usr/libexec/java_home utility is checked" # Mock being on macOS test_command.host_os = 'Darwin' # Mock 2 calls to check_output. test_command.subprocess.check_output.side_effect = [ '/path/to/java', 'javac 1.8.0_144\n' ] # Create a JDK wrapper by verification jdk = JDK.verify(command=test_command) # The JDK should have the path returned by the tool assert jdk.java_home == Path('/path/to/java') test_command.subprocess.check_output.assert_has_calls([ # First call is to /usr/lib/java_home mock.call( ['/usr/libexec/java_home'], universal_newlines=True, stderr=subprocess.STDOUT, ), # Second is a call to verify a valid Java version mock.call( [os.fsdecode(Path('/path/to/java/bin/javac')), '-version'], universal_newlines=True, stderr=subprocess.STDOUT, ), ]) # No console output output = capsys.readouterr() assert output.out == '' assert output.err == ''
def test_unparseable_javac_version(test_command, tmp_path, capsys): "If the javac version can't be parsed, the briefcase JDK is used" # Mock environ.get returning an explicit JAVA_HOME test_command.os.environ.get = mock.MagicMock(return_value='/path/to/java') # Mock return value from javac. test_command.subprocess.check_output.return_value = 'NONSENSE\n' # Create a directory to make it look like the Briefcase Java already exists. (tmp_path / 'tools' / 'java' / 'bin').mkdir(parents=True) # Create a JDK wrapper by verification jdk = JDK.verify(command=test_command) # The JDK should have the briefcase JAVA_HOME assert jdk.java_home == tmp_path / 'tools' / 'java' # A single call was made to check javac test_command.subprocess.check_output.assert_called_once_with( [os.fsdecode(Path('/path/to/java/bin/javac')), '-version'], universal_newlines=True, stderr=subprocess.STDOUT, ), # No console output (because Briefcase JDK exists) output = capsys.readouterr() assert output.out == '' assert output.err == ''
def test_no_javac(test_command, tmp_path, capsys): "If the JAVA_HOME doesn't point to a location with a bin/javac, the briefcase JDK is used" # Mock environ.get returning an explicit JAVA_HOME test_command.os.environ.get = mock.MagicMock( return_value='/path/to/nowhere') # Mock return value from javac failing because executable doesn't exist test_command.subprocess.check_output.side_effect = FileNotFoundError # Create a directory to make it look like the Briefcase Java already exists. (tmp_path / 'tools' / 'java' / 'bin').mkdir(parents=True) # Create a JDK wrapper by verification jdk = JDK.verify(command=test_command) # The JAVA_HOME should point at the Briefcase-provided JDK assert jdk.java_home == tmp_path / 'tools' / 'java' # A single call was made to check javac test_command.subprocess.check_output.assert_called_once_with( [os.fsdecode(Path('/path/to/nowhere/bin/javac')), '-version'], universal_newlines=True, stderr=subprocess.STDOUT, ), # No console output (because Briefcase JDK exists) output = capsys.readouterr() assert output.out == '' assert output.err == ''
def test_valid_provided_java_home(test_command, capsys): "If a valid JAVA_HOME is provided, it is used." # Mock environ.get returning an explicit JAVA_HOME test_command.os.environ.get = mock.MagicMock(return_value='/path/to/java') # Mock return value from javac. test_command.subprocess.check_output.return_value = 'javac 1.8.0_144\n' # Create a JDK wrapper by verification jdk = JDK.verify(command=test_command) # The JDK should have the path returned by the tool assert jdk.java_home == Path('/path/to/java') # A single call to check output test_command.subprocess.check_output.assert_called_once_with( [os.fsdecode(Path('/path/to/java/bin/javac')), '-version'], universal_newlines=True, stderr=subprocess.STDOUT, ), # No console output output = capsys.readouterr() assert output.out == '' assert output.err == ''
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(str(path)) test_command.shutil.rmtree.side_effect = rmtree # Mock the cached download path archive = MagicMock() archive.__str__.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 test_command.shutil.unpack_archive.assert_called_with( '/path/to/download.zip', extract_dir=str(tmp_path / "tools")) # The original archive was deleted archive.unlink.assert_called_once_with()
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(str(path)) test_command.shutil.rmtree.side_effect = rmtree # Mock the cached download path archive = MagicMock() archive.__str__.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 test_command.shutil.unpack_archive.assert_called_with( '/path/to/download.zip', extract_dir=str(tmp_path / "tools")) # The original archive was not deleted assert archive.unlink.call_count == 0
def test_jdk_download_failure(test_command, tmp_path): "If an error occurs downloading the JDK, an error is raised" # Mock Linux as the host test_command.host_os = 'Linux' # Mock a failure on download test_command.download_url.side_effect = requests_exceptions.ConnectionError # Invoking verify_jdk causes a network failure. with pytest.raises(NetworkFailure): JDK.verify(command=test_command) # That download was attempted 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", ) # No attempt was made to unpack the archive assert test_command.shutil.unpack_archive.call_count == 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()
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 archive = mock.MagicMock() archive.__str__.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 test_command.shutil.unpack_archive.assert_called_with( '/path/to/download.zip', extract_dir=str(tmp_path / "tools")) # The original archive was deleted archive.unlink.assert_called_once_with()
def verify(cls, command, install=True, jdk=None): """ Verify an Android SDK is available. If the ANDROID_SDK_ROOT environment variable is set, that location will be checked for a valid SDK. If the location provided doesn't contain an SDK, or no location is provided, an SDK is downloaded. :param command: The command making the verification request. :param install: Should the tool be installed if it is not found? :param jdk: The JDK instance to use. :returns: A valid Android SDK wrapper. If Android SDK is not available, and was not installed, raises MissingToolError. """ if jdk is None: jdk = JDK.verify(command, install=install) sdk_root = command.os.environ.get("ANDROID_SDK_ROOT") if sdk_root: sdk = AndroidSDK(command=command, jdk=jdk, root_path=Path(sdk_root)) if sdk.exists(): # Ensure licenses have been accepted sdk.verify_license() return sdk else: print( """ ************************************************************************* ** WARNING: ANDROID_SDK_ROOT does not point to an Android SDK ** ************************************************************************* The location pointed to by the ANDROID_SDK_ROOT environment variable: {sdk_root} doesn't appear to contain an Android SDK. Briefcase will use its own SDK instance. ************************************************************************* """.format( sdk_root=sdk_root ) ) # Build an SDK wrapper for the Briefcase SDK instance. sdk = AndroidSDK( command=command, jdk=jdk, root_path=command.tools_path / "android_sdk" ) if sdk.exists(): # Ensure licenses have been accepted sdk.verify_license() return sdk if install: sdk.install() return sdk else: raise MissingToolError('Android SDK')