Camera2: Automated tests for testing HAL2.0 interface: DO NOT MERGE

Change-Id: If5c922a0c0139b90c4781f022d80f7b9a0932e9e
This commit is contained in:
Igor Murashkin 2012-11-05 11:14:49 -08:00
parent 48697f6dc2
commit 7e38f5faac
11 changed files with 827 additions and 6 deletions

View file

@ -3,20 +3,27 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
camera2.cpp \
camera2_utils.cpp
camera2_utils.cpp \
main.cpp \
CameraMetadataTests.cpp \
CameraModuleTests.cpp \
CameraStreamTests.cpp \
CameraFrameTests.cpp \
LOCAL_SHARED_LIBRARIES := \
libutils \
libcutils \
libstlport \
libhardware \
libcamera_metadata \
libcameraservice \
libgui \
libsync \
libui
libui \
libdl
LOCAL_STATIC_LIBRARIES := \
libgtest \
libgtest_main
libgtest
LOCAL_C_INCLUDES += \
bionic \
@ -24,6 +31,8 @@ LOCAL_C_INCLUDES += \
external/gtest/include \
external/stlport/stlport \
system/media/camera/include \
frameworks/av/services/camera/libcameraservice \
frameworks/native/include \
LOCAL_MODULE:= camera2_test
LOCAL_MODULE_TAGS := tests

View file

@ -0,0 +1,128 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#define LOG_TAG "CameraFrameTest"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
#include "hardware/hardware.h"
#include "hardware/camera2.h"
#include "Camera2Device.h"
#include "utils/StrongPointer.h"
#include <gui/CpuConsumer.h>
#include <gui/SurfaceTextureClient.h>
#include <unistd.h>
#include "CameraStreamFixture.h"
#define CAMERA_FRAME_TIMEOUT 1000000000 //nsecs (1 secs)
#define CAMERA_HEAP_COUNT 2 //HALBUG: 1 means registerBuffers fails
#define CAMERA_FRAME_DEBUGGING 0
using namespace android;
using namespace android::camera2;
namespace android {
namespace camera2 {
namespace tests {
static CameraStreamParams STREAM_PARAMETERS = {
/*mCameraId*/ 0,
/*mFormat*/ HAL_PIXEL_FORMAT_YCrCb_420_SP,
/*mHeapCount*/ CAMERA_HEAP_COUNT
};
class CameraFrameTest
: public ::testing::TestWithParam<int>,
public CameraStreamFixture {
public:
CameraFrameTest() : CameraStreamFixture(STREAM_PARAMETERS) {
if (!HasFatalFailure()) {
CreateStream();
}
}
~CameraFrameTest() {
if (mDevice.get()) {
mDevice->waitUntilDrained();
}
DeleteStream();
}
virtual void SetUp() {
}
virtual void TearDown() {
}
protected:
};
TEST_P(CameraFrameTest, GetFrame) {
if (HasFatalFailure()) {
return;
}
/* Submit a PREVIEW type request, then wait until we get the frame back */
CameraMetadata previewRequest;
ASSERT_EQ(OK, mDevice->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
&previewRequest));
{
Vector<uint8_t> outputStreamIds;
outputStreamIds.push(mStreamId);
ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
outputStreamIds));
if (CAMERA_FRAME_DEBUGGING) {
int frameCount = 0;
ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_FRAME_COUNT,
&frameCount, 1));
}
}
if (CAMERA_FRAME_DEBUGGING) {
previewRequest.dump(STDOUT_FILENO);
}
for (int i = 0; i < GetParam(); ++i) {
ALOGV("Submitting capture request");
CameraMetadata tmpRequest = previewRequest;
ASSERT_EQ(OK, mDevice->capture(tmpRequest));
}
for (int i = 0; i < GetParam(); ++i) {
ASSERT_EQ(OK, mDevice->waitForNextFrame(CAMERA_FRAME_TIMEOUT));
CameraMetadata frameMetadata;
ASSERT_EQ(OK, mDevice->getNextFrame(&frameMetadata));
}
}
//FIXME: dont hardcode stream params, and also test multistream
INSTANTIATE_TEST_CASE_P(FrameParameterCombinations, CameraFrameTest,
testing::Range(1, 10));
}
}
}

