view s3/tests/s3_uploader_test.c @ 205:e07b4b5a66bb

Bad named files.
author MrJuneJune <me@mrjunejune.com>
date Sun, 15 Feb 2026 11:07:52 -0800
parents 008ca7780c8a
children
line wrap: on
line source

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