camera3_test: add camera_ids, camera_facing option

Add "--camera_ids" option for filter specific test camera id and
"--camera_facing" option for test specific camera facing.

BUG=b:79951967
TEST=Run 'cros_camera_test' with --test_camera_ids option or
--camera_facing, see if total number of run testcases change.

Change-Id: Id531508d865bff26b0ac97c08685b171c2d14c1d
Reviewed-on: https://chromium-review.googlesource.com/1161849
Commit-Ready: Kuo Jen Wei <inker@chromium.org>
Tested-by: Kuo Jen Wei <inker@chromium.org>
Reviewed-by: Shik Chen <shik@chromium.org>
diff --git a/camera3_test/camera3_frame_test.cc b/camera3_test/camera3_frame_test.cc
index 7305e85..f01b140 100644
--- a/camera3_test/camera3_frame_test.cc
+++ b/camera3_test/camera3_frame_test.cc
@@ -1673,7 +1673,7 @@
     Camera3FrameTest,
     Camera3SingleFrameTest,
     ::testing::Combine(
-        ::testing::ValuesIn(Camera3Module().GetCameraIds()),
+        ::testing::ValuesIn(Camera3Module().GetTestCameraIds()),
         ::testing::Values(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
                           HAL_PIXEL_FORMAT_YCbCr_420_888,
                           HAL_PIXEL_FORMAT_YCrCb_420_SP,
@@ -1693,7 +1693,7 @@
 INSTANTIATE_TEST_CASE_P(
     Camera3FrameTest,
     Camera3MultiFrameTest,
-    ::testing::Combine(::testing::ValuesIn(Camera3Module().GetCameraIds()),
+    ::testing::Combine(::testing::ValuesIn(Camera3Module().GetTestCameraIds()),
                        ::testing::Values(CAMERA3_TEMPLATE_PREVIEW,
                                          CAMERA3_TEMPLATE_STILL_CAPTURE,
                                          CAMERA3_TEMPLATE_VIDEO_RECORD,
@@ -1702,14 +1702,15 @@
                                          CAMERA3_TEMPLATE_MANUAL),
                        ::testing::Range(1, 10)));
 
-INSTANTIATE_TEST_CASE_P(Camera3FrameTest,
-                        Camera3MixedTemplateMultiFrameTest,
-                        ::testing::ValuesIn(Camera3Module().GetCameraIds()));
+INSTANTIATE_TEST_CASE_P(
+    Camera3FrameTest,
+    Camera3MixedTemplateMultiFrameTest,
+    ::testing::ValuesIn(Camera3Module().GetTestCameraIds()));
 
 INSTANTIATE_TEST_CASE_P(
     Camera3FrameTest,
     Camera3FlushRequestsTest,
-    ::testing::Combine(::testing::ValuesIn(Camera3Module().GetCameraIds()),
+    ::testing::Combine(::testing::ValuesIn(Camera3Module().GetTestCameraIds()),
                        ::testing::Values(CAMERA3_TEMPLATE_PREVIEW,
                                          CAMERA3_TEMPLATE_STILL_CAPTURE,
                                          CAMERA3_TEMPLATE_VIDEO_RECORD,
@@ -1718,32 +1719,36 @@
                                          CAMERA3_TEMPLATE_MANUAL),
                        ::testing::Values(10)));
 
-INSTANTIATE_TEST_CASE_P(Camera3FrameTest,
-                        Camera3MultiStreamFrameTest,
-                        ::testing::ValuesIn(Camera3Module().GetCameraIds()));
+INSTANTIATE_TEST_CASE_P(
+    Camera3FrameTest,
+    Camera3MultiStreamFrameTest,
+    ::testing::ValuesIn(Camera3Module().GetTestCameraIds()));
 
-INSTANTIATE_TEST_CASE_P(Camera3FrameTest,
-                        Camera3InvalidRequestTest,
-                        ::testing::ValuesIn(Camera3Module().GetCameraIds()));
+INSTANTIATE_TEST_CASE_P(
+    Camera3FrameTest,
+    Camera3InvalidRequestTest,
+    ::testing::ValuesIn(Camera3Module().GetTestCameraIds()));
 
 INSTANTIATE_TEST_CASE_P(
     Camera3FrameTest,
     Camera3SimpleCaptureFrames,
-    ::testing::Combine(::testing::ValuesIn(Camera3Module().GetCameraIds()),
+    ::testing::Combine(::testing::ValuesIn(Camera3Module().GetTestCameraIds()),
                        ::testing::Values(10)));
 
-INSTANTIATE_TEST_CASE_P(Camera3FrameTest,
-                        Camera3ResultTimestampsTest,
-                        ::testing::ValuesIn(Camera3Module().GetCameraIds()));
+INSTANTIATE_TEST_CASE_P(
+    Camera3FrameTest,
+    Camera3ResultTimestampsTest,
+    ::testing::ValuesIn(Camera3Module().GetTestCameraIds()));
 
-INSTANTIATE_TEST_CASE_P(Camera3FrameTest,
-                        Camera3InvalidBufferTest,
-                        ::testing::ValuesIn(Camera3Module().GetCameraIds()));
+INSTANTIATE_TEST_CASE_P(
+    Camera3FrameTest,
+    Camera3InvalidBufferTest,
+    ::testing::ValuesIn(Camera3Module().GetTestCameraIds()));
 
 static std::vector<std::tuple<int32_t, int32_t, int32_t, int32_t>>
 IterateCameraIdFormatResolution() {
   std::vector<std::tuple<int32_t, int32_t, int32_t, int32_t>> result;
-  auto cam_ids = Camera3Module().GetCameraIds();
+  auto cam_ids = Camera3Module().GetTestCameraIds();
   auto formats =
       std::vector<int>({HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
                         HAL_PIXEL_FORMAT_YCbCr_420_888, HAL_PIXEL_FORMAT_BLOB});
diff --git a/camera3_test/camera3_module_fixture.h b/camera3_test/camera3_module_fixture.h
index 7eab743..b8fe924 100644
--- a/camera3_test/camera3_module_fixture.h
+++ b/camera3_test/camera3_module_fixture.h
@@ -98,6 +98,10 @@
   // Get list of camera IDs
   std::vector<int> GetCameraIds();
 
+  // Get list of test camera IDs if specify in cmdline args, or default use
+  // |GetCameraIds|
+  std::vector<int> GetTestCameraIds();
+
   // Open camera device
   camera3_device* OpenDevice(int cam_id);
 
@@ -148,6 +152,10 @@
 
   const camera_module_t* cam_module_;
 
+  // Id of cameras to be tested exclusively. Empty vector for test all available
+  // cameras.
+  std::vector<int> test_camera_ids_;
+
   // This thread is needed because of the Chrome OS camera HAL adapter
   // assumption that all the camera_module functions should be called on the
   // same Chromium thread. It is expected to start this thread before gtest
diff --git a/camera3_test/camera3_module_test.cc b/camera3_test/camera3_module_test.cc
index e0e271f..f23ccc7 100644
--- a/camera3_test/camera3_module_test.cc
+++ b/camera3_test/camera3_module_test.cc
@@ -12,6 +12,7 @@
 #include <base/files/file_path.h>
 #include <base/logging.h>
 #include <base/macros.h>
+#include <base/strings/string_split.h>
 
 #include "camera3_test/camera3_perf_log.h"
 #include "camera3_test/camera3_test_data_forwarder.h"
@@ -98,6 +99,21 @@
   return out;
 }
 
+static std::vector<int> GetCmdLineTestCameraIds() {
+  auto id_str =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII("camera_ids");
+  std::vector<int> ids;
+  if (!id_str.empty()) {
+    auto id_strs = base::SplitString(id_str, ",",
+                                     base::WhitespaceHandling::TRIM_WHITESPACE,
+                                     base::SplitResult::SPLIT_WANT_ALL);
+    for (const auto& id : id_strs) {
+      ids.push_back(stoi(id));
+    }
+  }
+  return ids;
+}
+
 static void InitCameraModuleOnThread(camera_module_t* cam_module) {
   static CameraModuleCallbacksAux* callbacks = []() {
     auto* aux = new CameraModuleCallbacksAux();
@@ -115,26 +131,68 @@
   int num_builtin_cameras = cam_module->get_number_of_cameras();
   VLOGF(1) << "num_builtin_cameras = " << num_builtin_cameras;
   ASSERT_EQ(0, cam_module->set_callbacks(callbacks));
-  g_cam_module = cam_module;
 }
 
-static void InitCameraModule(void** cam_hal_handle,
-                             const char* camera_hal_path) {
-  *cam_hal_handle = dlopen(camera_hal_path, RTLD_NOW);
+// On successfully Initialized, |cam_module_| will pointed to valid
+// camera_module_t. Caller should be responsible to dlclose |cam_hal_handle|, if
+// it's not NULL.
+static void InitCameraModule(const base::FilePath& camera_hal_path,
+                             void** cam_hal_handle,
+                             camera_module_t** cam_module) {
+  *cam_hal_handle = dlopen(camera_hal_path.value().c_str(), RTLD_NOW);
   ASSERT_NE(nullptr, *cam_hal_handle) << "Failed to dlopen: " << dlerror();
 
-  camera_module_t* cam_module = static_cast<camera_module_t*>(
+  camera_module_t* module = static_cast<camera_module_t*>(
       dlsym(*cam_hal_handle, HAL_MODULE_INFO_SYM_AS_STR));
-  ASSERT_NE(nullptr, cam_module) << "Camera module is invalid";
-  ASSERT_NE(nullptr, cam_module->get_number_of_cameras)
+  ASSERT_NE(nullptr, module) << "Camera module is invalid";
+  ASSERT_NE(nullptr, module->get_number_of_cameras)
       << "get_number_of_cameras is not implemented";
-  ASSERT_NE(nullptr, cam_module->get_camera_info)
+  ASSERT_NE(nullptr, module->get_camera_info)
       << "get_camera_info is not implemented";
-  ASSERT_NE(nullptr, cam_module->common.methods->open)
-      << "open() is unimplemented";
-  ASSERT_EQ(0,
-            g_module_thread.PostTaskSync(
-                FROM_HERE, base::Bind(&InitCameraModuleOnThread, cam_module)));
+  ASSERT_NE(nullptr, module->common.methods->open) << "open() is unimplemented";
+  for (int id : GetCmdLineTestCameraIds()) {
+    ASSERT_GT(module->get_number_of_cameras(), id)
+        << "No such test camera id in HAL";
+  }
+  ASSERT_EQ(0, g_module_thread.PostTaskSync(
+                   FROM_HERE, base::Bind(&InitCameraModuleOnThread, module)));
+  *cam_module = module;
+}
+
+static void InitCameraModuleByHalPath(const base::FilePath& camera_hal_path,
+                                      void** cam_hal_handle) {
+  InitCameraModule(camera_hal_path, cam_hal_handle, &g_cam_module);
+}
+
+static void InitCameraModuleByFacing(int facing, void** cam_hal_handle) {
+  // Do cleanup when exit from ASSERT_XX
+  struct CleanupModule {
+    void operator()(void** cam_hal_handle) {
+      if (*cam_hal_handle) {
+        g_cam_module = NULL;
+        dlclose(*cam_hal_handle);
+        *cam_hal_handle = NULL;
+      }
+    }
+  };
+  for (const auto& hal_path : cros::GetCameraHalPaths()) {
+    InitCameraModule(hal_path, cam_hal_handle, &g_cam_module);
+    std::unique_ptr<void*, CleanupModule> cleanup_ptr(cam_hal_handle);
+    if (g_cam_module != NULL) {
+      Camera3Module camera_module;
+      for (int i = 0; i < camera_module.GetNumberOfCameras(); i++) {
+        camera_info info;
+        ASSERT_EQ(0, camera_module.GetCameraInfo(i, &info));
+        if (info.facing == facing) {
+          base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+              "camera_ids", std::to_string(i));
+          cleanup_ptr.release();
+          return;
+        }
+      }
+    }
+  }
+  FAIL() << "Cannot find camera with facing=" << facing;
 }
 
 static void InitPerfLog() {
@@ -162,6 +220,7 @@
 
 Camera3Module::Camera3Module()
     : cam_module_(GetCameraModule()),
+      test_camera_ids_(GetCmdLineTestCameraIds()),
       hal_thread_(&g_module_thread),
       dev_thread_("Camera3 Test Device Thread") {
   dev_thread_.Start();
@@ -196,6 +255,10 @@
   return ids;
 }
 
+std::vector<int> Camera3Module::GetTestCameraIds() {
+  return test_camera_ids_.empty() ? GetCameraIds() : test_camera_ids_;
+}
+
 void Camera3Module::GetStreamConfigEntry(int cam_id,
                                          int32_t key,
                                          camera_metadata_ro_entry_t* entry) {
@@ -1065,6 +1128,23 @@
       .append(negative);
 }
 
+// Return -ENOENT for no facing specified, -EINVAL for invalid facing name.
+static int GetCmdLineTestCameraFacing(const base::CommandLine& cmd_line) {
+  const std::string facing_names[] = {"back", "front"};
+  const auto& facing_name = cmd_line.GetSwitchValueASCII("camera_facing");
+  if (facing_name.empty())
+    return -ENOENT;
+  int idx = std::distance(
+      facing_names,
+      std::find(facing_names, facing_names + arraysize(facing_names),
+                facing_name));
+  if (idx == arraysize(facing_names)) {
+    ADD_FAILURE() << "Invalid facing name: " << facing_name;
+    return -EINVAL;
+  }
+  return idx;
+}
+
 bool InitializeTest(int* argc, char*** argv, void** cam_hal_handle) {
   // Set up logging so we can enable VLOGs with -v / --vmodule.
   base::CommandLine::Init(*argc, *argv);
@@ -1075,8 +1155,19 @@
   base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
   base::FilePath camera_hal_path =
       cmd_line->GetSwitchValuePath("camera_hal_path");
+  int facing = GetCmdLineTestCameraFacing(*cmd_line);
 
-  if (camera_hal_path.empty()) {
+  if (facing != -ENOENT) {
+    if (facing == -EINVAL) {
+      LOG(ERROR) << "Invalid camera facing name.";
+      return false;
+    } else if (!camera_hal_path.empty() ||
+               !camera3_test::GetCmdLineTestCameraIds().empty()) {
+      LOGF(ERROR) << "Cannot specify both --camera_hal_path/--camera_ids and "
+                     "--camera_facing.";
+      return false;
+    }
+  } else if (camera_hal_path.empty()) {
     std::vector<base::FilePath> camera_hal_paths = cros::GetCameraHalPaths();
 
     if (camera_hal_paths.size() == 1) {
@@ -1107,8 +1198,11 @@
 
   // Open camera HAL and get module
   camera3_test::g_module_thread.Start();
-  camera3_test::InitCameraModule(cam_hal_handle,
-                                 camera_hal_path.value().c_str());
+  if (facing != -ENOENT) {
+    camera3_test::InitCameraModuleByFacing(facing, cam_hal_handle);
+  } else {
+    camera3_test::InitCameraModuleByHalPath(camera_hal_path, cam_hal_handle);
+  }
 
   camera3_test::InitPerfLog();
 
diff --git a/camera3_test/camera3_preview_test.cc b/camera3_test/camera3_preview_test.cc
index eeec109..d9ca65b 100644
--- a/camera3_test/camera3_preview_test.cc
+++ b/camera3_test/camera3_preview_test.cc
@@ -52,8 +52,9 @@
   }
 }
 
-INSTANTIATE_TEST_CASE_P(Camera3PreviewTest,
-                        Camera3SinglePreviewTest,
-                        ::testing::ValuesIn(Camera3Module().GetCameraIds()));
+INSTANTIATE_TEST_CASE_P(
+    Camera3PreviewTest,
+    Camera3SinglePreviewTest,
+    ::testing::ValuesIn(Camera3Module().GetTestCameraIds()));
 
 }  // namespace camera3_test
diff --git a/camera3_test/camera3_recording_test.cc b/camera3_test/camera3_recording_test.cc
index ae46225..56e6c30 100644
--- a/camera3_test/camera3_recording_test.cc
+++ b/camera3_test/camera3_recording_test.cc
@@ -178,10 +178,10 @@
   // now, and all cameras are sorted by facing in SuperHAL.  I feel bad when
   // implementing the following hack (sigh).
   std::vector<std::tuple<int, int32_t, int32_t, float>> result;
-  auto cam_ids = Camera3Module().GetCameraIds();
-  if (cam_ids.size() < param_ids.size()) {
+  Camera3Module module;
+  if (module.GetCameraIds().size() < param_ids.size()) {
     // SuperHAL case
-    for (const auto& cam_id : cam_ids) {
+    for (const auto& cam_id : module.GetTestCameraIds()) {
       camera_info info;
       EXPECT_EQ(0, Camera3Module().GetCameraInfo(cam_id, &info));
       bool found_matching_param = false;
@@ -196,7 +196,7 @@
     }
   } else {
     // Single HAL case
-    for (const auto& cam_id : cam_ids) {
+    for (const auto& cam_id : module.GetTestCameraIds()) {
       if (std::find_if(
               params.begin(), params.end(),
               [&](const std::tuple<int, int32_t, int32_t, float>& item) {
diff --git a/camera3_test/camera3_reprocessing_test.cc b/camera3_test/camera3_reprocessing_test.cc
index ecd590d..f959df8 100644
--- a/camera3_test/camera3_reprocessing_test.cc
+++ b/camera3_test/camera3_reprocessing_test.cc
@@ -562,12 +562,12 @@
   }
 }
 
-// Return camera ids of cameras which has reprocessing capability
-static std::vector<int> EnumerateReprocessingCapCameras() {
+// Return ids of test cameras which has reprocessing capability
+static std::vector<int> EnumerateReprocessingTestCameras() {
   std::vector<int> ret_ids;
   std::ostringstream ss;
   Camera3Module m;
-  for (auto cam_id : m.GetCameraIds()) {
+  for (auto cam_id : m.GetTestCameraIds()) {
     camera_info info;
     m.GetCameraInfo(cam_id, &info);
     auto static_info = std::make_unique<Camera3Device::StaticInfo>(info);
@@ -579,16 +579,18 @@
       ss << ' ' << cam_id;
     }
   }
-  LOG(INFO) << "Camera with reprocessing capability:" << ss.str();
+  LOG(INFO) << "Test camera with reprocessing capability:" << ss.str();
   return ret_ids;
 }
 
-INSTANTIATE_TEST_CASE_P(Camera3FrameTest,
-                        Camera3ReprocessingTest,
-                        ::testing::ValuesIn(EnumerateReprocessingCapCameras()));
+INSTANTIATE_TEST_CASE_P(
+    Camera3FrameTest,
+    Camera3ReprocessingTest,
+    ::testing::ValuesIn(EnumerateReprocessingTestCameras()));
 
-INSTANTIATE_TEST_CASE_P(Camera3FrameTest,
-                        Camera3ReprocessingReorderTest,
-                        ::testing::ValuesIn(EnumerateReprocessingCapCameras()));
+INSTANTIATE_TEST_CASE_P(
+    Camera3FrameTest,
+    Camera3ReprocessingReorderTest,
+    ::testing::ValuesIn(EnumerateReprocessingTestCameras()));
 
 }  // namespace camera3_test
diff --git a/camera3_test/camera3_still_capture_test.cc b/camera3_test/camera3_still_capture_test.cc
index 6ada73a..a6314f1 100644
--- a/camera3_test/camera3_still_capture_test.cc
+++ b/camera3_test/camera3_still_capture_test.cc
@@ -263,14 +263,15 @@
       << "JPEG size result and request should match";
 }
 
-INSTANTIATE_TEST_CASE_P(Camera3StillCaptureTest,
-                        Camera3SimpleStillCaptureTest,
-                        ::testing::ValuesIn(Camera3Module().GetCameraIds()));
+INSTANTIATE_TEST_CASE_P(
+    Camera3StillCaptureTest,
+    Camera3SimpleStillCaptureTest,
+    ::testing::ValuesIn(Camera3Module().GetTestCameraIds()));
 
 static std::vector<std::tuple<int, ResolutionInfo, ResolutionInfo>>
 IterateCameraIdPreviewJpegResolution() {
   std::vector<std::tuple<int, ResolutionInfo, ResolutionInfo>> result;
-  auto cam_ids = Camera3Module().GetCameraIds();
+  auto cam_ids = Camera3Module().GetTestCameraIds();
   for (const auto& cam_id : cam_ids) {
     auto preview_resolutions = Camera3Module().GetSortedOutputResolutions(
         cam_id, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
diff --git a/camera3_test/camera3_stream_test.cc b/camera3_test/camera3_stream_test.cc
index 401fa0a..e7cc9ac 100644
--- a/camera3_test/camera3_stream_test.cc
+++ b/camera3_test/camera3_stream_test.cc
@@ -212,7 +212,7 @@
     Camera3StreamTest,
     Camera3SingleStreamTest,
     ::testing::Combine(
-        ::testing::ValuesIn(Camera3Module().GetCameraIds()),
+        ::testing::ValuesIn(Camera3Module().GetTestCameraIds()),
         ::testing::Values(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
                           HAL_PIXEL_FORMAT_YCbCr_420_888,
                           HAL_PIXEL_FORMAT_YCrCb_420_SP,
@@ -222,15 +222,16 @@
                           HAL_PIXEL_FORMAT_Y16,
                           HAL_PIXEL_FORMAT_RAW16)));
 
-INSTANTIATE_TEST_CASE_P(Camera3StreamTest,
-                        Camera3MultiStreamTest,
-                        ::testing::ValuesIn(Camera3Module().GetCameraIds()));
+INSTANTIATE_TEST_CASE_P(
+    Camera3StreamTest,
+    Camera3MultiStreamTest,
+    ::testing::ValuesIn(Camera3Module().GetTestCameraIds()));
 
 INSTANTIATE_TEST_CASE_P(
     Camera3StreamTest,
     Camera3StreamInvalidRotationTest,
     ::testing::Combine(
-        ::testing::ValuesIn(Camera3Module().GetCameraIds()),
+        ::testing::ValuesIn(Camera3Module().GetTestCameraIds()),
         ::testing::Values(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
                           HAL_PIXEL_FORMAT_YCbCr_420_888,
                           HAL_PIXEL_FORMAT_YCrCb_420_SP,