View file

@ -0,0 +1,126 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_NDEBUG 0
#define LOG_TAG "CameraMetadataTestFunctional"
#include "cutils/log.h"
#include "cutils/properties.h"
#include "utils/Errors.h"
#include "gtest/gtest.h"
#include "system/camera_metadata.h"
#include "hardware/hardware.h"
#include "hardware/camera2.h"
#include "Camera2Device.h"
#include "utils/StrongPointer.h"
#include <gui/CpuConsumer.h>
#include <gui/SurfaceTextureClient.h>
#include <string>
#include "CameraStreamFixture.h"
namespace android {
namespace camera2 {
namespace tests {
//FIXME: dont hardcode
static CameraStreamParams METADATA_STREAM_PARAMETERS = {
/*mCameraId*/ 0,
/*mFormat*/ HAL_PIXEL_FORMAT_YCrCb_420_SP,
/*mHeapCount*/ 2
};
class DISABLED_CameraMetadataTest
: public ::testing::Test,
public CameraStreamFixture {
public:
DISABLED_CameraMetadataTest()
: CameraStreamFixture(METADATA_STREAM_PARAMETERS) {
}
~DISABLED_CameraMetadataTest() {
}
int GetTypeFromTag(uint32_t tag) const {
return get_camera_metadata_tag_type(tag);
}
int GetTypeFromStaticTag(uint32_t tag) const {
const CameraMetadata& staticInfo = mDevice->info();
camera_metadata_ro_entry entry = staticInfo.find(tag);
return entry.type;
}
static void SetUpTestCase() {
}
static void TearDownTestCase()
{
}
protected:
};
TEST_F(DISABLED_CameraMetadataTest, types) {
if (HasFatalFailure()) {
return;
}
//FIXME: set this up in an external file of some sort (xml?)
{
char value[PROPERTY_VALUE_MAX];
property_get("ro.build.id", value, "");
std::string str_value(value);
if (str_value == "manta")
{
EXPECT_EQ(TYPE_BYTE,
GetTypeFromStaticTag(ANDROID_QUIRKS_TRIGGER_AF_WITH_AUTO));
EXPECT_EQ(TYPE_BYTE,
GetTypeFromStaticTag(ANDROID_QUIRKS_USE_ZSL_FORMAT));
EXPECT_EQ(TYPE_BYTE,
GetTypeFromStaticTag(ANDROID_QUIRKS_METERING_CROP_REGION));
}
}
/*
TODO:
go through all static metadata and make sure all fields we expect
that are there, ARE there.
dont worry about the type as its enforced by the metadata api
we can probably check the range validity though
*/
if (0) {
camera_metadata_ro_entry entry;
EXPECT_EQ(TYPE_BYTE, entry.type);
EXPECT_EQ(TYPE_INT32, entry.type);
EXPECT_EQ(TYPE_FLOAT, entry.type);
EXPECT_EQ(TYPE_INT64, entry.type);
EXPECT_EQ(TYPE_DOUBLE, entry.type);
EXPECT_EQ(TYPE_RATIONAL, entry.type);
}
}
}
}
}

View file

