• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

taosdata / TDengine / #4987

16 Mar 2026 12:26PM UTC coverage: 73.883% (+36.6%) from 37.305%
#4987

push

travis-ci

web-flow
feat: support secure delete option. (#34591)

209 of 391 new or added lines in 24 files covered. (53.45%)

3062 existing lines in 140 files now uncovered.

261133 of 353439 relevant lines covered (73.88%)

121262425.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.53
/source/os/test/osTimeTests.cpp
1
/*
2
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
3
 *
4
 * This program is free software: you can use, redistribute, and/or modify
5
 * it under the terms of the GNU Affero General Public License, version 3
6
 * or later ("AGPL"), as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * You should have received a copy of the GNU Affero General Public License
13
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14
 */
15

16
#include <gtest/gtest.h>
17
#include <iostream>
18
#include <thread>
19
#include <vector>
20
#include <chrono>
21

22
#pragma GCC diagnostic push
23
#pragma GCC diagnostic ignored "-Wwrite-strings"
24
#pragma GCC diagnostic ignored "-Wunused-function"
25
#pragma GCC diagnostic ignored "-Wunused-variable"
26
#pragma GCC diagnostic ignored "-Wsign-compare"
27
#pragma GCC diagnostic ignored "-Wsign-compare"
28
#pragma GCC diagnostic ignored "-Wformat"
29
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
30
#pragma GCC diagnostic ignored "-Wpointer-arith"
31

32
#include "os.h"
33
#include "tlog.h"
34

35
TEST(osTimeTests, taosLocalTime) {
384✔
36
  // Test 1: Test when both timep and result are not NULL
37
  time_t     timep = 1617531000;  // 2021-04-04 18:10:00
96✔
38
  struct tm  result;
39
  struct tm *local_time = taosLocalTime(&timep, &result, NULL, 0, NULL);
96✔
40
  ASSERT_NE(local_time, nullptr);
96✔
41
  ASSERT_EQ(local_time->tm_year, 121);
96✔
42
  ASSERT_EQ(local_time->tm_mon, 3);
96✔
43
  ASSERT_EQ(local_time->tm_mday, 4);
96✔
44
  ASSERT_EQ(local_time->tm_hour, 18);
96✔
45
  ASSERT_EQ(local_time->tm_min, 10);
96✔
46
  ASSERT_EQ(local_time->tm_sec, 00);
96✔
47

48
  // Test 2: Test when timep is NULL
49
  local_time = taosLocalTime(NULL, &result, NULL, 0, NULL);
96✔
50
  ASSERT_EQ(local_time, nullptr);
96✔
51

52
  // Test 4: Test when timep is negative on Windows
53
#ifdef WINDOWS
54
  time_t pos_timep = 1609459200;  // 2021-01-01 08:00:00
55
  local_time = taosLocalTime(&pos_timep, &result, NULL, 0, NULL);
56
  ASSERT_NE(local_time, nullptr);
57
  ASSERT_EQ(local_time->tm_year, 121);
58
  ASSERT_EQ(local_time->tm_mon, 0);
59
  ASSERT_EQ(local_time->tm_mday, 1);
60
  ASSERT_EQ(local_time->tm_hour, 8);
61
  ASSERT_EQ(local_time->tm_min, 0);
62
  ASSERT_EQ(local_time->tm_sec, 0);
63

64
  time_t neg_timep = -1617531000;  // 1918-09-29 21:50:00
65
  local_time = taosLocalTime(&neg_timep, &result, NULL, 0, NULL);
66
  ASSERT_NE(local_time, nullptr);
67
  ASSERT_EQ(local_time->tm_year, 18);
68
  ASSERT_EQ(local_time->tm_mon, 8);
69
  ASSERT_EQ(local_time->tm_mday, 29);
70
  ASSERT_EQ(local_time->tm_hour, 21);
71
  ASSERT_EQ(local_time->tm_min, 50);
72
  ASSERT_EQ(local_time->tm_sec, 0);
73

74
  time_t neg_timep2 = -315619200;  // 1960-01-01 08:00:00
75
  local_time = taosLocalTime(&neg_timep2, &result, NULL, 0, NULL);
76
  ASSERT_NE(local_time, nullptr);
77
  ASSERT_EQ(local_time->tm_year, 60);
78
  ASSERT_EQ(local_time->tm_mon, 0);
79
  ASSERT_EQ(local_time->tm_mday, 1);
80
  ASSERT_EQ(local_time->tm_hour, 8);
81
  ASSERT_EQ(local_time->tm_min, 0);
82
  ASSERT_EQ(local_time->tm_sec, 0);
83

84
  time_t zero_timep = 0;  // 1970-01-01 08:00:00
85
  local_time = taosLocalTime(&zero_timep, &result, NULL, 0, NULL);
86
  ASSERT_NE(local_time, nullptr);
87
  ASSERT_EQ(local_time->tm_year, 70);
88
  ASSERT_EQ(local_time->tm_mon, 0);
89
  ASSERT_EQ(local_time->tm_mday, 1);
90
  ASSERT_EQ(local_time->tm_hour, 8);
91
  ASSERT_EQ(local_time->tm_min, 0);
92
  ASSERT_EQ(local_time->tm_sec, 0);
93

94
  time_t neg_timep3 = -78115158887;
95
  local_time = taosLocalTime(&neg_timep3, &result, NULL, 0, NULL);
96
  ASSERT_EQ(local_time, nullptr);
97
#endif
98
}
99

100
TEST(osTimeTests, taosGmTimeR) {
384✔
101
  // Test 1: Test when both timep and result are not NULL
102
  time_t     timep = 1617531000;  // 2021-04-04 18:10:00
96✔
103
  struct tm  tmInfo;
104
  ASSERT_NE(taosGmTimeR(&timep, &tmInfo), nullptr);
96✔
105

106
  char buf[128];
107
  taosStrfTime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &tmInfo);
96✔
108
  ASSERT_STREQ(buf, "2021-04-04T10:10:00");
96✔
109
}
110

