xref: /openbmc/bmcweb/test/redfish-core/include/utils/time_utils_test.cpp (revision 40e9b92ec19acffb46f83a6e55b18974da5d708e)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 #include "utils/time_utils.hpp"
4 
5 #include <chrono>
6 #include <cstdint>
7 #include <ctime>
8 #include <limits>
9 #include <optional>
10 #include <version>
11 
12 #include <gtest/gtest.h>
13 
14 namespace redfish::time_utils
15 {
16 namespace
17 {
18 
TEST(FromDurationTest,PositiveTests)19 TEST(FromDurationTest, PositiveTests)
20 {
21     EXPECT_EQ(fromDurationString("PT12S"), std::chrono::milliseconds(12000));
22     EXPECT_EQ(fromDurationString("PT0.204S"), std::chrono::milliseconds(204));
23     EXPECT_EQ(fromDurationString("PT0.2S"), std::chrono::milliseconds(200));
24     EXPECT_EQ(fromDurationString("PT50M"), std::chrono::milliseconds(3000000));
25     EXPECT_EQ(fromDurationString("PT23H"), std::chrono::milliseconds(82800000));
26     EXPECT_EQ(fromDurationString("P51D"),
27               std::chrono::milliseconds(4406400000));
28     EXPECT_EQ(fromDurationString("PT2H40M10.1S"),
29               std::chrono::milliseconds(9610100));
30     EXPECT_EQ(fromDurationString("P20DT2H40M10.1S"),
31               std::chrono::milliseconds(1737610100));
32     EXPECT_EQ(fromDurationString(""), std::chrono::milliseconds(0));
33 }
34 
TEST(FromDurationTest,NegativeTests)35 TEST(FromDurationTest, NegativeTests)
36 {
37     EXPECT_EQ(fromDurationString("PTS"), std::nullopt);
38     EXPECT_EQ(fromDurationString("P1T"), std::nullopt);
39     EXPECT_EQ(fromDurationString("PT100M1000S100"), std::nullopt);
40     EXPECT_EQ(fromDurationString("PDTHMS"), std::nullopt);
41     EXPECT_EQ(fromDurationString("P9999999999999999999999999DT"), std::nullopt);
42     EXPECT_EQ(fromDurationString("PD222T222H222M222.222S"), std::nullopt);
43     EXPECT_EQ(fromDurationString("PT99999H9999999999999999999999M99999999999S"),
44               std::nullopt);
45     EXPECT_EQ(fromDurationString("PT-9H"), std::nullopt);
46 }
TEST(ToDurationTest,PositiveTests)47 TEST(ToDurationTest, PositiveTests)
48 {
49     EXPECT_EQ(toDurationString(std::chrono::milliseconds(12000)), "PT12.000S");
50     EXPECT_EQ(toDurationString(std::chrono::milliseconds(204)), "PT0.204S");
51     EXPECT_EQ(toDurationString(std::chrono::milliseconds(200)), "PT0.200S");
52     EXPECT_EQ(toDurationString(std::chrono::milliseconds(3000000)), "PT50M");
53     EXPECT_EQ(toDurationString(std::chrono::milliseconds(82800000)), "PT23H");
54     EXPECT_EQ(toDurationString(std::chrono::milliseconds(4406400000)), "P51DT");
55     EXPECT_EQ(toDurationString(std::chrono::milliseconds(9610100)),
56               "PT2H40M10.100S");
57     EXPECT_EQ(toDurationString(std::chrono::milliseconds(1737610100)),
58               "P20DT2H40M10.100S");
59 }
60 
TEST(ToDurationTest,NegativeTests)61 TEST(ToDurationTest, NegativeTests)
62 {
63     EXPECT_EQ(toDurationString(std::chrono::milliseconds(-250)), "");
64 }
65 
TEST(ToDurationStringFromUintTest,PositiveTests)66 TEST(ToDurationStringFromUintTest, PositiveTests)
67 {
68     uint64_t maxAcceptedTimeMs =
69         static_cast<uint64_t>(std::chrono::milliseconds::max().count());
70 
71     EXPECT_NE(toDurationStringFromUint(maxAcceptedTimeMs), std::nullopt);
72     EXPECT_EQ(toDurationStringFromUint(0), "PT");
73     EXPECT_EQ(toDurationStringFromUint(250), "PT0.250S");
74     EXPECT_EQ(toDurationStringFromUint(5000), "PT5.000S");
75 }
76 
TEST(ToDurationStringFromUintTest,NegativeTests)77 TEST(ToDurationStringFromUintTest, NegativeTests)
78 {
79     uint64_t minNotAcceptedTimeMs =
80         static_cast<uint64_t>(std::chrono::milliseconds::max().count()) + 1;
81 
82     EXPECT_EQ(toDurationStringFromUint(minNotAcceptedTimeMs), std::nullopt);
83     EXPECT_EQ(toDurationStringFromUint(static_cast<uint64_t>(-1)),
84               std::nullopt);
85 }
86 
TEST(GetDateTimeStdtime,ConversionTests)87 TEST(GetDateTimeStdtime, ConversionTests)
88 {
89     // some time before the epoch
90     EXPECT_EQ(getDateTimeStdtime(std::time_t{-1234567}),
91               "1970-01-01T00:00:00+00:00");
92 
93     // epoch
94     EXPECT_EQ(getDateTimeStdtime(std::time_t{0}), "1970-01-01T00:00:00+00:00");
95 
96     // Limits
97     EXPECT_EQ(getDateTimeStdtime(std::numeric_limits<std::time_t>::max()),
98               "9999-12-31T23:59:59+00:00");
99     EXPECT_EQ(getDateTimeStdtime(std::numeric_limits<std::time_t>::min()),
100               "1970-01-01T00:00:00+00:00");
101 }
102 
TEST(GetDateTimeUint,ConversionTests)103 TEST(GetDateTimeUint, ConversionTests)
104 {
105     EXPECT_EQ(getDateTimeUint(uint64_t{1638312095}),
106               "2021-11-30T22:41:35+00:00");
107     // some time in the future, beyond 2038
108     EXPECT_EQ(getDateTimeUint(uint64_t{41638312095}),
109               "3289-06-18T21:48:15+00:00");
110     // the maximum time we support
111     EXPECT_EQ(getDateTimeUint(uint64_t{253402300799}),
112               "9999-12-31T23:59:59+00:00");
113 
114     // returns the maximum Redfish date
115     EXPECT_EQ(getDateTimeUint(std::numeric_limits<uint64_t>::max()),
116               "9999-12-31T23:59:59+00:00");
117 
118     EXPECT_EQ(getDateTimeUint(std::numeric_limits<uint64_t>::min()),
119               "1970-01-01T00:00:00+00:00");
120 }
121 
TEST(GetDateTimeUintMs,ConverstionTests)122 TEST(GetDateTimeUintMs, ConverstionTests)
123 {
124     EXPECT_EQ(getDateTimeUintMs(uint64_t{1638312095123}),
125               "2021-11-30T22:41:35.123+00:00");
126     // returns the maximum Redfish date
127     EXPECT_EQ(getDateTimeUintMs(std::numeric_limits<uint64_t>::max()),
128               "9999-12-31T23:59:59.999+00:00");
129     EXPECT_EQ(getDateTimeUintMs(std::numeric_limits<uint64_t>::min()),
130               "1970-01-01T00:00:00.000+00:00");
131 }
132 
TEST(Utility,GetDateTimeUintUs)133 TEST(Utility, GetDateTimeUintUs)
134 {
135     EXPECT_EQ(getDateTimeUintUs(uint64_t{1638312095123456}),
136               "2021-11-30T22:41:35.123456+00:00");
137     // returns the maximum Redfish date
138     EXPECT_EQ(getDateTimeUintUs(std::numeric_limits<uint64_t>::max()),
139               "9999-12-31T23:59:59.999999+00:00");
140     EXPECT_EQ(getDateTimeUintUs(std::numeric_limits<uint64_t>::min()),
141               "1970-01-01T00:00:00.000000+00:00");
142 }
143 
TEST(Utility,DateStringToEpoch)144 TEST(Utility, DateStringToEpoch)
145 {
146     EXPECT_EQ(dateStringToEpoch("2021-11-30T22:41:35.123456+00:00"),
147               usSinceEpoch{1638312095123456});
148     // no timezone
149     EXPECT_EQ(dateStringToEpoch("2021-11-30T22:41:35.123456"),
150               usSinceEpoch{1638312095123456});
151     // Milliseconds precision
152     EXPECT_EQ(dateStringToEpoch("2021-11-30T22:41:35.123"),
153               usSinceEpoch{1638312095123000});
154     // Seconds precision
155     EXPECT_EQ(dateStringToEpoch("2021-11-30T22:41:35"),
156               usSinceEpoch{1638312095000000});
157 
158     // valid datetime format
159     EXPECT_EQ(dateStringToEpoch("20230531T000000Z"),
160               usSinceEpoch{1685491200000000});
161 
162     // valid datetime format
163     EXPECT_EQ(dateStringToEpoch("20230531"), usSinceEpoch{1685491200000000});
164 
165     // Non zero timezone
166     EXPECT_EQ(dateStringToEpoch("2021-11-30T22:41:35.123456+04:00"),
167               usSinceEpoch{1638297695123456});
168 
169     // Epoch
170     EXPECT_EQ(dateStringToEpoch("1970-01-01T00:00:00.000000+00:00"),
171               usSinceEpoch{0});
172 
173     // Max time
174     EXPECT_EQ(dateStringToEpoch("9999-12-31T23:59:59.999999+00:00"),
175               usSinceEpoch{253402300799999999});
176 
177     // Underflow
178     EXPECT_EQ(dateStringToEpoch("1969-12-30T23:59:59.999999+00:00"),
179               std::nullopt);
180 }
181 
TEST(Utility,DateStringToEpochWithInvalidDateTimeFormats)182 TEST(Utility, DateStringToEpochWithInvalidDateTimeFormats)
183 {
184     // invalid month (13)
185     EXPECT_EQ(dateStringToEpoch("2024-13-01T12:00:00Z"), std::nullopt);
186 
187     // invalid character for month
188     EXPECT_EQ(dateStringToEpoch("2024-X-01T12:00:00Z"), std::nullopt);
189 
190     // invalid day (32)
191     EXPECT_EQ(dateStringToEpoch("2024-07-32T12:00:00Z"), std::nullopt);
192 
193     // invalid character for day
194     EXPECT_EQ(dateStringToEpoch("2024-07-XT12:00:00Z"), std::nullopt);
195 
196     // invalid hour (25)
197     EXPECT_EQ(dateStringToEpoch("2024-07-01T25:00:00Z"), std::nullopt);
198 
199     // invalid character for hour
200     EXPECT_EQ(dateStringToEpoch("2024-07-01TX:00:00Z"), std::nullopt);
201 
202     // invalid minute (60)
203     // Date.h and std::chrono seem to disagree about whether there is a 60th
204     // minute in an hour.  Not clear if this is intended or not, but really
205     // isn't that important.  Let std::chrono pass with 61
206 #if __cpp_lib_chrono >= 201907L
207     EXPECT_EQ(dateStringToEpoch("2024-07-01T12:61:00Z"), std::nullopt);
208 #else
209     EXPECT_EQ(dateStringToEpoch("2024-07-01T12:60:00Z"), std::nullopt);
210 #endif
211 
212     // invalid character for minute
213     EXPECT_EQ(dateStringToEpoch("2024-13-01T12:X:00Z"), std::nullopt);
214 
215     // invalid second (60)
216     EXPECT_EQ(dateStringToEpoch("2024-07-01T12:00:XZ"), std::nullopt);
217 
218     // invalid character for second
219     EXPECT_EQ(dateStringToEpoch("2024-13-01T12:00:00Z"), std::nullopt);
220 
221     // invalid timezone
222     EXPECT_EQ(dateStringToEpoch("2024-07-01T12:00:00X"), std::nullopt);
223 
224     // invalid datetime format
225     EXPECT_EQ(dateStringToEpoch("202305"), std::nullopt);
226 
227     // invalid month (13), day (99)
228     EXPECT_EQ(dateStringToEpoch("19991399"), std::nullopt);
229 }
230 
TEST(Utility,GetDateTimeIso8601)231 TEST(Utility, GetDateTimeIso8601)
232 {
233     EXPECT_EQ(getDateTimeIso8601("20230531"), "2023-05-31T00:00:00+00:00");
234 
235     EXPECT_EQ(getDateTimeIso8601("20230531T000000Z"),
236               "2023-05-31T00:00:00+00:00");
237 
238     // invalid datetime
239     EXPECT_EQ(getDateTimeIso8601("202305"), std::nullopt);
240 }
241 
242 } // namespace
243 } // namespace redfish::time_utils
244