gpsd-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gpsd-dev] [PATCH 4/4] Add Valgrind tests for gps library interface vari


From: Robert Norris
Subject: [gpsd-dev] [PATCH 4/4] Add Valgrind tests for gps library interface variants.
Date: Fri, 10 Feb 2017 22:53:48 +0000

Tests normal gps_open(), gps_read(), gps_close() cycle via test programs.
.test_libgps --> direct C calls
.test_gpsmm  --> the C++ interface
.test_qgpsmm --> the C++ interface on Qt build.

Extends gps/fake.py to allow invoking of the specified client to connect
against an instance of gpsd.

Note some internal issues are flagged by Valgrind on Qt build with Qt4.
Thus these are ignored by specific suppression statements.
Further note that the Qt5 build seems fine.

TESTED.
'scons valgrind-audit' passes with no errors.
'scons valgrind-audit' correctly fails if the previous Qt build memory leak
 is reintroduced.
---
 SConstruct                |  4 ++--
 gps/fake.py               | 40 ++++++++++++++++++++++++++++++++++++++++
 valgrind-audit.py         | 24 ++++++++++++++++++++++++
 valgrind-suppressions-lib | 14 ++++++++++++++
 4 files changed, 80 insertions(+), 2 deletions(-)
 create mode 100644 valgrind-suppressions-lib

diff --git a/SConstruct b/SConstruct
index bc7ba644..5d273b14 100644
--- a/SConstruct
+++ b/SConstruct
@@ -1913,9 +1913,9 @@ method_regress = Utility('packet-regress', [test_packet], 
[
     '$SRCDIR/test_packet -c >/dev/null',
     ])
 
-# Run a valgrind audit on the daemon  - not in normal tests
+# Run a valgrind audit on the daemon & client libraries - not in normal tests
 valgrind_audit = Utility('valgrind-audit',
-    ['$SRCDIR/valgrind-audit.py', python_built_extensions, gpsd],
+    ['$SRCDIR/valgrind-audit.py', python_built_extensions, gpsd, test_libgps, 
test_gpsmm, test_qgpsmm],
     '$PYTHON $SRCDIR/valgrind-audit.py'
     )
 
diff --git a/gps/fake.py b/gps/fake.py
index 5ab636a6..60e2dbf6 100644
--- a/gps/fake.py
+++ b/gps/fake.py
@@ -554,6 +554,42 @@ class DaemonInstance(object):
             self.pid = None
 
 
+class LibError(BaseException):
+    def __init__(self, msg):
+        super(LibError, self).__init__()
+        self.msg = msg
+
+
+class LibInstance(object):
+    "Control a test program instance."
+    def __init__(self):
+        pass
+
+    def spawn(self, port, test_program="", options="", background=False, 
prefix=""):
+        "Spawn a test lib instance."
+        self.spawncmd = None
+
+        # Only look for test program in GPSD_HOME env variable
+        # i.e. don't try any system paths
+        if os.environ.get('GPSD_HOME'):
+            for path in os.environ['GPSD_HOME'].split(':'):
+                _spawncmd = "%s/%s" % (path, test_program)
+                if os.path.isfile(_spawncmd) and os.access(_spawncmd, os.X_OK):
+                    self.spawncmd = _spawncmd
+                    break
+
+        if not self.spawncmd:
+            raise LibError("Cannot execute %s" % self.spawncmd)
+        self.spawncmd += " %s localhost:%s" % (options, port)
+        if prefix:
+            self.spawncmd = prefix + " " + self.spawncmd.strip()
+        if background:
+            self.spawncmd += " &"
+        status = os.system(self.spawncmd)
+        if os.WIFSIGNALED(status) or os.WEXITSTATUS(status):
+            raise LibError("exited with status %d" % status)
+
+
 class TestSessionError(BaseException):
     def __init__(self, msg):
         super(TestSessionError, self).__init__()
@@ -574,6 +610,7 @@ class TestSession(object):
         self.tcp = tcp
         self.slow = slow
         self.daemon = DaemonInstance()
+        self.library = LibInstance()
         self.fakegpslist = {}
         self.client_id = 0
         self.readers = 0
@@ -596,6 +633,9 @@ class TestSession(object):
         self.daemon.spawn(background=True, prefix=self.prefix, port=self.port, 
options=self.options)
         self.daemon.wait_pid()
 
+    def run_client_program(self, test_program, prefix, options):
+        self.library.spawn(test_program=test_program, prefix=prefix, 
options=options, port=self.port)
+
     def set_predicate(self, pred):
         "Set a default go predicate for the session."
         self.default_predicate = pred
diff --git a/valgrind-audit.py b/valgrind-audit.py
index c674ef7f..cb703833 100755
--- a/valgrind-audit.py
+++ b/valgrind-audit.py
@@ -99,6 +99,30 @@ try:
 finally:
     test.cleanup()
 
+num = 5
+testClient = gps.fake.TestSession(options="-D %d" % debuglevel)
+testClient.progress = sys.stderr.write
+memcheck = "valgrind  --tool=memcheck --leak-check=full --error-exitcode=42 
--suppressions=valgrind-suppressions-lib"
+try:
+    print("\n*** Test #%d: Client library open / close." % num)
+    testClient.spawn()
+    testClient.wait(1)
+    testClient.run_client_program(test_program="test_libgps", prefix=memcheck, 
options="-f \'?WATCH={\"enable\":true,\"json\":true}\'")
+    print("*** Test #%d complete.\n" % num)
+    testClient.wait(1)
+    num=num+1
+    print("\n*** Test #%d: Client library open / close." % num)
+    testClient.run_client_program(test_program="test_gpsmm", prefix=memcheck, 
options="-l 2")
+    print("*** Test #%d complete.\n" % num)
+    testClient.wait(1)
+    num=num+1
+    print("\n*** Test #%d: Client library open / close." % num)
+    testClient.run_client_program(test_program="test_qgpsmm", prefix="export 
LD_LIBRARY_PATH=.; " + memcheck, options="-l 2")
+    print("*** Test #%d complete.\n" % num)
+finally:
+    testClient.cleanup()
+exit
+
 # The following sets edit modes for GNU EMACS
 # Local Variables:
 # mode:python
diff --git a/valgrind-suppressions-lib b/valgrind-suppressions-lib
new file mode 100644
index 00000000..49cfac4b
--- /dev/null
+++ b/valgrind-suppressions-lib
@@ -0,0 +1,14 @@
+# Suppress known library errors reported by valgrind.
+#
+# Qt4 dodgy functions:
+# QLibrary::setFileName
+# QLibrary::setFileNameVersion
+# NB seems OK under Qt5
+#
+{
+   suppressQt
+   Memcheck:Leak
+   match-leak-kinds: definite
+   ...
+   fun:*setFileName*
+}
-- 
2.11.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]