/*
* This file is part of the ZoneMinder Project. See AUTHORS file for contributors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "zm_catch2.h"
#include "zm_stream.h"
#include
#include
namespace {
// Minimal concrete StreamBase so the base constructor and destructor can be
// exercised without a monitor, a database or shared memory.
class TestStream : public StreamBase {
public:
void runStream() override {}
protected:
void processCommand(const CmdMsg *) override {}
};
bool fd_is_open(int fd) {
return fcntl(fd, F_GETFD) != -1;
}
// Destruct a TestStream with the given connkey and report whether fd 0
// survived. fd 0 is restored either way, so a failure here can't cascade into
// the rest of the suite.
bool stdin_survives_destruction(int connkey) {
REQUIRE(fd_is_open(STDIN_FILENO));
int saved = dup(STDIN_FILENO);
REQUIRE(saved != -1);
{
TestStream stream;
if (connkey) stream.setStreamQueue(connkey);
}
bool survived = fd_is_open(STDIN_FILENO);
if (!survived) REQUIRE(dup2(saved, STDIN_FILENO) != -1);
close(saved);
return survived;
}
} // namespace
TEST_CASE("StreamBase comms teardown") {
SECTION("destructing without openComms() leaves stdin alone") {
// Regression: lock_fd was initialised to 0 rather than -1, so closeComms()
// -- reached from ~StreamBase() -- saw `lock_fd >= 0` and called close(0),
// closing stdin. It only needed connkey > 0 and a runStream() that returned
// before openComms(). MonitorStream::runStream() does exactly that for
// STREAM_SINGLE and when the monitor fails to load, and mode=single URLs
// still carry a connkey.
REQUIRE(stdin_survives_destruction(123456));
}
SECTION("destructing with no connkey leaves stdin alone") {
// closeComms() is a no-op without a connkey, so this held even before the
// fix. Here to pin the guard down.
REQUIRE(stdin_survives_destruction(0));
}
}