111
TEST(osTimeTests, taosTimeGm) {
384✔
112
  char *timestr= "2021-04-04T18:10:00";
96✔
113
  struct tm tm = {0};
96✔
114

115
  taosStrpTime(timestr, "%Y-%m-%dT%H:%M:%S", &tm);
96✔
116
  int64_t seconds = taosTimeGm(&tm);
96✔
117
  ASSERT_EQ(seconds, 1617559800);
96✔
118
}
119

120
TEST(osTimeTests, taosMktime) {
384✔
121
  char *timestr= "2021-04-04T18:10:00";
96✔
122
  struct tm tm = {0};
96✔
123

124
  taosStrpTime(timestr, "%Y-%m-%dT%H:%M:%S", &tm);
96✔
125
  time_t seconds = taosMktime(&tm, NULL);
96✔
126
  ASSERT_EQ(seconds, 1617531000);
96✔
127
}
128

129
TEST(osTimeTests, invalidParameter) {
384✔
130
  void          *retp = NULL;
96✔
131
  int32_t        reti = 0;
96✔
132
  char           buf[1024] = {0};
96✔
133
  char           fmt[1024] = {0};
96✔
134
  struct tm      tm = {0};
96✔
135
  struct timeval tv = {0};
96✔
136

137
  retp = taosStrpTime(buf, fmt, NULL);
96✔
138
  EXPECT_EQ(retp, nullptr);
96✔
139
  retp = taosStrpTime(NULL, fmt, &tm);
96✔
140
  EXPECT_EQ(retp, nullptr);
96✔
141
  retp = taosStrpTime(buf, NULL, &tm);
96✔
142
  EXPECT_EQ(retp, nullptr);
96✔
143

144
  reti = taosGetTimeOfDay(NULL);
96✔
145
  EXPECT_NE(reti, 0);
96✔
146

147
  reti = taosTime(NULL);
96✔
148
  EXPECT_NE(reti, 0);
96✔
149

150
  tm.tm_year = 2024;
96✔
151
  tm.tm_mon = 10;
96✔
152
  tm.tm_mday = 23;
96✔
153
  tm.tm_hour = 12;
96✔
154
  tm.tm_min = 1;
96✔
155
  tm.tm_sec = 0;
96✔
156
  tm.tm_isdst = -1;
96✔
157
  time_t rett = taosMktime(&tm, NULL);
96✔
158
  EXPECT_NE(rett, 0);
96✔
159

160
  retp = taosLocalTime(NULL, &tm, NULL, 0, NULL);
96✔
161
  EXPECT_EQ(retp, nullptr);
96✔
162

163
  retp = taosLocalTime(&rett, NULL, NULL, 0, NULL);
96✔
164
  EXPECT_EQ(retp, nullptr);
96✔
165

166
  reti = taosSetGlobalTimezone(NULL);
96✔
167
  EXPECT_NE(reti, 0);
96✔
168
}
96✔
169

170
#ifndef WINDOWS
171
TEST(osTimeTests, truncateTimezoneStringRemovesLeadingSlash) {
384✔
172
  char tz[TD_TIMEZONE_LEN] = "/UTC";
96✔
173

174
  truncateTimezoneString(tz);
96✔
175

176
  EXPECT_STREQ(tz, "UTC");
96✔
177
}
96✔
178
#endif
179

180
TEST(osTimeTests, user_mktime64) {
384✔
181
  int64_t reti = 0;
96✔
182

183
  reti = user_mktime64(2024, 10, 23, 12, 3, 2, 1);
96✔
184
  EXPECT_NE(reti, 0);
96✔
185

186
  reti = user_mktime64(2024, 1, 23, 12, 3, 2, 1);
96✔
187
  EXPECT_NE(reti, 0);
96✔
188
}
96✔
189