@ -0,0 +1,107 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include "hardware/hardware.h"
#include "hardware/camera2.h"
#include "Camera2Device.h"
#include "camera2_utils.h"
namespace android {
namespace camera2 {
namespace tests {
template <bool InfoQuirk = false>
struct CameraModuleFixture {
CameraModuleFixture(int CameraID = -1) {
mCameraID = CameraID;
SetUp();
}
~CameraModuleFixture() {
TearDown();
}
private:
void SetUp() {
ASSERT_LE(0, hw_get_module(CAMERA_HARDWARE_MODULE_ID,
(const hw_module_t **)&mModule)) << "Could not load camera module";
ASSERT_NE((void*)0, mModule);
mNumberOfCameras = mModule->get_number_of_cameras();
ASSERT_LE(0, mNumberOfCameras);
ASSERT_EQ(
CAMERA_MODULE_API_VERSION_2_0, mModule->common.module_api_version)
<< "Wrong module API version";
/* For using this fixture in other tests only */
SetUpMixin();
}
void TearDown() {
TearDownMixin();
/* important: device must be destructed before closing module,
since it calls back into HAL */
mDevice.clear();
ASSERT_EQ(0, HWModuleHelpers::closeModule(&mModule->common))
<< "Failed to close camera HAL module";
}
void SetUpMixin() {
/* For using this fixture in other tests only */
if (mCameraID != -1) {
EXPECT_LE(0, mCameraID);
EXPECT_LT(mCameraID, mNumberOfCameras);
/* HALBUG (Exynos5); crashes if trying to initialize
before calling get_camera_info */
if (InfoQuirk) {
struct camera_info info;
ASSERT_EQ(OK, mModule->get_camera_info(mCameraID, &info));
}
mDevice = new Camera2Device(mCameraID);
ASSERT_EQ(OK, mDevice->initialize(mModule))
<< "Failed to initialize device " << mCameraID;
}
}
void TearDownMixin() {
}
protected:
int mNumberOfCameras;
camera_module_t *mModule;
sp<Camera2Device> mDevice;
private:
int mCameraID;
};
}
}
}

View file

@ -0,0 +1,120 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#define LOG_TAG "DISABLED_CameraModuleTest"
#define LOG_NDEBUG 0
#include <utils/Log.h>
#include "hardware/hardware.h"
#include "hardware/camera2.h"
#include "Camera2Device.h"
#include "utils/StrongPointer.h"
#include "CameraModuleFixture.h"
namespace android {
namespace camera2 {
namespace tests {
class DISABLED_CameraModuleTest : public ::testing::Test,
public CameraModuleFixture<> {
virtual void SetUp() {
//CameraModuleFixture::SetUp();
}
virtual void TearDown() {
//CameraModuleFixture::TearDown();
}
};
TEST_F(DISABLED_CameraModuleTest, LoadModule) {
if (HasFatalFailure()) {
return;
}
for (int i = 0; i < mNumberOfCameras; ++i) {
mDevice = new Camera2Device(i);
ASSERT_EQ(OK, mDevice->initialize(mModule))
<< "Failed to initialize device " << i;
mDevice.clear();
}
}
TEST_F(DISABLED_CameraModuleTest, LoadModuleBadIndices) {
if (HasFatalFailure()) {
return;
}
int idx[] = { -1, mNumberOfCameras, mNumberOfCameras + 1 };
for (unsigned i = 0; i < sizeof(idx)/sizeof(idx[0]); ++i) {
mDevice = new Camera2Device(idx[i]);
status_t deviceInitializeCode = mDevice->initialize(mModule);
EXPECT_NE(OK, deviceInitializeCode);
EXPECT_EQ(-ENODEV, deviceInitializeCode)
<< "Incorrect error code when trying to initialize invalid index "
<< idx[i];
mDevice.clear();
}
}
TEST_F(DISABLED_CameraModuleTest, GetCameraInfo) {
if (HasFatalFailure()) {
return;
}
for (int i = 0; i < mNumberOfCameras; ++i) {
struct camera_info info;
ASSERT_EQ(OK, mModule->get_camera_info(i, &info));
}
}
TEST_F(DISABLED_CameraModuleTest, GetCameraInfoBadIndices) {
if (HasFatalFailure()) {
return;
}
int idx[] = { -1, mNumberOfCameras, mNumberOfCameras + 1 };
for (unsigned i = 0; i < sizeof(idx)/sizeof(idx[0]); ++i) {
struct camera_info info;
EXPECT_NE(OK, mModule->get_camera_info(idx[i], &info));
EXPECT_EQ(-ENODEV, mModule->get_camera_info(idx[i], &info))
<< "Incorrect error code for get_camera_info idx= "
<< idx[i];
}
}
/**
* TODO: Additional test to add: open two cameras at once.
* (is allowed to fail, at least for now, but should not blow up)
*/
}
}
}

