[libcamera-devel,12/21] test: serialization: Add control serialization test

Message ID 20190924172503.30864-13-jacopo@jmondi.org
State Superseded
Headers show
Series
  • Implement control serialization
Related show

Commit Message

Jacopo Mondi Sept. 24, 2019, 5:24 p.m. UTC
Test the serialization procedure of a ControlList by manually
unwrapping a serialized data blob containing controls supported by
the VIMC camera and verify its content.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 test/meson.build                          |   1 +
 test/serialization/control_list.cpp       | 101 ++++++++++++
 test/serialization/meson.build            |  11 ++
 test/serialization/serialization_test.cpp | 189 ++++++++++++++++++++++
 test/serialization/serialization_test.h   |  65 ++++++++
 5 files changed, 367 insertions(+)
 create mode 100644 test/serialization/control_list.cpp
 create mode 100644 test/serialization/meson.build
 create mode 100644 test/serialization/serialization_test.cpp
 create mode 100644 test/serialization/serialization_test.h

Patch

diff --git a/test/meson.build b/test/meson.build
index 19e3031244a3..6d43273ca112 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -8,6 +8,7 @@  subdir('log')
 subdir('media_device')
 subdir('pipeline')
 subdir('process')
+subdir('serialization')
 subdir('stream')
 subdir('v4l2_subdevice')
 subdir('v4l2_videodevice')
