1 #include <systemd_target_parser.hpp>
2
3 #include <cstdio>
4 #include <cstdlib>
5 #include <filesystem>
6 #include <iostream>
7
8 #include <gtest/gtest.h>
9
10 namespace fs = std::filesystem;
11
12 // Enable debug by default for debug when needed
13 bool gVerbose = true;
14
TEST(TargetJsonParser,BasicGoodPath)15 TEST(TargetJsonParser, BasicGoodPath)
16 {
17 auto defaultData1 = R"(
18 {
19 "targets" : {
20 "multi-user.target" : {
21 "errorsToMonitor": ["default"],
22 "errorToLog": "xyz.openbmc_project.State.BMC.Error.MultiUserTargetFailure"},
23 "obmc-chassis-poweron@0.target" : {
24 "errorsToMonitor": ["timeout", "failed"],
25 "errorToLog": "xyz.openbmc_project.State.Chassis.Error.PowerOnTargetFailure"}
26 }
27 }
28 )"_json;
29
30 auto defaultData2 = R"(
31 {
32 "targets" : {
33 "obmc-host-start@0.target" : {
34 "errorsToMonitor": ["default"],
35 "errorToLog": "xyz.openbmc_project.State.Host.Error.HostStartFailure"},
36 "obmc-host-stop@0.target" : {
37 "errorsToMonitor": ["dependency"],
38 "errorToLog": "xyz.openbmc_project.State.Host.Error.HostStopFailure"}
39 }
40 }
41 )"_json;
42
43 std::FILE* tmpf = fopen("/tmp/good_file1.json", "w");
44 std::fputs(defaultData1.dump().c_str(), tmpf);
45 std::fclose(tmpf);
46
47 tmpf = fopen("/tmp/good_file2.json", "w");
48 std::fputs(defaultData2.dump().c_str(), tmpf);
49 std::fclose(tmpf);
50
51 std::vector<std::string> filePaths;
52 filePaths.emplace_back("/tmp/good_file1.json");
53 filePaths.emplace_back("/tmp/good_file2.json");
54
55 TargetErrorData targetData = parseFiles(filePaths);
56
57 EXPECT_EQ(targetData.size(), 4);
58 EXPECT_NE(targetData.find("multi-user.target"), targetData.end());
59 EXPECT_NE(targetData.find("obmc-chassis-poweron@0.target"),
60 targetData.end());
61 EXPECT_NE(targetData.find("obmc-host-start@0.target"), targetData.end());
62 EXPECT_NE(targetData.find("obmc-host-stop@0.target"), targetData.end());
63 targetEntry tgt = targetData["obmc-chassis-poweron@0.target"];
64 EXPECT_EQ(tgt.errorToLog,
65 "xyz.openbmc_project.State.Chassis.Error.PowerOnTargetFailure");
66 EXPECT_EQ(tgt.errorsToMonitor.size(), 2);
67 // Check a target with "default" for errorsToMonitor, should have 3 defaults
68 tgt = targetData["obmc-host-start@0.target"];
69 EXPECT_EQ(tgt.errorsToMonitor.size(), 3);
70
71 std::remove("/tmp/good_file1.json");
72 std::remove("/tmp/good_file2.json");
73 }
74
TEST(TargetJsonParser,InvalidErrorToMonitor)75 TEST(TargetJsonParser, InvalidErrorToMonitor)
76 {
77 auto invalidDataError = R"(
78 {
79 "targets" : {
80 "obmc-chassis-poweron@0.target" : {
81 "errorsToMonitor": ["timeout", "invalid"],
82 "errorToLog": "xyz.openbmc_project.State.Chassis.Error.PowerOnTargetFailure"}
83 }
84 }
85 )"_json;
86
87 std::FILE* tmpf = fopen("/tmp/invalid_error_file.json", "w");
88 std::fputs(invalidDataError.dump().c_str(), tmpf);
89 std::fclose(tmpf);
90
91 std::vector<std::string> filePaths;
92 filePaths.emplace_back("/tmp/invalid_error_file.json");
93
94 // Verify exception thrown on invalid errorsToMonitor
95 EXPECT_THROW(TargetErrorData targetData = parseFiles(filePaths),
96 std::out_of_range);
97 std::remove("/tmp/invalid_error_file.json");
98 }
99
TEST(TargetJsonParser,InvalidFileFormat)100 TEST(TargetJsonParser, InvalidFileFormat)
101 {
102 std::FILE* tmpf = fopen("/tmp/invalid_json_file.json", "w");
103 std::fputs(R"({"targets":{"missing closing quote}})", tmpf);
104 fclose(tmpf);
105
106 std::vector<std::string> filePaths;
107 filePaths.emplace_back("/tmp/invalid_json_file.json");
108
109 // Verify exception thrown on invalid json file format
110 EXPECT_THROW(TargetErrorData targetData = parseFiles(filePaths),
111 nlohmann::detail::parse_error);
112 std::remove("/tmp/invalid_json_file.json");
113 }
114
TEST(TargetJsonParser,NotJustDefault)115 TEST(TargetJsonParser, NotJustDefault)
116 {
117 auto notJustDefault = R"(
118 {
119 "targets" : {
120 "obmc-chassis-poweron@0.target" : {
121 "errorsToMonitor": ["timeout", "default"],
122 "errorToLog": "xyz.openbmc_project.State.Chassis.Error.PowerOnTargetFailure"}
123 }
124 }
125 )"_json;
126
127 std::FILE* tmpf = fopen("/tmp/not_just_default_file.json", "w");
128 std::fputs(notJustDefault.dump().c_str(), tmpf);
129 std::fclose(tmpf);
130
131 std::vector<std::string> filePaths;
132 filePaths.emplace_back("/tmp/not_just_default_file.json");
133
134 // Verify exception thrown on invalid errorsToMonitor
135 EXPECT_THROW(TargetErrorData targetData = parseFiles(filePaths),
136 std::invalid_argument);
137 std::remove("/tmp/not_just_default_file.json");
138 }
139