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