[TDD] add unittest for python3 tensor_filter subplugin
authorYelin Jeong <yelini.jeong@samsung.com>
Tue, 26 Mar 2024 23:45:51 +0000 (08:45 +0900)
committerjaeyun-jung <39614140+jaeyun-jung@users.noreply.github.com>
Fri, 3 May 2024 05:13:15 +0000 (14:13 +0900)
This patch adds unittest for python3 tensor_filter subplugin.
python3 tensor_filter will be upgraded to use v0 to v1.

Signed-off-by: Yelin Jeong <yelini.jeong@samsung.com>
tests/meson.build
tests/nnstreamer_filter_python3/unittest_filter_python3.cc [new file with mode: 0644]

index 5e28cb1..cc6a67e 100644 (file)
@@ -275,6 +275,17 @@ if gtest_dep.found()
     test('unittest_filter_tensorflow2_lite', unittest_filter_tensorflow2_lite, env: testenv)
   endif
 
+  if have_python3
+    unittest_filter_python3 = executable('unittest_filter_python3',
+      join_paths('nnstreamer_filter_python3', 'unittest_filter_python3.cc'),
+      dependencies: [nnstreamer_unittest_deps, python3_dep],
+      install: get_option('install-test'),
+      install_dir: unittest_install_dir
+    )
+
+    test('unittest_filter_python3', unittest_filter_python3, env: testenv)
+  endif
+
   # Run unittest_decoder
   if flatbuf_support_is_available
     unittest_decoder = executable('unittest_decoder',
diff --git a/tests/nnstreamer_filter_python3/unittest_filter_python3.cc b/tests/nnstreamer_filter_python3/unittest_filter_python3.cc
new file mode 100644 (file)
index 0000000..ab9c157
--- /dev/null
@@ -0,0 +1,320 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+/**
+ * @file    unittest_filter_python3.cc
+ * @date    26 Mar 2024
+ * @brief   Unit test for Python3 tensor filter sub-plugin
+ * @author  Yelin Jeong <yelini.jeong@samsung.com>
+ * @see     http://github.com/nnstreamer/nnstreamer
+ * @bug     No known bugs
+ *
+ */
+#include <gtest/gtest.h>
+#include <glib.h>
+#include <gst/gst.h>
+#include <unittest_util.h>
+
+#include <nnstreamer_plugin_api_filter.h>
+#include <nnstreamer_util.h>
+#include <tensor_common.h>
+
+/**
+ * @brief Set tensor filter properties
+ */
+static void
+_SetFilterProp (GstTensorFilterProperties *prop, const gchar *name, const gchar **models)
+{
+  memset (prop, 0, sizeof (GstTensorFilterProperties));
+  prop->fwname = name;
+  prop->fw_opened = 0;
+  prop->model_files = models;
+  prop->num_models = g_strv_length ((gchar **) models);
+}
+
+/**
+ * @brief Test subplugin existence.
+ */
+TEST (nnstreamerFilterPython3, checkExistence)
+{
+  const GstTensorFilterFramework *sp = nnstreamer_filter_find ("python3");
+  EXPECT_NE (sp, nullptr);
+}
+
+/**
+ * @brief Negative test case with invalid model file path
+ */
+TEST (nnstreamerFilterPython3, openClose00_n)
+{
+  int ret;
+  void *data = NULL;
+  const gchar *model_files[] = {
+    "some/invalid/model/path.py",
+    NULL,
+  };
+  GstTensorFilterProperties prop;
+
+  const GstTensorFilterFramework *sp = nnstreamer_filter_find ("python3");
+  EXPECT_NE (sp, nullptr);
+
+  _SetFilterProp (&prop, "python3", model_files);
+  ret = sp->open (&prop, &data);
+  EXPECT_NE (ret, 0);
+}
+
+/**
+ * @brief Positive case with open/close
+ */
+TEST (nnstreamerFilterPython3, openClose01)
+{
+  int ret;
+  void *data = NULL;
+  gchar *model_file;
+  const gchar *root_path = g_getenv ("NNSTREAMER_SOURCE_ROOT_PATH");
+  GstTensorFilterProperties prop;
+  model_file = g_build_filename (
+      root_path, "tests", "test_models", "models", "passthrough.py", NULL);
+  ASSERT_TRUE (g_file_test (model_file, G_FILE_TEST_EXISTS));
+
+  const gchar *model_files[] = {
+    model_file,
+    NULL,
+  };
+
+  const GstTensorFilterFramework *sp = nnstreamer_filter_find ("python3");
+  EXPECT_NE (sp, nullptr);
+  _SetFilterProp (&prop, "python3", model_files);
+
+  /* close before open */
+  sp->close (&prop, &data);
+
+  ret = sp->open (&prop, &data);
+  EXPECT_EQ (ret, 0);
+  sp->close (&prop, &data);
+
+  /* double close */
+  sp->close (&prop, &data);
+  g_free (model_file);
+}
+
+/**
+ * @brief Positive case with successful getModelInfo
+ */
+TEST (nnstreamerFilterPython3, getModelInfo00)
+{
+  int ret;
+  void *data = NULL;
+  gchar *model_file;
+  const gchar *root_path = g_getenv ("NNSTREAMER_SOURCE_ROOT_PATH");
+  GstTensorFilterProperties prop;
+  model_file = g_build_filename (
+      root_path, "tests", "test_models", "models", "passthrough.py", NULL);
+  ASSERT_TRUE (g_file_test (model_file, G_FILE_TEST_EXISTS));
+
+  const gchar *model_files[] = {
+    model_file,
+    NULL,
+  };
+
+  const GstTensorFilterFramework *sp = nnstreamer_filter_find ("python3");
+  EXPECT_NE (sp, nullptr);
+  _SetFilterProp (&prop, "python3", model_files);
+
+  ret = sp->open (&prop, &data);
+  EXPECT_EQ (ret, 0);
+
+  GstTensorsInfo in_info, out_info;
+
+  ret = sp->getModelInfo (NULL, NULL, data, GET_IN_OUT_INFO, &in_info, &out_info);
+  EXPECT_EQ (ret, 0);
+
+  constexpr uint32_t CHANNEL = 3;
+  constexpr uint32_t WIDTH = 280;
+  constexpr uint32_t HEIGHT = 40;
+
+  EXPECT_EQ (in_info.num_tensors, 1U);
+  EXPECT_EQ (in_info.info[0].dimension[0], CHANNEL);
+  EXPECT_EQ (in_info.info[0].dimension[1], WIDTH);
+  EXPECT_EQ (in_info.info[0].dimension[2], HEIGHT);
+  EXPECT_EQ (in_info.info[0].type, _NNS_UINT8);
+  EXPECT_EQ (out_info.num_tensors, 1U);
+  EXPECT_EQ (out_info.info[0].dimension[0], CHANNEL);
+  EXPECT_EQ (out_info.info[0].dimension[1], WIDTH);
+  EXPECT_EQ (out_info.info[0].dimension[2], HEIGHT);
+  EXPECT_EQ (out_info.info[0].type, _NNS_UINT8);
+
+  sp->close (&prop, &data);
+  gst_tensors_info_free (&in_info);
+  gst_tensors_info_free (&out_info);
+  g_free (model_file);
+}
+
+/**
+ * @brief Negative case calling getModelInfo before open
+ */
+TEST (nnstreamerFilterPython3, getModelInfo01_n)
+{
+  int ret;
+  void *data = NULL;
+  gchar *model_file;
+  const gchar *root_path = g_getenv ("NNSTREAMER_SOURCE_ROOT_PATH");
+  GstTensorFilterProperties prop;
+  model_file = g_build_filename (
+      root_path, "tests", "test_models", "models", "passthrough.py", NULL);
+  ASSERT_TRUE (g_file_test (model_file, G_FILE_TEST_EXISTS));
+
+  const gchar *model_files[] = {
+    model_file,
+    NULL,
+  };
+
+  const GstTensorFilterFramework *sp = nnstreamer_filter_find ("python3");
+  EXPECT_NE (sp, nullptr);
+
+  GstTensorsInfo in_info, out_info;
+
+  ret = sp->getModelInfo (NULL, NULL, data, SET_INPUT_INFO, &in_info, &out_info);
+  EXPECT_NE (ret, 0);
+  _SetFilterProp (&prop, "python3", model_files);
+
+  sp->close (&prop, &data);
+  g_free (model_file);
+}
+
+/**
+ * @brief Negative case with invalid argument
+ */
+TEST (nnstreamerFilterPython3, getModelInfo02_n)
+{
+  int ret;
+  void *data = NULL;
+  gchar *model_file;
+  const gchar *root_path = g_getenv ("NNSTREAMER_SOURCE_ROOT_PATH");
+  GstTensorFilterProperties prop;
+  model_file = g_build_filename (
+      root_path, "tests", "test_models", "models", "passthrough.py", NULL);
+  ASSERT_TRUE (g_file_test (model_file, G_FILE_TEST_EXISTS));
+
+  const gchar *model_files[] = {
+    model_file,
+    NULL,
+  };
+
+  const GstTensorFilterFramework *sp = nnstreamer_filter_find ("python3");
+  EXPECT_NE (sp, nullptr);
+  _SetFilterProp (&prop, "python3", model_files);
+
+  ret = sp->open (&prop, &data);
+  EXPECT_EQ (ret, 0);
+  sp->close (&prop, &data);
+
+  GstTensorsInfo in_info, out_info;
+
+  /* not supported */
+  ret = sp->getModelInfo (NULL, NULL, data, SET_INPUT_INFO, &in_info, &out_info);
+  EXPECT_NE (ret, 0);
+
+  sp->close (&prop, &data);
+  g_free (model_file);
+}
+
+/**
+ * @brief Negative test case with invoke before open
+ */
+TEST (nnstreamerFilterPython3, invoke00_n)
+{
+  int ret;
+  void *data = NULL;
+  GstTensorMemory input, output;
+  const gchar *root_path = g_getenv ("NNSTREAMER_SOURCE_ROOT_PATH");
+  GstTensorFilterProperties prop;
+  gchar *model_file = g_build_filename (
+      root_path, "tests", "test_models", "models", "passthrough.py", NULL);
+  const gchar *model_files[] = {
+    model_file,
+    NULL,
+  };
+
+  output.size = input.size = sizeof (float) * 1;
+
+  input.data = g_malloc (input.size);
+  output.data = g_malloc (output.size);
+
+  const GstTensorFilterFramework *sp = nnstreamer_filter_find ("python3");
+  EXPECT_NE (sp, nullptr);
+  _SetFilterProp (&prop, "python3", model_files);
+
+  ret = sp->invoke (NULL, NULL, data, &input, &output);
+  EXPECT_NE (ret, 0);
+
+  g_free (model_file);
+  g_free (input.data);
+  g_free (output.data);
+  sp->close (&prop, &data);
+}
+
+/**
+ * @brief Negative test case with invoke before open
+ */
+TEST (nnstreamerFilterPython3, invoke01)
+{
+  int ret;
+  void *data = NULL;
+  GstTensorMemory input, output;
+  const gchar *root_path = g_getenv ("NNSTREAMER_SOURCE_ROOT_PATH");
+  GstTensorFilterProperties prop;
+  gchar *model_file = g_build_filename (
+      root_path, "tests", "test_models", "models", "passthrough.py", NULL);
+  const gchar *model_files[] = {
+    model_file,
+    NULL,
+  };
+
+  output.size = input.size = sizeof (float) * 3 * 280 * 40; // channel * width * height
+
+  input.data = g_malloc (input.size);
+  output.data = g_malloc (output.size);
+
+  memset (input.data, 0, input.size);
+
+  const GstTensorFilterFramework *sp = nnstreamer_filter_find ("python3");
+  EXPECT_NE (sp, nullptr);
+  _SetFilterProp (&prop, "python3", model_files);
+
+  ret = sp->open (&prop, &data);
+  EXPECT_EQ (ret, 0);
+  EXPECT_NE (data, (void *) NULL);
+
+  ret = sp->invoke (NULL, NULL, data, &input, &output);
+
+  EXPECT_EQ (ret, 0);
+  EXPECT_EQ (output.size, input.size);
+
+  g_free (model_file);
+  g_free (input.data);
+  g_free (output.data);
+  sp->close (&prop, &data);
+}
+
+/**
+ * @brief Main gtest
+ */
+int
+main (int argc, char **argv)
+{
+  int result = -1;
+
+  try {
+    testing::InitGoogleTest (&argc, argv);
+  } catch (...) {
+    g_warning ("catch 'testing::internal::<unnamed>::ClassUniqueToAlwaysTrue'");
+  }
+
+  gst_init (&argc, &argv);
+
+  try {
+    result = RUN_ALL_TESTS ();
+  } catch (...) {
+    g_warning ("catch `testing::internal::GoogleTestFailureException`");
+  }
+
+  return result;
+}