forked from heavyai/heavydb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCommandLineTest.cpp
224 lines (205 loc) · 8.28 KB
/
CommandLineTest.cpp
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
/*
* Copyright 2019 OmniSci, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file CommandLineTest.cpp
* @brief Test suite for executables, scripts, their respecitve flags,
* and other functionality invoked from the command line.
*/
#include <gtest/gtest.h>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <boost/process.hpp>
// boost/process.hpp > ... > boost/asio/detail/socket_types.hpp > winsock2.h > windows.h
#include "Shared/cleanup_global_namespace.h"
#include "Logger/Logger.h"
#include "Shared/SysDefinitions.h"
#include "TestHelpers.h"
namespace bp = boost::process;
namespace bf = boost::filesystem;
using path = bf::path;
namespace {
bool find_file(const path& root, const path& fileName, path& result) {
bool found = false;
const bf::recursive_directory_iterator begin(root), end;
const auto it = std::find_if(begin, end, [&fileName](const bf::directory_entry& e) {
return e.path().filename() == fileName;
});
if (it != end) {
result = it->path();
found = true;
}
return found;
}
} // namespace
// Class to test the initheavy executable.
class InitDBTest : public testing::Test {
private:
path initdb_;
const std::string temp_dir_ = "temp_data";
const std::string nonexistant_dir_ = "temp_data2";
protected:
void SetUp() override {
ASSERT_FALSE(bf::exists(temp_dir_));
ASSERT_FALSE(bf::exists(nonexistant_dir_));
bf::create_directory(temp_dir_);
ASSERT_TRUE(find_file(bf::relative(path("../")), "initheavy", initdb_));
}
void TearDown() override { bf::remove_all(temp_dir_); }
public:
path get_executable() const { return initdb_; }
const std::string get_temp_dir() const { return temp_dir_; }
const std::string get_nonexistant_dir() const { return nonexistant_dir_; }
};
// Contains the a testcase that involves running an executable.
class CommandLineTestcase {
private:
path executable_;
int expected_return_code_;
std::string flags, expected_std_out_, expected_std_err_;
std::string std_out_line_, std_err_line_, std_out_string_ = "", std_err_string_ = "";
bp::ipstream std_out_pipe_, std_err_pipe_;
// Runs the testcase and evalutates return code, stdErr, and stdOut.
void evaluate() {
int returnCode = bp::system(executable_.string() + " " + flags,
bp::std_out > std_out_pipe_,
bp::std_err > std_err_pipe_);
while (std::getline(std_out_pipe_, std_out_line_)) {
std_out_string_ += std_out_line_;
}
while (std::getline(std_err_pipe_, std_err_line_)) {
std_err_string_ += std_err_line_;
}
// Since we are using raw strings, prune out any newlines.
boost::erase_all(expected_std_out_, "\n");
boost::erase_all(expected_std_err_, "\n");
ASSERT_EQ(returnCode, expected_return_code_);
ASSERT_EQ(std_out_string_, expected_std_out_);
ASSERT_EQ(std_err_string_, expected_std_err_);
}
public:
CommandLineTestcase(path e, std::string f, bool rc, std::string so, std::string se)
: executable_(e)
, expected_return_code_(rc)
, flags(f)
, expected_std_out_(so)
, expected_std_err_(se) {
evaluate();
}
};
// No data directory specified.
TEST_F(InitDBTest, NoDataFlag) {
CommandLineTestcase(get_executable(),
"",
1,
"",
"Usage Error: the option '--data' is required but missing");
}
// Help flag.
TEST_F(InitDBTest, Help) {
CommandLineTestcase(get_executable(),
"-h",
0,
R"(Options:
-h [ --help ] Print help messages
--data arg Directory path to OmniSci catalogs
-f [ --force ] Force overwriting of existing OmniSci
instance
--skip-geo Skip inserting sample geo data
--enable-thrift-logs [=arg(=1)] (=0) Enable writing messages directly from
thrift to stdout/stderr.
Logging:
--log-directory arg (="log") Logging directory. May be relative to
data directory, or absolute.
--log-file-name arg (=initheavy.{SEVERITY}.%Y%m%d-%H%M%S.log)
Log file name relative to
log-directory.
--log-symlink arg (=initheavy.{SEVERITY})
Symlink to active log.
--log-severity arg (=INFO) Log to file severity level: INFO
WARNING ERROR FATAL
--log-severity-clog arg (=ERROR) Log to console severity level: INFO
WARNING ERROR FATAL
--log-channels arg Log channel debug info: IR PTX ASM
--log-auto-flush arg (=1) Flush logging buffer to file after each
message.
--log-max-files arg (=100) Maximum number of log files to keep.
--log-min-free-space arg (=20971520) Minimum number of bytes left on device
before oldest log files are deleted.
--log-rotate-daily arg (=1) Start new log files at midnight.
--log-rotation-size arg (=10485760) Maximum file size in bytes before new
log files are started.)",
"");
}
// Base case - empty directory to init.
TEST_F(InitDBTest, EmptyDir) {
CommandLineTestcase(get_executable(), get_temp_dir(), 0, "", "");
}
// Blocked by existing database.
TEST_F(InitDBTest, AlreadyInit) {
CommandLineTestcase(get_executable(), get_temp_dir(), 0, "", "");
CommandLineTestcase(get_executable(),
get_temp_dir(),
1,
"",
"OmniSci catalogs already initialized at " + get_temp_dir() +
". Use -f to force reinitialization.");
}
// Blocked by existing cache.
TEST_F(InitDBTest, ExistingCache) {
boost::filesystem::create_directory(get_temp_dir() + "/" +
shared::kDefaultDiskCacheDirName);
CommandLineTestcase(get_executable(),
get_temp_dir(),
1,
"",
"OmniSci disk cache already exists at " + get_temp_dir() + "/" +
shared::kDefaultDiskCacheDirName +
". Use -f to force reinitialization.");
}
// Override existing database.
TEST_F(InitDBTest, Force) {
CommandLineTestcase(get_executable(), get_temp_dir(), 0, "", "");
CommandLineTestcase(get_executable(), get_temp_dir() + " -f", 0, "", "");
}
// Override existing cache
TEST_F(InitDBTest, ForceCache) {
boost::filesystem::create_directory(get_temp_dir() + "/" +
shared::kDefaultDiskCacheDirName);
boost::filesystem::create_directory(get_temp_dir() + "/" +
shared::kDefaultDiskCacheDirName + "/temp");
CommandLineTestcase(get_executable(), get_temp_dir() + " -f", 0, "", "");
ASSERT_FALSE(boost::filesystem::exists(get_temp_dir() + "/" +
shared::kDefaultDiskCacheDirName + "/temp"));
}
// Data directory does not exist.
TEST_F(InitDBTest, MissingDir) {
CommandLineTestcase(get_executable(),
get_nonexistant_dir(),
1,
"",
"Catalog basepath " + get_nonexistant_dir() + " does not exist.");
}
int main(int argc, char** argv) {
TestHelpers::init_logger_stderr_only(argc, argv);
testing::InitGoogleTest(&argc, argv);
int err{0};
try {
err = RUN_ALL_TESTS();
} catch (const std::exception& e) {
LOG(ERROR) << e.what();
}
return err;
}