View file

@ -0,0 +1,119 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include <gui/CpuConsumer.h>
#include <gui/SurfaceTextureClient.h>
#include "CameraModuleFixture.h"
namespace android {
namespace camera2 {
namespace tests {
struct CameraStreamParams {
int mCameraId;
int mFormat;
int mHeapCount;
};
class CameraStreamFixture
: public CameraModuleFixture</*InfoQuirk*/true> {
public:
CameraStreamFixture(CameraStreamParams p)
: CameraModuleFixture(p.mCameraId) {
mParam = p;
SetUp();
}
~CameraStreamFixture() {
TearDown();
}
private:
void SetUp() {
CameraStreamParams p = mParam;
sp<Camera2Device> device = mDevice;
/* use an arbitrary w,h */
{
const int tag = ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES;
const android::camera2::CameraMetadata& staticInfo = device->info();
camera_metadata_ro_entry entry = staticInfo.find(tag);
ASSERT_NE(0u, entry.count)
<< "Missing tag android.scaler.availableProcessedSizes";
ASSERT_LE(2u, entry.count);
/* this seems like it would always be the smallest w,h
but we actually make no contract that it's sorted asc */;
mWidth = entry.data.i32[0];
mHeight = entry.data.i32[1];
}
}
void TearDown() {
}
protected:
void CreateStream() {
sp<Camera2Device> device = mDevice;
CameraStreamParams p = mParam;
mCpuConsumer = new CpuConsumer(p.mHeapCount);
mCpuConsumer->setName(String8("CameraStreamTest::mCpuConsumer"));
mNativeWindow = new SurfaceTextureClient(
mCpuConsumer->getProducerInterface());
ASSERT_EQ(OK,
device->createStream(mNativeWindow,
mWidth, mHeight, p.mFormat, /*size (for jpegs)*/0,
&mStreamId));
ASSERT_NE(-1, mStreamId);
}
void DeleteStream() {
ASSERT_EQ(OK, mDevice->deleteStream(mStreamId));
}
/* consider factoring out this common code into
a CameraStreamFixture<T>, e.g.
class CameraStreamTest : TestWithParam<CameraStreamParameters>,
CameraStreamFixture<CameraStreamParameters>
to make it easier for other classes to not duplicate the params
*/
int mWidth;
int mHeight;
int mStreamId;
android::sp<CpuConsumer> mCpuConsumer;
android::sp<ANativeWindow> mNativeWindow;
private:
CameraStreamParams mParam;
};
}
}
}

View file

