diff --git a/.github/workflows/bats.yml b/.github/workflows/bats.yml index 7b75beea161..efc1e40bf86 100644 --- a/.github/workflows/bats.yml +++ b/.github/workflows/bats.yml @@ -16,7 +16,6 @@ jobs: - name: Run the Magic Nix Cache uses: DeterminateSystems/magic-nix-cache-action@v2 - uses: actions/checkout@v3 - - run: cd core/api && nix develop -c pnpm install --frozen-lockfile - name: Run bats tests run: | - . ./.env && cd core/api && nix develop -c make reset-bats + nix develop -c bats --setup-suite-file bats/setup_suite.bash -t bats/core/api diff --git a/.github/workflows/legacy-bats.yml b/.github/workflows/legacy-bats.yml new file mode 100644 index 00000000000..88681a40cd5 --- /dev/null +++ b/.github/workflows/legacy-bats.yml @@ -0,0 +1,22 @@ +name: "Legacy Bats test" + +on: + pull_request: + branches: [main] + +jobs: + integration: + name: Legacy Bats tests + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v3 + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@v4 + - name: Run the Magic Nix Cache + uses: DeterminateSystems/magic-nix-cache-action@v2 + - uses: actions/checkout@v3 + - run: cd core/api && nix develop -c pnpm install --frozen-lockfile + - name: Run bats tests + run: | + . ./.env && cd core/api && nix develop -c make reset-bats diff --git a/bats/core/api/public.bats b/bats/core/api/public.bats new file mode 100644 index 00000000000..0e1ac495089 --- /dev/null +++ b/bats/core/api/public.bats @@ -0,0 +1,18 @@ +#!/usr/bin/env bats + +load "../../helpers/_common.bash" + +setup_file() { + start_services "api" + await_api_is_up +} + +teardown_file() { + stop_services +} + +@test "public: can query globals" { + exec_graphql 'anon' 'globals' + network="$(graphql_output '.data.globals.network')" + [[ "${network}" = "regtest" ]] || exit 1 +} diff --git a/bats/gql/globals.gql b/bats/gql/globals.gql new file mode 100644 index 00000000000..150920389ad --- /dev/null +++ b/bats/gql/globals.gql @@ -0,0 +1,6 @@ +query Globals { + globals { + network + nodesIds + } +} diff --git a/bats/helpers/_common.bash b/bats/helpers/_common.bash new file mode 100644 index 00000000000..4e1adf3fc93 --- /dev/null +++ b/bats/helpers/_common.bash @@ -0,0 +1,132 @@ +export REPO_ROOT=$(git rev-parse --show-toplevel) + +CACHE_DIR=${BATS_TMPDIR:-tmp/bats}/galoy-bats-cache +mkdir -p "$CACHE_DIR" + +OATHKEEPER_PROXY=${OATHKEEPER_PROXY:-localhost:4455} + +SERVICES_PID_FILE=$REPO_ROOT/bats/.services_pid + +start_services() { + stop_services > /dev/null 2>&1 || true + background buck2 run //dev:up -- "$@" > "${REPO_ROOT}/bats/.e2e-services.log" + echo $! > "$SERVICES_PID_FILE" +} + +await_api_is_up() { + server_is_up() { + exec_graphql 'anon' 'globals' + network="$(graphql_output '.data.globals.network')" + [[ "${network}" = "regtest" ]] || exit 1 + } + + retry 600 1 server_is_up +} + +stop_services() { + [[ -f "$SERVICES_PID_FILE" ]] && kill -9 "$(cat "$SERVICES_PID_FILE")" > /dev/null || true + buck2 run //dev:down +} + +if ! type fail &>/dev/null; then + fail() { + echo "$1" + exit 1 + } +fi + +# Run the given command in the background. Useful for starting a +# node and then moving on with commands that exercise it for the +# test. +# +# Ensures that BATS' handling of file handles is taken into account; +# see +# https://github.com/bats-core/bats-core#printing-to-the-terminal +# https://github.com/sstephenson/bats/issues/80#issuecomment-174101686 +# for details. +background() { + "$@" 3>- & + echo $! +} + +# Taken from https://github.com/docker/swarm/blob/master/test/integration/helpers.bash +# Retry a command $1 times until it succeeds. Wait $2 seconds between retries. +retry() { + local attempts=$1 + shift + local delay=$1 + shift + local i + + for ((i = 0; i < attempts; i++)); do + if [[ "${BATS_TEST_DIRNAME}" = "" ]]; then + "$@" + else + run "$@" + fi + + if [[ "$status" -eq 0 ]]; then + return 0 + fi + sleep "$delay" + done + + echo "Command \"$*\" failed $attempts times. Output: $output" + false +} + +gql_query() { + cat "$(gql_file "$1")" | tr '\n' ' ' | sed 's/"/\\"/g' +} + +gql_file() { + echo "${REPO_ROOT}/bats/gql/$1.gql" +} + +new_idempotency_key() { + random_uuid +} + +exec_graphql() { + local token_name=$1 + local query_name=$2 + local variables=${3:-"{}"} + echo "GQL query - user: ${token_name} - query: ${query_name} - vars: ${variables}" + echo "{\"query\": \"$(gql_query "$query_name")\", \"variables\": $variables}" + + if [[ ${token_name} == "anon" ]]; then + AUTH_HEADER="" + else + AUTH_HEADER="Authorization: Bearer $(read_value "$token_name")" + fi + + if [[ "${BATS_TEST_DIRNAME}" != "" ]]; then + run_cmd="run" + else + run_cmd="" + fi + + gql_route="graphql" + + ${run_cmd} curl -s \ + -X POST \ + ${AUTH_HEADER:+ -H "$AUTH_HEADER"} \ + -H "Content-Type: application/json" \ + -H "X-Idempotency-Key: $(new_idempotency_key)" \ + -d "{\"query\": \"$(gql_query "$query_name")\", \"variables\": $variables}" \ + "${OATHKEEPER_PROXY}/${gql_route}" + + echo "GQL output: '$output'" +} + +graphql_output() { + echo "$output" | jq -r "$@" +} + +random_uuid() { + if [[ -e /proc/sys/kernel/random/uuid ]]; then + cat /proc/sys/kernel/random/uuid + else + uuidgen + fi +} diff --git a/bats/setup_suite.bash b/bats/setup_suite.bash new file mode 100644 index 00000000000..bc7dfa1b97e --- /dev/null +++ b/bats/setup_suite.bash @@ -0,0 +1,3 @@ +setup_suite() { + buck2 build //core/api:api +} diff --git a/dev/Tiltfile b/dev/Tiltfile index bef8d606a79..83695c4da78 100644 --- a/dev/Tiltfile +++ b/dev/Tiltfile @@ -1,34 +1,18 @@ -is_ci=("ci" in sys.argv) - config.define_string_list("test") +config.define_string_list("to-run", args = True) cfg = config.parse() -groups = { - "auth": [ - "oathkeeper", - "hydra", - "hydra-migrate", - "hydra-pg", - "kratos", - "kratos-pg", - ], - "core": [ - "apollo-router", - "mongodb", - "redis", - ], - "bitcoin": [ - "lnd1", - "bria", - "postgres-bria", - "fulcrum", - "bitcoind-signer", - "bitcoind", - ], - "tracing": [ - "otel-agent", - ], -} +is_ci=("ci" in sys.argv) + +def _buck2_dep_inputs(target): + cmd = [ + "buck2", + "uquery", + "\"inputs(deps('{}'))\"".format(target), + ] + file_paths = str(local(" ".join(cmd))).splitlines() + + return file_paths dashboard_target = "//apps/dashboard:dev" if is_ci: @@ -43,6 +27,7 @@ local_resource( "NEXTAUTH_SECRET": "secret", "PORT": "3001", }, + deps = _buck2_dep_inputs(dashboard_target), resource_deps = [ "hydra-dashboard", ], @@ -92,6 +77,7 @@ local_resource( labels = ["auth"], cmd = "buck2 build {}".format(consent_target), serve_cmd = "buck2 run {}".format(consent_target), + deps = _buck2_dep_inputs(consent_target), resource_deps = [ "apollo-router", "hydra", @@ -150,9 +136,13 @@ local_resource( port = 4012, ), ), + deps = _buck2_dep_inputs(api_target), resource_deps = [ "init-onchain", "lnd1", + "redis", + "mongodb", + "oathkeeper", ] ) @@ -166,13 +156,48 @@ local_resource( ] ) +docker_groups = { + "auth": [ + "oathkeeper", + "hydra", + "hydra-migrate", + "hydra-pg", + "kratos", + "kratos-pg", + ], + "core": [ + "apollo-router", + "mongodb", + "redis", + ], + "bitcoin": [ + "lnd1", + "bria", + "bitcoind", + ], + "tracing": [ + "otel-agent", + ], +} + +to_run = cfg.get("to-run", []) +if to_run != []: + enabled_resources = [] + for svc in to_run: + if svc == "all-docker": + for arg in docker_groups: + enabled_resources += docker_groups[arg] + else: + enabled_resources.append(svc) + config.set_enabled_resources(enabled_resources) + docker_compose("./docker-compose.deps.yml", project_name = "galoy-dev") -for service in groups["bitcoin"]: +for service in docker_groups["bitcoin"]: dc_resource(service, labels = ["bitcoin"]) -for service in groups["tracing"]: +for service in docker_groups["tracing"]: dc_resource(service, labels = ["tracing"]) -for service in groups["core"]: +for service in docker_groups["core"]: dc_resource(service, labels = ["core"]) -for service in groups["auth"]: +for service in docker_groups["auth"]: dc_resource(service, labels = ["auth"]) diff --git a/dev/docker-compose.deps.yml b/dev/docker-compose.deps.yml index 59719e90214..ba54cc7c2f8 100644 --- a/dev/docker-compose.deps.yml +++ b/dev/docker-compose.deps.yml @@ -11,6 +11,10 @@ services: command: serve -c /home/ory/oathkeeper.yml --sqa-opt-out volumes: - ${HOST_PROJECT_PATH:-.}/config/ory:/home/ory + depends_on: + - kratos + - hydra + - apollo-router hydra: image: oryd/hydra:v2.1.2 ports: