Skip to content

Commit 204a637

Browse files
authored
Add more unit tests (LLNL#243)
* Add more tests * Remove replicated code
1 parent 6bbeaf9 commit 204a637

11 files changed

+217
-107
lines changed

src/tools/cali-query/query_common.cpp

+27-72
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include "caliper/common/Log.h"
1414
#include "caliper/common/util/split.hpp"
1515

16+
#include "../../common/util/parse_util.h"
17+
1618
#include "../../services/Services.h"
1719

1820
#include "caliper/ConfigManager.h"
@@ -27,61 +29,14 @@ using namespace util;
2729
namespace
2830
{
2931

30-
inline bool
31-
is_one_of(char c, const char* characters)
32-
{
33-
for (const char* ptr = characters; *ptr != '\0'; ++ptr)
34-
if (*ptr == c)
35-
return true;
36-
37-
return false;
38-
}
39-
40-
/// \brief Read next character, ignoring whitespace
41-
char
42-
parse_char(std::istream& is)
43-
{
44-
char ret = '\0';
45-
46-
do {
47-
ret = is.get();
48-
} while (is.good() && isspace(ret));
49-
50-
return ret;
51-
}
52-
53-
/// \brief Parse text from stream, ignoring whitespace, until one of ",()" are found
54-
std::string
55-
parse_word(std::istream& is)
56-
{
57-
std::string ret;
58-
59-
while (is.good()) {
60-
auto c = is.get();
61-
62-
if (!is.good())
63-
break;
64-
if (isspace(c))
65-
continue;
66-
if (is_one_of(c, ",()\n")) {
67-
is.unget();
68-
break;
69-
}
70-
71-
ret.push_back(c);
72-
}
73-
74-
return ret;
75-
}
76-
7732
/// \brief Parse "(arg1, arg2, ...)" argument list, ignoring whitespace
7833
std::vector<std::string>
7934
parse_arglist(std::istream& is)
8035
{
8136
std::vector<std::string> ret;
8237
std::string word;
8338

84-
char c = parse_char(is);
39+
char c = util::read_char(is);
8540

8641
if (!is.good())
8742
return ret;
@@ -90,10 +45,10 @@ parse_arglist(std::istream& is)
9045
is.unget();
9146
return ret;
9247
}
93-
48+
9449
do {
95-
std::string str = parse_word(is);
96-
c = parse_char(is);
50+
std::string str = util::read_word(is, ",()");
51+
c = util::read_char(is);
9752

9853
if (!str.empty() && (c == ',' || c == ')'))
9954
ret.push_back(str);
@@ -103,20 +58,20 @@ parse_arglist(std::istream& is)
10358
is.unget();
10459
ret.clear();
10560
}
106-
61+
10762
return ret;
10863
}
10964

11065
std::pair< int, std::vector<std::string> >
11166
parse_functioncall(std::istream& is, const QuerySpec::FunctionSignature* defs)
11267
{
11368
// read function name
114-
std::string fname = parse_word(is);
69+
std::string fname = util::read_word(is, ",()");
11570

11671
if (fname.empty())
11772
return std::make_pair(-1, std::vector<std::string>());
11873

119-
// find function among given signatures
74+
// find function among given signatures
12075
int retid = 0;
12176

12277
for ( ; defs && defs[retid].name && (fname != defs[retid].name); ++retid)
@@ -127,7 +82,7 @@ parse_functioncall(std::istream& is, const QuerySpec::FunctionSignature* defs)
12782
return std::make_pair(-1, std::vector<std::string>());
12883
}
12984

130-
// read argument list
85+
// read argument list
13186
std::vector<std::string> args = parse_arglist(is);
13287
int argsize = static_cast<int>(args.size());
13388

@@ -159,7 +114,7 @@ QueryArgsParser::parse_args(const Args& args)
159114

160115
m_error = false;
161116
m_error_msg.clear();
162-
117+
163118
// parse CalQL query (if any)
164119

165120
if (args.is_set("query")) {
@@ -173,23 +128,23 @@ QueryArgsParser::parse_args(const Args& args)
173128
} else
174129
m_spec = p.spec();
175130
}
176-
131+
177132
// setup filter
178133

179134
if (args.is_set("select")) {
180135
m_spec.filter.selection = QuerySpec::FilterSelection::List;
181136
m_spec.filter.list = RecordSelector::parse(args.get("select"));
182137
}
183-
138+
184139
// setup attribute selection
185-
140+
186141
if (args.is_set("attributes")) {
187142
m_spec.attribute_selection.selection = QuerySpec::AttributeSelection::List;
188143
util::split(args.get("attributes"), ',', std::back_inserter(m_spec.attribute_selection.list));
189144
}
190-
145+
191146
// setup aggregation
192-
147+
193148
if (args.is_set("aggregate")) {
194149
// aggregation ops
195150
m_spec.aggregation_ops.selection = QuerySpec::AggregationSelection::Default;
@@ -203,20 +158,20 @@ QueryArgsParser::parse_args(const Args& args)
203158
char c;
204159

205160
const QuerySpec::FunctionSignature* defs = Aggregator::aggregation_defs();
206-
161+
207162
do {
208163
auto fpair = parse_functioncall(is, defs);
209164

210165
if (fpair.first >= 0)
211166
m_spec.aggregation_ops.list.emplace_back(defs[fpair.first], fpair.second);
212167

213-
c = parse_char(is);
168+
c = util::read_char(is);
214169
} while (is.good() && c == ',');
215170
}
216171

217-
// aggregation key
172+
// aggregation key
218173
m_spec.aggregation_key.selection = QuerySpec::AttributeSelection::Default;
219-
174+
220175
if (args.is_set("aggregate-key")) {
221176
std::string keystr = args.get("aggregate-key");
222177

@@ -228,12 +183,12 @@ QueryArgsParser::parse_args(const Args& args)
228183
}
229184
}
230185
}
231-
186+
232187
// setup sort
233-
188+
234189
if (args.is_set("sort")) {
235190
m_spec.sort.selection = QuerySpec::SortSelection::List;
236-
191+
237192
std::vector<std::string> list;
238193
util::split(args.get("sort"), ',', std::back_inserter(list));
239194

@@ -242,9 +197,9 @@ QueryArgsParser::parse_args(const Args& args)
242197
}
243198

244199
// setup formatter
245-
200+
246201
for (const QuerySpec::FunctionSignature* fmtsig = FormatProcessor::formatter_defs(); fmtsig && fmtsig->name; ++fmtsig) {
247-
// see if a formatting option is set
202+
// see if a formatting option is set
248203
if (args.is_set(fmtsig->name)) {
249204
m_spec.format.opt = QuerySpec::FormatSpec::User;
250205
m_spec.format.formatter = *fmtsig;
@@ -263,11 +218,11 @@ QueryArgsParser::parse_args(const Args& args)
263218

264219
return false;
265220
}
266-
221+
267222
break;
268223
}
269224
}
270-
225+
271226
return true;
272227
}
273228

test/ci_app_tests/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,13 @@ set(PYTHON_SCRIPTS
4444
test_aggregate.py
4545
test_basictrace.py
4646
test_c_api.py
47+
test_caliquery.py
4748
test_file_io.py
4849
test_json.py
4950
test_log.py
5051
test_multichannel.py
5152
test_report.py
53+
test_textlog.py
5254
test_thread.py
5355
test_validator.py
5456
calipertest.py)

test/ci_app_tests/calipertest.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,13 @@ def run_test_with_query(target_cmd, query_cmd, env):
7373
def run_test(target_cmd, env):
7474
""" Execute a command, and return its output """
7575

76-
target_proc = subprocess.Popen(target_cmd, env=env, stdout=subprocess.PIPE)
76+
target_proc = subprocess.Popen(target_cmd, env=env, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
7777
proc_out, proc_err = target_proc.communicate()
7878

7979
if (target_proc.returncode != 0):
8080
raise CaliperExecError('Command ' + str(target_cmd) + ' exited with ' + str(target_proc.returncode))
8181

82-
return proc_out
82+
return (proc_out,proc_err)
8383

8484

8585
def get_snapshots_from_text(query_output):

test/ci_app_tests/test_basictrace.py

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Basic smoke tests: create and read a simple trace
1+
# Basic smoke tests: create and read a simple trace, test various options
22

33
import json
44
import unittest
@@ -72,7 +72,7 @@ def test_default_scope_switch(self):
7272
snapshots, { 'cali.attribute.name': 'iteration',
7373
'cali.attribute.prop': '13' # CALI_ATTR_SCOPE_PROCESS | CALI_ATTR_ASVALUE
7474
}))
75-
75+
7676
def test_sec_unit_selection(self):
7777
target_cmd = [ './ci_test_basic' ]
7878
query_cmd = [ '../../src/tools/cali-query/cali-query', '--list-attributes', '-e', '--print-attributes', 'cali.attribute.name,time.unit' ]
@@ -139,7 +139,6 @@ def test_largetrace(self):
139139

140140
self.assertTrue(cat.has_snapshot_with_attributes(
141141
snapshots, { 'function' : 'main/foo', 'event.end#loop': 'fooloop', 'count' : '400' }))
142-
143142

