Files
battleship/test/host/test_robustness.c
T

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;
}