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 }