144143
def test_globals(self):
145144
target_cmd = [ './ci_test_basic' ]
@@ -158,7 +157,7 @@ def test_globals(self):
158157

159158
self.assertTrue(cat.has_snapshot_with_keys(
160159
snapshots, { 'cali.caliper.version' } ) )
161-
160+
162161
def test_esc(self):
163162
target_cmd = [ './ci_test_basic' ]
164163
query_cmd = [ '../../src/tools/cali-query/cali-query', '-j', '-s', 'cali.event.set' ]
@@ -172,7 +171,6 @@ def test_esc(self):
172171
obj = json.loads( cat.run_test_with_query(target_cmd, query_cmd, caliper_config) )
173172

174173
self.assertEqual(obj[0]['event.set# =\\weird ""attribute"= '], ' \\\\ weird," name",' )
175-
176174

177175
def test_macros(self):
178176
# Use ConfigManager API here
@@ -203,7 +201,7 @@ def test_macros(self):
203201
'function' : 'main/foo',
204202
'loop' : 'mainloop/fooloop',
205203
'iteration#fooloop' : '3' }))
206-
204+
207205
def test_property_override(self):
208206
target_cmd = [ './ci_test_macros' ]
209207
query_cmd = [ '../../src/tools/cali-query/cali-query', '-e', '--list-attributes' ]
@@ -263,7 +261,7 @@ def test_binding(self):
263261
snapshots = cat.get_snapshots_from_text(query_output)
264262

265263
self.assertTrue(cat.has_snapshot_with_attributes(
266-
snapshots, { 'testbinding' : 'binding.nested=outer/binding.nested=inner' }))
264+
snapshots, { 'testbinding' : 'binding.nested=outer/binding.nested=inner' }))
267265

268266
if __name__ == "__main__":
269267
unittest.main()

test/ci_app_tests/test_caliquery.py

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Some tests for the cali-query tool
2+
3+
import json
4+
import unittest
5+
6+
import calipertest as cat
7+
8+
class CaliperCaliQueryTest(unittest.TestCase):
9+
""" cali-query test cases """
10+
11+
def test_caliquery_args(self):
12+
target_cmd = [ './ci_test_aggregate' ]
13+
query_cmd = [ '../../src/tools/cali-query/cali-query', '-a', 'count(),sum(time.inclusive.duration)', '--aggregate-key=loop.id', '-s', 'loop.id=A', '--json' ]
14+
15+
caliper_config = {
16+
'CALI_CONFIG_PROFILE' : 'serial-trace',
17+
'CALI_RECORDER_FILENAME' : 'stdout',
18+
'CALI_LOG_VERBOSITY' : '0',
19+
}
20+
21+
obj = json.loads( cat.run_test_with_query(target_cmd, query_cmd, caliper_config) )
22+
23+
self.assertEqual(obj[0]["path"], "A")
24+
self.assertEqual(obj[0]["count"], 16)
25+
self.assertTrue("sum#time.inclusive.duration" in obj[0])
26+
27+
def test_caliquery_list_services(self):
28+
target_cmd = [ '../../src/tools/cali-query/cali-query', '--help=services' ]
29+
30+
env = {
31+
'CALI_LOG_VERBOSITY' : '0',
32+
}
33+
34+
service_targets = [
35+
'aggregate', 'event', 'recorder', 'report', 'timestamp', 'trace'
36+
]
37+
38+
_,report_err = cat.run_test(target_cmd, env)
39+
res = report_err.decode().split(',')
40+
41+
for target in service_targets:
42+
if not target in res:
43+
self.fail('%s not found in log' % target)
44+
45+
46+
if __name__ == "__main__":
47+
unittest.main()

test/ci_app_tests/test_ioservice.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def test_hatchet_profile_ioservice(self):
6262
'CALI_LOG_VERBOSITY' : '0'
6363
}
6464

65-
obj = json.loads( cat.run_test(target_cmd, caliper_config) )
65+
obj = json.loads( cat.run_test(target_cmd, caliper_config)[0] )
6666

6767
self.assertEqual(obj[1]['path'], 'main')
6868
self.assertEqual(int(obj[1]['Bytes read']), 16)

test/ci_app_tests/test_json.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def test_hatchetcontroller(self):
113113
'CALI_LOG_VERBOSITY' : '0'
114114
}
115115

116-
obj = json.loads( cat.run_test(target_cmd, caliper_config) )
116+
obj = json.loads( cat.run_test(target_cmd, caliper_config)[0] )
117117

118118
self.assertTrue( { 'data', 'columns', 'column_metadata', 'nodes' }.issubset(set(obj.keys())) )
119119

0 commit comments

Comments
 (0)