summaryrefslogtreecommitdiff
path: root/test/log/log_process.cpp
blob: 966b80cf3af76a3bc18bc038483f0325e8e083b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * log_process.cpp - Logging in isolated child process test
 */

#include <fcntl.h>
#include <iostream>
#include <random>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>

#include <libcamera/logging.h>

#include <libcamera/base/event_dispatcher.h>
#include <libcamera/base/log.h>
#include <libcamera/base/thread.h>
#include <libcamera/base/timer.h>
#include <libcamera/base/utils.h>

#include "libcamera/internal/process.h"

#include "test.h"

using namespace libcamera;
using namespace std;
using namespace std::chrono_literals;

static const string message("hello from the child");

LOG_DEFINE_CATEGORY(LogProcessTest)

class LogProcessTestChild
{
public:
	int run(int status, int num)
	{
		usleep(50000);

		string logPath = "/tmp/libcamera.worker.test." +
				 to_string(num) + ".log";
		if (logSetFile(logPath.c_str()) < 0)
			return TestSkip;

		LOG(LogProcessTest, Warning) << message;

		return status;
	}
};

class LogProcessTest : public Test
{
protected:
	int init()
	{
		random_device random;
		num_ = random();
		logPath_ = "/tmp/libcamera.worker.test." +
			   to_string(num_) + ".log";

		proc_.finished.connect(this, &LogProcessTest::procFinished);
		return 0;
	}

	int run()
	{
		EventDispatcher *dispatcher = Thread::current()->eventDispatcher();
		Timer timeout;

		int exitCode = 42;
		vector<std::string> args;
		args.push_back(to_string(exitCode));
		args.push_back(to_string(num_));
		int ret = proc_.start(self(), args);
		if (ret) {
			cerr << "failed to start process" << endl;
			return TestFail;
		}

		timeout.start(200ms);
		while (timeout.isRunning())
			dispatcher->processEvents();

		if (exitStatus_ != Process::NormalExit) {
			cerr << "process did not exit normally" << endl;
			return TestFail;
		}

		if (exitCode_ == TestSkip)
			return TestSkip;

		if (exitCode_ != exitCode) {
			cerr << "exit code should be " << exitCode
			     << ", actual is " << exitCode_ << endl;
			return TestFail;
		}

		int fd = open(logPath_.c_str(), O_RDONLY, S_IRUSR);
		if (fd < 0) {
			cerr << "failed to open tmp log file" << endl;
			return TestFail;
		}

		char buf[200];
		memset(buf, 0, sizeof(buf));
		if (read(fd, buf, sizeof(buf)) < 0) {
			cerr << "Failed to read tmp log file" << endl;
			close(fd);
			return TestFail;
		}
		close(fd);

		string str(buf);
		if (str.find(message) == string::npos)
			return TestFail;

		return TestPass;
	}

	void cleanup()
	{
		unlink(logPath_.c_str());
	}

private:
	void procFinished(enum Process::ExitStatus exitStatus, int exitCode)
	{
		exitStatus_ = exitStatus;
		exitCode_ = exitCode;
	}

	ProcessManager processManager_;

	Process proc_;
	Process::ExitStatus exitStatus_;
	string logPath_;
	int exitCode_;
	int num_;
};

/*
 * Can't use TEST_REGISTER() as single binary needs to act as both
 * parent and child processes.
 */
int main(int argc, char **argv)
{
	if (argc == 3) {
		int status = std::stoi(argv[1]);
		int num = std::stoi(argv[2]);
		LogProcessTestChild child;
		return child.run(status, num);
	}

	LogProcessTest test;
	test.setArgs(argc, argv);
	return test.execute();
}
dev_->setupLink(this, flags); if (ret) return ret; flags_ = flags; return 0; } /** * \brief Construct a MediaLink * \param[in] link The media link kernel data * \param[in] source The source pad at the origin of the link * \param[in] sink The sink pad at the destination of the link */ MediaLink::MediaLink(const struct media_v2_link *link, MediaPad *source, MediaPad *sink) : MediaObject(source->device(), link->id), source_(source), sink_(sink), flags_(link->flags) { } /** * \fn MediaLink::source() * \brief Retrieve the link's source pad * \return The source pad at the origin of the link */ /** * \fn MediaLink::sink() * \brief Retrieve the link's sink pad * \return The sink pad at the destination of the link */ /** * \fn MediaLink::flags() * \brief Retrieve the link's flags * * Link flags are a bitmask of flags defined by the Media Controller API * MEDIA_LNK_FL_* macros. * * \return The link flags */ /** * \class MediaPad * \brief The MediaPad represents a pad of an entity in the media graph * * Pads are created from the information provided by the Media Controller API * in the media_v2_pad structure. They reference the entity() they belong to. * * In addition to their graph id, media graph pads are identified by an index * unique in the context of the entity the pad belongs to. * * A pad can be either a 'source' pad or a 'sink' pad. This information is * captured in the pad flags(). * * Pads are connected through links. Links originating from a source pad are * outbound links, and links arriving at a sink pad are inbound links. Pads * reference all the links() that are connected to them. */ /** * \brief Construct a MediaPad * \param[in] pad The media pad kernel data * \param[in] entity The entity the pad belongs to */ MediaPad::MediaPad(const struct media_v2_pad *pad, MediaEntity *entity) : MediaObject(entity->device(), pad->id), index_(pad->index), entity_(entity), flags_(pad->flags) { } /** * \fn MediaPad::index() * \brief Retrieve the pad index * \return The 0-based pad index identifying the pad in the context of the * entity it belongs to */ /** * \fn MediaPad::entity() * \brief Retrieve the entity the pad belongs to * \return The MediaEntity the pad belongs to */ /** * \fn MediaPad::flags() * \brief Retrieve the pad flags * * Pad flags are a bitmask of flags defined by the Media Controller API * MEDIA_PAD_FL_* macros. * * \return The pad flags */ /** * \fn MediaPad::links() * \brief Retrieve all links in the pad * \return A list of links connected to the pad */ /** * \brief Add a new link to this pad * \param[in] link The MediaLink to add */ void MediaPad::addLink(MediaLink *link) { links_.push_back(link); } /** * \class MediaEntity * \brief The MediaEntity represents an entity in the media graph * * Entities are created from the information provided by the Media Controller * API in the media_v2_entity structure. They reference the pads() they contain. * * In addition to their graph id, media graph entities are identified by a * name() unique in the media device context. They implement a function() and * may expose a deviceNode(). */ /** * \fn MediaEntity::name() * \brief Retrieve the entity name * \return The entity name */ /** * \fn MediaEntity::function() * \brief Retrieve the entity's main function * * Media entity functions are expressed using the MEDIA_ENT_F_* macros * defined by the Media Controller API. * * \return The entity's function */ /** * \fn MediaEntity::flags() * \brief Retrieve the entity's flags * * Media entity flags are expressed using the MEDIA_ENT_FL_* macros * defined by the Media Controller API. * * \return The entity's flags */ /** * \fn MediaEntity::deviceNode() * \brief Retrieve the entity's device node path, if any * \return The entity's device node path, or an empty string if it is not set * \sa int setDeviceNode() */ /** * \fn MediaEntity::deviceMajor() * \brief Retrieve the major number of the interface associated with the entity