Skip to content

Commit

Permalink
PR #8406 from Eran: run-unit-tests.py no longer requires pyrealsense2…
Browse files Browse the repository at this point in the history
….pyd
  • Loading branch information
maloel authored Feb 24, 2021
2 parents 70cbf25 + dbcd90c commit 6170b56
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 40 deletions.
27 changes: 21 additions & 6 deletions unit-tests/py/rspy/devices.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,39 @@
# License: Apache 2.0. See LICENSE file in root directory.
# Copyright(c) 2021 Intel Corporation. All Rights Reserved.

from rspy import log

# We need both pyrealsense2 and acroname. We can work without acroname, but
# without rs no devices at all will be returned.
try:
from rspy import acroname
import pyrealsense2 as rs
log.d( rs )
try:
from rspy import acroname
except ModuleNotFoundError:
# Error should have already been printed
# We assume there's no brainstem library, meaning no acroname either
acroname = None
except ModuleNotFoundError:
# Error should have already been printed
# We assume there's no brainstem library, meaning no acroname either
log.w( 'No pyrealsense2 library is available! Running as if no cameras available...' )
import sys
log.d( 'sys.path=', sys.path )
rs = None
acroname = None
import pyrealsense2 as rs

import time
from rspy import log

_device_by_sn = None
_device_by_sn = dict()
_context = None


def query():
"""
Start a new LRS context, and collect all devices
"""
global rs
if not rs:
return
#
# Before we can start a context and query devices, we need to enable all the ports
# on the acroname, if any:
Expand Down
4 changes: 3 additions & 1 deletion unit-tests/py/rspy/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ def is_color_on():


def quiet_on():
print( "QUIET ON" )
global out
def out(*args):
pass
Expand Down Expand Up @@ -86,6 +85,9 @@ def d(*args):
def is_debug_on():
global _debug_on
return _debug_on
if '--debug' in sys.argv:
sys.argv.remove( '--debug' )
debug_on()


def i(*args):
Expand Down
19 changes: 12 additions & 7 deletions unit-tests/py/rspy/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
"""

import os, sys, subprocess, traceback, platform
import pyrealsense2 as rs

n_assertions = 0
n_failed_assertions = 0
Expand Down Expand Up @@ -46,23 +45,28 @@ def set_env_vars(env_vars):
for env_var, val in env_vars.items():
os.environ[env_var] = val
cmd = [sys.executable]
if 'site' not in sys.modules:
# -S : don't imply 'import site' on initialization
cmd += ["-S"]
if sys.flags.verbose:
# -v : verbose (trace import statements)
cmd += ["-v"]
cmd += sys.argv
cmd += ["rerun"]
p = subprocess.run( cmd, stderr=subprocess.PIPE, universal_newlines=True )
exit(p.returncode)
sys.exit( p.returncode )
sys.argv = sys.argv[:-1] # Remove the rerun

def find_first_device_or_exit():
"""
:return: the first device that was found, if no device is found the test is skipped. That way we can still run
the unit-tests when no device is connected and not fail the tests that check a connected device
"""
import pyrealsense2 as rs
c = rs.context()
if not c.devices.size(): # if no device is connected we skip the test
print("No device found, skipping test")
exit(0)
sys.exit( 0 )
return c.devices[0]

def find_devices_by_product_line_or_exit(product_line):
Expand All @@ -72,11 +76,12 @@ def find_devices_by_product_line_or_exit(product_line):
That way we can still run the unit-tests when no device is connected
and not fail the tests that check a connected device
"""
import pyrealsense2 as rs
c = rs.context()
devices_list = c.query_devices(product_line)
if devices_list.size() == 0:
print("No device of the" , product_line ,"product line was found; skipping test")
exit(0)
sys.exit( 0 )
return devices_list

def print_stack():
Expand Down Expand Up @@ -112,7 +117,7 @@ def check_failed():

def abort():
print("Abort was specified in a failed check. Aborting test")
exit(1)
sys.exit( 1 )

def check(exp, abort_if_failed = False):
"""
Expand Down Expand Up @@ -365,6 +370,6 @@ def print_results_and_exit():
passed = n_assertions - n_failed_assertions
print("test cases:", n_tests, "|" , n_failed_tests, "failed")
print("assertions:", n_assertions, "|", passed, "passed |", n_failed_assertions, "failed")
exit(1)
sys.exit(1)
print("All tests passed (" + str(n_assertions) + " assertions in " + str(n_tests) + " test cases)")
exit(0)
sys.exit(0)
71 changes: 45 additions & 26 deletions unit-tests/run-unit-tests.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
#!python3

# License: Apache 2.0. See LICENSE file in root directory.
# Copyright(c) 2020 Intel Corporation. All Rights Reserved.
# Copyright(c) 2021 Intel Corporation. All Rights Reserved.

import sys, os, subprocess, locale, re, platform, getopt
from abc import ABC, abstractmethod

# Add our py/ module directory to Python's list so we can use them
# Remove Python's default list of places to look for modules!
# We want only modules in the directories we specifically provide to be found,
# otherwise pyrs other than what we compiled might be found...
sys.path = list()
sys.path.append( '' ) # directs Python to search modules in the current directory first
# Add our py/ module directory
current_dir = os.path.dirname( os.path.abspath( __file__ ))
sys.path.insert( 1, current_dir + os.sep + "py" )
sys.path.append( current_dir + os.sep + "py" )

from rspy import log

def usage():
ourname = os.path.basename(sys.argv[0])
ourname = os.path.basename(sys.argv[0])
print( 'Syntax: ' + ourname + ' [options] [dir]' )
print( ' dir: the directory holding the executable tests to run (default to the build directory')
Expand Down Expand Up @@ -71,8 +75,6 @@ def is_executable(path_to_test):
for opt,arg in opts:
if opt in ('-h','--help'):
usage()
elif opt in ('--debug'):
log.debug_on()
elif opt in ('-v','--verbose'):
log.verbose_on()
elif opt in ('-q','--quiet'):
Expand Down Expand Up @@ -111,7 +113,7 @@ def is_executable(path_to_test):

# wrapper function for subprocess.run
def subprocess_run(cmd, stdout = None):
log.d( 'running:', cmd )
log.d( ' running:', cmd )
handle = None
try:
if stdout and stdout != subprocess.PIPE:
Expand Down Expand Up @@ -150,11 +152,16 @@ def subprocess_run(cmd, stdout = None):
# We need to add the directory not the file itself
pyrs_path = os.path.dirname(pyrs_path)
log.d( 'found pyrealsense pyd in:', pyrs_path )
# Add the necessary path to the PYTHONPATH environment variable so python will look for modules there
os.environ["PYTHONPATH"] = pyrs_path
# We also need to add the path to the python packages that the tests use
os.environ["PYTHONPATH"] += os.pathsep + (current_dir + os.sep + "py")
# We can simply change `sys.path` but any child python scripts won't see it. We change the environment instead.

# Figure out which sys.path we want the tests to see, assuming we have Python tests
# PYTHONPATH is what Python will ADD to sys.path for the child processes
# (We can simply change `sys.path` but any child python scripts won't see it; we change the environment instead)
#
# We also need to add the path to the python packages that the tests use
os.environ["PYTHONPATH"] = current_dir + os.sep + "py"
#
if pyrs:
os.environ["PYTHONPATH"] += os.pathsep + pyrs_path

def remove_newlines (lines):
for line in lines:
Expand Down Expand Up @@ -329,6 +336,11 @@ def __init__(self, testname, path_to_test):
@property
def command(self):
cmd = [sys.executable]
# The unit-tests should only find module we've specifically added -- but Python may have site packages
# that are automatically made available. We want to avoid those:
# -S : don't imply 'import site' on initialization
# NOTE: exit() is defined in site.py and works only if the site module is imported!
cmd += ['-S']
if sys.flags.verbose:
cmd += ["-v"]
cmd += [self.path_to_script]
Expand Down Expand Up @@ -390,9 +402,11 @@ def get_tests():
manifestfile = target + '/CMakeFiles/TargetDirectories.txt'
else:
manifestfile = target + '/../CMakeFiles/TargetDirectories.txt'
#log.d( manifestfile )
for manifest_ctx in grep(r'(?<=unit-tests/build/)\S+(?=/CMakeFiles/test-\S+.dir$)', manifestfile):
# We need to first create the test name so we can see if it fits the regex
testdir = manifest_ctx['match'].group(0) # "log/internal/test-all"
#log.d( testdir )
testparent = os.path.dirname(testdir) # "log/internal"
if testparent:
testname = 'test-' + testparent.replace('/', '-') + '-' + os.path.basename(testdir)[5:] # "test-log-internal-all"
Expand All @@ -409,20 +423,19 @@ def get_tests():

yield ExeTest(testname, exe)

# If we run python tests with no .pyd/.so file they will crash. Therefore we only run them if such a file was found
if pyrs:
# unit-test scripts are in the same directory as this script
for py_test in find(current_dir, '(^|/)test-.*\.py'):
testparent = os.path.dirname(py_test) # "log/internal" <- "log/internal/test-all.py"
if testparent:
testname = 'test-' + testparent.replace('/', '-') + '-' + os.path.basename(py_test)[5:-3] # remove .py
else:
testname = os.path.basename(py_test)[:-3]
# Python unit-test scripts are in the same directory as us... we want to consider running them
# (we may not if they're live and we have no pyrealsense2.pyd):
for py_test in find(current_dir, '(^|/)test-.*\.py'):
testparent = os.path.dirname(py_test) # "log/internal" <- "log/internal/test-all.py"
if testparent:
testname = 'test-' + testparent.replace('/', '-') + '-' + os.path.basename(py_test)[5:-3] # remove .py
else:
testname = os.path.basename(py_test)[:-3]

if regex and not pattern.search( testname ):
continue
if regex and not pattern.search( testname ):
continue

yield PyTest(testname, py_test)
yield PyTest(testname, py_test)


def devices_by_test_config( test ):
Expand Down Expand Up @@ -456,7 +469,8 @@ def test_wrapper( test, configuration = None ):


# Run all tests
sys.path.insert( 1, pyrs_path )
if pyrs:
sys.path.append( pyrs_path )
from rspy import devices
devices.query()
#
Expand All @@ -471,7 +485,7 @@ def test_wrapper( test, configuration = None ):
continue
#
if skip_live_tests:
log.d( test.name + ':', 'is live and there are no cameras; skipping' )
log.w( test.name + ':', 'is live and there are no cameras; skipping' )
continue
#
for configuration, serial_numbers in devices_by_test_config( test ):
Expand All @@ -483,6 +497,11 @@ def test_wrapper( test, configuration = None ):
test_wrapper( test, configuration )

log.progress()
#
if not n_tests:
log.e( 'No unit-tests found!' )
sys.exit(1)
#
n_errors = log.n_errors()
if n_errors:
log.out( log.red + str(n_errors) + log.reset, 'of', n_tests, 'test(s)', log.red + 'failed!' + log.reset + log.clear_eos )
Expand Down

0 comments on commit 6170b56

Please sign in to comment.