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