@@ -75,3 +75,103 @@ void connected_test::wait_for_no_db(std::string const & name)
7575{
7676 wait_for ([&, this ] {return !database_exists (name); });
7777}
78+
79+ unsigned long long extract_count_from_influxdb_response (std::string const & response)
80+ {
81+ // Parse count from JSON response: {"results":[{"statement_id":0,"series":[{"name":"table","columns":["time","count_value"],"values":[["1970-01-01T00:00:00Z",COUNT]]}]}]}
82+ // Structure: "values":[["timestamp",COUNT]]
83+ auto values_pos = response.find (" \" values\" :[[" );
84+ if (values_pos != std::string::npos) {
85+ // Find the inner array with timestamp and count: [["timestamp",COUNT]]
86+ // The count is the second value, so find the comma after the timestamp
87+ auto bracket = response.find (" [[" , values_pos);
88+ if (bracket != std::string::npos) {
89+ bracket += 2 ; // Skip [[
90+ // Skip timestamp (could be quoted string or number)
91+ auto comma = response.find (" ," , bracket);
92+ if (comma != std::string::npos) {
93+ comma++; // Skip comma
94+ // Skip whitespace
95+ while (comma < response.length () && (response[comma] == ' ' || response[comma] == ' \t ' )) {
96+ comma++;
97+ }
98+ // Extract the number
99+ auto num_start = comma;
100+ auto num_end = num_start;
101+ while (num_end < response.length () && std::isdigit (response[num_end])) {
102+ num_end++;
103+ }
104+ if (num_end > num_start) {
105+ try {
106+ return std::stoull (response.substr (num_start, num_end - num_start));
107+ } catch (...) {
108+ return 0 ;
109+ }
110+ }
111+ }
112+ }
113+ }
114+ return 0 ;
115+ }
116+
117+ bool connected_test::wait_for_async_inserts (unsigned long long expected_count, std::string const & table_name)
118+ {
119+ // Async API batches inserts, so we need to poll until count matches
120+ auto query = std::string (" select count(*) from " ) + db_name + " .." + table_name;
121+
122+ unsigned long long current_count = 0 ;
123+ unsigned retries = 0 ;
124+ const unsigned max_retries = 1000 ; // Much longer timeout for Windows async batching (up to ~100 seconds with exponential backoff)
125+ unsigned wait_ms = 100 ;
126+ const unsigned max_wait_ms = 1000 ; // Cap at 1 second between checks
127+
128+ std::cout << " Waiting for all " << expected_count << " async inserts to arrive..." << std::endl;
129+
130+ while (current_count < expected_count && retries < max_retries) {
131+ std::this_thread::sleep_for (std::chrono::milliseconds (wait_ms));
132+ retries++;
133+
134+ try {
135+ auto response = raw_db.get (query);
136+ current_count = extract_count_from_influxdb_response (response);
137+
138+ // Log more frequently when close to target (within 1% or 1000 entries)
139+ bool is_close = current_count > 0 && (expected_count - current_count) <= std::max (expected_count / 100 , 1000ULL );
140+ bool should_log = (retries % 50 == 0 ) || (current_count > 0 && retries < 10 ) || (is_close && retries % 5 == 0 );
141+
142+ if (should_log) {
143+ std::cout << " Poll attempt " << retries << " /" << max_retries
144+ << " : " << current_count << " /" << expected_count << " entries arrived" ;
145+ if (is_close && current_count < expected_count) {
146+ std::cout << " (" << (expected_count - current_count) << " remaining, waiting for final batch...)" ;
147+ }
148+ std::cout << std::endl;
149+ }
150+
151+ // Accept if we're very close (within 0.1% or 10 entries) - async batching can leave tiny remainder
152+ unsigned long long tolerance = std::max (expected_count / 1000 , 10ULL );
153+ if (current_count >= expected_count) {
154+ std::cout << " ✓ All " << expected_count << " entries arrived after " << retries << " polling attempts!" << std::endl;
155+ return true ;
156+ } else if (current_count + tolerance >= expected_count && retries >= 50 ) {
157+ // After 50 retries, accept if we're within tolerance
158+ std::cout << " ✓ " << current_count << " /" << expected_count << " entries arrived (within tolerance of " << tolerance << " ) after " << retries << " polling attempts!" << std::endl;
159+ return true ;
160+ }
161+ } catch (const std::exception& e) {
162+ // Query might fail early if no data yet, keep trying
163+ if (retries % 50 == 0 ) {
164+ std::cout << " Poll attempt " << retries << " : Query failed (no data yet), continuing..." << std::endl;
165+ }
166+ }
167+
168+ // Exponential backoff: increase wait time gradually, cap at max_wait_ms
169+ wait_ms += 10 ;
170+ if (wait_ms > max_wait_ms) {
171+ wait_ms = max_wait_ms;
172+ }
173+ }
174+
175+ std::cout << " ✗ Timeout: Only " << current_count << " /" << expected_count << " entries arrived after " << retries << " attempts" << std::endl;
176+ return false ;
177+ }
0 commit comments