90 lines
3.9 KiB
C
90 lines
3.9 KiB
C
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "http_api.h"
|
|
#include "sync_service.h"
|
|
|
|
typedef struct { uint32_t value; } test_random_t;
|
|
|
|
static uint32_t next_random(void *context) {
|
|
test_random_t *random = context;
|
|
random->value = random->value * 1664525U + 1013904223U;
|
|
return random->value;
|
|
}
|
|
|
|
static application_t new_application(test_random_t *random) {
|
|
application_t application;
|
|
application_init(&application, (random_source_t){.next_u32 = next_random, .context = random});
|
|
return application;
|
|
}
|
|
|
|
static void test_http_malformed_inputs_do_not_mutate(void) {
|
|
test_random_t random = {.value = 7U};
|
|
application_t application = new_application(&random);
|
|
http_api_t api;
|
|
http_api_init(&api, &application);
|
|
const char *const corpus[] = {"", "{", "[]", "{\"token\":", "{\"token\":null}",
|
|
"{\"name\":\"A\"}", "{\"token\":\"00000000000000000000000000000000\",\"gameId\":-1}",
|
|
"{\"type\":\"shot\"}", "{\"name\":\"A\",\"requestedRole\":\"player1\",\"extra\":1}"};
|
|
const http_api_route_t routes[] = {HTTP_API_ROUTE_JOIN, HTTP_API_ROUTE_RESUME, HTTP_API_ROUTE_CONFIG,
|
|
HTTP_API_ROUTE_START, HTTP_API_ROUTE_SHOT, HTTP_API_ROUTE_REMATCH, HTTP_API_ROUTE_ABORT};
|
|
for (size_t index = 0; index < 400U; ++index) {
|
|
const char *body = corpus[index % (sizeof(corpus) / sizeof(corpus[0]))];
|
|
const game_lifecycle_t before = application.lifecycle;
|
|
http_api_response_t response;
|
|
const http_api_request_t request = {.method = HTTP_API_POST, .route = routes[index % (sizeof(routes) / sizeof(routes[0]))],
|
|
.content_type_json = true, .body = body, .body_length = strlen(body)};
|
|
assert(http_api_handle(&api, &request, &response));
|
|
assert(response.status >= 400U && response.status < 600U && response.body_length < sizeof(response.body));
|
|
assert(memcmp(&before, &application.lifecycle, sizeof(before)) == 0);
|
|
}
|
|
char oversized[kRequestBodyCapacity + 2U];
|
|
memset(oversized, 'x', sizeof(oversized) - 1U);
|
|
oversized[sizeof(oversized) - 1U] = '\0';
|
|
http_api_response_t response;
|
|
const http_api_request_t request = {.method = HTTP_API_POST, .route = HTTP_API_ROUTE_JOIN, .content_type_json = true,
|
|
.body = oversized, .body_length = strlen(oversized)};
|
|
assert(http_api_handle(&api, &request, &response));
|
|
assert(response.status == 413U);
|
|
}
|
|
|
|
static void test_websocket_fuzz_and_connection_churn(void) {
|
|
test_random_t random = {.value = 19U};
|
|
application_t application = new_application(&random);
|
|
sync_service_t service;
|
|
sync_service_init(&service, &application);
|
|
for (uint16_t attempt = 0; attempt < 600U; ++attempt) {
|
|
char frame[kWebSocketFrameCapacity + 1U];
|
|
const size_t length = (size_t)(next_random(&random) % (kWebSocketFrameCapacity + 1U));
|
|
for (size_t index = 0; index < length; ++index) frame[index] = (char)(next_random(&random) & 0x7fU);
|
|
frame[length] = '\0';
|
|
const game_lifecycle_t before = application.lifecycle;
|
|
char output[kStateMessageCapacity] = {0};
|
|
size_t output_length = 0U;
|
|
bool changed = true;
|
|
bool close = false;
|
|
assert(sync_service_open(&service, 1, attempt));
|
|
assert(sync_service_receive(&service, 1, frame, length, attempt, output, &output_length, &changed, &close));
|
|
assert(!changed && output_length < sizeof(output));
|
|
assert(memcmp(&before, &application.lifecycle, sizeof(before)) == 0);
|
|
sync_service_close(&service, 1);
|
|
}
|
|
char too_large[kWebSocketFrameCapacity + 1U] = {0};
|
|
char output[kStateMessageCapacity] = {0};
|
|
size_t output_length = 0U;
|
|
bool changed = false;
|
|
bool close = false;
|
|
assert(sync_service_open(&service, 1, 0U));
|
|
assert(sync_service_receive(&service, 1, too_large, sizeof(too_large), 0U, output, &output_length, &changed, &close));
|
|
assert(!changed && strstr(output, "MALFORMED_JSON") != NULL);
|
|
sync_service_close(&service, 1);
|
|
}
|
|
|
|
int main(void) {
|
|
test_http_malformed_inputs_do_not_mutate();
|
|
test_websocket_fuzz_and_connection_churn();
|
|
puts("robustness tests passed");
|
|
return 0;
|
|
}
|