Browse Source

more PR corrections

test/local-setup
Silberengel 3 weeks ago
parent
commit
596d56dafa
  1. 26
      README.md
  2. 10
      config/runtime.exs
  3. 7
      config/test.exs
  4. 240
      setup.sh

26
README.md

@ -17,16 +17,17 @@ A Nostr index relay built with Phoenix 1.8 / Elixir. Stores and serves Nostr eve
### Automated setup ### Automated setup
Run the setup script — it installs Erlang/Elixir via asdf, starts the Apache AGE database container, and runs `mix setup`: Run the setup script — on Debian/Ubuntu it installs Erlang/Elixir from **Team RabbitMQ’s apt repositories** ([Elixir install guide](https://elixir-lang.org/install.html)); on Fedora/RHEL it uses **asdf**. It starts the Apache AGE database container and runs `mix setup`:
```bash ```bash
chmod +x setup.sh chmod +x setup.sh
./setup.sh ./setup.sh
``` ```
After setup, database credentials are written to `.env`. Source it before running any `mix` commands: After setup, database credentials are written to `.env` (including `REQUIRE_DB=true` for integration tests). Source it before running `mix` tasks that need the DB or asdf’s `mix` in a new terminal:
```bash ```bash
source "$HOME/.asdf/asdf.sh" # if `mix` is not found
source .env source .env
``` ```
@ -53,6 +54,7 @@ export POSTGRES_PORT=5455
export POSTGRES_USER=postgres export POSTGRES_USER=postgres
export POSTGRES_PASSWORD=postgres export POSTGRES_PASSWORD=postgres
export POSTGRES_DB=gc_index_relay_dev export POSTGRES_DB=gc_index_relay_dev
export REQUIRE_DB=true
mix setup mix setup
``` ```
@ -60,24 +62,12 @@ mix setup
### Starting the server ### Starting the server
```bash ```bash
source "$HOME/.asdf/asdf.sh" # if needed
source .env source .env
mix phx.server mix phx.server
``` ```
The relay is available at [http://localhost:4000](http://localhost:4000). After edits to `config/config.exs`, `config/dev.exs`, or `config/runtime.exs`, restart the server manually; other code is hot-reloaded. The relay listens on port **4000** by default (see `PORT` in `config/runtime.exs`). Open [http://localhost:4000](http://localhost:4000). After edits to `config/config.exs`, `config/dev.exs`, or `config/runtime.exs`, restart the server manually; other code is hot-reloaded.
## API
| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/api` | List available endpoints |
| `GET` | `/api/events` | Query events via URL params (`since`, `until`, `limit` required) |
| `POST` | `/api/events/filter` | Query events with a NIP-01 filter body (`limit` required) |
| `GET` | `/api/events/:id` | Fetch a single event by ID |
| `POST` | `/api/events` | Publish a new event |
| `DELETE` | `/api/events/:id` | Delete an event by ID |
| `GET` | `/api/swagger` | Swagger UI |
| `GET` | `/health` | Health check |
### NIP-11 relay info ### NIP-11 relay info
@ -95,13 +85,15 @@ Unit tests (no database required):
mix test.unit mix test.unit
``` ```
Integration tests (requires the database to be running): Integration tests (requires the database to be running). You must have `REQUIRE_DB=true` (included in `.env` from `setup.sh`) so the Repo starts under test:
```bash ```bash
source .env source .env
mix test.integration mix test.integration
``` ```
Without `.env`: `REQUIRE_DB=true mix test.integration`
Run the full integration probe against the relay API (covers all endpoints, CORS, NIP-11, NIP-70): Run the full integration probe against the relay API (covers all endpoints, CORS, NIP-11, NIP-70):
```bash ```bash

10
config/runtime.exs

@ -23,12 +23,14 @@ end
config :gc_index_relay, GcIndexRelayWeb.Endpoint, config :gc_index_relay, GcIndexRelayWeb.Endpoint,
http: [port: String.to_integer(System.get_env("PORT", "4000"))] http: [port: String.to_integer(System.get_env("PORT", "4000"))]
# Defaults match setup.sh / .env.example (Apache AGE on host port 5455). Production
# replaces this with DATABASE_URL in the block below.
config :gc_index_relay, GcIndexRelay.Repo, config :gc_index_relay, GcIndexRelay.Repo,
hostname: System.get_env("POSTGRES_HOST") || "localhost", hostname: System.get_env("POSTGRES_HOST") || "localhost",
port: String.to_integer(System.get_env("POSTGRES_PORT") || "5432"), port: String.to_integer(System.get_env("POSTGRES_PORT") || "5455"),
username: System.get_env("POSTGRES_USER"), username: System.get_env("POSTGRES_USER") || "postgres",
password: System.get_env("POSTGRES_PASSWORD"), password: System.get_env("POSTGRES_PASSWORD") || "postgres",
database: System.get_env("POSTGRES_DB") database: System.get_env("POSTGRES_DB") || "gc_index_relay_dev"
if config_env() == :prod do if config_env() == :prod do
database_url = database_url =

7
config/test.exs

@ -8,9 +8,10 @@ config :gc_index_relay, :start_repo, System.get_env("REQUIRE_DB") == "true"
# to provide built-in test partitioning in CI environment. # to provide built-in test partitioning in CI environment.
# Run `mix help test` for more information. # Run `mix help test` for more information.
config :gc_index_relay, GcIndexRelay.Repo, config :gc_index_relay, GcIndexRelay.Repo,
username: System.get_env("POSTGRES_USER"), username: System.get_env("POSTGRES_USER", "postgres"),
password: System.get_env("POSTGRES_PASSWORD"), password: System.get_env("POSTGRES_PASSWORD", "postgres"),
database: "#{System.get_env("POSTGRES_DB")}#{System.get_env("MIX_TEST_PARTITION")}", database:
"#{System.get_env("POSTGRES_DB", "gc_index_relay_dev")}#{System.get_env("MIX_TEST_PARTITION")}",
hostname: System.get_env("POSTGRES_HOST", "localhost"), hostname: System.get_env("POSTGRES_HOST", "localhost"),
port: String.to_integer(System.get_env("POSTGRES_PORT", "5455")), port: String.to_integer(System.get_env("POSTGRES_PORT", "5455")),
show_sensitive_data_on_connection_error: true, show_sensitive_data_on_connection_error: true,

240
setup.sh

@ -7,6 +7,10 @@
# - Docker must already be installed (https://docs.docker.com/engine/install/) # - Docker must already be installed (https://docs.docker.com/engine/install/)
# - sudo access to install OS packages (apt-get on Debian/Ubuntu, dnf/yum on Fedora/RHEL) # - sudo access to install OS packages (apt-get on Debian/Ubuntu, dnf/yum on Fedora/RHEL)
# #
# Debian / Ubuntu: Erlang + Elixir are installed from Team RabbitMQ’s apt repositories, as
# recommended on https://elixir-lang.org/install.html (Launchpad PPA on Ubuntu; Cloudsmith
# erlang debs on Debian amd64). Fedora/RHEL still use asdf-compiled Erlang.
#
# Usage: # Usage:
# chmod +x setup.sh # chmod +x setup.sh
# ./setup.sh # ./setup.sh
@ -51,6 +55,88 @@ require_cmd() {
command -v "$1" &>/dev/null || err "'$1' is not installed or not on PATH. $2" command -v "$1" &>/dev/null || err "'$1' is not installed or not on PATH. $2"
} }
# Install modern Erlang + Elixir via RabbitMQ-maintained apt repos (Elixir install docs).
# Returns 0 on success, 1 to fall back to asdf.
install_elixir_erlang_via_rabbitmq_apt() {
local id version
[ -f /etc/os-release ] || return 1
# shellcheck source=/dev/null
. /etc/os-release
id="${ID:-}"
version="${VERSION_CODENAME:-}"
if [ "$id" = "linuxmint" ]; then
version="${UBUNTU_CODENAME:-$version}"
fi
case "$id" in
ubuntu | pop | linuxmint)
log "Installing Erlang + Elixir via RabbitMQ Erlang PPA (https://elixir-lang.org/install.html)..."
sudo apt-get install -y software-properties-common
sudo add-apt-repository -y ppa:rabbitmq/rabbitmq-erlang
sudo apt-get update -qq
sudo apt-get install -y git elixir erlang
;;
debian)
if [ "$(uname -m)" != "x86_64" ]; then
warn "RabbitMQ Cloudsmith Erlang packages are amd64-only; use asdf on this architecture."
return 1
fi
case "$version" in
bullseye | bookworm | trixie)
log "Installing Erlang via Team RabbitMQ apt + elixir (Debian ${version}; https://www.rabbitmq.com/docs/install-debian)..."
sudo apt-get install -y curl gnupg apt-transport-https
curl -1sLf "https://keys.openpgp.org/vks/v1/by-fingerprint/0A9AF2115F4687BD29803A206B73A36E6026DFCA" |
sudo gpg --dearmor | sudo tee /usr/share/keyrings/com.rabbitmq.team.gpg >/dev/null
sudo tee /etc/apt/sources.list.d/rabbitmq-erlang.list >/dev/null <<EOF
deb [arch=amd64 signed-by=/usr/share/keyrings/com.rabbitmq.team.gpg] https://deb1.rabbitmq.com/rabbitmq-erlang/debian/${version} ${version} main
deb [arch=amd64 signed-by=/usr/share/keyrings/com.rabbitmq.team.gpg] https://deb2.rabbitmq.com/rabbitmq-erlang/debian/${version} ${version} main
EOF
sudo apt-get update -qq
sudo apt-get install -y \
erlang-base \
erlang-asn1 \
erlang-crypto \
erlang-eldap \
erlang-ftp \
erlang-inets \
erlang-mnesia \
erlang-os-mon \
erlang-parsetools \
erlang-public-key \
erlang-runtime-tools \
erlang-snmp \
erlang-ssl \
erlang-syntax-tools \
erlang-tftp \
erlang-tools \
erlang-xmerl
sudo apt-get install -y git elixir
;;
*)
warn "Debian ${version:-unknown} not supported for RabbitMQ Erlang apt (expected bullseye, bookworm, or trixie)."
return 1
;;
esac
;;
*)
return 1
;;
esac
hash -r
if ! command -v elixir &>/dev/null; then
warn "elixir not found on PATH after apt install."
return 1
fi
if ! elixir --version 2>/dev/null | grep -qE 'Elixir 1\.(1[5-9]|[2-9][0-9])'; then
warn "Elixir from apt is below 1.15; falling back to asdf."
return 1
fi
log "$(elixir --version 2>/dev/null | grep Elixir || true)"
return 0
}
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# 1. Pre-flight checks # 1. Pre-flight checks
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@ -111,65 +197,81 @@ else
fi fi
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# 3. asdf version manager # 2b. Erlang + Elixir (apt on Debian/Ubuntu via RabbitMQ repos, else asdf)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
if [ ! -d "$ASDF_DIR" ]; then ELIXIR_FROM_APT=0
log "Installing asdf $ASDF_VERSION..." if command -v apt-get &>/dev/null; then
git clone https://github.com/asdf-vm/asdf.git "$ASDF_DIR" --branch "$ASDF_VERSION" if install_elixir_erlang_via_rabbitmq_apt; then
else ELIXIR_FROM_APT=1
log "asdf already installed at $ASDF_DIR" log "Using apt-installed Erlang/Elixir (no asdf Erlang/Elixir steps)."
else
warn "RabbitMQ apt path skipped or failed — installing Erlang/Elixir with asdf."
fi
fi fi
# Source asdf for this script session if [ "$ELIXIR_FROM_APT" -eq 0 ]; then
# shellcheck source=/dev/null # ---------------------------------------------------------------------------
source "$ASDF_DIR/asdf.sh" # 3. asdf version manager
# ---------------------------------------------------------------------------
# Persist asdf sourcing to the user's shell rc (idempotent)
add_asdf_to_rc() {
local rc="$1"
local line='. "$HOME/.asdf/asdf.sh"'
if [ -f "$rc" ] && ! grep -qF 'asdf/asdf.sh' "$rc"; then
echo "" >> "$rc"
echo "# asdf version manager" >> "$rc"
echo "$line" >> "$rc"
log "Added asdf to $rc (will take effect in new shells)"
fi
}
add_asdf_to_rc "$HOME/.bashrc"
add_asdf_to_rc "$HOME/.zshrc" 2>/dev/null || true
# --------------------------------------------------------------------------- if [ ! -d "$ASDF_DIR" ]; then
# 4. Erlang log "Installing asdf $ASDF_VERSION..."
# --------------------------------------------------------------------------- git clone https://github.com/asdf-vm/asdf.git "$ASDF_DIR" --branch "$ASDF_VERSION"
else
log "asdf already installed at $ASDF_DIR"
fi
asdf plugin add erlang 2>/dev/null || true # shellcheck source=/dev/null
source "$ASDF_DIR/asdf.sh"
add_asdf_to_rc() {
local rc="$1"
local line='. "$HOME/.asdf/asdf.sh"'
if [ -f "$rc" ] && ! grep -qF 'asdf/asdf.sh' "$rc"; then
echo "" >> "$rc"
echo "# asdf version manager" >> "$rc"
echo "$line" >> "$rc"
log "Added asdf to $rc (will take effect in new shells)"
fi
}
add_asdf_to_rc "$HOME/.bashrc"
add_asdf_to_rc "$HOME/.zshrc" 2>/dev/null || true
# ---------------------------------------------------------------------------
# 4. Erlang
# ---------------------------------------------------------------------------
asdf plugin add erlang 2>/dev/null || true
if asdf list erlang 2>/dev/null | grep -qF "$ERLANG_VERSION"; then
log "Erlang $ERLANG_VERSION already installed"
else
log "Installing Erlang $ERLANG_VERSION (compiles from source — takes a few minutes)..."
asdf install erlang "$ERLANG_VERSION"
fi
if asdf list erlang 2>/dev/null | grep -qF "$ERLANG_VERSION"; then asdf global erlang "$ERLANG_VERSION"
log "Erlang $ERLANG_VERSION already installed"
else
log "Installing Erlang $ERLANG_VERSION (compiles from source — takes a few minutes)..."
asdf install erlang "$ERLANG_VERSION"
fi
asdf global erlang "$ERLANG_VERSION" # ---------------------------------------------------------------------------
# 5. Elixir
# ---------------------------------------------------------------------------
# --------------------------------------------------------------------------- asdf plugin add elixir 2>/dev/null || true
# 5. Elixir
# ---------------------------------------------------------------------------
asdf plugin add elixir 2>/dev/null || true if asdf list elixir 2>/dev/null | grep -qF "$ELIXIR_VERSION"; then
log "Elixir $ELIXIR_VERSION already installed"
else
log "Installing Elixir $ELIXIR_VERSION..."
asdf install elixir "$ELIXIR_VERSION"
fi
if asdf list elixir 2>/dev/null | grep -qF "$ELIXIR_VERSION"; then asdf global elixir "$ELIXIR_VERSION"
log "Elixir $ELIXIR_VERSION already installed" log "$(elixir --version | grep 'Elixir')"
else else
log "Installing Elixir $ELIXIR_VERSION..." hash -r
asdf install elixir "$ELIXIR_VERSION"
fi fi
asdf global elixir "$ELIXIR_VERSION"
log "$(elixir --version | grep 'Elixir')"
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# 6. Apache AGE database (Docker) # 6. Apache AGE database (Docker)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@ -210,12 +312,14 @@ export POSTGRES_PORT=$POSTGRES_PORT
export POSTGRES_USER=$POSTGRES_USER export POSTGRES_USER=$POSTGRES_USER
export POSTGRES_PASSWORD=$POSTGRES_PASSWORD export POSTGRES_PASSWORD=$POSTGRES_PASSWORD
export POSTGRES_DB=$POSTGRES_DB export POSTGRES_DB=$POSTGRES_DB
export REQUIRE_DB=true
EOF EOF
else else
log ".env already exists — skipping (delete it to regenerate)" log ".env already exists — skipping (delete it to regenerate)"
fi fi
# Export for the current session so mix setup can connect # Export DB vars for this session so mix setup can connect. Do not export REQUIRE_DB here —
# that would make a follow-up `mix test.unit` in the same shell start the Repo. It is only in `.env` for integration tests.
export POSTGRES_HOST POSTGRES_PORT POSTGRES_USER POSTGRES_PASSWORD POSTGRES_DB export POSTGRES_HOST POSTGRES_PORT POSTGRES_USER POSTGRES_PASSWORD POSTGRES_DB
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@ -224,9 +328,15 @@ export POSTGRES_HOST POSTGRES_PORT POSTGRES_USER POSTGRES_PASSWORD POSTGRES_DB
cd "$PROJECT_DIR" cd "$PROJECT_DIR"
log "Installing Hex and Rebar (if needed)..." if [ "$ELIXIR_FROM_APT" -eq 1 ]; then
mix local.hex --force --if-missing require_cmd mix "apt elixir package should provide mix; check PATH includes /usr/bin"
mix local.rebar --force --if-missing else
require_cmd mix "asdf should provide mix; run: source \"\$HOME/.asdf/asdf.sh\" or open a new terminal"
fi
log "Installing Hex and Rebar..."
mix local.hex --force
mix local.rebar --force
log "Fetching dependencies..." log "Fetching dependencies..."
mix deps.get mix deps.get
@ -241,11 +351,27 @@ mix setup
echo echo
log "Setup complete!" log "Setup complete!"
echo echo
echo " To start the server:" if [ "$ELIXIR_FROM_APT" -eq 1 ]; then
echo " source .env" echo " To start the server (system Elixir from apt):"
echo " mix phx.server" echo " cd \"$PROJECT_DIR\" && source .env && mix phx.server"
echo echo
echo " Then open: http://localhost:4000" echo " Then open: http://localhost:4000"
echo " REST API: http://localhost:4000/api/events" echo " REST API: http://localhost:4000/api/events"
echo echo
warn "Open a new terminal (or run 'source ~/.bashrc') for asdf to work in future sessions." echo " Integration tests:"
echo " source .env && mix test.integration"
echo
warn "If mix is not found in a new terminal, ensure /usr/bin is on your PATH."
else
echo " To start the server (use asdf’s mix — see warning below if mix is missing):"
echo " source \"\$HOME/.asdf/asdf.sh\" # once per shell, if needed"
echo " cd \"$PROJECT_DIR\" && source .env && mix phx.server"
echo
echo " Then open: http://localhost:4000"
echo " REST API: http://localhost:4000/api/events"
echo
echo " Integration tests: same shell with .env (includes REQUIRE_DB=true):"
echo " source .env && mix test.integration"
echo
warn "Open a new terminal (or run 'source ~/.bashrc') so asdf provides mix/elixir in future sessions."
fi

Loading…
Cancel
Save