Skip to content

Commit

Permalink
Added check for java 8 or newer (#258)
Browse files Browse the repository at this point in the history
  • Loading branch information
rhythmize authored and ukanga committed May 19, 2019
1 parent 1b10580 commit 808e1b9
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 16 deletions.
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Running pyxform from local source
=================================

Note that you must uninstall any globally installed ``pyxform`` instance in order to use local modules.
Please install java 8 or newer version.

From the command line::

Expand Down
61 changes: 61 additions & 0 deletions pyxform/tests_v1/test_validators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
"""Test validators."""

import sys
from unittest import TestCase

from pyxform.validators.odk_validate import check_java_version

if sys.version_info >= (3, 3):
from unittest.mock import patch # pylint: disable=E0611,E0401
else:
try:
from mock import patch
except ImportError:
raise ImportError("Pyxform test suite requires the 'mock' library.")

JAVA_7 = """java version "1.7.0_201"
OpenJDK Runtime Environment (IcedTea 2.6.17) (7u211-2.6.17-0ubuntu0.1)
OpenJDK 64-Bit Server VM (build 24.201-b00, mixed mode)
"""
JAVA_8 = """java version "1.8.0_211"
Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)
"""

OPENJDK_11 = """openjdk version "11.0.3" 2019-04-16
OpenJDK Runtime Environment (build 11.0.3+4)
OpenJDK 64-Bit Server VM (build 11.0.3+4, mixed mode)
"""


class TestValidators(TestCase):
"""Test validators."""

def test_check_java_version(self):
"""Test check_java_version()"""
mock_func = 'pyxform.validators.odk_validate.run_popen_with_timeout'
with patch(mock_func) as mock_popen:
mock_popen.side_effect = OSError(
"[Errno 2] No such file or directory")
with self.assertRaises(EnvironmentError) as error:
check_java_version()
self.assertEqual(
str(error.exception),
"pyxform odk validate dependency: java not found")

with patch(mock_func) as mock_popen:
mock_popen.return_value = (0, False, '', JAVA_7)
with self.assertRaises(EnvironmentError) as error:
check_java_version()
self.assertEqual(
str(error.exception), "pyxform odk validate dependency: "
"java 8 or newer version not found")

with patch(mock_func) as mock_popen:
mock_popen.return_value = (0, False, '', JAVA_8)
check_java_version()

with patch(mock_func) as mock_popen:
mock_popen.return_value = (0, False, '', OPENJDK_11)
check_java_version()
57 changes: 41 additions & 16 deletions pyxform/validators/odk_validate/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from __future__ import print_function

# -*- coding: utf-8 -*-
"""
odk_validate.py
A python wrapper around ODK Validate
"""
from __future__ import print_function
import os
import re
import sys
from pyxform.validators.util import run_popen_with_timeout, decode_stream, \
XFORM_SPEC_PATH, check_readable
Expand All @@ -16,10 +17,12 @@


class ODKValidateError(Exception):
"""ODK Validation exception error."""
pass


def install_exists():
"""Returns True if ODK_VALIDATE_PATH exists."""
return os.path.exists(ODK_VALIDATE_PATH)


Expand All @@ -37,33 +40,53 @@ def install_ok(bin_file_path=ODK_VALIDATE_PATH):
path_to_xform=XFORM_SPEC_PATH, bin_file_path=bin_file_path)
if return_code == 1:
return False
else:
return True

return True

def _java_installed():
stderr = run_popen_with_timeout(["java", "-version"], 100)[3]
stderr = stderr.strip().decode('utf-8')
return "java version" in stderr or "openjdk version" in stderr

def check_java_version():
"""Check java version is greater than or equal to java 8.
def check_xform(path_to_xform):
Raises EnvironmentError exception if java version is less than java 8.
"""
try:
stderr = str(run_popen_with_timeout(["java", "-version"], 100)[3])
except OSError as os_error:
stderr = str(os_error)
# convert string to unicode for python2
if sys.version_info.major < 3:
stderr = stderr.strip().decode('utf-8')
if "java version" not in stderr and "openjdk version" not in stderr:
raise EnvironmentError(
"pyxform odk validate dependency: java not found")
# extract version number from version string
java_version_str = stderr.split('\n')[0]
# version number is usually inside double-quotes.
# Using regex to find that in the string
java_version = re.findall(r'\"(.+?)\"', java_version_str)[0]
major, minor, _ = java_version.split('.')
if not ((int(major) == 1 and int(minor) >= 8) or int(major) >= 8):
raise EnvironmentError(
"pyxform odk validate dependency: "
"java 8 or newer version not found")


def check_xform(path_to_xform):
"""Run ODK Validate against the XForm in `path_to_xform`.
Returns an array of warnings if the form is valid.
Throws an exception if it is not
"""
# provide useful error message if java is not installed
if not _java_installed():
raise EnvironmentError(
"pyxform odk validate dependency: java not found")
# check for available java version
check_java_version()

# resultcode indicates validity of the form
# timeout indicates whether validation ran out of time to complete
# stdout is not used because it has some warnings that always
# appear and can be ignored.
# stderr is treated as a warning if the form is valid or an error
# if it is invalid.
returncode, timeout, stdout, stderr = _call_validator(
returncode, timeout, _stdout, stderr = _call_validator(
path_to_xform=path_to_xform)
warnings = []
stderr = decode_stream(stderr)
Expand All @@ -73,14 +96,16 @@ def check_xform(path_to_xform):
else:
if returncode > 0: # Error invalid
raise ODKValidateError(
b'ODK Validate Errors:\n' + ErrorCleaner.odk_validate(stderr).encode('utf-8'))
b'ODK Validate Errors:\n' +
ErrorCleaner.odk_validate(stderr).encode('utf-8'))
elif returncode == 0:
if stderr:
warnings.append('ODK Validate Warnings:\n' + stderr)
return warnings
elif returncode < 0:
return ["Bad return code from ODK Validate."]

return warnings


if __name__ == '__main__':
print(__doc__)
Expand Down
1 change: 1 addition & 0 deletions requirements.pip
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ traceback2==1.4.0 # via unittest2
unicodecsv==0.14.1
unittest2==1.1.0
xlrd==1.2.0
mock==3.0.4

0 comments on commit 808e1b9

Please sign in to comment.