xref: /6.6.0/phosphor/tests/module/export_test.cc (revision d92caa4f)
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    {{"arg1", "arg2"}}
31};
32
33class MockTraceContext : public phosphor::TraceContext {
34public:
35    using TraceContext::TraceContext;
36
37    // Expose normally protected method as public for testing.
38    void public_addThreadName(uint64_t id, const std::string& name) {
39        addThreadName(id, name);
40    }
41};
42
43class ExportTest : public testing::Test {
44public:
45    ExportTest() : context(MockTraceContext(make_fixed_buffer(0, 1))) {
46    }
47
48    void fillContextBuffer() {
49        while (!context.getBuffer()->isFull()) {
50            auto* chunk = context.getBuffer()->getChunk();
51            while (!chunk->isFull()) {
52                chunk->addEvent() = phosphor::TraceEvent(
53                        &tpi,
54                        phosphor::TraceEvent::Type::Instant,
55                        0,
56                        {{0, 0}},
57                        {{phosphor::TraceArgument::Type::is_none,
58                                 phosphor::TraceArgument::Type::is_none}});
59            }
60        }
61    }
62
63    void addOneToContextBuffer() {
64        auto* chunk = context.getBuffer()->getChunk();
65        chunk->addEvent() = phosphor::TraceEvent(
66                &tpi,
67                phosphor::TraceEvent::Type::Instant,
68                0,
69                {{0, 0}},
70                {{phosphor::TraceArgument::Type::is_none,
71                         phosphor::TraceArgument::Type::is_none}});
72    }
73
74    void addThreadsToContext(size_t count) {
75        for (size_t i = 0; i < count; ++i) {
76            context.public_addThreadName(i, std::to_string(i));
77        }
78    }
79
80protected:
81    MockTraceContext context;
82};
83
84TEST_F(ExportTest, FullBufferTest) {
85    fillContextBuffer();
86    JSONExport exporter(context);
87    phosphor::StringPtr p;
88    do {
89        p = exporter.read(80);
90        EXPECT_LE(p->size(), 80);
91    } while (p->size());
92    EXPECT_EQ("", *exporter.read(4096));
93}
94
95TEST_F(ExportTest, fulltest) {
96    fillContextBuffer();
97    JSONExport exporter(context);
98    auto p = exporter.read();
99    EXPECT_TRUE(exporter.done());
100    EXPECT_EQ('}', (*p)[p->size() - 2]);
101    EXPECT_EQ('\n', (*p)[p->size() - 1]);
102}
103
104TEST_F(ExportTest, SingleEvent) {
105    addOneToContextBuffer();
106    JSONExport exporter(context);
107    auto p = exporter.read();
108    EXPECT_EQ('}', (*p)[p->size() - 2]);
109    EXPECT_EQ('\n', (*p)[p->size() - 1]);
110    EXPECT_EQ("", *exporter.read(4096));
111}
112
113TEST_F(ExportTest, SingleThreadFullBuffer) {
114    addThreadsToContext(1);
115    fillContextBuffer();
116    JSONExport exporter(context);
117    auto p = exporter.read();
118    EXPECT_EQ('}', (*p)[p->size() - 2]);
119    EXPECT_EQ('\n', (*p)[p->size() - 1]);
120    EXPECT_EQ("", *exporter.read(4096));
121}
122
123TEST_F(ExportTest, LotsOfThreadsFullBuffer) {
124    addThreadsToContext(100);
125    fillContextBuffer();
126    JSONExport exporter(context);
127    auto p = exporter.read();
128    EXPECT_EQ('}', (*p)[p->size() - 2]);
129    EXPECT_EQ('\n', (*p)[p->size() - 1]);
130    EXPECT_EQ("", *exporter.read(4096));
131}
132
133TEST_F(ExportTest, LotsOfThreadsEmptyBuffer) {
134    addThreadsToContext(100);
135    JSONExport exporter(context);
136    auto p = exporter.read();
137    EXPECT_EQ('}', (*p)[p->size() - 2]);
138    EXPECT_EQ('\n', (*p)[p->size() - 1]);
139    EXPECT_EQ("", *exporter.read(4096));
140}
141
142TEST_F(ExportTest, test) {
143    JSONExport exporter(context);
144    phosphor::StringPtr p;
145    do {
146        p = exporter.read(80);
147        EXPECT_LE(p->size(), 80);
148    } while (p->size());
149    EXPECT_EQ("", *exporter.read(4096));
150}
151
152class MockFileStopCallback : public FileStopCallback {
153public:
154    using FileStopCallback::FileStopCallback;
155
156    StringPtr generateFilePathAsPtr() {
157        return FileStopCallback::generateFilePathAsPtr();
158    }
159};
160
161TEST(MockFileStopCallbackTest, valid_name) {
162    MockFileStopCallback callback("test.json");
163    EXPECT_EQ("test.json", *callback.generateFilePathAsPtr());
164
165    callback = MockFileStopCallback("test.%p.json");
166    auto filename_pid_regex = testing::MatchesRegex(
167#if GTEST_USES_POSIX_RE
168        "test.[0-9]+.json");
169#else
170        "test.\\d+.json");
171#endif
172
173    EXPECT_THAT(*callback.generateFilePathAsPtr(), filename_pid_regex);
174
175    callback = MockFileStopCallback("test.%d.json");
176    auto filename_date_regex = testing::MatchesRegex(
177#if GTEST_USES_POSIX_RE
178        "test.[0-9]{4}.[0-9]{2}.[0-9]{2}T[0-9]{2}.[0-9]{2}.[0-9]{2}Z.json");
179#else
180        "test.\\d+.\\d+.\\d+T\\d+.\\d+.\\d+Z.json");
181#endif
182
183    EXPECT_THAT(*callback.generateFilePathAsPtr(), filename_date_regex);
184}
185
186class FileStopCallbackTest : public testing::Test {
187public:
188    FileStopCallbackTest() = default;
189    ~FileStopCallbackTest() {
190        if (filename != "") {
191            std::remove(filename.c_str());
192        }
193    }
194
195protected:
196    std::string filename;
197};
198
199TEST_F(FileStopCallbackTest, test_to_file) {
200    phosphor::TraceLog log;
201    filename = "filecallbacktest.json";
202
203    log.start(phosphor::TraceConfig(phosphor::BufferMode::fixed, 80000)
204                  .setStoppedCallback(
205                      std::make_shared<FileStopCallback>(filename)));
206    while (log.isEnabled()) {
207        log.logEvent(
208            &tpi, phosphor::TraceEvent::Type::Instant, 0, NoneType());
209    }
210}
211
212TEST_F(FileStopCallbackTest, file_open_fail) {
213    phosphor::TraceLog log;
214    filename = "";
215    log.start(phosphor::TraceConfig(phosphor::BufferMode::fixed, 80000)
216                  .setStoppedCallback(
217                      std::make_shared<FileStopCallback>(filename)));
218    EXPECT_THROW(log.stop(), std::runtime_error);
219}
220