curl/tests/unit/unit1399.c
Stefan Eissing fbcf10ab84
progress: fx CURLINFO time reporting
Whack the times reported for a transfer (see
https://curl.se/libcurl/c/curl_easy_getinfo.html#TIMES) into order for
all variations of up-/download, http/ftp etc. Make sure they are
reported in the documented order.

There is still the *possibility* of PRETRANSFER being longer then
POSTTRANSFER, if a server sends a response before an upload is done.
POST is the time the first response byte is received, and PRE is the
time the last byte was sent by curl.

This may happen with more likelihood on HTTP/2 and 3 for a server
rejected upload. But for successful uploads, the answer will almost over
come afterwards.

Undo the previous twists in lib500.c tests, adjust pytest timeline
checks.

Fixes #21828
Reported-by: BazaarAcc32 on github
Closes #21843
2026-06-07 14:39:10 +02:00

135 lines
4.6 KiB
C

/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "unitcheck.h"
#include "urldata.h"
#include "progress.h"
static CURLcode t1399_setup(struct Curl_easy **easy)
{
CURLcode result = CURLE_OK;
global_init(CURL_GLOBAL_ALL);
*easy = curl_easy_init();
if(!*easy) {
curl_global_cleanup();
return CURLE_OUT_OF_MEMORY;
}
return result;
}
static void t1399_stop(struct Curl_easy *easy)
{
curl_easy_cleanup(easy);
curl_global_cleanup();
}
/*
* Invoke Curl_pgrsTime for TIMER_STARTSINGLE to trigger the behavior that
* manages is_t_startransfer_set, but fake the t_startsingle time for purposes
* of the test.
*/
static void fake_t_startsingle_time(struct Curl_easy *data,
struct curltime fake_now,
int seconds_offset)
{
Curl_pgrsTime(data, TIMER_STARTSINGLE);
data->progress.t_startsingle.tv_sec = fake_now.tv_sec + seconds_offset;
data->progress.t_startsingle.tv_usec = fake_now.tv_usec;
}
static bool usec_matches_seconds(timediff_t time_usec, int expected_seconds)
{
static int usec_magnitude = 1000000;
int time_sec = (int)(time_usec / usec_magnitude);
bool same = (time_sec == expected_seconds);
curl_mfprintf(stderr, "is %d us same as %d seconds? %s\n",
(int)time_usec, expected_seconds,
same ? "Yes" : "No");
return same;
}
static void expect_timer_seconds(struct Curl_easy *data, int seconds)
{
char msg[64];
curl_msnprintf(msg, sizeof(msg), "about %d seconds should have passed",
seconds);
fail_unless(usec_matches_seconds(data->progress.t_nslookup, seconds), msg);
fail_unless(usec_matches_seconds(data->progress.t_connect, seconds), msg);
fail_unless(usec_matches_seconds(data->progress.t_appconnect, seconds), msg);
fail_unless(usec_matches_seconds(data->progress.t_pretransfer, seconds),
msg);
fail_unless(usec_matches_seconds(data->progress.t_starttransfer, seconds),
msg);
}
/* Scenario: simulate a redirect. When a redirect occurs, t_nslookup,
* t_connect, t_appconnect, t_pretransfer, and t_starttransfer are additive.
* E.g., if t_starttransfer took 2 seconds initially and took another 1
* second for the redirect request, then the resulting t_starttransfer should
* be 3 seconds. */
static CURLcode test_unit1399(const char *arg)
{
struct Curl_easy *data;
struct curltime now = curlx_now();
UNITTEST_BEGIN(t1399_setup(&data))
data->multi = NULL;
data->progress.now = now;
data->progress.t_nslookup = 0;
data->progress.t_connect = 0;
data->progress.t_appconnect = 0;
data->progress.t_pretransfer = 0;
data->progress.t_starttransfer = 0;
data->progress.t_redirect = 0;
data->progress.start.tv_sec = now.tv_sec - 2;
data->progress.start.tv_usec = now.tv_usec;
fake_t_startsingle_time(data, now, -2);
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
Curl_pgrsTime(data, TIMER_CONNECT);
Curl_pgrsTime(data, TIMER_APPCONNECT);
Curl_pgrsTime(data, TIMER_PRETRANSFER);
Curl_pgrsTime(data, TIMER_STARTTRANSFER);
expect_timer_seconds(data, 2);
/* now simulate the redirect */
data->progress.t_redirect = data->progress.t_starttransfer + 1;
fake_t_startsingle_time(data, now, -1);
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
Curl_pgrsTime(data, TIMER_CONNECT);
Curl_pgrsTime(data, TIMER_APPCONNECT);
Curl_pgrsTime(data, TIMER_PRETRANSFER);
/* ensure t_starttransfer is only set on the first invocation by attempting
* to set it twice */
Curl_pgrsTime(data, TIMER_STARTTRANSFER);
Curl_pgrsTime(data, TIMER_STARTTRANSFER);
expect_timer_seconds(data, 3);
UNITTEST_END(t1399_stop(data))
}