aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/run_tests
diff options
context:
space:
mode:
Diffstat (limited to 'tools/run_tests')
-rw-r--r--tools/run_tests/artifacts/build_artifact_python.bat4
-rwxr-xr-xtools/run_tests/artifacts/build_artifact_python.sh4
-rw-r--r--tools/run_tests/generated/sources_and_headers.json27
-rwxr-xr-xtools/run_tests/helper_scripts/build_python.sh6
-rwxr-xr-xtools/run_tests/python_utils/jobset.py6
-rwxr-xr-xtools/run_tests/python_utils/port_server.py16
-rw-r--r--tools/run_tests/python_utils/report_utils.py2
-rw-r--r--tools/run_tests/python_utils/start_port_server.py19
-rwxr-xr-xtools/run_tests/python_utils/watch_dirs.py3
-rwxr-xr-xtools/run_tests/run_interop_tests.py54
-rwxr-xr-xtools/run_tests/run_tests.py6
11 files changed, 85 insertions, 62 deletions
diff --git a/tools/run_tests/artifacts/build_artifact_python.bat b/tools/run_tests/artifacts/build_artifact_python.bat
index d277668c94..795e80dc40 100644
--- a/tools/run_tests/artifacts/build_artifact_python.bat
+++ b/tools/run_tests/artifacts/build_artifact_python.bat
@@ -22,6 +22,10 @@ pip install -rrequirements.txt
set GRPC_PYTHON_BUILD_WITH_CYTHON=1
+@rem Allow build_ext to build C/C++ files in parallel
+@rem by enabling a monkeypatch. It speeds up the build a lot.
+set GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS=2
+
mkdir -p %ARTIFACTS_OUT%
set ARTIFACT_DIR=%cd%\%ARTIFACTS_OUT%
diff --git a/tools/run_tests/artifacts/build_artifact_python.sh b/tools/run_tests/artifacts/build_artifact_python.sh
index 2878005bb2..9a2e0f739f 100755
--- a/tools/run_tests/artifacts/build_artifact_python.sh
+++ b/tools/run_tests/artifacts/build_artifact_python.sh
@@ -22,6 +22,10 @@ export PYTHON=${PYTHON:-python}
export PIP=${PIP:-pip}
export AUDITWHEEL=${AUDITWHEEL:-auditwheel}
+# Allow build_ext to build C/C++ files in parallel
+# by enabling a monkeypatch. It speeds up the build a lot.
+export GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS=2
+
mkdir -p "${ARTIFACTS_OUT}"
ARTIFACT_DIR="$PWD/${ARTIFACTS_OUT}"
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index ade814a844..1bbacc41f0 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -9142,7 +9142,7 @@
"src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h",
"src/core/tsi/alts/frame_protector/frame_handler.h",
"src/core/tsi/alts/handshaker/alts_handshaker_client.h",
- "src/core/tsi/alts/handshaker/alts_tsi_event.h",
+ "src/core/tsi/alts/handshaker/alts_shared_resource.h",
"src/core/tsi/alts/handshaker/alts_tsi_handshaker.h",
"src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h",
"src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h",
@@ -9173,8 +9173,8 @@
"src/core/tsi/alts/frame_protector/frame_handler.h",
"src/core/tsi/alts/handshaker/alts_handshaker_client.cc",
"src/core/tsi/alts/handshaker/alts_handshaker_client.h",
- "src/core/tsi/alts/handshaker/alts_tsi_event.cc",
- "src/core/tsi/alts/handshaker/alts_tsi_event.h",
+ "src/core/tsi/alts/handshaker/alts_shared_resource.cc",
+ "src/core/tsi/alts/handshaker/alts_shared_resource.h",
"src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc",
"src/core/tsi/alts/handshaker/alts_tsi_handshaker.h",
"src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h",
@@ -9654,7 +9654,8 @@
"src/core/lib/transport/status_metadata.cc",
"src/core/lib/transport/timeout_encoding.cc",
"src/core/lib/transport/transport.cc",
- "src/core/lib/transport/transport_op_string.cc"
+ "src/core/lib/transport/transport_op_string.cc",
+ "src/core/lib/uri/uri_parser.cc"
],
"third_party": false,
"type": "filegroup"
@@ -9811,7 +9812,8 @@
"src/core/lib/transport/status_metadata.h",
"src/core/lib/transport/timeout_encoding.h",
"src/core/lib/transport/transport.h",
- "src/core/lib/transport/transport_impl.h"
+ "src/core/lib/transport/transport_impl.h",
+ "src/core/lib/uri/uri_parser.h"
],
"is_filegroup": true,
"language": "c",
@@ -9962,7 +9964,8 @@
"src/core/lib/transport/status_metadata.h",
"src/core/lib/transport/timeout_encoding.h",
"src/core/lib/transport/transport.h",
- "src/core/lib/transport/transport_impl.h"
+ "src/core/lib/transport/transport_impl.h",
+ "src/core/lib/uri/uri_parser.h"
],
"third_party": false,
"type": "filegroup"
@@ -10040,8 +10043,7 @@
"src/core/ext/filters/client_channel/resolver_registry.h",
"src/core/ext/filters/client_channel/retry_throttle.h",
"src/core/ext/filters/client_channel/subchannel.h",
- "src/core/ext/filters/client_channel/subchannel_index.h",
- "src/core/ext/filters/client_channel/uri_parser.h"
+ "src/core/ext/filters/client_channel/subchannel_index.h"
],
"is_filegroup": true,
"language": "c",
@@ -10089,9 +10091,7 @@
"src/core/ext/filters/client_channel/subchannel.cc",
"src/core/ext/filters/client_channel/subchannel.h",
"src/core/ext/filters/client_channel/subchannel_index.cc",
- "src/core/ext/filters/client_channel/subchannel_index.h",
- "src/core/ext/filters/client_channel/uri_parser.cc",
- "src/core/ext/filters/client_channel/uri_parser.h"
+ "src/core/ext/filters/client_channel/subchannel_index.h"
],
"third_party": false,
"type": "filegroup"
@@ -11227,6 +11227,7 @@
"include/grpcpp/impl/codegen/rpc_service_method.h",
"include/grpcpp/impl/codegen/security/auth_context.h",
"include/grpcpp/impl/codegen/serialization_traits.h",
+ "include/grpcpp/impl/codegen/server_callback.h",
"include/grpcpp/impl/codegen/server_context.h",
"include/grpcpp/impl/codegen/server_interceptor.h",
"include/grpcpp/impl/codegen/server_interface.h",
@@ -11302,6 +11303,7 @@
"include/grpcpp/impl/codegen/rpc_service_method.h",
"include/grpcpp/impl/codegen/security/auth_context.h",
"include/grpcpp/impl/codegen/serialization_traits.h",
+ "include/grpcpp/impl/codegen/server_callback.h",
"include/grpcpp/impl/codegen/server_context.h",
"include/grpcpp/impl/codegen/server_interceptor.h",
"include/grpcpp/impl/codegen/server_interface.h",
@@ -11451,6 +11453,7 @@
"include/grpcpp/support/config.h",
"include/grpcpp/support/proto_buffer_reader.h",
"include/grpcpp/support/proto_buffer_writer.h",
+ "include/grpcpp/support/server_callback.h",
"include/grpcpp/support/slice.h",
"include/grpcpp/support/status.h",
"include/grpcpp/support/status_code_enum.h",
@@ -11555,6 +11558,7 @@
"include/grpcpp/support/config.h",
"include/grpcpp/support/proto_buffer_reader.h",
"include/grpcpp/support/proto_buffer_writer.h",
+ "include/grpcpp/support/server_callback.h",
"include/grpcpp/support/slice.h",
"include/grpcpp/support/status.h",
"include/grpcpp/support/status_code_enum.h",
@@ -11564,6 +11568,7 @@
"include/grpcpp/support/time.h",
"src/cpp/client/channel_cc.cc",
"src/cpp/client/client_context.cc",
+ "src/cpp/client/client_interceptor.cc",
"src/cpp/client/create_channel.cc",
"src/cpp/client/create_channel_internal.cc",
"src/cpp/client/create_channel_internal.h",
diff --git a/tools/run_tests/helper_scripts/build_python.sh b/tools/run_tests/helper_scripts/build_python.sh
index 6990244e51..eb3ea9e1f5 100755
--- a/tools/run_tests/helper_scripts/build_python.sh
+++ b/tools/run_tests/helper_scripts/build_python.sh
@@ -80,6 +80,8 @@ function toolchain() {
fi
}
+# TODO(jtattermusch): this adds dependency on grealpath on mac
+# (brew install coreutils) for little reason.
# Command to invoke the linux command `realpath` or equivalent.
function script_realpath() {
# Find `realpath`
@@ -112,6 +114,10 @@ export CFLAGS="-I$ROOT/include -std=gnu99 -fno-wrapv $CFLAGS"
export GRPC_PYTHON_BUILD_WITH_CYTHON=1
export LANG=en_US.UTF-8
+# Allow build_ext to build C/C++ files in parallel
+# by enabling a monkeypatch. It speeds up the build a lot.
+export GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS=4
+
# If ccache is available on Linux, use it.
if [ "$(is_linux)" ]; then
# We're not on Darwin (Mac OS X)
diff --git a/tools/run_tests/python_utils/jobset.py b/tools/run_tests/python_utils/jobset.py
index b732e1e03e..578712c393 100755
--- a/tools/run_tests/python_utils/jobset.py
+++ b/tools/run_tests/python_utils/jobset.py
@@ -13,8 +13,6 @@
# limitations under the License.
"""Run a group of subprocesses and then finish."""
-from __future__ import print_function
-
import logging
import multiprocessing
import os
@@ -118,7 +116,7 @@ def eintr_be_gone(fn):
while True:
try:
return fn()
- except IOError, e:
+ except IOError as e:
if e.errno != errno.EINTR:
raise
@@ -144,7 +142,7 @@ def message(tag, msg, explanatory_text=None, do_newline=False):
if do_newline or explanatory_text is not None else ''))
sys.stdout.flush()
return
- except IOError, e:
+ except IOError as e:
if e.errno != errno.EINTR:
raise
diff --git a/tools/run_tests/python_utils/port_server.py b/tools/run_tests/python_utils/port_server.py
index 83e09c09d0..243eef6827 100755
--- a/tools/run_tests/python_utils/port_server.py
+++ b/tools/run_tests/python_utils/port_server.py
@@ -14,15 +14,17 @@
# limitations under the License.
"""Manage TCP ports for unit tests; started by run_tests.py"""
+from __future__ import print_function
+
import argparse
-from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
+from six.moves.BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
+from six.moves.socketserver import ThreadingMixIn
import hashlib
import os
import socket
import sys
import time
import random
-from SocketServer import ThreadingMixIn
import threading
import platform
@@ -32,7 +34,7 @@ import platform
_MY_VERSION = 20
if len(sys.argv) == 2 and sys.argv[1] == 'dump_version':
- print _MY_VERSION
+ print(_MY_VERSION)
sys.exit(0)
argp = argparse.ArgumentParser(description='Server for httpcli_test')
@@ -47,7 +49,7 @@ if args.logfile is not None:
sys.stderr = open(args.logfile, 'w')
sys.stdout = sys.stderr
-print 'port server running on port %d' % args.port
+print('port server running on port %d' % args.port)
pool = []
in_use = {}
@@ -74,7 +76,7 @@ def can_connect(port):
try:
s.connect(('localhost', port))
return True
- except socket.error, e:
+ except socket.error as e:
return False
finally:
s.close()
@@ -86,7 +88,7 @@ def can_bind(port, proto):
try:
s.bind(('localhost', port))
return True
- except socket.error, e:
+ except socket.error as e:
return False
finally:
s.close()
@@ -95,7 +97,7 @@ def can_bind(port, proto):
def refill_pool(max_timeout, req):
"""Scan for ports not marked for being in use"""
chk = [
- port for port in list(range(1025, 32766))
+ port for port in range(1025, 32766)
if port not in cronet_restricted_ports
]
random.shuffle(chk)
diff --git a/tools/run_tests/python_utils/report_utils.py b/tools/run_tests/python_utils/report_utils.py
index b2a256ce29..8d8dedb929 100644
--- a/tools/run_tests/python_utils/report_utils.py
+++ b/tools/run_tests/python_utils/report_utils.py
@@ -13,8 +13,6 @@
# limitations under the License.
"""Generate XML and HTML test reports."""
-from __future__ import print_function
-
try:
from mako.runtime import Context
from mako.template import Template
diff --git a/tools/run_tests/python_utils/start_port_server.py b/tools/run_tests/python_utils/start_port_server.py
index 37995acbdf..0a32bf4418 100644
--- a/tools/run_tests/python_utils/start_port_server.py
+++ b/tools/run_tests/python_utils/start_port_server.py
@@ -12,8 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import urllib
-import jobset
+from __future__ import print_function
+
+from . import jobset
+
+import six.moves.urllib.request as request
import logging
import os
import socket
@@ -33,8 +36,8 @@ def start_port_server():
# otherwise, leave it up
try:
version = int(
- urllib.urlopen('http://localhost:%d/version_number' %
- _PORT_SERVER_PORT).read())
+ request.urlopen('http://localhost:%d/version_number' %
+ _PORT_SERVER_PORT).read())
logging.info('detected port server running version %d', version)
running = True
except Exception as e:
@@ -51,7 +54,7 @@ def start_port_server():
running = (version >= current_version)
if not running:
logging.info('port_server version mismatch: killing the old one')
- urllib.urlopen(
+ request.urlopen(
'http://localhost:%d/quitquitquit' % _PORT_SERVER_PORT).read()
time.sleep(1)
if not running:
@@ -92,7 +95,7 @@ def start_port_server():
# try one final time: maybe another build managed to start one
time.sleep(1)
try:
- urllib.urlopen(
+ request.urlopen(
'http://localhost:%d/get' % _PORT_SERVER_PORT).read()
logging.info(
'last ditch attempt to contact port server succeeded')
@@ -101,11 +104,11 @@ def start_port_server():
logging.exception(
'final attempt to contact port server failed')
port_log = open(logfile, 'r').read()
- print port_log
+ print(port_log)
sys.exit(1)
try:
port_server_url = 'http://localhost:%d/get' % _PORT_SERVER_PORT
- urllib.urlopen(port_server_url).read()
+ request.urlopen(port_server_url).read()
logging.info('port server is up and ready')
break
except socket.timeout:
diff --git a/tools/run_tests/python_utils/watch_dirs.py b/tools/run_tests/python_utils/watch_dirs.py
index d2ad303a07..f2f1c006df 100755
--- a/tools/run_tests/python_utils/watch_dirs.py
+++ b/tools/run_tests/python_utils/watch_dirs.py
@@ -15,13 +15,14 @@
import os
import time
+from six import string_types
class DirWatcher(object):
"""Helper to watch a (set) of directories for modifications."""
def __init__(self, paths):
- if isinstance(paths, basestring):
+ if isinstance(paths, string_types):
paths = [paths]
self._done = False
self.paths = list(paths)
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 5722a88182..ff6682c3cf 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -63,17 +63,17 @@ _SKIP_ADVANCED = [
'unimplemented_service'
]
+_SKIP_SPECIAL_STATUS_MESSAGE = ['special_status_message']
+
_TEST_TIMEOUT = 3 * 60
# disable this test on core-based languages,
# see https://github.com/grpc/grpc/issues/9779
_SKIP_DATA_FRAME_PADDING = ['data_frame_padding']
-# report suffix is important for reports to get picked up by internal CI
-_INTERNAL_CL_XML_REPORT = 'sponge_log.xml'
-
-# report suffix is important for reports to get picked up by internal CI
-_XML_REPORT = 'report.xml'
+# report suffix "sponge_log.xml" is important for reports to get picked up by internal CI
+_DOCKER_BUILD_XML_REPORT = 'interop_docker_build/sponge_log.xml'
+_TESTS_XML_REPORT = 'interop_test/sponge_log.xml'
class CXXLanguage:
@@ -100,7 +100,7 @@ class CXXLanguage:
return {}
def unimplemented_test_cases(self):
- return _SKIP_DATA_FRAME_PADDING
+ return _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return []
@@ -129,7 +129,7 @@ class CSharpLanguage:
return {}
def unimplemented_test_cases(self):
- return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING
+ return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return _SKIP_COMPRESSION
@@ -158,7 +158,7 @@ class CSharpCoreCLRLanguage:
return {}
def unimplemented_test_cases(self):
- return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING
+ return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return _SKIP_COMPRESSION
@@ -188,10 +188,10 @@ class DartLanguage:
return {}
def unimplemented_test_cases(self):
- return _SKIP_COMPRESSION
+ return _SKIP_COMPRESSION + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
- return _SKIP_COMPRESSION
+ return _SKIP_COMPRESSION + _SKIP_SPECIAL_STATUS_MESSAGE
def __str__(self):
return 'dart'
@@ -248,7 +248,7 @@ class JavaOkHttpClient:
return {}
def unimplemented_test_cases(self):
- return _SKIP_DATA_FRAME_PADDING
+ return _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def __str__(self):
return 'javaokhttp'
@@ -309,7 +309,7 @@ class Http2Server:
return {}
def unimplemented_test_cases(self):
- return _TEST_CASES + _SKIP_DATA_FRAME_PADDING
+ return _TEST_CASES + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return _TEST_CASES
@@ -339,7 +339,7 @@ class Http2Client:
return {}
def unimplemented_test_cases(self):
- return _TEST_CASES
+ return _TEST_CASES + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return _TEST_CASES
@@ -431,7 +431,7 @@ class PHPLanguage:
return {}
def unimplemented_test_cases(self):
- return _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING
+ return _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return []
@@ -456,7 +456,7 @@ class PHP7Language:
return {}
def unimplemented_test_cases(self):
- return _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING
+ return _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return []
@@ -491,7 +491,7 @@ class ObjcLanguage:
# cmdline argument. Here we return all but one test cases as unimplemented,
# and depend upon ObjC test's behavior that it runs all cases even when
# we tell it to run just one.
- return _TEST_CASES[1:] + _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING
+ return _TEST_CASES[1:] + _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return _SKIP_COMPRESSION
@@ -526,7 +526,7 @@ class RubyLanguage:
return {}
def unimplemented_test_cases(self):
- return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING
+ return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE
def unimplemented_test_cases_server(self):
return _SKIP_COMPRESSION
@@ -610,7 +610,7 @@ _TEST_CASES = [
'custom_metadata', 'status_code_and_message', 'unimplemented_method',
'client_compressed_unary', 'server_compressed_unary',
'client_compressed_streaming', 'server_compressed_streaming',
- 'unimplemented_service'
+ 'unimplemented_service', 'special_status_message'
]
_AUTH_TEST_CASES = [
@@ -1161,8 +1161,9 @@ argp.add_argument(
default=False,
action='store_const',
const=True,
- help=('Put reports into subdirectories to improve '
- 'presentation of results by Internal CI.'))
+ help=(
+ '(Deprecated, has no effect) Put reports into subdirectories to improve '
+ 'presentation of results by Internal CI.'))
argp.add_argument(
'--bq_result_table',
default='',
@@ -1251,8 +1252,12 @@ if args.use_docker:
if args.verbose:
print('Jobs to run: \n%s\n' % '\n'.join(str(j) for j in build_jobs))
- num_failures, _ = jobset.run(
+ num_failures, build_resultset = jobset.run(
build_jobs, newline_on_success=True, maxjobs=args.jobs)
+
+ report_utils.render_junit_xml_report(build_resultset,
+ _DOCKER_BUILD_XML_REPORT)
+
if num_failures == 0:
jobset.message(
'SUCCESS',
@@ -1315,7 +1320,7 @@ try:
for language in languages:
for test_case in _TEST_CASES:
if not test_case in language.unimplemented_test_cases():
- if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION:
+ if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION + _SKIP_SPECIAL_STATUS_MESSAGE:
tls_test_job = cloud_to_prod_jobspec(
language,
test_case,
@@ -1517,10 +1522,7 @@ try:
write_cmdlog_maybe(server_manual_cmd_log, 'interop_server_cmds.sh')
write_cmdlog_maybe(client_manual_cmd_log, 'interop_client_cmds.sh')
- xml_report_name = _XML_REPORT
- if args.internal_ci:
- xml_report_name = _INTERNAL_CL_XML_REPORT
- report_utils.render_junit_xml_report(resultset, xml_report_name)
+ report_utils.render_junit_xml_report(resultset, _TESTS_XML_REPORT)
for name, job in resultset.items():
if "http2" in name:
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 44151f49fb..62bb6da7a7 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -1512,7 +1512,7 @@ if args.travis:
_FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'}
if 'all' in args.language:
- lang_list = _LANGUAGES.keys()
+ lang_list = list(_LANGUAGES.keys())
else:
lang_list = args.language
# We don't support code coverage on some languages
@@ -1719,9 +1719,9 @@ def _has_epollexclusive():
try:
subprocess.check_call(binary)
return True
- except subprocess.CalledProcessError, e:
+ except subprocess.CalledProcessError as e:
return False
- except OSError, e:
+ except OSError as e:
# For languages other than C and Windows the binary won't exist
return False