Mercurial
comparison mrjunejune/test/integration_test.c @ 126:e7899c93da77
Remove playground.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Thu, 08 Jan 2026 18:03:34 -0800 |
| parents | 96628cf126a0 |
| children | 7eb79fd91c7e |
comparison
equal
deleted
inserted
replaced
| 125:f236c895604e | 126:e7899c93da77 |
|---|---|
| 1 #include "seobeo/seobeo.h" | 1 #include "seobeo/test/test.h" |
| 2 #include <stdio.h> | |
| 3 #include <stdlib.h> | |
| 4 #include <string.h> | |
| 5 #include <unistd.h> | |
| 6 #include <sys/wait.h> | |
| 7 #include <signal.h> | |
| 8 #include <assert.h> | |
| 9 | |
| 10 #define TEST_PORT "6969" | |
| 11 #define TEST_HOST "127.0.0.1" | |
| 12 #define MAX_RESPONSE_SIZE (1024 * 1024) | |
| 13 #ifndef SNAPSHOT_DIR | |
| 14 // TODO: Make it as current directory /snapshots... | |
| 15 #define SNAPSHOT_DIR "mrjunejune/test/snapshots" | |
| 16 #endif | |
| 17 | 2 |
| 18 // Test case structure | 3 // Test case structure |
| 19 typedef struct { | 4 typedef struct { |
| 20 const char *path; | 5 const char *path; |
| 21 int expected_status; | 6 int expected_status; |
| 115 } | 100 } |
| 116 | 101 |
| 117 return 0; | 102 return 0; |
| 118 } | 103 } |
| 119 | 104 |
| 120 // Helper: Create test client | |
| 121 Seobeo_Handle* create_test_client() | |
| 122 { | |
| 123 Seobeo_Handle *client = Seobeo_Stream_Handle_Client_Create(TEST_HOST, TEST_PORT, FALSE); | |
| 124 if (!client || client->socket < 0) | |
| 125 { | |
| 126 if (client) | |
| 127 { | |
| 128 Seobeo_Handle_Destroy(client); | |
| 129 } | |
| 130 return NULL; | |
| 131 } | |
| 132 return client; | |
| 133 } | |
| 134 | |
| 135 // Helper: Generate default HTTP GET request | |
| 136 int generate_http_get_request(char *buffer, size_t buffer_size, const char *path) | |
| 137 { | |
| 138 return snprintf( | |
| 139 buffer, buffer_size, | |
| 140 "GET %s HTTP/1.1\r\n" | |
| 141 "Host: %s\r\n" | |
| 142 "Connection: close\r\n" | |
| 143 "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" | |
| 144 "User-Agent: SeobeoTestClient/1.0\r\n" | |
| 145 "\r\n", | |
| 146 path, TEST_HOST | |
| 147 ); | |
| 148 } | |
| 149 | |
| 150 // Helper: Send HTTP request | |
| 151 int send_http_request(Seobeo_Handle *client, const char *path, const char *custom_request) | |
| 152 { | |
| 153 char request_buffer[4096]; | |
| 154 int request_len; | |
| 155 | |
| 156 if (custom_request) | |
| 157 { | |
| 158 request_len = snprintf(request_buffer, sizeof(request_buffer), "%s", custom_request); | |
| 159 } | |
| 160 else | |
| 161 { | |
| 162 request_len = generate_http_get_request(request_buffer, sizeof(request_buffer), path); | |
| 163 } | |
| 164 | |
| 165 if (request_len < 0 || request_len >= sizeof(request_buffer)) | |
| 166 { | |
| 167 fprintf(stderr, "Request buffer too small\n"); | |
| 168 return -1; | |
| 169 } | |
| 170 | |
| 171 Seobeo_Handle_Queue(client, (uint8*)request_buffer, (uint32)request_len); | |
| 172 return Seobeo_Handle_Flush(client); | |
| 173 } | |
| 174 | |
| 175 // Helper: Read HTTP response | |
| 176 int read_http_response(Seobeo_Handle *client, char **response_out, size_t *response_len_out) | |
| 177 { | |
| 178 char *response = malloc(MAX_RESPONSE_SIZE); | |
| 179 if (!response) | |
| 180 { | |
| 181 return -1; | |
| 182 } | |
| 183 | |
| 184 size_t total_bytes = 0; | |
| 185 int attempts = 0; | |
| 186 const int max_attempts = 100; | |
| 187 | |
| 188 while (attempts++ < max_attempts && total_bytes < MAX_RESPONSE_SIZE - 1) | |
| 189 { | |
| 190 int bytes_read = Seobeo_Handle_Read(client); | |
| 191 | |
| 192 if (bytes_read > 0) | |
| 193 { | |
| 194 size_t to_copy = client->read_buffer_len; | |
| 195 if (total_bytes + to_copy > MAX_RESPONSE_SIZE - 1) | |
| 196 { | |
| 197 to_copy = MAX_RESPONSE_SIZE - 1 - total_bytes; | |
| 198 } | |
| 199 | |
| 200 memcpy(response + total_bytes, client->read_buffer, to_copy); | |
| 201 total_bytes += to_copy; | |
| 202 Seobeo_Handle_Consume(client, (uint32)to_copy); | |
| 203 } | |
| 204 else if (bytes_read == -2) | |
| 205 { | |
| 206 // Connection closed | |
| 207 break; | |
| 208 } | |
| 209 else if (bytes_read == 0) | |
| 210 { | |
| 211 // Would block | |
| 212 usleep(10000); | |
| 213 continue; | |
| 214 } | |
| 215 else | |
| 216 { | |
| 217 free(response); | |
| 218 return -1; | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 response[total_bytes] = '\0'; | |
| 223 *response_out = response; | |
| 224 *response_len_out = total_bytes; | |
| 225 | |
| 226 return (total_bytes > 0) ? 0 : -1; | |
| 227 } | |
| 228 | |
| 229 // Helper: Parse HTTP status code | |
| 230 int parse_http_status(const char *response) | |
| 231 { | |
| 232 if (!response || strlen(response) < 12) | |
| 233 { | |
| 234 return -1; | |
| 235 } | |
| 236 | |
| 237 const char *status_start = strstr(response, "HTTP/1.1 "); | |
| 238 if (!status_start) | |
| 239 { | |
| 240 status_start = strstr(response, "HTTP/1.0 "); | |
| 241 } | |
| 242 | |
| 243 if (!status_start) | |
| 244 { | |
| 245 return -1; | |
| 246 } | |
| 247 | |
| 248 int status_code; | |
| 249 if (sscanf(status_start + 9, "%d", &status_code) == 1) | |
| 250 { | |
| 251 return status_code; | |
| 252 } | |
| 253 | |
| 254 return -1; | |
| 255 } | |
| 256 | |
| 257 // Helper: Check if status is a redirect | |
| 258 int is_redirect_status(int status) | |
| 259 { | |
| 260 return (status >= 300 && status < 400); | |
| 261 } | |
| 262 | |
| 263 // Helper: Execute a test case | |
| 264 int execute_test_case(TestCase *test, pid_t server_pid) | 105 int execute_test_case(TestCase *test, pid_t server_pid) |
| 265 { | 106 { |
| 266 printf(" Testing: GET %s (expecting %d)\n", test->path, test->expected_status); | 107 printf(" Testing: GET %s (expecting %d)\n", test->path, test->expected_status); |
| 267 | 108 |
| 268 Seobeo_Handle *client = create_test_client(); | 109 int32 max_url_length = 1024*3; |
| 269 if (!client) | 110 char *url = malloc(sizeof(char)*max_url_length); |
| 270 { | 111 snprintf(url, max_url_length, "%s%s", TEST_URL, test->path); |
| 271 printf(" ✗ Failed to create client connection\n"); | 112 Seobeo_Client_Request *p_req = Seobeo_Client_Request_Create(url); |
| 272 return -1; | 113 if (!p_req) |
| 273 } | 114 { |
| 274 | 115 printf("Can't create requests"); |
| 275 if (send_http_request(client, test->path, NULL) < 0) | 116 return -1; |
| 276 { | 117 } |
| 277 printf(" ✗ Failed to send request\n"); | 118 |
| 278 Seobeo_Handle_Destroy(client); | 119 Seobeo_Client_Response *p_resp = Seobeo_Client_Request_Execute(p_req); |
| 279 return -1; | 120 if (!p_resp) |
| 280 } | 121 { |
| 281 | 122 printf("No response"); |
| 282 char *response = NULL; | 123 return -1; |
| 283 size_t response_len = 0; | 124 } |
| 284 if (read_http_response(client, &response, &response_len) < 0) | 125 |
| 285 { | 126 if (p_resp->status_code != test->expected_status) |
| 286 printf(" ✗ Failed to read response\n"); | |
| 287 Seobeo_Handle_Destroy(client); | |
| 288 return -1; | |
| 289 } | |
| 290 | |
| 291 test->actual_response = response; | |
| 292 test->response_len = response_len; | |
| 293 | |
| 294 int actual_status = parse_http_status(response); | |
| 295 if (actual_status != test->expected_status) | |
| 296 { | 127 { |
| 297 printf(" ✗ Status mismatch: expected %d, got %d\n", | 128 printf(" ✗ Status mismatch: expected %d, got %d\n", |
| 298 test->expected_status, actual_status); | 129 test->expected_status, p_resp->status_code); |
| 299 Seobeo_Handle_Destroy(client); | 130 Seobeo_Client_Response_Destroy(p_resp); |
| 300 return -1; | 131 Seobeo_Client_Request_Destroy(p_req); |
| 301 } | 132 return -1; |
| 302 | 133 } |
| 303 printf(" ✓ Status code: %d\n", actual_status); | 134 |
| 304 | 135 printf(" ✓ Status code: %d\n", p_resp->status_code); |
| 305 // For redirects, skip content comparison | 136 |
| 306 if (is_redirect_status(actual_status)) | 137 if (p_resp->status_code == 200) |
| 307 { | |
| 308 printf(" ⚠ Redirect status - skipping content comparison\n"); | |
| 309 Seobeo_Handle_Destroy(client); | |
| 310 return 0; | |
| 311 } | |
| 312 | |
| 313 // Only verify 200 OK responses against snapshots | |
| 314 if (actual_status == 200) | |
| 315 { | 138 { |
| 316 if (!test->expected_content) | 139 if (!test->expected_content) |
| 317 { | 140 { |
| 318 printf(" ✗ No expected snapshot found: %s\n", test->expected_file_path); | 141 printf(" ✗ No expected snapshot found: %s\n", test->expected_file_path); |
| 319 printf(" → Run: bazel run //mrjunejune:create_snapshots\n"); | 142 printf(" → Run: bazel run //mrjunejune:create_snapshots\n"); |
| 320 Seobeo_Handle_Destroy(client); | 143 Seobeo_Client_Response_Destroy(p_resp); |
| 144 Seobeo_Client_Request_Destroy(p_req); | |
| 321 return -1; | 145 return -1; |
| 322 } | 146 } |
| 323 | 147 |
| 324 if (strcmp(response, test->expected_content) != 0) | 148 if (strcmp(p_resp->body, test->expected_content) != 0) |
| 325 { | 149 { |
| 326 printf(" ✗ Response does not match expected snapshot\n"); | 150 printf(" ✗ Response does not match expected snapshot\n"); |
| 327 printf(" Expected file: %s\n", test->expected_file_path); | 151 printf(" Expected file: %s\n", test->expected_file_path); |
| 328 Seobeo_Handle_Destroy(client); | 152 Seobeo_Client_Response_Destroy(p_resp); |
| 153 Seobeo_Client_Request_Destroy(p_req); | |
| 329 return -1; | 154 return -1; |
| 330 } | 155 } |
| 331 | 156 |
| 332 printf(" ✓ Response matches snapshot (%zu bytes)\n", response_len); | 157 printf(" ✓ Response matches snapshot (%zu bytes)\n", p_resp->body_length); |
| 333 } | 158 } |
| 334 | 159 |
| 335 Seobeo_Handle_Destroy(client); | 160 Seobeo_Client_Response_Destroy(p_resp); |
| 161 Seobeo_Client_Request_Destroy(p_req); | |
| 336 return 0; | 162 return 0; |
| 337 } | 163 } |
| 338 | 164 |
| 339 // Helper: Execute custom request test | 165 int send_post_file(Seobeo_Handle *p_req, const char *path, const char *file_data, size_t file_size) |
| 340 int execute_custom_request_test(const char *name, const char *custom_request, | |
| 341 int expected_status, pid_t server_pid) | |
| 342 { | |
| 343 printf(" Testing: %s (expecting %d)\n", name, expected_status); | |
| 344 | |
| 345 Seobeo_Handle *client = create_test_client(); | |
| 346 if (!client) | |
| 347 { | |
| 348 printf(" ✗ Failed to create client connection\n"); | |
| 349 return -1; | |
| 350 } | |
| 351 | |
| 352 if (send_http_request(client, NULL, custom_request) < 0) | |
| 353 { | |
| 354 printf(" ✗ Failed to send request\n"); | |
| 355 Seobeo_Handle_Destroy(client); | |
| 356 return -1; | |
| 357 } | |
| 358 | |
| 359 char *response = NULL; | |
| 360 size_t response_len = 0; | |
| 361 if (read_http_response(client, &response, &response_len) < 0) | |
| 362 { | |
| 363 printf(" ✗ Failed to read response\n"); | |
| 364 Seobeo_Handle_Destroy(client); | |
| 365 return -1; | |
| 366 } | |
| 367 | |
| 368 int actual_status = parse_http_status(response); | |
| 369 if (actual_status != expected_status) | |
| 370 { | |
| 371 printf(" ✗ Status mismatch: expected %d, got %d\n", | |
| 372 expected_status, actual_status); | |
| 373 free(response); | |
| 374 Seobeo_Handle_Destroy(client); | |
| 375 return -1; | |
| 376 } | |
| 377 | |
| 378 printf(" ✓ Status code: %d\n", actual_status); | |
| 379 printf(" ✓ Response received (%zu bytes)\n", response_len); | |
| 380 | |
| 381 free(response); | |
| 382 Seobeo_Handle_Destroy(client); | |
| 383 return 0; | |
| 384 } | |
| 385 | |
| 386 // Helper: Send POST request with file data | |
| 387 int send_post_file(Seobeo_Handle *client, const char *path, const char *file_data, size_t file_size) | |
| 388 { | 166 { |
| 389 char request_buffer[8192]; | 167 char request_buffer[8192]; |
| 390 int header_len = snprintf( | 168 int header_len = snprintf( |
| 391 request_buffer, sizeof(request_buffer), | 169 request_buffer, sizeof(request_buffer), |
| 392 "POST %s HTTP/1.1\r\n" | 170 "POST %s HTTP/1.1\r\n" |
| 403 fprintf(stderr, "Request header too large\n"); | 181 fprintf(stderr, "Request header too large\n"); |
| 404 return -1; | 182 return -1; |
| 405 } | 183 } |
| 406 | 184 |
| 407 // Send headers | 185 // Send headers |
| 408 Seobeo_Handle_Queue(client, (uint8*)request_buffer, (uint32)header_len); | 186 Seobeo_Handle_Queue(p_req, (uint8*)request_buffer, (uint32)header_len); |
| 409 | 187 |
| 410 // Send file data in chunks if needed | 188 // Send file data in chunks if needed |
| 411 size_t remaining = file_size; | 189 size_t remaining = file_size; |
| 412 const char *ptr = file_data; | 190 const char *ptr = file_data; |
| 413 while (remaining > 0) | 191 while (remaining > 0) |
| 414 { | 192 { |
| 415 size_t chunk_size = remaining > 4096 ? 4096 : remaining; | 193 size_t chunk_size = remaining > 4096 ? 4096 : remaining; |
| 416 Seobeo_Handle_Queue(client, (uint8*)ptr, (uint32)chunk_size); | 194 Seobeo_Handle_Queue(p_req, (uint8*)ptr, (uint32)chunk_size); |
| 417 ptr += chunk_size; | 195 ptr += chunk_size; |
| 418 remaining -= chunk_size; | 196 remaining -= chunk_size; |
| 419 } | 197 } |
| 420 | 198 |
| 421 return Seobeo_Handle_Flush(client); | 199 return Seobeo_Handle_Flush(p_req); |
| 422 } | 200 } |
| 423 | 201 |
| 424 // Helper: Extract JSON field value from response body | |
| 425 char* extract_json_field(const char *json, const char *field, char *buffer, size_t buffer_size) | 202 char* extract_json_field(const char *json, const char *field, char *buffer, size_t buffer_size) |
| 426 { | 203 { |
| 427 char search_pattern[256]; | 204 char search_pattern[256]; |
| 428 snprintf(search_pattern, sizeof(search_pattern), "\"%s\":\"", field); | 205 snprintf(search_pattern, sizeof(search_pattern), "\"%s\":\"", field); |
| 429 | 206 |
| 450 buffer[len] = '\0'; | 227 buffer[len] = '\0'; |
| 451 | 228 |
| 452 return buffer; | 229 return buffer; |
| 453 } | 230 } |
| 454 | 231 |
| 455 // Helper: Test POST file conversion | |
| 456 int test_file_conversion(const char *endpoint, const char *test_file_path, | 232 int test_file_conversion(const char *endpoint, const char *test_file_path, |
| 457 const char *expected_format, pid_t server_pid) | 233 const char *expected_format, pid_t server_pid) |
| 458 { | 234 { |
| 459 printf(" Testing: POST %s\n", endpoint); | 235 printf(" Testing: POST %s\n", endpoint); |
| 460 | 236 |
| 461 // Read test file | 237 // Read test file |
| 462 size_t file_size; | 238 size_t file_size; |
| 463 char *file_data = read_file(test_file_path, &file_size); | 239 char *file_data = read_file(test_file_path, &file_size); |
| 464 if (!file_data) | 240 if (!file_data) { |
| 465 { | |
| 466 printf(" ✗ Failed to read test file: %s\n", test_file_path); | 241 printf(" ✗ Failed to read test file: %s\n", test_file_path); |
| 467 return -1; | 242 return -1; |
| 468 } | 243 } |
| 469 | 244 |
| 470 printf(" → Loaded test file (%zu bytes)\n", file_size); | 245 char url[1024]; |
| 471 | 246 snprintf(url, sizeof(url), "%s%s", TEST_URL, endpoint); |
| 472 // Create client and send request | 247 |
| 473 Seobeo_Handle *client = create_test_client(); | 248 Seobeo_Client_Request *p_req = Seobeo_Client_Request_Create(url); |
| 474 if (!client) | 249 Seobeo_Client_Request_Set_Method(p_req, "POST"); |
| 475 { | 250 Seobeo_Client_Request_Set_Body(p_req, (uint8*)file_data, (uint32)file_size); |
| 476 printf(" ✗ Failed to create client connection\n"); | 251 Seobeo_Client_Request_Add_Header_Array(p_req, "Content-Type: application/octet-stream"); |
| 477 free(file_data); | 252 |
| 478 return -1; | 253 Seobeo_Client_Response *p_resp = Seobeo_Client_Request_Execute(p_req); |
| 479 } | |
| 480 | |
| 481 if (send_post_file(client, endpoint, file_data, file_size) < 0) | |
| 482 { | |
| 483 printf(" ✗ Failed to send POST request\n"); | |
| 484 free(file_data); | |
| 485 Seobeo_Handle_Destroy(client); | |
| 486 return -1; | |
| 487 } | |
| 488 | |
| 489 free(file_data); | 254 free(file_data); |
| 490 | 255 |
| 491 // Read response | 256 if (!p_resp || p_resp->status_code != 200) { |
| 492 char *response = NULL; | 257 printf(" ✗ Conversion failed with status: %d\n", p_resp ? p_resp->status_code : 0); |
| 493 size_t response_len = 0; | 258 if (p_resp) Seobeo_Client_Response_Destroy(p_resp); |
| 494 if (read_http_response(client, &response, &response_len) < 0) | 259 |
| 495 { | 260 Seobeo_Client_Response_Destroy(p_resp); |
| 496 printf(" ✗ Failed to read response\n"); | 261 Seobeo_Client_Request_Destroy(p_req); |
| 497 Seobeo_Handle_Destroy(client); | 262 return -1; |
| 498 return -1; | 263 } |
| 499 } | 264 |
| 500 | 265 // Extract download URL from JSON body |
| 501 Seobeo_Handle_Destroy(client); | 266 char download_url_path[512]; |
| 502 | 267 if (!extract_json_field((char*)p_resp->body, "download_url", download_url_path, sizeof(download_url_path))) { |
| 503 // Parse status | 268 printf(" ✗ Failed to extract download_url\n"); |
| 504 int status = parse_http_status(response); | 269 Seobeo_Client_Response_Destroy(p_resp); |
| 505 if (status != 200) | 270 Seobeo_Client_Request_Destroy(p_req); |
| 506 { | 271 return -1; |
| 507 printf(" ✗ Conversion failed with status: %d\n", status); | 272 } |
| 508 printf(" Response: %s\n", response); | 273 |
| 509 free(response); | 274 printf(" ✓ Conversion succeeded. Download URL: %s\n", download_url_path); |
| 510 return -1; | 275 Seobeo_Client_Response_Destroy(p_resp); |
| 511 } | 276 Seobeo_Client_Request_Destroy(p_req); |
| 512 | 277 |
| 513 printf(" ✓ Status code: 200\n"); | 278 printf(" → Testing download: GET %s\n", download_url_path); |
| 514 | 279 char full_download_url[1024]; |
| 515 // Extract download URL from JSON response | 280 snprintf(full_download_url, sizeof(full_download_url), "%s%s", TEST_URL, download_url_path); |
| 516 const char *body = strstr(response, "\r\n\r\n"); | 281 |
| 517 if (!body) | 282 p_req = Seobeo_Client_Request_Create(full_download_url); |
| 518 { | 283 p_resp = Seobeo_Client_Request_Execute(p_req); |
| 519 printf(" ✗ No response body found\n"); | 284 |
| 520 free(response); | 285 if (!p_resp || p_resp->status_code != 200) |
| 521 return -1; | 286 { |
| 522 } | 287 printf(" ✗ Download failed\n"); |
| 523 body += 4; | 288 if (p_resp) Seobeo_Client_Response_Destroy(p_resp); |
| 524 | 289 Seobeo_Client_Request_Destroy(p_req); |
| 525 char download_url[512]; | 290 return -1; |
| 526 if (!extract_json_field(body, "download_url", download_url, sizeof(download_url))) | 291 } |
| 527 { | 292 |
| 528 printf(" ✗ Failed to extract download_url from response\n"); | 293 printf(" ✓ Downloaded converted file (%u bytes)\n", p_resp->body_length); |
| 529 printf(" Response body: %s\n", body); | 294 |
| 530 free(response); | 295 Seobeo_Client_Response_Destroy(p_resp); |
| 531 return -1; | 296 Seobeo_Client_Request_Destroy(p_req); |
| 532 } | |
| 533 | |
| 534 printf(" ✓ Conversion succeeded\n"); | |
| 535 printf(" ✓ Download URL: %s\n", download_url); | |
| 536 free(response); | |
| 537 | |
| 538 // Test downloading the converted file | |
| 539 printf(" → Testing download: GET %s\n", download_url); | |
| 540 | |
| 541 client = create_test_client(); | |
| 542 if (!client) | |
| 543 { | |
| 544 printf(" ✗ Failed to create client for download\n"); | |
| 545 return -1; | |
| 546 } | |
| 547 | |
| 548 if (send_http_request(client, download_url, NULL) < 0) | |
| 549 { | |
| 550 printf(" ✗ Failed to send download request\n"); | |
| 551 Seobeo_Handle_Destroy(client); | |
| 552 return -1; | |
| 553 } | |
| 554 | |
| 555 response = NULL; | |
| 556 response_len = 0; | |
| 557 if (read_http_response(client, &response, &response_len) < 0) | |
| 558 { | |
| 559 printf(" ✗ Failed to read download response\n"); | |
| 560 Seobeo_Handle_Destroy(client); | |
| 561 return -1; | |
| 562 } | |
| 563 | |
| 564 Seobeo_Handle_Destroy(client); | |
| 565 | |
| 566 status = parse_http_status(response); | |
| 567 if (status != 200) | |
| 568 { | |
| 569 printf(" ✗ Download failed with status: %d\n", status); | |
| 570 free(response); | |
| 571 return -1; | |
| 572 } | |
| 573 | |
| 574 // Find body in download response | |
| 575 body = strstr(response, "\r\n\r\n"); | |
| 576 if (!body) | |
| 577 { | |
| 578 printf(" ✗ No file data in download response\n"); | |
| 579 free(response); | |
| 580 return -1; | |
| 581 } | |
| 582 body += 4; | |
| 583 | |
| 584 size_t downloaded_size = response_len - (body - response); | |
| 585 | |
| 586 // Verify content type in response headers | |
| 587 const char *content_type = strstr(response, "Content-Type: "); | |
| 588 if (!content_type) | |
| 589 { | |
| 590 printf(" ✗ No Content-Type header in download\n"); | |
| 591 free(response); | |
| 592 return -1; | |
| 593 } | |
| 594 | |
| 595 if (strstr(content_type, expected_format) == NULL) | |
| 596 { | |
| 597 printf(" ✗ Wrong content type (expected %s)\n", expected_format); | |
| 598 free(response); | |
| 599 return -1; | |
| 600 } | |
| 601 | |
| 602 printf(" ✓ Downloaded converted file (%zu bytes)\n", downloaded_size); | |
| 603 printf(" ✓ Content-Type: %s\n", expected_format); | |
| 604 | |
| 605 free(response); | |
| 606 return 0; | 297 return 0; |
| 607 } | 298 } |
| 608 | 299 |
| 609 // Helper: Start test server | |
| 610 pid_t start_test_server(const char *server_binary) | 300 pid_t start_test_server(const char *server_binary) |
| 611 { | 301 { |
| 612 pid_t server_pid = fork(); | 302 pid_t server_pid = fork(); |
| 613 | 303 |
| 614 if (server_pid < 0) | 304 if (server_pid < 0) |
| 692 } | 382 } |
| 693 | 383 |
| 694 // Main integration test | 384 // Main integration test |
| 695 int test_server_client_integration(const char *server_binary) | 385 int test_server_client_integration(const char *server_binary) |
| 696 { | 386 { |
| 697 printf("=== Server-Client Integration Test ===\n"); | 387 printf("=== Server-p_req Integration Test ===\n"); |
| 698 printf("MODE: Verifying Against Snapshots\n\n"); | 388 printf("MODE: Verifying Against Snapshots\n\n"); |
| 699 | 389 |
| 700 char cwd[1024]; | 390 char cwd[1024]; |
| 701 if (getcwd(cwd, sizeof(cwd)) != NULL) | 391 if (getcwd(cwd, sizeof(cwd)) != NULL) |
| 702 { | |
| 703 printf("Working directory: %s\n", cwd); | 392 printf("Working directory: %s\n", cwd); |
| 704 } | |
| 705 | 393 |
| 706 if (access(server_binary, X_OK) != 0) | 394 if (access(server_binary, X_OK) != 0) |
| 707 { | 395 { |
| 708 printf("Server binary not found: %s\n", server_binary); | 396 printf("Server binary not found: %s\n", server_binary); |
| 709 perror("access"); | 397 perror("access"); |
| 712 printf("Server binary: %s\n", server_binary); | 400 printf("Server binary: %s\n", server_binary); |
| 713 printf("Snapshot directory: %s\n\n", SNAPSHOT_DIR); | 401 printf("Snapshot directory: %s\n\n", SNAPSHOT_DIR); |
| 714 | 402 |
| 715 pid_t server_pid = start_test_server(server_binary); | 403 pid_t server_pid = start_test_server(server_binary); |
| 716 if (server_pid < 0) | 404 if (server_pid < 0) |
| 717 { | 405 return -1; |
| 718 return -1; | |
| 719 } | |
| 720 | 406 |
| 721 int failed_tests = 0; | 407 int failed_tests = 0; |
| 722 int passed_tests = 0; | 408 int passed_tests = 0; |
| 723 | 409 |
| 724 // Define test cases - paths that should succeed (200 OK) | |
| 725 TestCase success_tests[] = { | 410 TestCase success_tests[] = { |
| 726 {"/", 200, NULL, NULL, NULL, 0}, | 411 {"/", 200, NULL, NULL, NULL, 0}, |
| 727 {"/resume", 200, NULL, NULL, NULL, 0}, | 412 {"/resume", 200, NULL, NULL, NULL, 0}, |
| 728 {"/tools", 200, NULL, NULL, NULL, 0}, | 413 {"/tools", 200, NULL, NULL, NULL, 0}, |
| 729 {"/tools/markdown_to_html", 200, NULL, NULL, NULL, 0}, | 414 {"/tools/markdown_to_html", 200, NULL, NULL, NULL, 0}, |
| 730 {"/tools/file_converter", 200, NULL, NULL, NULL, 0}, | 415 {"/tools/file_converter", 200, NULL, NULL, NULL, 0}, |
| 731 }; | 416 }; |
| 732 int num_success_tests = sizeof(success_tests) / sizeof(success_tests[0]); | 417 int num_success_tests = sizeof(success_tests) / sizeof(success_tests[0]); |
| 733 | 418 |
| 734 // Define test cases - paths that should redirect (301) | |
| 735 TestCase redirect_tests[] = { | 419 TestCase redirect_tests[] = { |
| 736 {"/index.html", 301, NULL, NULL, NULL, 0}, | 420 {"/index.html", 301, NULL, NULL, NULL, 0}, |
| 737 {"/resume/index.html", 301, NULL, NULL, NULL, 0}, | 421 {"/resume/index.html", 301, NULL, NULL, NULL, 0}, |
| 738 {"/tools/index.html", 301, NULL, NULL, NULL, 0}, | 422 {"/tools/index.html", 301, NULL, NULL, NULL, 0}, |
| 739 {"/tools/markdown_to_html/index.html", 301, NULL, NULL, NULL, 0}, | 423 {"/tools/markdown_to_html/index.html", 301, NULL, NULL, NULL, 0}, |
| 740 {"/tools/file_converter/index.html", 301, NULL, NULL, NULL, 0}, | 424 {"/tools/file_converter/index.html", 301, NULL, NULL, NULL, 0}, |
| 741 }; | 425 }; |
| 742 int num_redirect_tests = sizeof(redirect_tests) / sizeof(redirect_tests[0]); | 426 int num_redirect_tests = sizeof(redirect_tests) / sizeof(redirect_tests[0]); |
| 743 | 427 |
| 744 // Define test cases - paths that should fail (404) | |
| 745 TestCase failure_tests[] = { | 428 TestCase failure_tests[] = { |
| 746 {"/nonexistent", 404, NULL, NULL, NULL, 0}, | 429 {"/nonexistent", 404, NULL, NULL, NULL, 0}, |
| 747 {"/does/not/exist", 404, NULL, NULL, NULL, 0}, | 430 {"/does/not/exist", 404, NULL, NULL, NULL, 0}, |
| 748 {"/missing.html", 404, NULL, NULL, NULL, 0}, | 431 {"/missing.html", 404, NULL, NULL, NULL, 0}, |
| 749 }; | 432 }; |
| 750 int num_failure_tests = sizeof(failure_tests) / sizeof(failure_tests[0]); | 433 int num_failure_tests = sizeof(failure_tests) / sizeof(failure_tests[0]); |
| 751 | 434 |
| 752 // Initialize all test cases | |
| 753 for (int i = 0; i < num_success_tests; i++) | 435 for (int i = 0; i < num_success_tests; i++) |
| 754 { | |
| 755 init_test_case(&success_tests[i]); | 436 init_test_case(&success_tests[i]); |
| 756 } | 437 |
| 757 for (int i = 0; i < num_redirect_tests; i++) | 438 for (int i = 0; i < num_redirect_tests; i++) |
| 758 { | |
| 759 init_test_case(&redirect_tests[i]); | 439 init_test_case(&redirect_tests[i]); |
| 760 } | 440 |
| 761 for (int i = 0; i < num_failure_tests; i++) | 441 for (int i = 0; i < num_failure_tests; i++) |
| 762 { | |
| 763 init_test_case(&failure_tests[i]); | 442 init_test_case(&failure_tests[i]); |
| 764 } | 443 |
| 765 | |
| 766 // Run success tests | |
| 767 printf("Running tests for paths that should succeed:\n"); | 444 printf("Running tests for paths that should succeed:\n"); |
| 768 for (int i = 0; i < num_success_tests; i++) | 445 for (int i = 0; i < num_success_tests; i++) |
| 769 { | 446 { |
| 770 if (execute_test_case(&success_tests[i], server_pid) == 0) | 447 if (execute_test_case(&success_tests[i], server_pid) == 0) |
| 771 { | |
| 772 passed_tests++; | 448 passed_tests++; |
| 773 } | |
| 774 else | 449 else |
| 775 { | |
| 776 failed_tests++; | 450 failed_tests++; |
| 777 } | |
| 778 } | 451 } |
| 779 | 452 |
| 780 printf("\n"); | 453 printf("\n"); |
| 781 | 454 |
| 782 // Run redirect tests | |
| 783 printf("Running tests for paths that should redirect:\n"); | 455 printf("Running tests for paths that should redirect:\n"); |
| 784 for (int i = 0; i < num_redirect_tests; i++) | 456 for (int i = 0; i < num_redirect_tests; i++) |
| 785 { | 457 { |
| 786 if (execute_test_case(&redirect_tests[i], server_pid) == 0) | 458 if (execute_test_case(&redirect_tests[i], server_pid) == 0) |
| 787 { | |
| 788 passed_tests++; | 459 passed_tests++; |
| 789 } | |
| 790 else | 460 else |
| 791 { | |
| 792 failed_tests++; | 461 failed_tests++; |
| 793 } | |
| 794 } | 462 } |
| 795 | 463 |
| 796 printf("\n"); | 464 printf("\n"); |
| 797 | 465 |
| 798 // Run failure tests | |
| 799 printf("Running tests for paths that should fail:\n"); | 466 printf("Running tests for paths that should fail:\n"); |
| 800 for (int i = 0; i < num_failure_tests; i++) | 467 for (int i = 0; i < num_failure_tests; i++) |
| 801 { | 468 { |
| 802 if (execute_test_case(&failure_tests[i], server_pid) == 0) | 469 if (execute_test_case(&failure_tests[i], server_pid) == 0) |
| 803 { | |
| 804 passed_tests++; | 470 passed_tests++; |
| 805 } | |
| 806 else | 471 else |
| 807 { | |
| 808 failed_tests++; | 472 failed_tests++; |
| 809 } | |
| 810 } | 473 } |
| 811 | 474 |
| 812 printf("\n"); | 475 printf("\n"); |
| 813 | 476 |
| 814 // Test with custom request | |
| 815 printf("Running tests with custom requests:\n"); | |
| 816 char custom_request[4096]; | |
| 817 snprintf(custom_request, sizeof(custom_request), | |
| 818 "GET / HTTP/1.1\r\n" | |
| 819 "Host: %s\r\n" | |
| 820 "Connection: close\r\n" | |
| 821 "X-Custom-Header: TestValue\r\n" | |
| 822 "\r\n", | |
| 823 TEST_HOST); | |
| 824 | |
| 825 if (execute_custom_request_test("Custom headers GET /", custom_request, 200, server_pid) == 0) | |
| 826 { | |
| 827 passed_tests++; | |
| 828 } | |
| 829 else | |
| 830 { | |
| 831 failed_tests++; | |
| 832 } | |
| 833 | |
| 834 printf("\n"); | |
| 835 | |
| 836 // Test POST endpoints | |
| 837 printf("Running tests for POST conversion endpoints:\n"); | 477 printf("Running tests for POST conversion endpoints:\n"); |
| 838 | |
| 839 // Test image-to-webp conversion | |
| 840 if (test_file_conversion("/api/convert/image-to-webp", | 478 if (test_file_conversion("/api/convert/image-to-webp", |
| 841 "mrjunejune/test/shiba.webp", | 479 "mrjunejune/test/shiba.webp", |
| 842 "image/webp", | 480 "image/webp", |
| 843 server_pid) == 0) | 481 server_pid) == 0) |
| 844 { | |
| 845 passed_tests++; | 482 passed_tests++; |
| 846 } | |
| 847 else | 483 else |
| 848 { | |
| 849 failed_tests++; | 484 failed_tests++; |
| 850 } | |
| 851 | 485 |
| 852 printf("\n"); | 486 printf("\n"); |
| 853 | 487 |
| 854 // Test video-to-mp4 conversion | |
| 855 if (test_file_conversion("/api/convert/video-to-mp4", | 488 if (test_file_conversion("/api/convert/video-to-mp4", |
| 856 "mrjunejune/test/test_avi.avi", | 489 "mrjunejune/test/test_avi.avi", |
| 857 "video/mp4", | 490 "video/mp4", |
| 858 server_pid) == 0) | 491 server_pid) == 0) |
| 859 { | |
| 860 passed_tests++; | 492 passed_tests++; |
| 861 } | |
| 862 else | 493 else |
| 863 { | |
| 864 failed_tests++; | 494 failed_tests++; |
| 865 } | 495 |
| 866 | |
| 867 // Cleanup test cases | |
| 868 for (int i = 0; i < num_success_tests; i++) | 496 for (int i = 0; i < num_success_tests; i++) |
| 869 { | |
| 870 cleanup_test_case(&success_tests[i]); | 497 cleanup_test_case(&success_tests[i]); |
| 871 } | |
| 872 for (int i = 0; i < num_redirect_tests; i++) | 498 for (int i = 0; i < num_redirect_tests; i++) |
| 873 { | |
| 874 cleanup_test_case(&redirect_tests[i]); | 499 cleanup_test_case(&redirect_tests[i]); |
| 875 } | |
| 876 for (int i = 0; i < num_failure_tests; i++) | 500 for (int i = 0; i < num_failure_tests; i++) |
| 877 { | |
| 878 cleanup_test_case(&failure_tests[i]); | 501 cleanup_test_case(&failure_tests[i]); |
| 879 } | |
| 880 | 502 |
| 881 stop_test_server(server_pid); | 503 stop_test_server(server_pid); |
| 882 | 504 |
| 883 printf("\n=== Test Summary ===\n"); | 505 printf("\n=== Test Summary ===\n"); |
| 884 printf("Passed: %d\n", passed_tests); | 506 printf("Passed: %d\n", passed_tests); |
| 891 { | 513 { |
| 892 printf("=== Seobeo Integration Tests ===\n\n"); | 514 printf("=== Seobeo Integration Tests ===\n\n"); |
| 893 | 515 |
| 894 const char *server_binary = "./mrjunejune_server"; | 516 const char *server_binary = "./mrjunejune_server"; |
| 895 if (argc > 1) | 517 if (argc > 1) |
| 896 { | |
| 897 server_binary = argv[1]; | 518 server_binary = argv[1]; |
| 898 } | |
| 899 | 519 |
| 900 int result = test_server_client_integration(server_binary); | 520 int result = test_server_client_integration(server_binary); |
| 901 | 521 |
| 902 if (result == 0) | 522 if (result == 0) |
| 903 { | |
| 904 printf("\n✓ All tests passed!\n"); | 523 printf("\n✓ All tests passed!\n"); |
| 905 } | |
| 906 else | 524 else |
| 907 { | |
| 908 printf("\n✗ Some tests failed\n"); | 525 printf("\n✗ Some tests failed\n"); |
| 909 } | |
| 910 | 526 |
| 911 return result; | 527 return result; |
| 912 } | 528 } |