diff --git a/test/serialization/control_list.cpp b/test/serialization/control_list.cpp
new file mode 100644
index 000000000000..2cefec0cdc00
--- /dev/null
+++ b/test/serialization/control_list.cpp
@@ -0,0 +1,101 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * control_list.cpp - Serialize and de-serialize a list of controls
+ */
+
+#include <iostream>
+
+#include <libcamera/camera.h>
+#include <libcamera/camera_manager.h>
+#include <libcamera/controls.h>
+
+#include "serialization_test.h"
+#include "serializer.h"
+#include "test.h"
+
+using namespace std;
+using namespace libcamera;
+
+class ControlListSerializeTest : public SerializationTest
+{
+private:
+	void initializeValidationMatrix()
+	{
+		valueValidationMatrix[0][0] = Saturation;
+		valueValidationMatrix[0][1] = DataTypeInteger;
+		valueValidationMatrix[0][2] = 8;
+		valueValidationMatrix[0][3] = 50;
+		valueValidationMatrix[0][4] = false;
+		valueValidationMatrix[1][0] = Contrast;
+		valueValidationMatrix[1][1] = DataTypeInteger;
+		valueValidationMatrix[1][2] = 8;
+		valueValidationMatrix[1][3] = 128;
+		valueValidationMatrix[1][4] = false;
+		valueValidationMatrix[2][0] = Brightness;
+		valueValidationMatrix[2][1] = DataTypeInteger;
+		valueValidationMatrix[2][2] = 8;
+		valueValidationMatrix[2][3] = 255;
+		valueValidationMatrix[2][4] = false;
+
+		numCtrls_ = 3;
+	}
+
+	int init()
+	{
+		return SerializationTest::init();
+	}
+
+	int run()
+	{
+		ControlList list(camera_->controls());
+
+		/*
+		 * Set a 3 controls and manually unroll the serialized
+		 * buffer to verify its content.
+		 *
+		 * \todo Test less trivial control types once we have them.
+		 */
+		list[Brightness] = 255;
+		list[Contrast] = 128;
+		list[Saturation] = 50;
+
+		initializeValidationMatrix();
+
+		/* Serialize and verify the produced blob size. */
+		std::unique_ptr<DataBlob> blob = list.serialize();
+		if (!blob) {
+			cerr << "Failed to serialize the control list" << endl;
+			return TestFail;
+		}
+
+		int ret = validateValueBlobSize(blob.get());
+		if (ret)
+			return ret;
+
+		/* Validate each serialized data value. */
+		uint8_t *b = blob->data();
+		for (unsigned int i = 0; i < numCtrls_; ++i) {
+			if (!validateValueBlob(b))
+				return TestFail;
+
+			b += VALUE_BLOB_SIZE;
+		}
+
+		/* De-serialize a control list and re-validate it. */
+		ControlList newList(camera_->controls());
+		newList.deserialize(blob->data(), blob->size());
+		for (auto it : newList) {
+			const ControlInfo *info = it.first;
+			ControlValue &control = it.second;
+
+			if (!validateDataValue(info->id(), control))
+				return TestFail;
+		}
+
+		return TestPass;
+	}
+};
+
+TEST_REGISTER(ControlListSerializeTest)
diff --git a/test/serialization/meson.build b/test/serialization/meson.build
new file mode 100644
index 000000000000..511f05cbbd1f
--- /dev/null
+++ b/test/serialization/meson.build
@@ -0,0 +1,11 @@ 
+serialization_tests = [
+    [ 'control_list',              'control_list.cpp' ],
+]
+
+foreach t : serialization_tests
+    exe = executable(t[0], [t[1], 'serialization_test.cpp'],
+                     dependencies : libcamera_dep,
+                     link_with : test_libraries,
+                     include_directories : test_includes_internal)
+    test(t[0], exe, suite : 'serialization', is_parallel : true)
+endforeach
diff --git a/test/serialization/serialization_test.cpp b/test/serialization/serialization_test.cpp
new file mode 100644
index 000000000000..8db70bb1de02
--- /dev/null
+++ b/test/serialization/serialization_test.cpp
@@ -0,0 +1,189 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * serialization_test.cpp - Base class for serialization tests
+ */
+
+#include "serialization_test.h"
+
+#include <iostream>
+
+#include <libcamera/camera.h>
+#include <libcamera/camera_manager.h>
+#include <libcamera/controls.h>
+
+#include "test.h"
+#include "serializer.h"
+
+using namespace std;
+using namespace libcamera;
+
+SerializationTest::SerializationTest()
+	: sensor_(nullptr), numCtrls_(0), cm_(nullptr)
+{
+}
+
+int SerializationTest::init()
+{
+	cm_ = new CameraManager();
+
+	if (cm_->start()) {
+		cerr << "Failed to start camera manager" << endl;
+		return TestFail;
+	}
+
+	camera_ = cm_->get("VIMC Sensor B");
+	if (!camera_) {
+		cerr << "Can not find VIMC camera" << endl;
+		return TestSkip;
+	}
+
+	return TestPass;
+}
+
+void SerializationTest::cleanup()
+{
+	delete sensor_;
+
+	if (camera_) {
+		camera_->release();
+		camera_.reset();
+	}
+
+	cm_->stop();
+	delete cm_;
+}
+
+int SerializationTest::initSubdevice()
+{
+	enumerator_ = DeviceEnumerator::create();
+	if (!enumerator_) {
+		cerr << "Failed to create device enumerator" << endl;
+		return TestFail;
+	}
+
+	if (enumerator_->enumerate()) {
+		cerr << "Failed to enumerate media devices" << endl;
+		return TestFail;
+	}
+
+	DeviceMatch dm("vimc");
+	media_ = enumerator_->search(dm);
+	if (!media_) {
+		cerr << "Unable to find \'vimc\' media device node" << endl;
+		return TestSkip;
+	}
+
+	sensor_ = V4L2Subdevice::fromEntityName(media_.get(), "Sensor B");
+	if (sensor_->open()) {
+		cerr << "Unable to open video subdevice \"Sensor B\""
+		     << endl;
+		return TestFail;
+	}
+
+	return TestPass;
+}
+
+int SerializationTest::validateValueBlobSize(DataBlob *blob)
+{
+	size_t blobSize = blob->size();
+	if (blobSize % Serializer::BLOB_ALIGN_BYTES) {
+		cerr << "Serialized control list has incorrect alignement"
+		     << endl;
+		return TestFail;
+	}
+
+	size_t expectedSize = VALUE_BLOB_SIZE * numCtrls_;
+	if (blobSize != expectedSize) {
+		cerr << "Serialized control list has incorrect size: "
+		     << " expected size " << expectedSize
+		     << " got " << blobSize << endl;
+		return TestFail;
+	}
+
+	return TestPass;
+}
+
+bool SerializationTest::validateValueBlob(uint8_t *blob)
+{
+	uint32_t id = *(reinterpret_cast<uint32_t *>(blob));
+	uint32_t type = *(reinterpret_cast<uint32_t *>(Serializer::VALUE_BLOB_TYPE(blob)));
+	uint32_t size = *(reinterpret_cast<uint32_t *>(Serializer::VALUE_BLOB_SIZE(blob)));
+	uint32_t value = *(reinterpret_cast<uint32_t*>(Serializer::VALUE_BLOB_DATA(blob)));
+	bool found = false;
+
+	cout << "Testing serialized control:  " << id << " - "
+	     << type << " - " << size << " - " << value << endl;
+
+	for (unsigned int i = 0; i < numCtrls_; ++i) {
+		if (valueValidationMatrix[i][VALUE_CTRL_ID] != id)
+			continue;
+
+		found = true;
+
+		unsigned int *entry = valueValidationMatrix[i];
+		if (entry[VALUE_CTRL_FLAG]) {
+			cerr << "The control with id " << id
+			     << " has been serialized twice" << endl;
+			return false;
+		}
+		entry[VALUE_CTRL_FLAG] = true;
+
+		if (entry[VALUE_CTRL_TYPE] != type ||
+		    entry[VALUE_CTRL_SIZE] != size ||
+		    entry[VALUE_CTRL_VALUE] != value) {
+			cerr << "The control with id " << id
+			     << " has been wrongly serialized" << endl;
+			return false;
+		}
+	}
+
+	if (!found) {
+		cerr << "Non-existing control with id " << id << endl;
+		return false;
+	}
+
+	cout << "Serialization of control:  " << id << " = Success."
+	     << endl;
+
+	return true;
+}
+
+bool SerializationTest::validateDataValue(unsigned int id, const DataValue &dataValue)
+{
+	uint32_t value = dataValue.getInt();
+	DataType type = dataValue.type();
+	size_t dataSize = DataSize[type];
+	size_t size = dataValue.size();
+	bool found = false;
+
+	cout << "Testing de-serialized control: " << id << " - "
+	     << type << " - " << size << " - " << value << endl;
+
+	for (unsigned int i = 0; i < numCtrls_; ++i) {
+		if (valueValidationMatrix[i][VALUE_CTRL_ID] != id)
+			continue;
+
+		found = true;
+
+		unsigned int *entry = valueValidationMatrix[i];
+		if (entry[VALUE_CTRL_TYPE] != dataValue.type() ||
+		    dataSize != dataValue.size() ||
+		    entry[VALUE_CTRL_VALUE] != value) {
+			cerr << "The control with id " << id
+			     << " has been wrongly de-serialized" << endl;
+			return false;
+		}
+	}
+
+	if (!found) {
+		cerr << "Non-existing control with id " << id << endl;
+		return false;
+	}
+
+	cout << "De-serialization of control: " << id << " = Success."
+	     << endl;
+
+	return true;
+}
diff --git a/test/serialization/serialization_test.h b/test/serialization/serialization_test.h
new file mode 100644
index 000000000000..87dc5a84a505
--- /dev/null
+++ b/test/serialization/serialization_test.h
@@ -0,0 +1,65 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * serialization_test.h - Base class for serialization tests
+ */
+#ifndef __LIBCAMERA_SERIALIZATION_TEST_H__
+#define __LIBCAMERA_SERIALIZATION_TEST_H__
+
+#include <libcamera/camera.h>
+#include <libcamera/camera_manager.h>
+#include <libcamera/controls.h>
+
+#include "device_enumerator.h"
+#include "media_device.h"
+#include "serializer.h"
+#include "test.h"
+#include "v4l2_subdevice.h"
+
+using namespace libcamera;
+
+class SerializationTest : public Test
+{
+public:
+	SerializationTest();
+
+protected:
+	static constexpr unsigned int CTRL_MAX			= 10;
+
+	/* Value validation matrix */
+	unsigned int valueValidationMatrix[3][5];
+
+	/* Indices on the validation matrix */
+	static constexpr unsigned int VALUE_CTRL_ID		= 0;
+	static constexpr unsigned int VALUE_CTRL_TYPE		= 1;
+	static constexpr unsigned int VALUE_CTRL_SIZE		= 2;
+	static constexpr unsigned int VALUE_CTRL_VALUE		= 3;
+	static constexpr unsigned int VALUE_CTRL_FLAG		= 4;
+
+	/*
+	 * Serialized values sizes.
+	 * \todo Assume a serialized value is 24 bytes as all control
+	 * values are simple integers.
+	 */
+	static constexpr unsigned int VALUE_BLOB_DATA_SIZE	= 8;
+	static constexpr unsigned int VALUE_BLOB_SIZE		= 24;
+
+	int init();
+	void cleanup();
+
+	int initSubdevice();
+
+	int validateValueBlobSize(DataBlob *blob);
+	bool validateValueBlob(uint8_t *dataBlob);
+	bool validateDataValue(unsigned int id, const DataValue &dataValue);
+
+	std::unique_ptr<DeviceEnumerator> enumerator_;
+	std::shared_ptr<MediaDevice> media_;
+	std::shared_ptr<Camera> camera_;
+	V4L2Subdevice *sensor_;
+	unsigned int numCtrls_;
+	CameraManager *cm_;
+};
+
+#endif /* __LIBCAMERA_SERIALIZATION_TEST_H__ */