Mercurial
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 217:7ef4c9d2a72d | 231:09a96dcb2b4c |
|---|---|
| 1 #include "s3/s3_uploader.h" | |
| 2 | |
| 3 #include <stdio.h> | |
| 4 #include <stdlib.h> | |
| 5 #include <string.h> | |
| 6 | |
| 7 // Simple .env parser | |
| 8 static char *parse_env_value(const char *env_content, const char *key) | |
| 9 { | |
| 10 const char *pos = strstr(env_content, key); | |
| 11 if (!pos) return NULL; | |
| 12 | |
| 13 pos += strlen(key); | |
| 14 if (*pos != '=') return NULL; | |
| 15 pos++; | |
| 16 | |
| 17 const char *end = pos; | |
| 18 while (*end && *end != '\n' && *end != '\r') end++; | |
| 19 | |
| 20 size_t len = end - pos; | |
| 21 char *value = malloc(len + 1); | |
| 22 memcpy(value, pos, len); | |
| 23 value[len] = '\0'; | |
| 24 return value; | |
| 25 } | |
| 26 | |
| 27 static char *load_file(const char *path) | |
| 28 { | |
| 29 FILE *f = fopen(path, "r"); | |
| 30 if (!f) return NULL; | |
| 31 | |
| 32 fseek(f, 0, SEEK_END); | |
| 33 long size = ftell(f); | |
| 34 fseek(f, 0, SEEK_SET); | |
| 35 | |
| 36 char *content = malloc(size + 1); | |
| 37 fread(content, 1, size, f); | |
| 38 content[size] = '\0'; | |
| 39 fclose(f); | |
| 40 return content; | |
| 41 } | |
| 42 | |
| 43 int main(int argc, char **argv) | |
| 44 { | |
| 45 // Try to load .env file - check multiple locations for bazel runfiles | |
| 46 char *env_content = load_file(".env"); | |
| 47 if (!env_content) | |
| 48 { | |
| 49 env_content = load_file("zenbu/.env"); // bazel runfiles path | |
| 50 } | |
| 51 if (!env_content) | |
| 52 { | |
| 53 env_content = load_file("../.env"); | |
| 54 } | |
| 55 if (!env_content) | |
| 56 { | |
| 57 env_content = load_file("../../.env"); | |
| 58 } | |
| 59 | |
| 60 char *access_key = NULL; | |
| 61 char *secret_key = NULL; | |
| 62 | |
| 63 if (env_content) | |
| 64 { | |
| 65 access_key = parse_env_value(env_content, "AWS_MRJUNEJUNE_ACCESS_KEY"); | |
| 66 secret_key = parse_env_value(env_content, "AWS_MRJUNEJUNE_SECRET_ACCESS_KEY"); | |
| 67 free(env_content); | |
| 68 } | |
| 69 | |
| 70 // Fall back to environment variables | |
| 71 if (!access_key) access_key = getenv("AWS_ACCESS_KEY_ID") ? strdup(getenv("AWS_ACCESS_KEY_ID")) : NULL; | |
| 72 if (!secret_key) secret_key = getenv("AWS_SECRET_ACCESS_KEY") ? strdup(getenv("AWS_SECRET_ACCESS_KEY")) : NULL; | |
| 73 | |
| 74 if (!access_key || !secret_key) | |
| 75 { | |
| 76 printf("Missing credentials. Set in .env file or environment:\n"); | |
| 77 printf(" AWS_MRJUNEJUNE_ACCESS_KEY / AWS_ACCESS_KEY_ID\n"); | |
| 78 printf(" AWS_MRJUNEJUNE_SECRET_ACCESS_KEY / AWS_SECRET_ACCESS_KEY\n"); | |
| 79 return 1; | |
| 80 } | |
| 81 | |
| 82 S3_Config config = { | |
| 83 .access_key_id = access_key, | |
| 84 .secret_access_key = secret_key, | |
| 85 .region = "us-west-2", | |
| 86 .bucket = "mrjunejune", | |
| 87 .endpoint = NULL, | |
| 88 .use_path_style = FALSE | |
| 89 }; | |
| 90 | |
| 91 printf("S3 Uploader Test\n"); | |
| 92 printf("================\n"); | |
| 93 printf("Region: %s\n", config.region); | |
| 94 printf("Bucket: %s\n", config.bucket); | |
| 95 printf("\n"); | |
| 96 | |
| 97 // Test 1: Upload string data | |
| 98 printf("Test 1: Uploading string data...\n"); | |
| 99 const char *test_data = "Hello from S3 uploader test!"; | |
| 100 S3_Result result = S3_Upload_Data(&config, | |
| 101 (const uint8 *)test_data, | |
| 102 strlen(test_data), | |
| 103 "test/hello.txt", | |
| 104 "text/plain"); | |
| 105 if (result.success) | |
| 106 { | |
| 107 printf(" SUCCESS! ETag: %s\n", result.etag ? result.etag : "(none)"); | |
| 108 } | |
| 109 else | |
| 110 { | |
| 111 printf(" FAILED! Status: %d, Error: %s\n", | |
| 112 result.status_code, | |
| 113 result.error_message ? result.error_message : "(unknown)"); | |
| 114 } | |
| 115 S3_Result_Destroy(&result); | |
| 116 | |
| 117 // Test 2: Content type detection | |
| 118 printf("\nTest 2: Content type detection...\n"); | |
| 119 printf(" .html -> %s\n", S3_Guess_Content_Type("page.html")); | |
| 120 printf(" .png -> %s\n", S3_Guess_Content_Type("image.png")); | |
| 121 printf(" .json -> %s\n", S3_Guess_Content_Type("data.json")); | |
| 122 printf(" .xyz -> %s\n", S3_Guess_Content_Type("unknown.xyz")); | |
| 123 | |
| 124 // Test 3: Generate presigned PUT URL | |
| 125 printf("\nTest 3: Generating presigned PUT URL...\n"); | |
| 126 S3_Presigned_URL put_url = S3_Presign_Put(&config, | |
| 127 "uploads/client-upload.png", | |
| 128 "image/png", | |
| 129 3600); // 1 hour | |
| 130 if (put_url.success) | |
| 131 { | |
| 132 printf(" SUCCESS!\n"); | |
| 133 printf(" URL: %s\n", put_url.url); | |
| 134 printf("\n Client can upload with:\n"); | |
| 135 printf(" curl -X PUT -H \"Content-Type: image/png\" --data-binary @file.png \"$URL\"\n"); | |
| 136 } | |
| 137 else | |
| 138 { | |
| 139 printf(" FAILED! Error: %s\n", put_url.error_message ? put_url.error_message : "(unknown)"); | |
| 140 } | |
| 141 S3_Presigned_URL_Destroy(&put_url); | |
| 142 | |
| 143 // Test 4: Generate presigned GET URL | |
| 144 printf("\nTest 4: Generating presigned GET URL...\n"); | |
| 145 S3_Presigned_URL get_url = S3_Presign_Get(&config, | |
| 146 "uploads/client-upload.png", | |
| 147 3600); // 1 hour | |
| 148 if (get_url.success) | |
| 149 { | |
| 150 printf(" SUCCESS!\n"); | |
| 151 printf(" URL: %s\n", get_url.url); | |
| 152 printf("\n Client can download with:\n"); | |
| 153 printf(" curl \"$URL\" -o file.png\n"); | |
| 154 } | |
| 155 else | |
| 156 { | |
| 157 printf(" FAILED! Error: %s\n", get_url.error_message ? get_url.error_message : "(unknown)"); | |
| 158 } | |
| 159 S3_Presigned_URL_Destroy(&get_url); | |
| 160 | |
| 161 // Test 5: Upload file (if provided as argument) | |
| 162 if (argc >= 3) | |
| 163 { | |
| 164 printf("\nTest 5: Uploading file...\n"); | |
| 165 printf(" Local: %s\n", argv[1]); | |
| 166 printf(" S3 Key: %s\n", argv[2]); | |
| 167 | |
| 168 result = S3_Upload_File(&config, argv[1], argv[2]); | |
| 169 if (result.success) | |
| 170 { | |
| 171 printf(" SUCCESS! ETag: %s\n", result.etag ? result.etag : "(none)"); | |
| 172 } | |
| 173 else | |
| 174 { | |
| 175 printf(" FAILED! Status: %d, Error: %s\n", | |
| 176 result.status_code, | |
| 177 result.error_message ? result.error_message : "(unknown)"); | |
| 178 } | |
| 179 S3_Result_Destroy(&result); | |
| 180 } | |
| 181 else | |
| 182 { | |
| 183 printf("\nTest 5: Skipped (no file path provided)\n"); | |
| 184 printf(" Usage: %s <local_file> <s3_key>\n", argv[0]); | |
| 185 } | |
| 186 | |
| 187 printf("\nDone!\n"); | |
| 188 | |
| 189 free(access_key); | |
| 190 free(secret_key); | |
| 191 return 0; | |
| 192 } |