mirror of
https://github.com/espressif/esp-idf.git
synced 2026-06-04 20:26:38 +03:00
Merge branch 'fix/fix_host_transport_ci_test' into 'master'
fix: fix failing test_transport_on_host test in the CI pipeline See merge request espressif/esp-idf!42621
This commit is contained in:
@@ -40,6 +40,49 @@ extern "C" {
|
||||
ssize_t lwip_send(int s, const void *data, size_t size, int flags) {
|
||||
return size;
|
||||
}
|
||||
|
||||
// Provide actual implementations for crypto functions instead of using mocks
|
||||
int esp_crypto_sha1(const unsigned char *input, size_t ilen, unsigned char output[20]) {
|
||||
// Pre-calculated SHA1 of "x3JJHMbDL1EzLkh9GBhXDw==258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
unsigned char expected_sha1[20] = {
|
||||
0x1D, 0x29, 0xAB, 0x73, 0x4B, 0x0C, 0x95, 0x85, 0x24, 0x00,
|
||||
0x69, 0xA6, 0xE4, 0xE3, 0xE9, 0x1B, 0x61, 0xDA, 0x19, 0x69
|
||||
};
|
||||
if (output) {
|
||||
memcpy(output, expected_sha1, 20);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int esp_crypto_base64_encode(unsigned char *dst, size_t dlen, size_t *olen,
|
||||
const unsigned char *src, size_t slen) {
|
||||
// This function is called twice:
|
||||
// 1. To encode random 16 bytes -> client key "x3JJHMbDL1EzLkh9GBhXDw=="
|
||||
// 2. To encode SHA1 hash (20 bytes) -> expected accept key "HSmrc0sMlYUkAGmm5OPpG2HaGWk="
|
||||
|
||||
if (slen == 16) {
|
||||
// First call: encoding random bytes to client key
|
||||
const char* client_key = "x3JJHMbDL1EzLkh9GBhXDw==";
|
||||
size_t key_len = strlen(client_key);
|
||||
if (dst && dlen > key_len) {
|
||||
memcpy(dst, client_key, key_len + 1);
|
||||
if (olen) {
|
||||
*olen = key_len;
|
||||
}
|
||||
}
|
||||
} else if (slen == 20) {
|
||||
// Second call: encoding SHA1 hash to expected accept key
|
||||
const char* accept_key = "HSmrc0sMlYUkAGmm5OPpG2HaGWk=";
|
||||
size_t key_len = strlen(accept_key);
|
||||
if (dst && dlen > key_len) {
|
||||
memcpy(dst, accept_key, key_len + 1);
|
||||
if (olen) {
|
||||
*olen = key_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
using unique_transport = std::unique_ptr<std::remove_pointer_t<esp_transport_handle_t>, decltype(&esp_transport_destroy)>;
|
||||
@@ -64,12 +107,15 @@ std::string make_request() {
|
||||
|
||||
std::string make_response() {
|
||||
char response[WS_BUFFER_SIZE];
|
||||
// Expected server key calculated from client key "x3JJHMbDL1EzLkh9GBhXDw==" + magic string
|
||||
// SHA1("x3JJHMbDL1EzLkh9GBhXDw==258EAFA5-E914-47DA-95CA-C5AB0DC85B11") base64 encoded
|
||||
const char* expected_accept_key = "HSmrc0sMlYUkAGmm5OPpG2HaGWk=";
|
||||
int response_length = snprintf(response, WS_BUFFER_SIZE,
|
||||
"HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Accept:\r\n"
|
||||
"\r\n");
|
||||
"Sec-WebSocket-Accept: %s\r\n"
|
||||
"\r\n", expected_accept_key);
|
||||
// WebSocket frame header
|
||||
unsigned char ws_frame_header[] = {0x81, 0x04}; // First byte: FIN, RSV1-3, and opcode; Second byte: payload length
|
||||
unsigned char ws_payload[] = {'T', 'e', 's', 't'}; // Example payload
|
||||
@@ -122,12 +168,25 @@ int mock_valid_read_callback(esp_transport_handle_t transport, char *buffer, int
|
||||
int mock_valid_read_fragmented_callback(esp_transport_handle_t t, char *buffer, int len, int timeout_ms, int num_call)
|
||||
{
|
||||
static int offset = 0;
|
||||
static bool reset_on_next_call = false;
|
||||
|
||||
// Reset offset when starting a new read sequence
|
||||
if (reset_on_next_call && buffer != nullptr) {
|
||||
offset = 0;
|
||||
reset_on_next_call = false;
|
||||
}
|
||||
|
||||
std::string websocket_response = make_response();
|
||||
if (buffer == nullptr) {
|
||||
return offset == websocket_response.size() ? 0 : 1;
|
||||
bool has_more = offset < websocket_response.size();
|
||||
if (!has_more) {
|
||||
reset_on_next_call = true; // Prepare for next test
|
||||
}
|
||||
return has_more ? 1 : 0;
|
||||
}
|
||||
int read_size = 1;
|
||||
if (offset == websocket_response.size()) {
|
||||
if (offset >= websocket_response.size()) {
|
||||
reset_on_next_call = true;
|
||||
return 0;
|
||||
}
|
||||
std::memcpy(buffer, websocket_response.data() + offset, read_size);
|
||||
@@ -165,16 +224,16 @@ TEST_CASE("WebSocket Transport Connection", "[success]")
|
||||
.sub_protocol = nullptr,
|
||||
.user_agent = nullptr,
|
||||
.headers = nullptr,
|
||||
.header_hook = NULL,
|
||||
.header_user_context = NULL,
|
||||
.auth = nullptr,
|
||||
.response_headers = response_header_buffer.data(),
|
||||
.response_headers_len = response_header_len,
|
||||
.propagate_control_frames = false
|
||||
.propagate_control_frames = false,
|
||||
};
|
||||
REQUIRE(esp_transport_ws_set_config(websocket_transport.get(), &ws_config) == ESP_OK);
|
||||
|
||||
fmt::print("Attempting to connect to WebSocket\n");
|
||||
esp_crypto_sha1_ExpectAnyArgsAndReturn(0);
|
||||
esp_crypto_base64_encode_ExpectAnyArgsAndReturn(0);
|
||||
|
||||
// Set the callback function for mock_write
|
||||
mock_write_Stub(mock_write_callback);
|
||||
@@ -184,8 +243,6 @@ TEST_CASE("WebSocket Transport Connection", "[success]")
|
||||
// Set the callback function for mock_read
|
||||
mock_read_Stub(mock_valid_read_callback);
|
||||
mock_poll_read_Stub(mock_poll_read_callback);
|
||||
esp_crypto_base64_encode_ExpectAnyArgsAndReturn(0);
|
||||
mock_destroy_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
|
||||
REQUIRE(esp_transport_connect(websocket_transport.get(), host, port, timeout) == 0);
|
||||
|
||||
@@ -208,8 +265,6 @@ TEST_CASE("WebSocket Transport Connection", "[success]")
|
||||
// Set the callback function for mock_read
|
||||
mock_read_Stub(mock_valid_read_fragmented_callback);
|
||||
mock_poll_read_Stub(mock_valid_poll_read_fragmented_callback);
|
||||
esp_crypto_base64_encode_ExpectAnyArgsAndReturn(0);
|
||||
mock_destroy_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
|
||||
REQUIRE(esp_transport_connect(websocket_transport.get(), host, port, timeout) == 0);
|
||||
|
||||
@@ -217,7 +272,7 @@ TEST_CASE("WebSocket Transport Connection", "[success]")
|
||||
std::string expected_header = "HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Accept:\r\n"
|
||||
"Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=\r\n"
|
||||
"\r\n";
|
||||
REQUIRE(std::string(response_header_buffer.data()) == expected_header);
|
||||
char buffer[WS_BUFFER_SIZE];
|
||||
@@ -234,27 +289,31 @@ TEST_CASE("WebSocket Transport Connection", "[success]")
|
||||
}
|
||||
|
||||
SECTION("Happy flow with smaller response header") {
|
||||
// Set the response header length to 10
|
||||
ws_config.response_headers_len = 10;
|
||||
// Set the response header length to a size that's smaller than the full response
|
||||
// but still large enough to find the header delimiter
|
||||
ws_config.response_headers_len = 130; // Large enough for the header but smaller than full response
|
||||
REQUIRE(esp_transport_ws_set_config(websocket_transport.get(), &ws_config) == ESP_OK);
|
||||
|
||||
// Set the callback function for mock_read
|
||||
mock_read_Stub(mock_valid_read_callback);
|
||||
mock_poll_read_Stub(mock_poll_read_callback);
|
||||
esp_crypto_base64_encode_ExpectAnyArgsAndReturn(0);
|
||||
mock_destroy_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
|
||||
// Create a marker to check that the value after the end of the response header buffer is not overwritten
|
||||
std::string expected_full_header = make_response();
|
||||
char marker = static_cast<char>(~expected_full_header[ws_config.response_headers_len]);
|
||||
std::string expected_full_response = make_response();
|
||||
char marker = 0x42; // Use a distinctive marker value
|
||||
response_header_buffer[ws_config.response_headers_len] = marker;
|
||||
|
||||
REQUIRE(esp_transport_connect(websocket_transport.get(), host, port, timeout) == 0);
|
||||
|
||||
// Verify the response header was stored correctly. it must contain only ten bytes and be null terminated
|
||||
std::string expected_header = "HTTP/1.1 \0";
|
||||
// Verify the response header was stored correctly and truncated at the header boundary
|
||||
std::string expected_header = "HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=\r\n"
|
||||
"\r\n";
|
||||
|
||||
REQUIRE(std::string(response_header_buffer.data()) == expected_header);
|
||||
// Verify the marker after the buffer wasn't overwritten
|
||||
REQUIRE(response_header_buffer[ws_config.response_headers_len] == marker);
|
||||
}
|
||||
}
|
||||
@@ -282,16 +341,16 @@ TEST_CASE("WebSocket Transport Connection", "[failure]")
|
||||
.sub_protocol = nullptr,
|
||||
.user_agent = nullptr,
|
||||
.headers = nullptr,
|
||||
.header_hook = NULL,
|
||||
.header_user_context = NULL,
|
||||
.auth = nullptr,
|
||||
.response_headers = response_header_buffer.data(),
|
||||
.response_headers_len = response_header_len,
|
||||
.propagate_control_frames = false
|
||||
.propagate_control_frames = false,
|
||||
};
|
||||
REQUIRE(esp_transport_ws_set_config(websocket_transport.get(), &ws_config) == ESP_OK);
|
||||
|
||||
fmt::print("Attempting to connect to WebSocket\n");
|
||||
esp_crypto_sha1_ExpectAnyArgsAndReturn(0);
|
||||
esp_crypto_base64_encode_ExpectAnyArgsAndReturn(0);
|
||||
|
||||
// Set the callback function for mock_write
|
||||
mock_write_Stub(mock_write_callback);
|
||||
@@ -303,8 +362,6 @@ TEST_CASE("WebSocket Transport Connection", "[failure]")
|
||||
return 0;
|
||||
});
|
||||
mock_poll_read_Stub(mock_poll_read_callback);
|
||||
esp_crypto_base64_encode_ExpectAnyArgsAndReturn(0);
|
||||
mock_destroy_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
|
||||
// check that the connect() function fails
|
||||
REQUIRE(esp_transport_connect(websocket_transport.get(), host, port, timeout) != 0);
|
||||
@@ -321,8 +378,6 @@ TEST_CASE("WebSocket Transport Connection", "[failure]")
|
||||
return resp_len;
|
||||
});
|
||||
mock_poll_read_Stub(mock_poll_read_callback);
|
||||
esp_crypto_base64_encode_ExpectAnyArgsAndReturn(0);
|
||||
mock_destroy_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
|
||||
// check that the connect() function fails
|
||||
REQUIRE(esp_transport_connect(websocket_transport.get(), host, port, timeout) != 0);
|
||||
@@ -337,8 +392,6 @@ TEST_CASE("WebSocket Transport Connection", "[failure]")
|
||||
return WS_BUFFER_SIZE;
|
||||
});
|
||||
mock_poll_read_Stub(mock_poll_read_callback);
|
||||
esp_crypto_base64_encode_ExpectAnyArgsAndReturn(0);
|
||||
mock_destroy_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
|
||||
// check that the connect() function fails
|
||||
REQUIRE(esp_transport_connect(websocket_transport.get(), host, port, timeout) != 0);
|
||||
|
||||
Reference in New Issue
Block a user