190
TEST(osTimeTests, taosLocalTimeBenchmark) {
384✔
191
  const int threads = 400;
96✔
192
  const int iters = 1000000;
96✔
193

194
  std::atomic<uint64_t> ok{0}, err{0};
96✔
195
  std::vector<std::thread> ths;
96✔
196

197
  char tsTimezoneStr[TD_TIMEZONE_LEN] = {0};
96✔
198
  (void)initTimezoneInfo();
96✔
199

200
  // Use a fixed timestamp to avoid extra syscalls in the hot loop
201
  time_t tp = taosGetTimestampSec();
96✔
202

203
  auto start = std::chrono::steady_clock::now();
96✔
204
  ths.reserve(threads);
96✔
205
  for (int i = 0; i < threads; ++i) {
38,496✔
206
    ths.emplace_back([&]() {
75,552✔
207
      struct tm tm1;
208
      for (int j = 0; j < iters; ++j) {
2,147,483,647✔
209
        if (taosLocalTime(&tp, &tm1, NULL, 0, NULL) != nullptr) {
2,147,483,647✔
210
          ok.fetch_add(1, std::memory_order_relaxed);
2,147,483,647✔
211
        } else {
UNCOV
212
          err.fetch_add(1, std::memory_order_relaxed);
×
213
        }
214
      }
215
    });
202,953,600✔
216
  }
217
  for (auto &t : ths) t.join();
38,496✔
218
  auto end = std::chrono::steady_clock::now();
96✔
219

220
  auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
96✔
221
  const uint64_t total = static_cast<uint64_t>(threads) * static_cast<uint64_t>(iters);
96✔
222
  double qps = ms > 0 ? (double)total / ((double)ms / 1000.0) : 0.0;
96✔
223

224
  std::cout << "[taosLocalTime bench] threads=" << threads
96✔
225
            << " iters=" << iters
96✔
226
            << " total_calls=" << total
96✔
227
            << " ok=" << ok.load()
192✔
228
            << " err=" << err.load()
192✔
229
            << " elapsed_ms=" << ms
96✔
230
            << " throughput_calls_per_sec=" << qps
96✔
231
            << std::endl;
96✔
232

233
  // Ensure correctness: all calls should succeed
234
  EXPECT_EQ(ok.load(), total);
192✔
235
  EXPECT_EQ(err.load(), 0u);
192✔
236
}
96✔
237

238
#ifdef WINDOWS
239
#else
240
TEST(osTimeTests, tzConcurrencyBreakTest) {
384✔
241
  constexpr int kReaderThreads = 16;
96✔
242
  constexpr int kDurationSec = 3;
96✔
243

244
  ASSERT_EQ(initTimezoneInfo(), TSDB_CODE_SUCCESS);
96✔
245

246
  std::atomic<bool> stop{false};
96✔
247
  std::atomic<uint64_t> errors{0};
96✔
248
  std::vector<std::thread> threads;
192✔
249

250
  time_t tp = taosGetTimestampSec();
96✔
251

252
  threads.emplace_back([&]() {
192✔
253
    const char* tzs[] = {
96✔
254
      "UTC",
255
      "Asia/Shanghai",
256
      "America/New_York",
257
      "Europe/Berlin"
258
    };
259

260
    int i = 0;
96✔
261
    while (!stop.load(std::memory_order_relaxed)) {
17,952✔
262
      setenv("TZ", tzs[i++ % 4], 1);
17,856✔
263
      tzset();
17,856✔
264
      std::this_thread::sleep_for(std::chrono::milliseconds(10));
17,856✔
265
    }
266
  });
96✔
267

268
  for (int i = 0; i < kReaderThreads; ++i) {
1,632✔
269
    threads.emplace_back([&]() {
2,976✔
270
      struct tm tm1;
271
      while (!stop.load(std::memory_order_relaxed)) {
438,003,072✔
272
        if (!taosLocalTime(&tp, &tm1, nullptr, 0, nullptr)) {
487,816,512✔
UNCOV
273
          errors.fetch_add(1, std::memory_order_relaxed);
×
UNCOV
274
          continue;
×
275
        }
276

277
        if (tm1.tm_sec < 0 || tm1.tm_sec > 60 ||
438,001,632✔
278
            tm1.tm_min < 0 || tm1.tm_min > 59 ||
492,641,568✔
279
            tm1.tm_hour < 0 || tm1.tm_hour > 23 ||
500,430,528✔
280
            tm1.tm_mday < 1 || tm1.tm_mday > 31 ||
495,815,424✔
281
            tm1.tm_mon < 0 || tm1.tm_mon > 11) {
500,748,864✔
UNCOV
282
          errors.fetch_add(1, std::memory_order_relaxed);
×
283
        }
284
      }
UNCOV
285
    });
×
286
  }
287

288
  std::this_thread::sleep_for(std::chrono::seconds(kDurationSec));
96✔
289

290
  stop.store(true, std::memory_order_relaxed);
96✔
291

292
  for (auto& thread : threads) {
1,728✔
293
    if (thread.joinable()) {
1,632✔
294
      thread.join();
1,632✔
295
    }
296
  }
297

298
  std::cout << "Test completed with " << errors.load() << " errors" << std::endl;
192✔
299
  
300
  unsetenv("TZ");
96✔
301
  tzset();
96✔
302
}
303
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc