aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp
diff options
context:
space:
mode:
authorgalaxycrab <UgnineSirdis@ydb.tech>2023-08-04 13:13:41 +0300
committergalaxycrab <UgnineSirdis@ydb.tech>2023-08-04 14:42:46 +0300
commit0378da6ac1a3be2823cd3031fbf0ae403d962995 (patch)
treebb4a84db2196119cf270670b446c875e7a4d0e50 /library/cpp
parentcf273f7a9b5bb6d23c1f3c8ab236a4af1f511724 (diff)
downloadydb-0378da6ac1a3be2823cd3031fbf0ae403d962995.tar.gz
KIKIMR-18702 JUnit tests. Save captured test output even when abort happened
Diffstat (limited to 'library/cpp')
-rw-r--r--library/cpp/testing/unittest/junit.cpp69
-rw-r--r--library/cpp/testing/unittest/junit.h29
2 files changed, 97 insertions, 1 deletions
diff --git a/library/cpp/testing/unittest/junit.cpp b/library/cpp/testing/unittest/junit.cpp
index 6d80a204ff..44771ecd14 100644
--- a/library/cpp/testing/unittest/junit.cpp
+++ b/library/cpp/testing/unittest/junit.cpp
@@ -8,6 +8,7 @@
#include <util/generic/size_literals.h>
#include <util/stream/file.h>
#include <util/stream/input.h>
+#include <util/system/backtrace.h>
#include <util/system/env.h>
#include <util/system/file.h>
#include <util/system/fs.h>
@@ -16,6 +17,7 @@
#include <util/system/tempfile.h>
#include <stdio.h>
+#include <signal.h>
#if defined(_win_)
#include <io.h>
@@ -186,7 +188,8 @@ TJUnitProcessor::~TJUnitProcessor() {
}
void TJUnitProcessor::OnBeforeTest(const TTest* test) {
- Y_UNUSED(test);
+ CurrentTest.emplace(test);
+ CaptureSignal(this);
if (!GetForkTests() || GetIsForked()) {
StdErrCapturer = MakeHolder<TOutputCapturer>(TOutputCapturer::STDERR_FD);
StdOutCapturer = MakeHolder<TOutputCapturer>(TOutputCapturer::STDOUT_FD);
@@ -228,6 +231,7 @@ void TJUnitProcessor::OnFinish(const TFinish* descr) {
} else {
MergeSubprocessReport();
}
+ UncaptureSignal();
}
TString TJUnitProcessor::BuildFileName(size_t index, const TStringBuf extension) const {
@@ -296,6 +300,69 @@ void TJUnitProcessor::MakeTmpFileNameForForkedTests() {
}
}
+static TJUnitProcessor* CurrentJUnitProcessor = nullptr;
+
+void TJUnitProcessor::CaptureSignal(TJUnitProcessor* processor) {
+ CurrentJUnitProcessor = processor;
+ processor->PrevAbortHandler = signal(SIGABRT, &TJUnitProcessor::SignalHandler);
+ if (processor->PrevAbortHandler == SIG_ERR) {
+ processor->PrevAbortHandler = nullptr;
+ }
+ processor->PrevSegvHandler = signal(SIGSEGV, &TJUnitProcessor::SignalHandler);
+ if (processor->PrevSegvHandler == SIG_ERR) {
+ processor->PrevSegvHandler = nullptr;
+ }
+}
+
+void TJUnitProcessor::UncaptureSignal() {
+ if (CurrentJUnitProcessor) {
+ if (CurrentJUnitProcessor->PrevAbortHandler != nullptr) {
+ signal(SIGABRT, CurrentJUnitProcessor->PrevAbortHandler);
+ } else {
+ signal(SIGABRT, SIG_DFL);
+ }
+
+ if (CurrentJUnitProcessor->PrevSegvHandler != nullptr) {
+ signal(SIGSEGV, CurrentJUnitProcessor->PrevSegvHandler);
+ } else {
+ signal(SIGSEGV, SIG_DFL);
+ }
+ }
+}
+
+void TJUnitProcessor::SignalHandler(int signal) {
+ if (CurrentJUnitProcessor) {
+ if (CurrentJUnitProcessor->CurrentTest) {
+ TError errDesc;
+ errDesc.test = *CurrentJUnitProcessor->CurrentTest;
+ if (signal == SIGABRT) {
+ errDesc.msg = "Test aborted";
+ } else {
+ errDesc.msg = "Segmentation fault";
+ PrintBackTrace();
+ }
+ CurrentJUnitProcessor->OnError(&errDesc);
+
+ TFinish finishDesc;
+ finishDesc.Success = false;
+ finishDesc.test = *CurrentJUnitProcessor->CurrentTest;
+ CurrentJUnitProcessor->OnFinish(&finishDesc);
+ }
+
+ CurrentJUnitProcessor->Save();
+
+ if (signal == SIGABRT) {
+ if (CurrentJUnitProcessor->PrevAbortHandler) {
+ CurrentJUnitProcessor->PrevAbortHandler(signal);
+ }
+ } else {
+ if (CurrentJUnitProcessor->PrevSegvHandler) {
+ CurrentJUnitProcessor->PrevSegvHandler(signal);
+ }
+ }
+ }
+}
+
#define CHECK_CALL(expr) if (int resultCode = (expr); resultCode < 0) { \
Cerr << "Faield to write to xml. Result code: " << resultCode << Endl; \
return; \
diff --git a/library/cpp/testing/unittest/junit.h b/library/cpp/testing/unittest/junit.h
index 1797055877..27b73013ca 100644
--- a/library/cpp/testing/unittest/junit.h
+++ b/library/cpp/testing/unittest/junit.h
@@ -4,6 +4,8 @@
#include <util/generic/maybe.h>
#include <util/system/tempfile.h>
+#include <optional>
+
namespace NUnitTest {
extern const TString Y_UNITTEST_OUTPUT_CMDLINE_OPTION;
@@ -52,6 +54,26 @@ class TJUnitProcessor : public ITestSuiteProcessor {
}
};
+ // Holds a copy of TTest structure for current test
+ class TCurrentTest {
+ public:
+ TCurrentTest(const TTest* test)
+ : TestName(test->name)
+ , Unit(*test->unit)
+ , Test{&Unit, TestName.c_str()}
+ {
+ }
+
+ operator const TTest*() const {
+ return &Test;
+ }
+
+ private:
+ TString TestName;
+ TUnit Unit;
+ TTest Test;
+ };
+
struct TOutputCapturer;
public:
@@ -96,6 +118,10 @@ private:
void MakeTmpFileNameForForkedTests();
static void TransferFromCapturer(THolder<TJUnitProcessor::TOutputCapturer>& capturer, TString& out, IOutputStream& outStream);
+ static void CaptureSignal(TJUnitProcessor* processor);
+ static void UncaptureSignal();
+ static void SignalHandler(int signal);
+
private:
const TString FileName; // cmd line param
const TString ExecName; // cmd line param
@@ -105,6 +131,9 @@ private:
THolder<TOutputCapturer> StdErrCapturer;
THolder<TOutputCapturer> StdOutCapturer;
TInstant StartCurrentTestTime;
+ void (*PrevAbortHandler)(int) = nullptr;
+ void (*PrevSegvHandler)(int) = nullptr;
+ std::optional<TCurrentTest> CurrentTest;
};
} // namespace NUnitTest