@ -0,0 +1,148 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#define LOG_TAG "DISABLED_CameraStreamTest"
#define LOG_NDEBUG 0
#include <utils/Log.h>
#include "hardware/hardware.h"
#include "hardware/camera2.h"
#include "Camera2Device.h"
#include "utils/StrongPointer.h"
#include <gui/CpuConsumer.h>
#include <gui/SurfaceTextureClient.h>
#include "CameraStreamFixture.h"
using namespace android;
using namespace android::camera2;
namespace android {
namespace camera2 {
namespace tests {
class DISABLED_CameraStreamTest
: public ::testing::TestWithParam<CameraStreamParams>,
public CameraStreamFixture {
public:
DISABLED_CameraStreamTest() : CameraStreamFixture(GetParam()) {
}
~DISABLED_CameraStreamTest() {
}
virtual void SetUp() {
}
virtual void TearDown() {
}
protected:
};
TEST_P(DISABLED_CameraStreamTest, CreateStream) {
if (HasFatalFailure()) {
return;
}
CreateStream();
if (HasFatalFailure()) {
return;
}
DeleteStream();
}
//TODO: use a combinatoric generator
static CameraStreamParams TestParameters[] = {
{
/*cameraId*/ 0,
/*mFormat*/ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
/*mHeapCount*/ 1
},
{
/*cameraId*/ 0,
/*mFormat*/ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
/*mHeapCount*/ 2
},
{
/*cameraId*/ 0,
/*mFormat*/ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
/*mHeapCount*/ 3
},
{
/*cameraId*/ 0,
/*mFormat*/ HAL_PIXEL_FORMAT_YCrCb_420_SP, // NV21
/*mHeapCount*/ 1
},
{
/*cameraId*/ 0,
/*mFormat*/ HAL_PIXEL_FORMAT_YCrCb_420_SP,
/*mHeapCount*/ 2
},
{
/*cameraId*/ 0,
/*mFormat*/ HAL_PIXEL_FORMAT_YCrCb_420_SP,
/*mHeapCount*/ 3
},
{
/*cameraId*/ 0,
/*mFormat*/ HAL_PIXEL_FORMAT_YV12,
/*mHeapCount*/ 1
},
{
/*cameraId*/ 0,
/*mFormat*/ HAL_PIXEL_FORMAT_YV12,
/*mHeapCount*/ 2
},
{
/*cameraId*/ 0,
/*mFormat*/ HAL_PIXEL_FORMAT_YV12,
/*mHeapCount*/ 3
},
{
/*cameraId*/ 0,
/*mFormat*/ HAL_PIXEL_FORMAT_RAW_SENSOR,
/*mHeapCount*/ 1
},
{
/*cameraId*/ 0,
/*mFormat*/ HAL_PIXEL_FORMAT_RAW_SENSOR,
/*mHeapCount*/ 2
},
{
/*cameraId*/ 0,
/*mFormat*/ HAL_PIXEL_FORMAT_RAW_SENSOR,
/*mHeapCount*/ 3
},
};
INSTANTIATE_TEST_CASE_P(StreamParameterCombinations, DISABLED_CameraStreamTest,
testing::ValuesIn(TestParameters));
}
}
}

View file

@ -30,6 +30,8 @@
#include "camera2_utils.h"
namespace android {
namespace camera2 {
namespace tests {
class Camera2Test: public testing::Test {
public:
@ -103,6 +105,11 @@ class Camera2Test: public testing::Test {
}
}
static void TearDownTestCase() {
hw_module_t *module = reinterpret_cast<hw_module_t*>(sCameraModule);
ASSERT_EQ(0, HWModuleHelpers::closeModule(module));
}
static const camera_module_t *getCameraModule() {
return sCameraModule;
}
@ -606,7 +613,7 @@ TEST_F(Camera2Test, ConstructDefaultRequests) {
}
}
TEST_F(Camera2Test, Capture1Jpeg) {
TEST_F(Camera2Test, DISABLED_Capture1Jpeg) {
status_t res;
for (int id = 0; id < getNumCameras(); id++) {
@ -720,5 +727,6 @@ TEST_F(Camera2Test, Capture1Jpeg) {
}
}
} // namespace tests
} // namespace camera2
} // namespace android

View file

@ -21,8 +21,11 @@
#include "utils/Log.h"
#include "camera2_utils.h"
#include <dlfcn.h>
namespace android {
namespace camera2 {
namespace tests {
/**
* MetadataQueue
@ -578,4 +581,22 @@ void FrameWaiter::onFrameAvailable() {
mCondition.signal();
}
int HWModuleHelpers::closeModule(hw_module_t* module) {
int status;
if (!module) {
return -EINVAL;
}
status = dlclose(module->dso);
if (status != 0) {
char const *err_str = dlerror();
ALOGE("%s dlclose failed, error: %s", __func__, err_str ?: "unknown");
}
return status;
}
} // namespace tests
} // namespace camera2
} // namespace android

View file

@ -27,6 +27,8 @@
#include <utils/Condition.h>
namespace android {
namespace camera2 {
namespace tests {
/**
* Queue class for both sending requests to a camera2 device, and for receiving
@ -233,4 +235,11 @@ class FrameWaiter : public CpuConsumer::FrameAvailableListener {
Condition mCondition;
};
struct HWModuleHelpers {
/* attempt to unload the library with dlclose */
static int closeModule(hw_module_t* module);
};
}
}
}

26
tests/camera2/main.cpp Normal file
View file

@ -0,0 +1,26 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
return ret;
}