Mercurial
diff s3/tests/s3_uploader_test.c @ 231:09a96dcb2b4c hg-web
[merge] Join existing hg-web branch head
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Sun, 02 Aug 2026 16:50:48 -0700 |
| parents | 008ca7780c8a |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/s3/tests/s3_uploader_test.c Sun Aug 02 16:50:48 2026 -0700 @@ -0,0 +1,192 @@ +#include "s3/s3_uploader.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// Simple .env parser +static char *parse_env_value(const char *env_content, const char *key) +{ + const char *pos = strstr(env_content, key); + if (!pos) return NULL; + + pos += strlen(key); + if (*pos != '=') return NULL; + pos++; + + const char *end = pos; + while (*end && *end != '\n' && *end != '\r') end++; + + size_t len = end - pos; + char *value = malloc(len + 1); + memcpy(value, pos, len); + value[len] = '\0'; + return value; +} + +static char *load_file(const char *path) +{ + FILE *f = fopen(path, "r"); + if (!f) return NULL; + + fseek(f, 0, SEEK_END); + long size = ftell(f); + fseek(f, 0, SEEK_SET); + + char *content = malloc(size + 1); + fread(content, 1, size, f); + content[size] = '\0'; + fclose(f); + return content; +} + +int main(int argc, char **argv) +{ + // Try to load .env file - check multiple locations for bazel runfiles + char *env_content = load_file(".env"); + if (!env_content) + { + env_content = load_file("zenbu/.env"); // bazel runfiles path + } + if (!env_content) + { + env_content = load_file("../.env"); + } + if (!env_content) + { + env_content = load_file("../../.env"); + } + + char *access_key = NULL; + char *secret_key = NULL; + + if (env_content) + { + access_key = parse_env_value(env_content, "AWS_MRJUNEJUNE_ACCESS_KEY"); + secret_key = parse_env_value(env_content, "AWS_MRJUNEJUNE_SECRET_ACCESS_KEY"); + free(env_content); + } + + // Fall back to environment variables + if (!access_key) access_key = getenv("AWS_ACCESS_KEY_ID") ? strdup(getenv("AWS_ACCESS_KEY_ID")) : NULL; + if (!secret_key) secret_key = getenv("AWS_SECRET_ACCESS_KEY") ? strdup(getenv("AWS_SECRET_ACCESS_KEY")) : NULL; + + if (!access_key || !secret_key) + { + printf("Missing credentials. Set in .env file or environment:\n"); + printf(" AWS_MRJUNEJUNE_ACCESS_KEY / AWS_ACCESS_KEY_ID\n"); + printf(" AWS_MRJUNEJUNE_SECRET_ACCESS_KEY / AWS_SECRET_ACCESS_KEY\n"); + return 1; + } + + S3_Config config = { + .access_key_id = access_key, + .secret_access_key = secret_key, + .region = "us-west-2", + .bucket = "mrjunejune", + .endpoint = NULL, + .use_path_style = FALSE + }; + + printf("S3 Uploader Test\n"); + printf("================\n"); + printf("Region: %s\n", config.region); + printf("Bucket: %s\n", config.bucket); + printf("\n"); + + // Test 1: Upload string data + printf("Test 1: Uploading string data...\n"); + const char *test_data = "Hello from S3 uploader test!"; + S3_Result result = S3_Upload_Data(&config, + (const uint8 *)test_data, + strlen(test_data), + "test/hello.txt", + "text/plain"); + if (result.success) + { + printf(" SUCCESS! ETag: %s\n", result.etag ? result.etag : "(none)"); + } + else + { + printf(" FAILED! Status: %d, Error: %s\n", + result.status_code, + result.error_message ? result.error_message : "(unknown)"); + } + S3_Result_Destroy(&result); + + // Test 2: Content type detection + printf("\nTest 2: Content type detection...\n"); + printf(" .html -> %s\n", S3_Guess_Content_Type("page.html")); + printf(" .png -> %s\n", S3_Guess_Content_Type("image.png")); + printf(" .json -> %s\n", S3_Guess_Content_Type("data.json")); + printf(" .xyz -> %s\n", S3_Guess_Content_Type("unknown.xyz")); + + // Test 3: Generate presigned PUT URL + printf("\nTest 3: Generating presigned PUT URL...\n"); + S3_Presigned_URL put_url = S3_Presign_Put(&config, + "uploads/client-upload.png", + "image/png", + 3600); // 1 hour + if (put_url.success) + { + printf(" SUCCESS!\n"); + printf(" URL: %s\n", put_url.url); + printf("\n Client can upload with:\n"); + printf(" curl -X PUT -H \"Content-Type: image/png\" --data-binary @file.png \"$URL\"\n"); + } + else + { + printf(" FAILED! Error: %s\n", put_url.error_message ? put_url.error_message : "(unknown)"); + } + S3_Presigned_URL_Destroy(&put_url); + + // Test 4: Generate presigned GET URL + printf("\nTest 4: Generating presigned GET URL...\n"); + S3_Presigned_URL get_url = S3_Presign_Get(&config, + "uploads/client-upload.png", + 3600); // 1 hour + if (get_url.success) + { + printf(" SUCCESS!\n"); + printf(" URL: %s\n", get_url.url); + printf("\n Client can download with:\n"); + printf(" curl \"$URL\" -o file.png\n"); + } + else + { + printf(" FAILED! Error: %s\n", get_url.error_message ? get_url.error_message : "(unknown)"); + } + S3_Presigned_URL_Destroy(&get_url); + + // Test 5: Upload file (if provided as argument) + if (argc >= 3) + { + printf("\nTest 5: Uploading file...\n"); + printf(" Local: %s\n", argv[1]); + printf(" S3 Key: %s\n", argv[2]); + + result = S3_Upload_File(&config, argv[1], argv[2]); + if (result.success) + { + printf(" SUCCESS! ETag: %s\n", result.etag ? result.etag : "(none)"); + } + else + { + printf(" FAILED! Status: %d, Error: %s\n", + result.status_code, + result.error_message ? result.error_message : "(unknown)"); + } + S3_Result_Destroy(&result); + } + else + { + printf("\nTest 5: Skipped (no file path provided)\n"); + printf(" Usage: %s <local_file> <s3_key>\n", argv[0]); + } + + printf("\nDone!\n"); + + free(access_key); + free(secret_key); + return 0; +}