xref: /6.6.0/phosphor/tests/module/export_test.cc (revision c687f338)
1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2016 Couchbase, Inc
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17
18#include <gmock/gmock.h>
19#include <gtest/gtest.h>
20
21#include "phosphor/tools/export.h"
22
23using phosphor::tools::JSONExport;
24using phosphor::tools::FileStopCallback;
25using namespace phosphor;
26
27tracepoint_info tpi = {
28    "category",
29    "name",
30    TraceEvent::Type::Instant,
31    {{"arg1", "arg2"}},
32    {{TraceArgument::Type::is_none, TraceArgument::Type::is_none}}
33};
34
35class MockTraceContext : public phosphor::TraceContext {
36public:
37    using TraceContext::TraceContext;
38
39    // Expose normally protected method as public for testing.
40    void public_addThreadName(uint64_t id, const std::string& name) {
41        addThreadName(id, name);
42    }
43};
44
45class ExportTest : public testing::Test {
46public:
47    ExportTest() : context(MockTraceContext(make_fixed_buffer(0, 1))) {
48    }
49
50    void fillContextBuffer() {
51        while (!context.getBuffer()->isFull()) {
52            auto* chunk = context.getBuffer()->getChunk();
53            while (!chunk->isFull()) {
54                chunk->addEvent() = phosphor::TraceEvent(
55                        &tpi,
56                        {{0, 0}});
57            }
58        }
59    }
60
61    void addOneToContextBuffer() {
62        auto* chunk = context.getBuffer()->getChunk();
63        chunk->addEvent() = phosphor::TraceEvent(
64                &tpi,
65                {{0, 0}});
66    }
67
68    void addThreadsToContext(size_t count) {
69        for (size_t i = 0; i < count; ++i) {
70            context.public_addThreadName(i, std::to_string(i));
71        }
72    }
73
74protected:
75    MockTraceContext context;
76};
77
78TEST_F(ExportTest, FullBufferTest) {
79    fillContextBuffer();
80    JSONExport exporter(context);
81    phosphor::StringPtr p;
82    do {
83        p = exporter.read(80);
84        EXPECT_LE(p->size(), 80);
85    } while (p->size());
86    EXPECT_EQ("", *exporter.read(4096));
87}
88
89TEST_F(ExportTest, fulltest) {
90    fillContextBuffer();
91    JSONExport exporter(context);
92    auto p = exporter.read();
93    EXPECT_TRUE(exporter.done());
94    EXPECT_EQ('}', (*p)[p->size() - 2]);
95    EXPECT_EQ('\n', (*p)[p->size() - 1]);
96}
97
98TEST_F(ExportTest, SingleEvent) {
99    addOneToContextBuffer();
100    JSONExport exporter(context);
101    auto p = exporter.read();
102    EXPECT_EQ('}', (*p)[p->size() - 2]);
103    EXPECT_EQ('\n', (*p)[p->size() - 1]);
104    EXPECT_EQ("", *exporter.read(4096));
105}
106
107TEST_F(ExportTest, SingleThreadFullBuffer) {
108    addThreadsToContext(1);
109    fillContextBuffer();
110    JSONExport exporter(context);
111    auto p = exporter.read();
112    EXPECT_EQ('}', (*p)[p->size() - 2]);
113    EXPECT_EQ('\n', (*p)[p->size() - 1]);
114    EXPECT_EQ("", *exporter.read(4096));
115}
116
117TEST_F(ExportTest, LotsOfThreadsFullBuffer) {
118    addThreadsToContext(100);
119    fillContextBuffer();
120    JSONExport exporter(context);
121    auto p = exporter.read();
122    EXPECT_EQ('}', (*p)[p->size() - 2]);
123    EXPECT_EQ('\n', (*p)[p->size() - 1]);
124    EXPECT_EQ("", *exporter.read(4096));
125}
126
127TEST_F(ExportTest, LotsOfThreadsEmptyBuffer) {
128    addThreadsToContext(100);
129    JSONExport exporter(context);
130    auto p = exporter.read();
131    EXPECT_EQ('}', (*p)[p->size() - 2]);
132    EXPECT_EQ('\n', (*p)[p->size() - 1]);
133    EXPECT_EQ("", *exporter.read(4096));
134}
135
136TEST_F(ExportTest, test) {
137    JSONExport exporter(context);
138    phosphor::StringPtr p;
139    do {
140        p = exporter.read(80);
141        EXPECT_LE(p->size(), 80);
142    } while (p->size());
143    EXPECT_EQ("", *exporter.read(4096));
144}
145
146class MockFileStopCallback : public FileStopCallback {
147public:
148    using FileStopCallback::FileStopCallback;
149
150    StringPtr generateFilePathAsPtr() {
151        return FileStopCallback::generateFilePathAsPtr();
152    }
153};
154
155TEST(MockFileStopCallbackTest, valid_name) {
156    MockFileStopCallback callback("test.json");
157    EXPECT_EQ("test.json", *callback.generateFilePathAsPtr());
158
159    callback = MockFileStopCallback("test.%p.json");
160    auto filename_pid_regex = testing::MatchesRegex(
161#if GTEST_USES_POSIX_RE
162        "test.[0-9]+.json");
163#else
164        "test.\\d+.json");
165#endif
166
167    EXPECT_THAT(*callback.generateFilePathAsPtr(), filename_pid_regex);
168
169    callback = MockFileStopCallback("test.%d.json");
170    auto filename_date_regex = testing::MatchesRegex(
171#if GTEST_USES_POSIX_RE
172        "test.[0-9]{4}.[0-9]{2}.[0-9]{2}T[0-9]{2}.[0-9]{2}.[0-9]{2}Z.json");
173#else
174        "test.\\d+.\\d+.\\d+T\\d+.\\d+.\\d+Z.json");
175#endif
176
177    EXPECT_THAT(*callback.generateFilePathAsPtr(), filename_date_regex);
178}
179
180class FileStopCallbackTest : public testing::Test {
181public:
182    FileStopCallbackTest() = default;
183    ~FileStopCallbackTest() {
184        if (filename != "") {
185            std::remove(filename.c_str());
186        }
187    }
188
189protected:
190    std::string filename;
191};
192
193TEST_F(FileStopCallbackTest, test_to_file) {
194    phosphor::TraceLog log;
195    filename = "filecallbacktest.json";
196
197    log.start(phosphor::TraceConfig(phosphor::BufferMode::fixed, 80000)
198                  .setStoppedCallback(
199                      std::make_shared<FileStopCallback>(filename)));
200    while (log.isEnabled()) {
201        log.logEvent(
202            &tpi, 0, NoneType());
203    }
204}
205
206TEST_F(FileStopCallbackTest, file_open_fail) {
207    phosphor::TraceLog log;
208    filename = "";
209    log.start(phosphor::TraceConfig(phosphor::BufferMode::fixed, 80000)
210                  .setStoppedCallback(
211                      std::make_shared<FileStopCallback>(filename)));
212    EXPECT_THROW(log.stop(), std::runtime_error);
213}
214