diff --git a/Dockerfile.testdb b/Dockerfile.testdb new file mode 100644 index 0000000..75bf9e5 --- /dev/null +++ b/Dockerfile.testdb @@ -0,0 +1,39 @@ +# Standalone PostgreSQL image with the DE schema migrated and synthetic, +# anonymized test data baked in, for functional/integration testing of DE +# services. This is separate from the root Dockerfile (the migration runner) +# and is not part of the production build/deploy path. +# +# The schema and data are applied at BUILD time (see testdata/build/bake.sh) so +# the container comes up already populated. Build: +# docker build -f Dockerfile.testdb -t de-database-testdb . +# Run: +# docker run -d --name detest -p 5432:5432 de-database-testdb +# Connect: +# postgres://de:de@localhost:5432/de?sslmode=disable + +FROM migrate/migrate:4 AS migrate + +FROM postgres:12 + +# Bake the cluster into a path OUTSIDE the base image's declared +# VOLUME (/var/lib/postgresql/data); writes under that volume during build are +# discarded, which would throw away the baked data. +ENV PGDATA=/var/lib/postgresql/dedata +ENV POSTGRES_USER=de +ENV POSTGRES_DB=de +ENV POSTGRES_PASSWORD=de + +COPY --from=migrate /usr/local/bin/migrate /usr/local/bin/migrate +COPY migrations /migrations +COPY testdata/ /testdata/ + +# initdb + migrate + load run as the postgres user; the baked data dir must be +# owned by it for the runtime entrypoint to start cleanly. +USER postgres +RUN bash /testdata/build/bake.sh + +HEALTHCHECK --interval=10s --timeout=5s --start-period=20s --retries=5 \ + CMD pg_isready -U de -d de || exit 1 + +# Inherit the base postgres image's entrypoint/CMD, which starts the server. +# On startup it finds a populated $PGDATA and serves it directly (no init). diff --git a/README.md b/README.md index 8f5a581..e9f7dff 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,106 @@ Remove the most recent migration from the database: $ migrate -database "$DBURL" -path migrations down 1 ``` +## Test database container image + +For functional and integration testing of DE services, this repository also +builds a standalone PostgreSQL image that comes up with the DE schema already +migrated and a small set of synthetic, anonymized test data preloaded. It is +separate from the production migration-runner image described above (the root +`Dockerfile`) and is **not** part of the production build/deploy path. + +The schema and data are baked into the image at build time, so a container starts +up ready to use. The image, its build script, and the test data live alongside +the migrations: + +- `Dockerfile.testdb` — builds the image. +- `testdata/` — the build script and the synthetic data files (see + [`testdata/README.md`](testdata/README.md) for details and conventions). +- `docker-compose.yml` — runs the database, and optionally the apps service. + +### Using Docker Compose + +``` +$ docker compose up -d de-database # just the database (fast) +$ docker compose up -d # database + apps service (first build is slow) +$ docker compose up -d --build # force a rebuild after changes +$ docker compose down -v # stop and drop volumes +``` + +The database listens on host port `5432` and apps on `60000` by default. Override +either if a port is already in use: + +``` +$ DE_DB_PORT=5440 APPS_PORT=60001 docker compose up -d +``` + +Other compose stacks can wait for a ready database with: + +```yaml +depends_on: + de-database: + condition: service_healthy +``` + +#### apps service + +The compose stack can also run the [`apps`](https://github.com/cyverse-de/apps) +service against the test database, so its endpoints can be exercised directly. The +apps image builds from `../apps` by default, so that repository is expected next to +this one (both under `.../cyverse-de/`); point elsewhere with +`APPS_CONTEXT=/path/to/apps docker compose up -d`. Its test config is +`testdata/apps/apps.properties`. + +apps boots against the test database, and with the metadata service also in the +stack (below) its metadata-backed endpoints work too — e.g. +`curl 'http://localhost:60000/apps/66666666-6666-6666-6666-666666666601/metadata?user=testuser01'` +returns the seeded app AVUs. The central app listing/details endpoints, however, +also call the **iplant-groups** and **permissions** services mid-request and error +until those are added to the stack; reference/DB-only endpoints +(`/apps/elements/*`, `/tool-requests`, `/reference-genomes`, `/`) work regardless. +Most endpoints take a `user` query parameter naming a seeded user (Swagger UI at +`/docs`). See [`testdata/apps/README.md`](testdata/apps/README.md). + +#### metadata service + +The stack also runs the [`metadata`](https://github.com/cyverse-de/metadata) +service (built from `../metadata`, override with `METADATA_CONTEXT`) plus a +`rabbitmq` broker it requires at startup. Because the metadata service addresses +its tables unqualified, it connects as a dedicated `metadata` database role whose +`search_path` resolves the `metadata` schema first (created by +`testdata/sql/90_metadata_role.sql`). Its test config is +`testdata/metadata/metadata.properties`; it listens on `60010` by default +(`METADATA_PORT`). See [`testdata/metadata/README.md`](testdata/metadata/README.md). + +### Using Docker directly + +``` +$ docker build -f Dockerfile.testdb -t de-database-testdb . +$ docker run -d --name de-database-testdb -p 5432:5432 de-database-testdb +``` + +### Connecting + +The database name, user, and password are all `de`, and the `de` account owns the +database and all schemas: + +``` +postgres://de:de@localhost:5432/de?sslmode=disable +``` + +The container exposes a `pg_isready` health check, so you can wait for it to +finish coming up before pointing tests at it: + +``` +$ until docker exec de-database-testdb pg_isready -U de -d de; do sleep 1; done +``` + +The preloaded data is sized to support functional/regression testing of DE +services. For the apps service in particular, `testdata/COVERAGE.md` maps read +endpoints to the fixtures that exercise them, and `testdata/verify/apps_smoke.sql` +provides a sanity report plus assertions. See `testdata/README.md` for the full +contents and conventions. + [1]: https://github.com/cyverse-de/de-db [2]: https://github.com/cyverse-de/metadata-db [3]: https://github.com/cyverse-de/permissions-db diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..0a19007 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,110 @@ +# Test stack for functional/integration testing of DE services. Not part of the +# production build/deploy path. +# +# docker compose up -d # build (first run) and start +# docker compose up -d --build # force a rebuild after changes +# docker compose down -v # stop and drop volumes +# +# Services: +# de-database the baked test database (schema + synthetic data) +# rabbitmq message broker required by the metadata service at startup +# apps the apps service, built from ../apps, pointed at de-database +# metadata the metadata service, built from ../metadata +# +# The apps and metadata build contexts default to ../apps and ../metadata, so this +# repo (de-database) and those repos are expected side by side under +# .../cyverse-de/; override with APPS_CONTEXT / METADATA_CONTEXT. The apps image +# only needs the database to boot (its service clients are lazy); metadata needs +# both the database and rabbitmq. Many apps endpoints (the main app +# listing/details) also call the iplant-groups and permissions services, which are +# not yet in the stack, so those error until added. See testdata/apps/README.md +# and testdata/metadata/README.md. +# +# Bring up just the database (the service builds are slow on first run): +# docker compose up -d de-database +# +# Host ports default to 5432 (db), 60000 (apps), 60010 (metadata), 5672 (rabbitmq); +# override any if already in use: +# DE_DB_PORT=5440 APPS_PORT=60001 METADATA_PORT=60011 RABBITMQ_PORT=5673 docker compose up -d +# Override the service build contexts: +# APPS_CONTEXT=/path/to/apps METADATA_CONTEXT=/path/to/metadata docker compose up -d +# +# Connect: postgres://de:de@localhost:5432/de?sslmode=disable +# apps at http://localhost:60000 (Swagger UI at /docs) +# metadata at http://localhost:60010 (Swagger UI at /docs) +# +# Other compose stacks can wait for a ready database with: +# depends_on: +# de-database: +# condition: service_healthy + +services: + de-database: + build: + context: . + dockerfile: Dockerfile.testdb + image: de-database-testdb + container_name: de-database-testdb + ports: + - "${DE_DB_PORT:-5432}:5432" + environment: + POSTGRES_USER: de + POSTGRES_DB: de + POSTGRES_PASSWORD: de + healthcheck: + test: ["CMD", "pg_isready", "-U", "de", "-d", "de"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 20s + + rabbitmq: + image: rabbitmq:3-management + container_name: de-rabbitmq-test + environment: + # RabbitMQ's built-in "guest" user only works over localhost, so define a + # user the metadata container can use across the compose network. + RABBITMQ_DEFAULT_USER: de + RABBITMQ_DEFAULT_PASS: de + ports: + - "${RABBITMQ_PORT:-5672}:5672" + - "${RABBITMQ_MGMT_PORT:-15672}:15672" + healthcheck: + test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"] + interval: 10s + timeout: 5s + retries: 10 + start_period: 30s + + apps: + build: + context: ${APPS_CONTEXT:-../apps} + dockerfile: Dockerfile + image: cyverse-de/apps:test + container_name: de-apps-test + depends_on: + de-database: + condition: service_healthy + ports: + - "${APPS_PORT:-60000}:60000" + volumes: + - ./testdata/apps/apps.properties:/etc/iplant/de/apps.properties:ro + + metadata: + build: + context: ${METADATA_CONTEXT:-../metadata} + dockerfile: Dockerfile + image: cyverse-de/metadata:test + container_name: de-metadata-test + depends_on: + de-database: + condition: service_healthy + rabbitmq: + condition: service_healthy + ports: + - "${METADATA_PORT:-60010}:60000" + volumes: + - ./testdata/metadata/metadata.properties:/etc/iplant/de/metadata.properties:ro + # The metadata image's default CMD is "--help"; override it to run the server. + # (The apps image has no such default, so it needs no command here.) + command: ["--config", "/etc/iplant/de/metadata.properties"] diff --git a/testdata/COVERAGE.md b/testdata/COVERAGE.md new file mode 100644 index 0000000..4f3a276 --- /dev/null +++ b/testdata/COVERAGE.md @@ -0,0 +1,67 @@ +# Apps service test-data coverage + +This maps the `apps` service (`../apps`) read paths to the fixtures in `sql/` that +exercise them, for building golden-master regression tests ahead of a Go rewrite. + +Legend: **DB** = fully exercisable with this image alone; **+meta** = also needs the +metadata service running against this DB; **+perms** = also needs the permissions +service; **ext** = data comes from an external system (Tapis/Agave) and is not in +this DB at all. + +## Fixtures and what they add + +| File | Domain | +|------|--------| +| `00_users.sql` | 10 synthetic users | +| `10_integration_and_tools.sql` | integration_data, container_images (incl. OSG image), tools (executable/interactive/OSG), tasks (incl. external/Agave task + pipeline + showcase tasks) | +| `15_container_settings.sql` | container_settings, devices, volumes, ports, interactive proxy settings | +| `20_apps.sql` | 10 apps: simple, multi-version (deleted/disabled), OSG, external, pipeline, parameters-showcase; app_versions; app_steps | +| `22_parameters.sql` | every parameter type, parameter_values (incl. tree parent/child), file_parameters, validation_rules + arguments | +| `25_pipelines.sql` | workflow_io_maps + input_output_mapping (2-step pipeline) | +| `28_app_docs_refs.sql` | app_documentation, app_references | +| `30_workspaces_categories.sql` | per-user workspace + Workspace/dev/favorites categories; Beta + Bioinformatics public categories; suggested_groups | +| `35_tool_requests.sql` | tool_requests + tool_request_statuses | +| `45_publication_requests.sql` | app_publication_requests + statuses; extra ratings | +| `70_metadata.sql` | metadata AVUs incl. Beta/ontology/community AVUs | +| `80_permissions.sql` | permissions subjects (user + group), resources, grants | + +## Endpoint coverage + +| Endpoint (read) | Tier | Fixtures | +|-----------------|------|----------| +| `GET /apps` (search/list, paging) | DB | 20, 22, 30, 45 (ratings), 80 (public set) | +| `GET /apps/:sys/:id/listing` | DB | 20, 45 | +| `GET /apps/:sys/:id` (job view) | DB | 20, 22, 15 | +| `GET /apps/:sys/:id/details` | DB | 20, 28, 45 | +| `GET /apps/:sys/:id/documentation` | DB | 28 | +| `GET /apps/:sys/:id/tasks` | DB | 10, 20 | +| `GET /apps/:sys/:id/tools` | DB | 10, 15 | +| `GET /apps/:sys/:id/versions/...` | DB | 20 (3-version app; deleted/disabled) | +| `GET /apps/categories` (+ counts) | DB | 30 | +| `GET /apps/categories/:sys/:cat` | DB | 30 | +| `GET /apps/categories/featured` (Beta) | +meta | 30, 70 (beta AVU) | +| `is_favorite` flag in listings | DB | 30 (favorites category) | +| `GET /apps/pipelines/:id/ui` | DB | 20, 22, 25 | +| `GET /tools`, `GET /tools/:id` | DB | 10, 15 | +| `GET /tools/:id/apps` | DB | 10, 20 | +| `GET /tool-requests`, `/status-codes` | DB | 35 | +| `GET /reference-genomes` | DB | migration-seeded `genome_reference` | +| `GET /admin/integration-data` | DB | 10 | +| `GET /admin/apps/publication-requests` | DB | 45 | +| `GET /apps/elements/*` (param/tool/value types, formats, info types, rule types, data sources) | DB | migration-seeded reference data | +| `GET /apps/:id/metadata` (AVUs) | +meta | 70 | +| `GET /apps/communities/...`, `/apps/hierarchies/...` | +meta | 70 (community/ontology AVUs) | +| `POST /apps/permission-lister`, `/apps/sharing` | +perms | 80 | +| `GET /apps/hpc/...` (Tapis apps) | ext | n/a (external system) | + +## Notes for the rewrite + +- The pipeline app (`Test Pipeline 1`, `66666666-…-609`) has `step_count = 2` / + `task_count = 2` and an input→output mapping — use it for pipeline + multi-step + listing assertions. +- The versioned app (`66666666-…-606`) has three versions; `1.0.0` is deleted and + `2.0.0` is disabled, so default listings should show only `3.0.0`. +- `is_favorite` is true for `Test App 1` when listing as `testuser01` (it's in that + user's "Favorite Apps" category, child_index 1 of the workspace root). +- `+meta`/`+perms` rows are seeded now but only become testable once those services + are added to the harness; until then, assert those endpoints separately. diff --git a/testdata/README.md b/testdata/README.md new file mode 100644 index 0000000..d372873 --- /dev/null +++ b/testdata/README.md @@ -0,0 +1,107 @@ +# DE test database image + +This directory holds everything needed to build a standalone PostgreSQL image +with the full DE schema migrated and a small, synthetic, **anonymized** dataset +preloaded. It is meant for functional/integration testing of DE services against +a real database. + +It is intentionally separate from the production migration-runner image (the +repository root `Dockerfile`) and is **not** part of the production build/deploy +path. The migrations and the root `Dockerfile` are not modified by anything here. + +## Layout + +- `../Dockerfile.testdb` — builds the image. The schema and data are baked in at + build time so the container starts up already populated. +- `build/bake.sh` — runs during `docker build`: initializes the cluster, installs + the `uuid-ossp`, `moddatetime`, and `btree_gist` extensions, runs all + migrations, then loads the data files below. +- `sql/*.sql` — the synthetic data, loaded in filename order. Each file is one + domain; the numeric prefixes enforce referential ordering. +- `COVERAGE.md` — maps apps-service read endpoints to the fixtures that exercise + them (and flags endpoints that also need the metadata or permissions service). +- `verify/apps_smoke.sql` — sanity report + assertions for the apps fixtures. + +## Build and run + +```sh +docker build -f Dockerfile.testdb -t de-database-testdb . +docker run -d --name detest -p 5432:5432 de-database-testdb + +# Wait for readiness (data is baked, so this is quick): +until docker exec detest pg_isready -U de -d de; do sleep 1; done + +# Connect: +psql 'postgres://de:de@localhost:5432/de?sslmode=disable' +``` + +## What's in the data + +Reference/lookup tables (data formats, parameter types, tool types, job types, +permission levels, reference genomes, tool architectures, status codes, etc.) and +the seeded `` user, public workspace, and fixture apps come from the +migrations themselves (`migrations/000019_data_fixtures.up.sql`) and are **not** +duplicated here. The files in `sql/` add the user-content layer on top: + +- `00_users` — ~10 synthetic users (`testuserNN@example.org`). +- `10_integration_and_tools` — integration data, container images, tools + (executable / interactive / OSG), and tasks (incl. an external/Agave task). +- `15_container_settings` — container settings, devices, volumes, ports, and the + interactive (VICE) proxy settings. +- `20_apps` — 10 apps: simple, a multi-version app (deleted + disabled versions), + OSG, external, a 2-step pipeline, and a parameters-showcase app; plus versions + and steps. +- `22_parameters` — every major parameter type, selection options + (`parameter_values`, incl. a parent/child tree), file parameters, and + validation rules. +- `25_pipelines` — `workflow_io_maps` + `input_output_mapping` for the pipeline. +- `28_app_docs_refs` — app documentation and references. +- `30_workspaces_categories` — per-user workspaces mirroring the apps bootstrap + (root "Workspace" + "Apps under development" + "Favorite Apps"); public Beta and + Bioinformatics categories; suggested groups. +- `35_tool_requests` — tool installation requests with status histories. +- `40_operators` — VICE operators (drive `job_listings.operator_base_url`). +- `45_publication_requests` — app publication requests + statuses; extra ratings. +- `50_jobs` — analyses across the common statuses, including a batch parent with + children and interactive jobs tied to operators; job steps and status updates. +- `60_launches` — submissions, quick launches, instant launches. +- `70_metadata` — core `metadata` schema content (AVUs, tags, comments, favorites, + ratings), including Beta/ontology/community AVUs for metadata-service-backed + apps features. +- `72_metadata_templates` — the metadata template/attribute system: a template + with attributes of several value types (incl. an Enum with values, a Grouping + with nested sub-attributes, and a synonym pair), plus a deleted template. + References the migration-seeded `value_types`. +- `74_metadata_ontologies` — a synthetic ontology with classes and a parent/child + hierarchy. +- `76_metadata_pid_requests` — permanent-ID (DOI) requests with status histories + (references the migration-seeded request types and status codes). +- `80_permissions` — the `permissions` schema (user + group subjects, resources, + grants). +- `90_metadata_role` — a dedicated `metadata` DB login role (search_path + `metadata, public`) for the metadata service; see `metadata/README.md`. + +## Apps service coverage + +The fixtures are sized to support **golden-master regression tests** for the +`apps` service (ahead of a Go rewrite). See `COVERAGE.md` for the endpoint → +fixture matrix. After building, run the smoke checks: + +```sh +psql 'postgres://de:de@localhost:5432/de?sslmode=disable' -f testdata/verify/apps_smoke.sql +``` + +Some apps endpoints (communities, ontology hierarchies, app metadata AVUs, the +Beta category, sharing/permission listing) read through the **metadata** or +**permissions** services rather than the database directly. The supporting rows +are seeded here, but those endpoints are only testable once those services are +running against this same database. + +## Conventions for adding data + +- Use deterministic literal UUIDs for synthetic rows so cross-file references + stay stable; reference migration-seeded rows by natural key (e.g. + `(SELECT id FROM job_types WHERE name='DE' AND system_id='de' LIMIT 1)`), never + by a hardcoded fixture UUID. +- Keep inserts idempotent with `ON CONFLICT DO NOTHING`. +- Anonymize everything; this image is public. diff --git a/testdata/apps/README.md b/testdata/apps/README.md new file mode 100644 index 0000000..4951653 --- /dev/null +++ b/testdata/apps/README.md @@ -0,0 +1,54 @@ +# apps service test config + +`apps.properties` is the configuration for running the `apps` service in the +docker-compose test stack (defined in the repo-root `docker-compose.yml`), pointed +at the `de-database` test image. + +It is mounted into the container at `/etc/iplant/de/apps.properties`, which is the +default path the apps service reads (`apps.core` `--config` default). + +## Scope: database-only (limited) + +The apps service connects to the database eagerly at startup and boots fine with +only the database present. Its other service clients (metadata, permissions, +iplant-groups, jex, data-info, notification-agent) are lazy — only contacted on +first use — so the service starts, but **many endpoints still call those services +mid-request** and fail when they are absent. + +Verified against this stack (apps + DB only): + +- **Works now:** endpoints that read reference/DB data without resolving a user + workspace or filtering by permission — e.g. `/apps/elements/*` (parameter + types, info types, data formats, tool types, rule types, value types, data + sources), `/tool-requests`, `/reference-genomes`. The status endpoint `/`. +- **Fails without iplant-groups:** anything that resolves or bootstraps a user's + workspace. The app listing path (`GET /apps`, and the combined listing it uses) + dereferences an iplant-groups lookup and returns + `UnknownHostException: iplant-groups`. +- **Fails without permissions:** app listing/details and per-app permission + filtering (`UnknownHostException: permissions`). +- **Fails without metadata:** communities, ontology hierarchies, app metadata + AVUs, the Beta featured listing. + +So to exercise the central app listing/details/version endpoints you need at +least **iplant-groups + permissions** (and **metadata** for the metadata-backed +ones) added to the stack — apps + DB alone covers only the reference/DB-only +endpoints above. See [`../COVERAGE.md`](../COVERAGE.md) for the per-endpoint +service tiers. + +## Requests need a user + +Most endpoints require a `user` query parameter. The service appends +`apps.uid.domain` to it, so `?user=testuser01` becomes `testuser01@example.org`, +matching the seeded fixture users. Example: + +```sh +curl 'http://localhost:60000/apps?user=testuser01' +``` + +## Keep in sync with the fixtures + +The workspace/category and Beta-AVU settings here must match the seeded data in +`../sql/` (root category `Workspace`, `Apps under development` at index 0, +`Favorite Apps` at index 1, beta attr `n2t.net/ark:/99152/h1459`). If you change +those in the fixtures, update them here too. diff --git a/testdata/apps/apps.properties b/testdata/apps/apps.properties new file mode 100644 index 0000000..33a82dd --- /dev/null +++ b/testdata/apps/apps.properties @@ -0,0 +1,66 @@ +# Test configuration for the apps service in the docker-compose test stack. +# Mounted at /etc/iplant/de/apps.properties (the apps.core --config default). +# +# Scope: DB-only. The apps service connects eagerly to the database at boot but +# reaches its other clients (metadata, permissions, iplant-groups, jex, +# data-info, notification-agent) only lazily, on first use. Those base URLs are +# left at their in-cluster defaults below and are unreachable in this stack, so +# endpoints that depend on them will error until those services are added. All +# database-backed endpoints work. See ../COVERAGE.md for the endpoint breakdown. +# +# All values are placeholders for local testing; nothing is sent to any real +# service. + +# Application details. +apps.app.listen-port = 60000 +apps.app.environment-name = test + +# Feature flags. Tapis is disabled so no HPC/Tapis backend is needed. The Tapis +# credentials below are still validated at boot even when disabled, so they are +# present as dummy placeholders and are never used. +apps.features.tapis = false +apps.features.tapis.jobs = false + +apps.tapis.key = not_a_key +apps.tapis.secret = not_a_secret +apps.tapis.redirect-uri = http://localhost/de/oauth/callback/tapis +apps.tapis.callback-base = http://localhost/de/tapis-cb + +# Database settings (the de-database test image, service name "de-database"). +apps.db.driver = org.postgresql.Driver +apps.db.subprotocol = postgresql +apps.db.host = de-database +apps.db.port = 5432 +apps.db.name = de +apps.db.user = de +apps.db.password = de + +# Required-at-boot settings (no default in the service; boot fails if absent). +# Use a request query param of ?user=testuserNN so the fully-qualified username +# becomes testuserNN@example.org, matching the seeded fixture users. +apps.uid.domain = example.org +apps.ui.base-url = http://localhost:3000 +apps.email.app-deletion.from = noreply@example.org +apps.email.app-request.from = noreply@example.org +apps.email.app-request.to = admin@example.org + +# Workspace / app-category settings. These MUST match the seeded fixtures so +# workspace bootstrap, the favorites flag, and Beta behavior line up. +apps.workspace.root-app-category = Workspace +apps.workspace.default-app-categories = ["Apps under development","Favorite Apps"] +apps.workspace.dev-app-category-index = 0 +apps.workspace.favorites-app-category-index = 1 +apps.workspace.public-id = 00000000-0000-0000-0000-000000000000 +apps.workspace.metadata.beta.attr.iri = n2t.net/ark:/99152/h1459 +apps.workspace.metadata.beta.attr.label = releaseStatus +apps.workspace.metadata.beta.value = beta + +# External service base URLs. Left at in-cluster defaults; unreachable in this +# DB-only stack and contacted only lazily. Listed for discoverability — point +# these at real/stub services when those are added to the stack. +apps.metadata.base-url = http://metadata:60000 +apps.permissions.base-url = http://permissions:60000 +apps.iplant-groups.base-url = http://iplant-groups:60000 +apps.jex.base-url = http://jex-events:60000 +apps.data-info.base-url = http://data-info:60000 +apps.notificationagent.base-url = http://notification-agent:60000 diff --git a/testdata/build/bake.sh b/testdata/build/bake.sh new file mode 100644 index 0000000..a30c828 --- /dev/null +++ b/testdata/build/bake.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# +# Build-time setup for the test database image. Initializes a PostgreSQL cluster, +# installs the required extensions, runs all migrations, and loads the synthetic +# test data. The resulting data directory is baked into the image so the +# container starts up already populated. +# +# Intended to run during `docker build` (see Dockerfile.testdb) as the postgres +# user. Not used at container runtime. + +set -euo pipefail + +: "${PGDATA:?PGDATA must be set}" +db_user="${POSTGRES_USER:-de}" +db_name="${POSTGRES_DB:-de}" +db_pass="${POSTGRES_PASSWORD:-de}" +sock_dir=/var/run/postgresql + +# Initialize the cluster. The DE account is the bootstrap superuser, so it owns +# the database and every schema and can create extensions, satisfying the +# prerequisites documented in the repository README. +pwfile="$(mktemp)" +printf '%s' "$db_pass" > "$pwfile" +initdb --pgdata="$PGDATA" --username="$db_user" --pwfile="$pwfile" \ + --auth-local=trust --auth-host=scram-sha-256 --encoding=UTF8 +rm -f "$pwfile" + +# Allow service containers to connect over TCP. The baked pg_hba.conf/postgresql.conf +# govern runtime auth because the entrypoint skips initialization on a populated +# data directory. +echo "listen_addresses = '*'" >> "$PGDATA/postgresql.conf" +echo "host all all all scram-sha-256" >> "$PGDATA/pg_hba.conf" + +# Bring up a temporary, socket-only server for the build steps. +pg_ctl --pgdata="$PGDATA" --wait \ + --options="-c listen_addresses='' -c unix_socket_directories=$sock_dir" start + +createdb --host="$sock_dir" --username="$db_user" "$db_name" + +psql --set=ON_ERROR_STOP=1 --host="$sock_dir" --username="$db_user" --dbname="$db_name" <<'SQL' +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; +CREATE EXTENSION IF NOT EXISTS moddatetime; +CREATE EXTENSION IF NOT EXISTS btree_gist; +SQL + +migrate -path /migrations \ + -database "postgres://$db_user@/$db_name?sslmode=disable&host=$sock_dir" up + +for f in /testdata/sql/*.sql; do + echo ">> loading ${f}" + psql --set=ON_ERROR_STOP=1 --host="$sock_dir" --username="$db_user" --dbname="$db_name" --file="$f" +done + +# Clean shutdown so the baked data directory is left consistent. +pg_ctl --pgdata="$PGDATA" --mode=fast --wait stop diff --git a/testdata/metadata/README.md b/testdata/metadata/README.md new file mode 100644 index 0000000..850eeb8 --- /dev/null +++ b/testdata/metadata/README.md @@ -0,0 +1,56 @@ +# metadata service test config + +`metadata.properties` configures the `metadata` service for the docker-compose +test stack, against the `de-database` test image. It is mounted into the container +at `/etc/iplant/de/metadata.properties` (the default config path). + +## Database access + +The metadata service references its tables unqualified (`avus`, `tags`, +`comments`, `ratings`, …) and has no schema/search_path setting — it only picks a +database name. In the consolidated DE schema those tables live in the `metadata` +schema of the `de` database, and some names (`ratings`, `comments`) also exist in +`public`. So the service connects as a dedicated **`metadata` login role** (created +by [`../sql/90_metadata_role.sql`](../sql/90_metadata_role.sql)) whose +`search_path` is `metadata, public, pg_catalog`. That resolves each unqualified +name to the metadata schema first. The `apps` service keeps using the `de` role +(public-first), so the two never collide. + +## AMQP / RabbitMQ + +Unlike apps, the metadata service opens an AMQP connection **at startup** and fails +fast if the broker is unreachable, so the compose stack includes a `rabbitmq` +service. RabbitMQ's built-in `guest` user only works over localhost, so the stack +defines a `de` user (`RABBITMQ_DEFAULT_USER/PASS`) and the config points at +`amqp://de:de@rabbitmq:5672`. + +## Test data + +The `metadata` schema is preloaded with synthetic data for exercising (and +eventually regression-testing a rewrite of) the metadata service. See the +fixtures in `../sql/`: + +- `70_metadata.sql` — AVUs, tags + attached tags, comments, favorites, ratings. +- `72_metadata_templates.sql` — `value_types` reference data plus a metadata + template whose attributes cover several value types, including an Enum attribute + with values, an attribute group with nested sub-attributes, and a synonym pair. +- `74_metadata_ontologies.sql` — an ontology with classes and a parent/child + hierarchy. +- `76_metadata_pid_requests.sql` — permanent-ID (DOI) requests with status + histories and the `permanent_id_request_status_codes` reference data. + +`value_types` and `permanent_id_request_status_codes` are reference data the +service expects to exist; production has them but the consolidated de-database +migrations do not seed them, so the fixtures do. Verified end-to-end against the +running service, e.g. `GET /templates?user=testuser01` returns the active template +and `GET /templates/?user=testuser01` returns its full attribute list. + +## Working with apps + +The apps service reaches metadata at `http://metadata:60000` (its +`apps.metadata.base-url` default). With metadata up, apps's metadata-backed +features (app metadata AVUs, communities, ontology hierarchies, the Beta featured +listing) can talk to a live metadata service. Note the central app +listing/details endpoints additionally need the **iplant-groups** and +**permissions** services, which are not yet in the stack — see +[`../apps/README.md`](../apps/README.md) and [`../COVERAGE.md`](../COVERAGE.md). diff --git a/testdata/metadata/metadata.properties b/testdata/metadata/metadata.properties new file mode 100644 index 0000000..e07c97d --- /dev/null +++ b/testdata/metadata/metadata.properties @@ -0,0 +1,31 @@ +# Test configuration for the metadata service in the docker-compose test stack. +# Mounted at /etc/iplant/de/metadata.properties (the metadata.core --config default). +# +# The metadata service references its tables unqualified and has no schema setting, +# so it connects as the dedicated `metadata` login role (created by +# testdata/sql/90_metadata_role.sql) whose search_path is `metadata, public`. That +# resolves the metadata-schema tables — including the ones whose names also exist +# in public (ratings, comments) — to the correct schema. +# +# All values are placeholders for local testing. + +# Application details. +metadata.app.listen-port = 60000 +metadata.app.environment-name = test + +# Database settings (de-database test image; db "de", metadata role/search_path). +metadata.db.subprotocol = postgresql +metadata.db.host = de-database +metadata.db.port = 5432 +metadata.db.name = de +metadata.db.user = metadata +metadata.db.password = metadata + +# AMQP. The metadata service opens this connection at startup (fail-fast), so a +# broker must be reachable. RabbitMQ's default "guest" user is restricted to +# localhost, so the stack defines a "de" user instead. +metadata.amqp.uri = amqp://de:de@rabbitmq:5672 +metadata.amqp.exchange.name = de +metadata.amqp.exchange.type = topic +metadata.amqp.exchange.durable = true +metadata.amqp.exchange.auto-delete = false diff --git a/testdata/sql/00_users.sql b/testdata/sql/00_users.sql new file mode 100644 index 0000000..dacaee6 --- /dev/null +++ b/testdata/sql/00_users.sql @@ -0,0 +1,20 @@ +-- Synthetic, anonymized users. All values are invented; none are copied from any +-- real deployment. DE usernames carry an @domain; the permissions schema stores +-- the bare username (see 80_permissions.sql). +BEGIN; +SET search_path = public, pg_catalog; + +INSERT INTO users (id, username) VALUES + ('11111111-1111-1111-1111-111111111101', 'testuser01@example.org'), + ('11111111-1111-1111-1111-111111111102', 'testuser02@example.org'), + ('11111111-1111-1111-1111-111111111103', 'testuser03@example.org'), + ('11111111-1111-1111-1111-111111111104', 'testuser04@example.org'), + ('11111111-1111-1111-1111-111111111105', 'testuser05@example.org'), + ('11111111-1111-1111-1111-111111111106', 'testuser06@example.org'), + ('11111111-1111-1111-1111-111111111107', 'testuser07@example.org'), + ('11111111-1111-1111-1111-111111111108', 'testuser08@example.org'), + ('11111111-1111-1111-1111-111111111109', 'testuser09@example.org'), + ('11111111-1111-1111-1111-111111111110', 'testuser10@example.org') +ON CONFLICT (id) DO NOTHING; + +COMMIT; diff --git a/testdata/sql/10_integration_and_tools.sql b/testdata/sql/10_integration_and_tools.sql new file mode 100644 index 0000000..4012626 --- /dev/null +++ b/testdata/sql/10_integration_and_tools.sql @@ -0,0 +1,67 @@ +-- Integration data, container images, tools, and tasks for the synthetic apps. +-- Reference/lookup rows (tool_types, job_types) are seeded by the migrations and +-- are referenced here by natural key rather than by hardcoded UUID. Natural-key +-- subqueries use LIMIT 1 because a few seeded lookup names are not unique. +BEGIN; +SET search_path = public, pg_catalog; + +INSERT INTO integration_data (id, integrator_name, integrator_email, user_id) VALUES + ('22222222-2222-2222-2222-222222222201', 'Test Integrator One', 'testuser01@example.org', '11111111-1111-1111-1111-111111111101'), + ('22222222-2222-2222-2222-222222222202', 'Test Integrator Two', 'testuser02@example.org', '11111111-1111-1111-1111-111111111102'), + ('22222222-2222-2222-2222-222222222203', 'Test Integrator Three', 'testuser03@example.org', '11111111-1111-1111-1111-111111111103') +ON CONFLICT (id) DO NOTHING; + +INSERT INTO container_images (id, name, tag, url, osg_image_path) VALUES + ('33333333-3333-3333-3333-333333333301', 'test/tool-one', '1.0.0', 'https://example.org/test/tool-one', NULL), + ('33333333-3333-3333-3333-333333333302', 'test/tool-two', '2.1.0', 'https://example.org/test/tool-two', NULL), + ('33333333-3333-3333-3333-333333333303', 'test/interactive-app', 'latest', 'https://example.org/test/interactive-app', NULL), + ('33333333-3333-3333-3333-333333333304', 'test/osg-tool', '1.0.0', 'https://example.org/test/osg-tool', '/cvmfs/singularity.opensciencegrid.org/test/osg-tool:1.0.0') +ON CONFLICT (id) DO NOTHING; + +INSERT INTO tools (id, name, location, description, version, integration_data_id, tool_type_id, container_images_id, interactive) VALUES + ('44444444-4444-4444-4444-444444444401', 'Test Tool 1', '', 'First synthetic executable tool', '1.0.0', + '22222222-2222-2222-2222-222222222201', (SELECT id FROM tool_types WHERE name = 'executable' LIMIT 1), + '33333333-3333-3333-3333-333333333301', false), + ('44444444-4444-4444-4444-444444444402', 'Test Tool 2', '', 'Second synthetic executable tool', '2.1.0', + '22222222-2222-2222-2222-222222222201', (SELECT id FROM tool_types WHERE name = 'executable' LIMIT 1), + '33333333-3333-3333-3333-333333333302', false), + ('44444444-4444-4444-4444-444444444403', 'Test Tool 3', '', 'Third synthetic executable tool', '1.0.0', + '22222222-2222-2222-2222-222222222202', (SELECT id FROM tool_types WHERE name = 'executable' LIMIT 1), + '33333333-3333-3333-3333-333333333301', false), + ('44444444-4444-4444-4444-444444444404', 'Test Tool 4', '', 'Fourth synthetic executable tool', '0.9.0', + '22222222-2222-2222-2222-222222222202', (SELECT id FROM tool_types WHERE name = 'executable' LIMIT 1), + NULL, false), + ('44444444-4444-4444-4444-444444444405', 'Test Interactive Tool', '', 'Synthetic interactive (VICE) tool', 'latest', + '22222222-2222-2222-2222-222222222203', (SELECT id FROM tool_types WHERE name = 'interactive' LIMIT 1), + '33333333-3333-3333-3333-333333333303', true), + ('44444444-4444-4444-4444-444444444406', 'Test OSG Tool', '', 'Synthetic OSG tool', '1.0.0', + '22222222-2222-2222-2222-222222222203', (SELECT id FROM tool_types WHERE name = 'osg' LIMIT 1), + '33333333-3333-3333-3333-333333333304', false) +ON CONFLICT (id) DO NOTHING; + +-- Tasks. task07 is an external (Agave/HPC-style) task: no local tool, an external_app_id, +-- and the Agave job type, which drives the external_app_count/overall_job_type branches. +INSERT INTO tasks (id, name, description, label, tool_id, external_app_id, job_type_id) VALUES + ('55555555-5555-5555-5555-555555555501', 'Test Task 1', 'Task for Test App 1', 'Test Task 1', + '44444444-4444-4444-4444-444444444401', NULL, (SELECT id FROM job_types WHERE name = 'DE' AND system_id = 'de' LIMIT 1)), + ('55555555-5555-5555-5555-555555555502', 'Test Task 2', 'Task for Test App 2', 'Test Task 2', + '44444444-4444-4444-4444-444444444402', NULL, (SELECT id FROM job_types WHERE name = 'DE' AND system_id = 'de' LIMIT 1)), + ('55555555-5555-5555-5555-555555555503', 'Test Task 3', 'Task for Test App 3', 'Test Task 3', + '44444444-4444-4444-4444-444444444403', NULL, (SELECT id FROM job_types WHERE name = 'DE' AND system_id = 'de' LIMIT 1)), + ('55555555-5555-5555-5555-555555555504', 'Test Task 4', 'Task for Test App 4', 'Test Task 4', + '44444444-4444-4444-4444-444444444404', NULL, (SELECT id FROM job_types WHERE name = 'DE' AND system_id = 'de' LIMIT 1)), + ('55555555-5555-5555-5555-555555555505', 'Test Task 5', 'Task for Test Interactive App', 'Test Task 5', + '44444444-4444-4444-4444-444444444405', NULL, (SELECT id FROM job_types WHERE name = 'Interactive' AND system_id = 'interactive' LIMIT 1)), + ('55555555-5555-5555-5555-555555555506', 'Test OSG Task', 'Task for Test OSG App', 'Test OSG Task', + '44444444-4444-4444-4444-444444444406', NULL, (SELECT id FROM job_types WHERE name = 'OSG' AND system_id = 'osg' LIMIT 1)), + ('55555555-5555-5555-5555-555555555507', 'Test External Task', 'External Agave task for Test External App', 'Test External Task', + NULL, 'test-agave-app-00000001', (SELECT id FROM job_types WHERE name = 'Agave' AND system_id = 'agave' LIMIT 1)), + ('55555555-5555-5555-5555-555555555508', 'Pipeline Step One Task', 'First step of the test pipeline', 'Pipeline Step One', + '44444444-4444-4444-4444-444444444401', NULL, (SELECT id FROM job_types WHERE name = 'DE' AND system_id = 'de' LIMIT 1)), + ('55555555-5555-5555-5555-555555555509', 'Pipeline Step Two Task', 'Second step of the test pipeline', 'Pipeline Step Two', + '44444444-4444-4444-4444-444444444402', NULL, (SELECT id FROM job_types WHERE name = 'DE' AND system_id = 'de' LIMIT 1)), + ('55555555-5555-5555-5555-555555555510', 'Parameters Showcase Task', 'Task exercising every parameter type', 'Parameters Showcase', + '44444444-4444-4444-4444-444444444401', NULL, (SELECT id FROM job_types WHERE name = 'DE' AND system_id = 'de' LIMIT 1)) +ON CONFLICT (id) DO NOTHING; + +COMMIT; diff --git a/testdata/sql/15_container_settings.sql b/testdata/sql/15_container_settings.sql new file mode 100644 index 0000000..2b6020d --- /dev/null +++ b/testdata/sql/15_container_settings.sql @@ -0,0 +1,35 @@ +-- Container settings for the synthetic tools (resource limits, network, working +-- dir). The interactive tool also gets proxy settings and a published port; one +-- tool gets a device and a volume mount. These feed the tool details and app job +-- view responses. +BEGIN; +SET search_path = public, pg_catalog; + +INSERT INTO interactive_apps_proxy_settings (id, image, name, frontend_url, cas_url, cas_validate) VALUES + ('d0000000-0000-0000-0000-0000000000a1', 'test/vice-proxy:latest', 'vice-proxy', + 'https://vice.test.example.org', 'https://cas.test.example.org', 'https://cas.test.example.org/validate') +ON CONFLICT (id) DO NOTHING; + +INSERT INTO container_settings + (id, tools_id, cpu_shares, memory_limit, min_memory_limit, min_cpu_cores, max_cpu_cores, min_disk_space, network_mode, working_directory, name, interactive_apps_proxy_settings_id) VALUES + ('c5000000-0000-0000-0000-000000000001', '44444444-4444-4444-4444-444444444401', 1024, 2147483648, 1073741824, 1, 4, 1073741824, 'bridge', '/work', 'test-tool-1', NULL), + ('c5000000-0000-0000-0000-000000000002', '44444444-4444-4444-4444-444444444402', 1024, 4294967296, 2147483648, 1, 8, 2147483648, 'bridge', '/work', 'test-tool-2', NULL), + ('c5000000-0000-0000-0000-000000000003', '44444444-4444-4444-4444-444444444403', 512, 1073741824, 536870912, 1, 2, 536870912, 'bridge', '/work', 'test-tool-3', NULL), + ('c5000000-0000-0000-0000-000000000004', '44444444-4444-4444-4444-444444444404', 512, 1073741824, 536870912, 1, 2, 536870912, 'none', '/work', 'test-tool-4', NULL), + ('c5000000-0000-0000-0000-000000000005', '44444444-4444-4444-4444-444444444405', 2048, 8589934592, 4294967296, 2, 8, 4294967296, 'bridge', '/work', 'test-interactive-tool', 'd0000000-0000-0000-0000-0000000000a1'), + ('c5000000-0000-0000-0000-000000000006', '44444444-4444-4444-4444-444444444406', 1024, 2147483648, 1073741824, 1, 4, 1073741824, 'bridge', '/work', 'test-osg-tool', NULL) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO container_devices (id, container_settings_id, host_path, container_path) VALUES + ('c5d00000-0000-0000-0000-000000000001', 'c5000000-0000-0000-0000-000000000001', '/dev/fuse', '/dev/fuse') +ON CONFLICT (id) DO NOTHING; + +INSERT INTO container_volumes (id, container_settings_id, host_path, container_path) VALUES + ('c5b00000-0000-0000-0000-000000000001', 'c5000000-0000-0000-0000-000000000001', '/tmp/test-host', '/data') +ON CONFLICT (id) DO NOTHING; + +INSERT INTO container_ports (id, container_settings_id, host_port, container_port, bind_to_host) VALUES + ('c5c00000-0000-0000-0000-000000000005', 'c5000000-0000-0000-0000-000000000005', NULL, 8080, false) +ON CONFLICT (id) DO NOTHING; + +COMMIT; diff --git a/testdata/sql/20_apps.sql b/testdata/sql/20_apps.sql new file mode 100644 index 0000000..5c62a8a --- /dev/null +++ b/testdata/sql/20_apps.sql @@ -0,0 +1,86 @@ +-- Synthetic apps, their versions, and steps. Apps 1-5 are simple single-version +-- DE/interactive apps (each with one step + a basic parameter group). Apps 6-10 +-- add coverage: a multi-version app (with deleted/disabled versions), an OSG app, +-- an external (Agave/HPC-style) app, a multi-step pipeline, and a parameters +-- showcase app. Parameters for the showcase/pipeline tasks live in 22_parameters.sql. +-- A non-deleted app_version is what makes an app appear in the app_listing view. +BEGIN; +SET search_path = public, pg_catalog; + +INSERT INTO apps (id, name, description, wiki_url) VALUES + ('66666666-6666-6666-6666-666666666601', 'Test App 1', 'First synthetic app', NULL), + ('66666666-6666-6666-6666-666666666602', 'Test App 2', 'Second synthetic app', NULL), + ('66666666-6666-6666-6666-666666666603', 'Test App 3', 'Third synthetic app', NULL), + ('66666666-6666-6666-6666-666666666604', 'Test App 4', 'Fourth synthetic app', NULL), + ('66666666-6666-6666-6666-666666666605', 'Test Interactive App', 'Synthetic interactive (VICE) app', NULL), + ('66666666-6666-6666-6666-666666666606', 'Test Versioned App', 'App with multiple versions', NULL), + ('66666666-6666-6666-6666-666666666607', 'Test OSG App', 'Synthetic OSG app', NULL), + ('66666666-6666-6666-6666-666666666608', 'Test External App', 'Synthetic external (Agave/HPC) app', NULL), + ('66666666-6666-6666-6666-666666666609', 'Test Pipeline 1', 'Two-step synthetic pipeline', NULL), + ('66666666-6666-6666-6666-666666666610', 'Test Parameters App', 'App exercising every parameter type', NULL) +ON CONFLICT (id) DO NOTHING; + +-- App versions. App 6 has three versions: 1.0.0 is deleted, 2.0.0 is disabled, +-- 3.0.0 is the active latest (version_order ascending, newest highest). +INSERT INTO app_versions (id, app_id, version, version_order, deleted, disabled, integration_data_id, integration_date, edited_date) VALUES + ('77777777-7777-7777-7777-777777777701', '66666666-6666-6666-6666-666666666601', '1.0.0', 0, false, false, '22222222-2222-2222-2222-222222222201', now(), now()), + ('77777777-7777-7777-7777-777777777702', '66666666-6666-6666-6666-666666666602', '1.0.0', 0, false, false, '22222222-2222-2222-2222-222222222201', now(), now()), + ('77777777-7777-7777-7777-777777777703', '66666666-6666-6666-6666-666666666603', '1.0.0', 0, false, false, '22222222-2222-2222-2222-222222222202', now(), now()), + ('77777777-7777-7777-7777-777777777704', '66666666-6666-6666-6666-666666666604', '1.0.0', 0, false, false, '22222222-2222-2222-2222-222222222202', now(), now()), + ('77777777-7777-7777-7777-777777777705', '66666666-6666-6666-6666-666666666605', '1.0.0', 0, false, false, '22222222-2222-2222-2222-222222222203', now(), now()), + ('77777777-7777-7777-7777-777777777761', '66666666-6666-6666-6666-666666666606', '1.0.0', 0, true, false, '22222222-2222-2222-2222-222222222201', now(), now()), + ('77777777-7777-7777-7777-777777777762', '66666666-6666-6666-6666-666666666606', '2.0.0', 1, false, true, '22222222-2222-2222-2222-222222222201', now(), now()), + ('77777777-7777-7777-7777-777777777763', '66666666-6666-6666-6666-666666666606', '3.0.0', 2, false, false, '22222222-2222-2222-2222-222222222201', now(), now()), + ('77777777-7777-7777-7777-777777777771', '66666666-6666-6666-6666-666666666607', '1.0.0', 0, false, false, '22222222-2222-2222-2222-222222222203', now(), now()), + ('77777777-7777-7777-7777-777777777781', '66666666-6666-6666-6666-666666666608', '1.0.0', 0, false, false, '22222222-2222-2222-2222-222222222203', now(), now()), + ('77777777-7777-7777-7777-777777777791', '66666666-6666-6666-6666-666666666609', '1.0.0', 0, false, false, '22222222-2222-2222-2222-222222222201', now(), now()), + ('77777777-7777-7777-7777-7777777777a1', '66666666-6666-6666-6666-666666666610', '1.0.0', 0, false, false, '22222222-2222-2222-2222-222222222202', now(), now()) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO app_steps (id, app_version_id, task_id, step) VALUES + ('88888888-8888-8888-8888-888888888801', '77777777-7777-7777-7777-777777777701', '55555555-5555-5555-5555-555555555501', 0), + ('88888888-8888-8888-8888-888888888802', '77777777-7777-7777-7777-777777777702', '55555555-5555-5555-5555-555555555502', 0), + ('88888888-8888-8888-8888-888888888803', '77777777-7777-7777-7777-777777777703', '55555555-5555-5555-5555-555555555503', 0), + ('88888888-8888-8888-8888-888888888804', '77777777-7777-7777-7777-777777777704', '55555555-5555-5555-5555-555555555504', 0), + ('88888888-8888-8888-8888-888888888805', '77777777-7777-7777-7777-777777777705', '55555555-5555-5555-5555-555555555505', 0), + ('88888888-8888-8888-8888-888888888861', '77777777-7777-7777-7777-777777777761', '55555555-5555-5555-5555-555555555501', 0), + ('88888888-8888-8888-8888-888888888862', '77777777-7777-7777-7777-777777777762', '55555555-5555-5555-5555-555555555501', 0), + ('88888888-8888-8888-8888-888888888863', '77777777-7777-7777-7777-777777777763', '55555555-5555-5555-5555-555555555501', 0), + ('88888888-8888-8888-8888-888888888871', '77777777-7777-7777-7777-777777777771', '55555555-5555-5555-5555-555555555506', 0), + ('88888888-8888-8888-8888-888888888881', '77777777-7777-7777-7777-777777777781', '55555555-5555-5555-5555-555555555507', 0), + ('88888888-8888-8888-8888-888888888891', '77777777-7777-7777-7777-777777777791', '55555555-5555-5555-5555-555555555508', 0), + ('88888888-8888-8888-8888-888888888892', '77777777-7777-7777-7777-777777777791', '55555555-5555-5555-5555-555555555509', 1), + ('88888888-8888-8888-8888-8888888888a1', '77777777-7777-7777-7777-7777777777a1', '55555555-5555-5555-5555-555555555510', 0) +ON CONFLICT (id) DO NOTHING; + +-- Basic parameter group + two parameters (file input + text) for apps 1-5. +INSERT INTO parameter_groups (id, task_id, name, label, description, display_order) VALUES + ('99999999-9999-9999-9999-999999999901', '55555555-5555-5555-5555-555555555501', 'Parameters', 'Parameters', 'Inputs for Test App 1', 0), + ('99999999-9999-9999-9999-999999999902', '55555555-5555-5555-5555-555555555502', 'Parameters', 'Parameters', 'Inputs for Test App 2', 0), + ('99999999-9999-9999-9999-999999999903', '55555555-5555-5555-5555-555555555503', 'Parameters', 'Parameters', 'Inputs for Test App 3', 0), + ('99999999-9999-9999-9999-999999999904', '55555555-5555-5555-5555-555555555504', 'Parameters', 'Parameters', 'Inputs for Test App 4', 0), + ('99999999-9999-9999-9999-999999999905', '55555555-5555-5555-5555-555555555505', 'Parameters', 'Parameters', 'Inputs for Test Interactive App', 0) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO parameters (id, parameter_group_id, name, label, ordering, display_order, parameter_type, required, description) VALUES + ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa011', '99999999-9999-9999-9999-999999999901', '-i', 'Input file', 0, 0, (SELECT id FROM parameter_types WHERE name = 'FileInput' LIMIT 1), true, 'Input file for Test App 1'), + ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa012', '99999999-9999-9999-9999-999999999901', '-n', 'Sample name', 1, 1, (SELECT id FROM parameter_types WHERE name = 'Text' LIMIT 1), false, 'Sample name for Test App 1'), + ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa021', '99999999-9999-9999-9999-999999999902', '-i', 'Input file', 0, 0, (SELECT id FROM parameter_types WHERE name = 'FileInput' LIMIT 1), true, 'Input file for Test App 2'), + ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa022', '99999999-9999-9999-9999-999999999902', '-n', 'Sample name', 1, 1, (SELECT id FROM parameter_types WHERE name = 'Text' LIMIT 1), false, 'Sample name for Test App 2'), + ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa031', '99999999-9999-9999-9999-999999999903', '-i', 'Input file', 0, 0, (SELECT id FROM parameter_types WHERE name = 'FileInput' LIMIT 1), true, 'Input file for Test App 3'), + ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa032', '99999999-9999-9999-9999-999999999903', '-n', 'Sample name', 1, 1, (SELECT id FROM parameter_types WHERE name = 'Text' LIMIT 1), false, 'Sample name for Test App 3'), + ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa041', '99999999-9999-9999-9999-999999999904', '-i', 'Input file', 0, 0, (SELECT id FROM parameter_types WHERE name = 'FileInput' LIMIT 1), true, 'Input file for Test App 4'), + ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa042', '99999999-9999-9999-9999-999999999904', '-n', 'Sample name', 1, 1, (SELECT id FROM parameter_types WHERE name = 'Text' LIMIT 1), false, 'Sample name for Test App 4'), + ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa051', '99999999-9999-9999-9999-999999999905', '-i', 'Input file', 0, 0, (SELECT id FROM parameter_types WHERE name = 'FileInput' LIMIT 1), true, 'Input file for Test Interactive App'), + ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa052', '99999999-9999-9999-9999-999999999905', '-n', 'Sample name', 1, 1, (SELECT id FROM parameter_types WHERE name = 'Text' LIMIT 1), false, 'Sample name for Test Interactive App') +ON CONFLICT (id) DO NOTHING; + +INSERT INTO file_parameters (id, parameter_id, info_type, data_format, data_source_id) VALUES + ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbb001', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa011', (SELECT id FROM info_type WHERE name = 'File' LIMIT 1), (SELECT id FROM data_formats WHERE name = 'Unspecified' LIMIT 1), (SELECT id FROM data_source WHERE name = 'file' LIMIT 1)), + ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbb002', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa021', (SELECT id FROM info_type WHERE name = 'File' LIMIT 1), (SELECT id FROM data_formats WHERE name = 'Unspecified' LIMIT 1), (SELECT id FROM data_source WHERE name = 'file' LIMIT 1)), + ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbb003', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa031', (SELECT id FROM info_type WHERE name = 'File' LIMIT 1), (SELECT id FROM data_formats WHERE name = 'Unspecified' LIMIT 1), (SELECT id FROM data_source WHERE name = 'file' LIMIT 1)), + ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbb004', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa041', (SELECT id FROM info_type WHERE name = 'File' LIMIT 1), (SELECT id FROM data_formats WHERE name = 'Unspecified' LIMIT 1), (SELECT id FROM data_source WHERE name = 'file' LIMIT 1)), + ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbb005', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa051', (SELECT id FROM info_type WHERE name = 'File' LIMIT 1), (SELECT id FROM data_formats WHERE name = 'Unspecified' LIMIT 1), (SELECT id FROM data_source WHERE name = 'file' LIMIT 1)) +ON CONFLICT (id) DO NOTHING; + +COMMIT; diff --git a/testdata/sql/22_parameters.sql b/testdata/sql/22_parameters.sql new file mode 100644 index 0000000..1bda4ec --- /dev/null +++ b/testdata/sql/22_parameters.sql @@ -0,0 +1,83 @@ +-- Parameters for the pipeline tasks (08, 09) and the parameters-showcase task (10). +-- The showcase covers every major parameter type, selection options +-- (parameter_values, including a parent/child tree relationship), file parameters, +-- and validation rules. Parameter-type / rule-type / info-type / data-format / +-- data-source rows are migration-seeded and referenced by natural key (LIMIT 1 +-- because some seeded names are not unique). +BEGIN; +SET search_path = public, pg_catalog; + +INSERT INTO parameter_groups (id, task_id, name, label, description, display_order) VALUES + ('99999999-9999-9999-9999-999999999908', '55555555-5555-5555-5555-555555555508', 'Parameters', 'Step One', 'Inputs for pipeline step one', 0), + ('99999999-9999-9999-9999-999999999909', '55555555-5555-5555-5555-555555555509', 'Parameters', 'Step Two', 'Inputs for pipeline step two', 0), + ('99999999-9999-9999-9999-999999999910', '55555555-5555-5555-5555-555555555510', 'Parameters', 'All Inputs', 'One parameter of every type', 0) +ON CONFLICT (id) DO NOTHING; + +-- Pipeline step parameters: each step has a file input and a file output; the +-- step-one output is wired to the step-two input in 25_pipelines.sql. +INSERT INTO parameters (id, parameter_group_id, name, label, ordering, display_order, parameter_type, required, description) VALUES + ('a2000000-0000-0000-0000-000000000801', '99999999-9999-9999-9999-999999999908', '-i', 'Input file', 0, 0, (SELECT id FROM parameter_types WHERE name = 'FileInput' LIMIT 1), true, 'Pipeline step one input'), + ('a2000000-0000-0000-0000-000000000802', '99999999-9999-9999-9999-999999999908', '-o', 'Output file', 1, 1, (SELECT id FROM parameter_types WHERE name = 'FileOutput' LIMIT 1), false, 'Pipeline step one output'), + ('a2000000-0000-0000-0000-000000000901', '99999999-9999-9999-9999-999999999909', '-i', 'Input file', 0, 0, (SELECT id FROM parameter_types WHERE name = 'FileInput' LIMIT 1), true, 'Pipeline step two input'), + ('a2000000-0000-0000-0000-000000000902', '99999999-9999-9999-9999-999999999909', '-o', 'Output file', 1, 1, (SELECT id FROM parameter_types WHERE name = 'FileOutput' LIMIT 1), false, 'Pipeline step two output') +ON CONFLICT (id) DO NOTHING; + +-- Parameters-showcase: one of each major type. +INSERT INTO parameters (id, parameter_group_id, name, label, ordering, display_order, parameter_type, required, description) VALUES + ('a3000000-0000-0000-0000-000000000001', '99999999-9999-9999-9999-999999999910', '-i', 'Input file', 0, 0, (SELECT id FROM parameter_types WHERE name = 'FileInput' LIMIT 1), true, 'A file input'), + ('a3000000-0000-0000-0000-000000000002', '99999999-9999-9999-9999-999999999910', '-o', 'Output file', 1, 1, (SELECT id FROM parameter_types WHERE name = 'FileOutput' LIMIT 1), false, 'A file output'), + ('a3000000-0000-0000-0000-000000000003', '99999999-9999-9999-9999-999999999910', '-d', 'Input folder', 2, 2, (SELECT id FROM parameter_types WHERE name = 'FolderInput' LIMIT 1), false, 'A folder input'), + ('a3000000-0000-0000-0000-000000000004', '99999999-9999-9999-9999-999999999910', '-m', 'Multiple files', 3, 3, (SELECT id FROM parameter_types WHERE name = 'MultiFileSelector' LIMIT 1), false, 'A multi-file selector'), + ('a3000000-0000-0000-0000-000000000005', '99999999-9999-9999-9999-999999999910', '-g', 'Reference genome', 4, 4, (SELECT id FROM parameter_types WHERE name = 'ReferenceGenome' LIMIT 1), false, 'A reference genome'), + ('a3000000-0000-0000-0000-000000000006', '99999999-9999-9999-9999-999999999910', '-t', 'Text value', 5, 5, (SELECT id FROM parameter_types WHERE name = 'Text' LIMIT 1), false, 'A text value'), + ('a3000000-0000-0000-0000-000000000007', '99999999-9999-9999-9999-999999999910', '-T', 'Multi-line text', 6, 6, (SELECT id FROM parameter_types WHERE name = 'MultiLineText' LIMIT 1), false, 'A multi-line text value'), + ('a3000000-0000-0000-0000-000000000008', '99999999-9999-9999-9999-999999999910', '-n', 'Number value', 7, 7, (SELECT id FROM parameter_types WHERE name = 'Number' LIMIT 1), false, 'A number value'), + ('a3000000-0000-0000-0000-000000000009', '99999999-9999-9999-9999-999999999910', '-N', 'Integer value', 8, 8, (SELECT id FROM parameter_types WHERE name = 'Integer' LIMIT 1), false, 'An integer value'), + ('a3000000-0000-0000-0000-000000000010', '99999999-9999-9999-9999-999999999910', '-D', 'Double value', 9, 9, (SELECT id FROM parameter_types WHERE name = 'Double' LIMIT 1), false, 'A double value'), + ('a3000000-0000-0000-0000-000000000011', '99999999-9999-9999-9999-999999999910', '-f', 'Flag value', 10, 10, (SELECT id FROM parameter_types WHERE name = 'Flag' LIMIT 1), false, 'A boolean flag'), + ('a3000000-0000-0000-0000-000000000012', '99999999-9999-9999-9999-999999999910', '-s', 'Text selection', 11, 11, (SELECT id FROM parameter_types WHERE name = 'TextSelection' LIMIT 1), false, 'A single-select text list'), + ('a3000000-0000-0000-0000-000000000013', '99999999-9999-9999-9999-999999999910', '-S', 'Integer selection', 12, 12, (SELECT id FROM parameter_types WHERE name = 'IntegerSelection' LIMIT 1), false, 'A single-select integer list'), + ('a3000000-0000-0000-0000-000000000014', '99999999-9999-9999-9999-999999999910', 'ENVVAR','Environment var', 13, 13, (SELECT id FROM parameter_types WHERE name = 'EnvironmentVariable' LIMIT 1), false, 'An environment variable'), + ('a3000000-0000-0000-0000-000000000015', '99999999-9999-9999-9999-999999999910', 'info', 'Info text', 14, 14, (SELECT id FROM parameter_types WHERE name = 'Info' LIMIT 1), false, 'Informational display text') +ON CONFLICT (id) DO NOTHING; + +-- Selection options. The text selection includes a parent option with a nested +-- child to exercise the parameter_values self-reference (tree selections). +INSERT INTO parameter_values (id, parameter_id, parent_id, is_default, display_order, name, value, label) VALUES + ('a4000000-0000-0000-0000-000000000001', 'a3000000-0000-0000-0000-000000000012', NULL, true, 0, 'alpha', 'alpha', 'Alpha'), + ('a4000000-0000-0000-0000-000000000002', 'a3000000-0000-0000-0000-000000000012', NULL, false, 1, 'beta', 'beta', 'Beta'), + ('a4000000-0000-0000-0000-000000000003', 'a3000000-0000-0000-0000-000000000012', 'a4000000-0000-0000-0000-000000000002', false, 0, 'beta-child', 'beta-child', 'Beta Child'), + ('a4000000-0000-0000-0000-000000000011', 'a3000000-0000-0000-0000-000000000013', NULL, true, 0, 'one', '1', 'One'), + ('a4000000-0000-0000-0000-000000000012', 'a3000000-0000-0000-0000-000000000013', NULL, false, 1, 'two', '2', 'Two') +ON CONFLICT (id) DO NOTHING; + +-- File parameters for the file-typed showcase parameters. +INSERT INTO file_parameters (id, parameter_id, info_type, data_format, data_source_id) VALUES + ('bf000000-0000-0000-0000-000000000001', 'a3000000-0000-0000-0000-000000000001', (SELECT id FROM info_type WHERE name = 'File' LIMIT 1), (SELECT id FROM data_formats WHERE name = 'Unspecified' LIMIT 1), (SELECT id FROM data_source WHERE name = 'file' LIMIT 1)), + ('bf000000-0000-0000-0000-000000000002', 'a3000000-0000-0000-0000-000000000002', (SELECT id FROM info_type WHERE name = 'File' LIMIT 1), (SELECT id FROM data_formats WHERE name = 'Unspecified' LIMIT 1), (SELECT id FROM data_source WHERE name = 'stdout' LIMIT 1)), + ('bf000000-0000-0000-0000-000000000003', 'a3000000-0000-0000-0000-000000000003', (SELECT id FROM info_type WHERE name = 'File' LIMIT 1), (SELECT id FROM data_formats WHERE name = 'Unspecified' LIMIT 1), (SELECT id FROM data_source WHERE name = 'file' LIMIT 1)), + ('bf000000-0000-0000-0000-000000000004', 'a3000000-0000-0000-0000-000000000004', (SELECT id FROM info_type WHERE name = 'File' LIMIT 1), (SELECT id FROM data_formats WHERE name = 'Unspecified' LIMIT 1), (SELECT id FROM data_source WHERE name = 'file' LIMIT 1)), + ('bf000000-0000-0000-0000-000000000005', 'a3000000-0000-0000-0000-000000000005', (SELECT id FROM info_type WHERE name = 'ReferenceGenome' LIMIT 1), (SELECT id FROM data_formats WHERE name = 'Unspecified' LIMIT 1), (SELECT id FROM data_source WHERE name = 'file' LIMIT 1)), + ('bf000000-0000-0000-0000-000000000801', 'a2000000-0000-0000-0000-000000000801', (SELECT id FROM info_type WHERE name = 'File' LIMIT 1), (SELECT id FROM data_formats WHERE name = 'Unspecified' LIMIT 1), (SELECT id FROM data_source WHERE name = 'file' LIMIT 1)), + ('bf000000-0000-0000-0000-000000000802', 'a2000000-0000-0000-0000-000000000802', (SELECT id FROM info_type WHERE name = 'File' LIMIT 1), (SELECT id FROM data_formats WHERE name = 'Unspecified' LIMIT 1), (SELECT id FROM data_source WHERE name = 'stdout' LIMIT 1)), + ('bf000000-0000-0000-0000-000000000901', 'a2000000-0000-0000-0000-000000000901', (SELECT id FROM info_type WHERE name = 'File' LIMIT 1), (SELECT id FROM data_formats WHERE name = 'Unspecified' LIMIT 1), (SELECT id FROM data_source WHERE name = 'file' LIMIT 1)), + ('bf000000-0000-0000-0000-000000000902', 'a2000000-0000-0000-0000-000000000902', (SELECT id FROM info_type WHERE name = 'File' LIMIT 1), (SELECT id FROM data_formats WHERE name = 'Unspecified' LIMIT 1), (SELECT id FROM data_source WHERE name = 'stdout' LIMIT 1)) +ON CONFLICT (id) DO NOTHING; + +-- Validation rules: a regex on the text param, an int range on the integer param, +-- and a double range on the number param. +INSERT INTO validation_rules (id, parameter_id, rule_type) VALUES + ('c0000000-0000-0000-0000-000000000001', 'a3000000-0000-0000-0000-000000000006', (SELECT id FROM rule_type WHERE name = 'Regex' LIMIT 1)), + ('c0000000-0000-0000-0000-000000000002', 'a3000000-0000-0000-0000-000000000009', (SELECT id FROM rule_type WHERE name = 'IntRange' LIMIT 1)), + ('c0000000-0000-0000-0000-000000000003', 'a3000000-0000-0000-0000-000000000008', (SELECT id FROM rule_type WHERE name = 'DoubleRange' LIMIT 1)) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO validation_rule_arguments (id, rule_id, ordering, argument_value) VALUES + ('c1000000-0000-0000-0000-000000000001', 'c0000000-0000-0000-0000-000000000001', 0, '^[A-Za-z0-9_]+$'), + ('c1000000-0000-0000-0000-000000000002', 'c0000000-0000-0000-0000-000000000002', 0, '0'), + ('c1000000-0000-0000-0000-000000000003', 'c0000000-0000-0000-0000-000000000002', 1, '100'), + ('c1000000-0000-0000-0000-000000000004', 'c0000000-0000-0000-0000-000000000003', 0, '0.0'), + ('c1000000-0000-0000-0000-000000000005', 'c0000000-0000-0000-0000-000000000003', 1, '1.0') +ON CONFLICT (id) DO NOTHING; + +COMMIT; diff --git a/testdata/sql/25_pipelines.sql b/testdata/sql/25_pipelines.sql new file mode 100644 index 0000000..9b9842f --- /dev/null +++ b/testdata/sql/25_pipelines.sql @@ -0,0 +1,18 @@ +-- Pipeline wiring for the two-step Test Pipeline 1 (app 66...609, version 77...791): +-- step one's output parameter feeds step two's input parameter. This drives +-- step_count/task_count in app_listing and the pipeline endpoints. +BEGIN; +SET search_path = public, pg_catalog; + +INSERT INTO workflow_io_maps (id, app_version_id, source_step, target_step) VALUES + ('d1000000-0000-0000-0000-000000000001', '77777777-7777-7777-7777-777777777791', + '88888888-8888-8888-8888-888888888891', '88888888-8888-8888-8888-888888888892') +ON CONFLICT (id) DO NOTHING; + +INSERT INTO input_output_mapping (mapping_id, input, output) VALUES + ('d1000000-0000-0000-0000-000000000001', + 'a2000000-0000-0000-0000-000000000901', -- step two input file + 'a2000000-0000-0000-0000-000000000802') -- step one output file +ON CONFLICT (mapping_id, input, external_input) DO NOTHING; + +COMMIT; diff --git a/testdata/sql/28_app_docs_refs.sql b/testdata/sql/28_app_docs_refs.sql new file mode 100644 index 0000000..c7d7797 --- /dev/null +++ b/testdata/sql/28_app_docs_refs.sql @@ -0,0 +1,19 @@ +-- App documentation and references, keyed by app_version_id. created_by/modified_by +-- are user UUIDs. +BEGIN; +SET search_path = public, pg_catalog; + +INSERT INTO app_documentation (app_version_id, value, created_by, modified_by) VALUES + ('77777777-7777-7777-7777-777777777701', '# Test App 1\n\nMarkdown documentation for Test App 1.', '11111111-1111-1111-1111-111111111101', '11111111-1111-1111-1111-111111111101'), + ('77777777-7777-7777-7777-777777777763', '# Test Versioned App 3.0.0\n\nDocs for the latest version.', '11111111-1111-1111-1111-111111111101', '11111111-1111-1111-1111-111111111101'), + ('77777777-7777-7777-7777-777777777791', '# Test Pipeline 1\n\nA two-step pipeline.', '11111111-1111-1111-1111-111111111101', '11111111-1111-1111-1111-111111111101'), + ('77777777-7777-7777-7777-7777777777a1', '# Test Parameters App\n\nShowcases every parameter type.', '11111111-1111-1111-1111-111111111102', '11111111-1111-1111-1111-111111111102') +ON CONFLICT (app_version_id) DO NOTHING; + +INSERT INTO app_references (id, app_version_id, reference_text) VALUES + ('e1000000-0000-0000-0000-000000000001', '77777777-7777-7777-7777-777777777701', 'Test Author A. (2024). A synthetic reference. Journal of Testing, 1(1), 1-10.'), + ('e1000000-0000-0000-0000-000000000002', '77777777-7777-7777-7777-777777777701', 'https://example.org/test-app-1/docs'), + ('e1000000-0000-0000-0000-000000000003', '77777777-7777-7777-7777-777777777763', 'Test Author B. (2024). Versioned app methods. Journal of Testing, 2(1), 11-20.') +ON CONFLICT (id) DO NOTHING; + +COMMIT; diff --git a/testdata/sql/30_workspaces_categories.sql b/testdata/sql/30_workspaces_categories.sql new file mode 100644 index 0000000..251c47f --- /dev/null +++ b/testdata/sql/30_workspaces_categories.sql @@ -0,0 +1,84 @@ +-- Per-user workspaces and the app-category hierarchy. This mirrors the apps +-- service's workspace bootstrap (apps/persistence/workspace.clj + config): each +-- user's workspace has a root category "Workspace" with two subcategories, +-- "Apps under development" at child_index 0 (the dev/private category) and +-- "Favorite Apps" at child_index 1 (the favorites category that drives the +-- is_favorite flag in app_listing). workspace and app_categories reference each +-- other, so workspaces are inserted with a null root and patched afterward. +BEGIN; +SET search_path = public, pg_catalog; + +INSERT INTO workspace (id, user_id, root_category_id, is_public) VALUES + ('eeeeeeee-eeee-eeee-eeee-eeeeeeeeee01', '11111111-1111-1111-1111-111111111101', NULL, false), + ('eeeeeeee-eeee-eeee-eeee-eeeeeeeeee02', '11111111-1111-1111-1111-111111111102', NULL, false), + ('eeeeeeee-eeee-eeee-eeee-eeeeeeeeee03', '11111111-1111-1111-1111-111111111103', NULL, false), + ('eeeeeeee-eeee-eeee-eeee-eeeeeeeeee04', '11111111-1111-1111-1111-111111111104', NULL, false) +ON CONFLICT (id) DO NOTHING; + +-- Root + dev (index 0) + favorites (index 1) categories for each user. +INSERT INTO app_categories (id, name, description, workspace_id) VALUES + ('ca000000-0000-0000-0000-000000000001', 'Workspace', 'Root category for testuser01', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeee01'), + ('ca000000-0000-0000-0000-000000000101', 'Apps under development', 'Private apps for testuser01', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeee01'), + ('ca000000-0000-0000-0000-000000000201', 'Favorite Apps', 'Favorites for testuser01', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeee01'), + ('ca000000-0000-0000-0000-000000000002', 'Workspace', 'Root category for testuser02', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeee02'), + ('ca000000-0000-0000-0000-000000000102', 'Apps under development', 'Private apps for testuser02', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeee02'), + ('ca000000-0000-0000-0000-000000000202', 'Favorite Apps', 'Favorites for testuser02', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeee02'), + ('ca000000-0000-0000-0000-000000000003', 'Workspace', 'Root category for testuser03', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeee03'), + ('ca000000-0000-0000-0000-000000000103', 'Apps under development', 'Private apps for testuser03', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeee03'), + ('ca000000-0000-0000-0000-000000000203', 'Favorite Apps', 'Favorites for testuser03', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeee03'), + ('ca000000-0000-0000-0000-000000000004', 'Workspace', 'Root category for testuser04', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeee04'), + ('ca000000-0000-0000-0000-000000000104', 'Apps under development', 'Private apps for testuser04', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeee04'), + ('ca000000-0000-0000-0000-000000000204', 'Favorite Apps', 'Favorites for testuser04', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeee04') +ON CONFLICT (id) DO NOTHING; + +UPDATE workspace SET root_category_id = 'ca000000-0000-0000-0000-000000000001' WHERE id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeee01'; +UPDATE workspace SET root_category_id = 'ca000000-0000-0000-0000-000000000002' WHERE id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeee02'; +UPDATE workspace SET root_category_id = 'ca000000-0000-0000-0000-000000000003' WHERE id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeee03'; +UPDATE workspace SET root_category_id = 'ca000000-0000-0000-0000-000000000004' WHERE id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeee04'; + +-- Wire dev (index 0) and favorites (index 1) under each user's root category. +INSERT INTO app_category_group (parent_category_id, child_category_id, child_index) VALUES + ('ca000000-0000-0000-0000-000000000001', 'ca000000-0000-0000-0000-000000000101', 0), + ('ca000000-0000-0000-0000-000000000001', 'ca000000-0000-0000-0000-000000000201', 1), + ('ca000000-0000-0000-0000-000000000002', 'ca000000-0000-0000-0000-000000000102', 0), + ('ca000000-0000-0000-0000-000000000002', 'ca000000-0000-0000-0000-000000000202', 1), + ('ca000000-0000-0000-0000-000000000003', 'ca000000-0000-0000-0000-000000000103', 0), + ('ca000000-0000-0000-0000-000000000003', 'ca000000-0000-0000-0000-000000000203', 1), + ('ca000000-0000-0000-0000-000000000004', 'ca000000-0000-0000-0000-000000000104', 0), + ('ca000000-0000-0000-0000-000000000004', 'ca000000-0000-0000-0000-000000000204', 1) +ON CONFLICT (parent_category_id, child_category_id) DO NOTHING; + +-- A second public category under the seeded "Public Apps" root (which owns "Beta"). +INSERT INTO app_categories (id, name, description, workspace_id) +SELECT 'cb000000-0000-0000-0000-000000000001', 'Bioinformatics', 'Public bioinformatics apps', workspace_id +FROM app_categories WHERE name = 'Beta' LIMIT 1 +ON CONFLICT (id) DO NOTHING; + +INSERT INTO app_category_group (parent_category_id, child_category_id, child_index) +SELECT (SELECT id FROM app_categories WHERE name = 'Public Apps' LIMIT 1), 'cb000000-0000-0000-0000-000000000001', 1 +ON CONFLICT (parent_category_id, child_category_id) DO NOTHING; + +-- Categorize apps: favorites + dev (private) for users, and public placements. +INSERT INTO app_category_app (app_category_id, app_id) VALUES + ('ca000000-0000-0000-0000-000000000201', '66666666-6666-6666-6666-666666666601'), -- testuser01 favorite + ('ca000000-0000-0000-0000-000000000101', '66666666-6666-6666-6666-666666666606'), -- testuser01 private (versioned app) + ('ca000000-0000-0000-0000-000000000102', '66666666-6666-6666-6666-666666666603'), -- testuser02 private + ('cb000000-0000-0000-0000-000000000001', '66666666-6666-6666-6666-666666666603'), -- Bioinformatics (public) + ('cb000000-0000-0000-0000-000000000001', '66666666-6666-6666-6666-666666666610') -- Bioinformatics (public) +ON CONFLICT (app_category_id, app_id) DO NOTHING; + +-- Publish apps to the seeded public "Beta" category. +INSERT INTO app_category_app (app_category_id, app_id) +SELECT (SELECT id FROM app_categories WHERE name = 'Beta' LIMIT 1), app_id +FROM (VALUES + ('66666666-6666-6666-6666-666666666601'::uuid), + ('66666666-6666-6666-6666-666666666602'::uuid), + ('66666666-6666-6666-6666-666666666609'::uuid)) AS v(app_id) +ON CONFLICT (app_category_id, app_id) DO NOTHING; + +-- A suggested category for an app (admin categorization hint). +INSERT INTO suggested_groups (app_id, app_category_id) +SELECT '66666666-6666-6666-6666-666666666604', id FROM app_categories WHERE name = 'Beta' LIMIT 1 +ON CONFLICT (app_id, app_category_id) DO NOTHING; + +COMMIT; diff --git a/testdata/sql/35_tool_requests.sql b/testdata/sql/35_tool_requests.sql new file mode 100644 index 0000000..ecff401 --- /dev/null +++ b/testdata/sql/35_tool_requests.sql @@ -0,0 +1,26 @@ +-- Tool installation requests with status histories. tool_architectures and +-- tool_request_status_codes are migration-seeded and referenced by natural key. +BEGIN; +SET search_path = public, pg_catalog; + +INSERT INTO tool_requests + (id, tool_name, description, source_url, doc_url, version, attribution, multithreaded, + test_data_path, instructions, additional_info, requestor_id, tool_architecture_id) VALUES + ('f5a00000-0000-0000-0000-000000000001', 'Requested Tool A', 'Please install tool A', + 'https://example.org/tool-a/source', 'https://example.org/tool-a/docs', '1.0.0', 'Test Author A', false, + '/iplant/home/testuser01/tool-a-test', 'Run with default options', NULL, + '11111111-1111-1111-1111-111111111101', (SELECT id FROM tool_architectures WHERE name ILIKE '%64%' LIMIT 1)), + ('f5a00000-0000-0000-0000-000000000002', 'Requested Tool B', 'Please install tool B', + 'https://example.org/tool-b/source', 'https://example.org/tool-b/docs', '2.3.1', 'Test Author B', true, + '/iplant/home/testuser02/tool-b-test', 'Requires GPU', NULL, + '11111111-1111-1111-1111-111111111102', (SELECT id FROM tool_architectures WHERE name ILIKE '%64%' LIMIT 1)) +ON CONFLICT (id) DO NOTHING; + +-- Request A progressed Submitted -> Completion; request B is still Submitted. +INSERT INTO tool_request_statuses (id, tool_request_id, tool_request_status_code_id, updater_id, comments, date_assigned) VALUES + ('f5b00000-0000-0000-0000-000000000001', 'f5a00000-0000-0000-0000-000000000001', (SELECT id FROM tool_request_status_codes WHERE name = 'Submitted' LIMIT 1), '11111111-1111-1111-1111-111111111101', 'Request submitted', '2024-05-01 10:00:00'), + ('f5b00000-0000-0000-0000-000000000002', 'f5a00000-0000-0000-0000-000000000001', (SELECT id FROM tool_request_status_codes WHERE name = 'Completion' LIMIT 1), '11111111-1111-1111-1111-111111111103', 'Tool installed', '2024-05-03 12:00:00'), + ('f5b00000-0000-0000-0000-000000000003', 'f5a00000-0000-0000-0000-000000000002', (SELECT id FROM tool_request_status_codes WHERE name = 'Submitted' LIMIT 1), '11111111-1111-1111-1111-111111111102', 'Request submitted', '2024-05-05 09:00:00') +ON CONFLICT (id) DO NOTHING; + +COMMIT; diff --git a/testdata/sql/40_operators.sql b/testdata/sql/40_operators.sql new file mode 100644 index 0000000..d08f682 --- /dev/null +++ b/testdata/sql/40_operators.sql @@ -0,0 +1,12 @@ +-- VICE operators. base_url is what the job_listings view exposes as +-- operator_base_url for interactive analyses. last_reconciled_at/reconciled_by +-- are left null together to satisfy the operators_reconcile_fields_check. +BEGIN; +SET search_path = public, pg_catalog; + +INSERT INTO operators (id, name, url, base_url, priority) VALUES + ('cccccccc-cccc-cccc-cccc-cccccccccc01', 'test-operator-1', 'https://operator1.test.example.org', 'https://vice1.test.example.org', 0), + ('cccccccc-cccc-cccc-cccc-cccccccccc02', 'test-operator-2', 'https://operator2.test.example.org', 'https://vice2.test.example.org', 1) +ON CONFLICT (id) DO NOTHING; + +COMMIT; diff --git a/testdata/sql/45_publication_requests.sql b/testdata/sql/45_publication_requests.sql new file mode 100644 index 0000000..e0ef838 --- /dev/null +++ b/testdata/sql/45_publication_requests.sql @@ -0,0 +1,25 @@ +-- App publication requests with status histories, plus additional app ratings so +-- multiple apps have multi-user averages in app_listing / rating_listing. +BEGIN; +SET search_path = public, pg_catalog; + +INSERT INTO app_publication_requests (id, requestor_id, app_id) VALUES + ('f6a00000-0000-0000-0000-000000000001', '11111111-1111-1111-1111-111111111101', '66666666-6666-6666-6666-666666666601'), + ('f6a00000-0000-0000-0000-000000000002', '11111111-1111-1111-1111-111111111102', '66666666-6666-6666-6666-666666666603') +ON CONFLICT (id) DO NOTHING; + +INSERT INTO app_publication_request_statuses (id, app_publication_request_id, app_publication_request_status_code_id, updater_id, comments, date_assigned) VALUES + ('f6b00000-0000-0000-0000-000000000001', 'f6a00000-0000-0000-0000-000000000001', (SELECT id FROM app_publication_request_status_codes WHERE name = 'Submitted' LIMIT 1), '11111111-1111-1111-1111-111111111101', 'Publication requested', '2024-05-10 10:00:00'), + ('f6b00000-0000-0000-0000-000000000002', 'f6a00000-0000-0000-0000-000000000002', (SELECT id FROM app_publication_request_status_codes WHERE name = 'Submitted' LIMIT 1), '11111111-1111-1111-1111-111111111102', 'Publication requested', '2024-05-11 10:00:00'), + ('f6b00000-0000-0000-0000-000000000003', 'f6a00000-0000-0000-0000-000000000002', (SELECT id FROM app_publication_request_status_codes WHERE name = 'Completion' LIMIT 1), '11111111-1111-1111-1111-111111111103', 'Published', '2024-05-12 15:00:00') +ON CONFLICT (id) DO NOTHING; + +-- Additional ratings (public.ratings is UNIQUE on (user_id, app_id)). +INSERT INTO ratings (id, user_id, app_id, rating) VALUES + ('a1a1a1a1-0000-0000-0000-000000000004', '11111111-1111-1111-1111-111111111105', '66666666-6666-6666-6666-666666666602', 4), + ('a1a1a1a1-0000-0000-0000-000000000005', '11111111-1111-1111-1111-111111111106', '66666666-6666-6666-6666-666666666603', 5), + ('a1a1a1a1-0000-0000-0000-000000000006', '11111111-1111-1111-1111-111111111107', '66666666-6666-6666-6666-666666666603', 3), + ('a1a1a1a1-0000-0000-0000-000000000007', '11111111-1111-1111-1111-111111111101', '66666666-6666-6666-6666-666666666606', 5) +ON CONFLICT (id) DO NOTHING; + +COMMIT; diff --git a/testdata/sql/50_jobs.sql b/testdata/sql/50_jobs.sql new file mode 100644 index 0000000..c06d4d8 --- /dev/null +++ b/testdata/sql/50_jobs.sql @@ -0,0 +1,88 @@ +-- Synthetic analyses (jobs) spanning the common statuses, including a batch +-- parent with two children and two interactive jobs tied to operators. jobs.app_id +-- holds the app UUID as text (the job system stores it denormalized). Each +-- non-parent job gets a job_step; a couple get a job_status_updates trail. +BEGIN; +SET search_path = public, pg_catalog; + +INSERT INTO jobs (id, job_name, job_description, app_name, app_description, result_folder_path, + start_date, end_date, status, notify, user_id, app_id, job_type_id, parent_id, + planned_end_date, app_version_id, operator_id) VALUES + ('dddddddd-dddd-dddd-dddd-dddddddddd01', 'Test Analysis 1', '', 'Test App 1', 'First synthetic app', + '/iplant/home/testuser01/analyses/test-analysis-1', '2024-01-15 10:00:00+00', '2024-01-15 10:20:00+00', + 'Completed', true, '11111111-1111-1111-1111-111111111101', '66666666-6666-6666-6666-666666666601', + (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), NULL, NULL, '77777777-7777-7777-7777-777777777701', NULL), + ('dddddddd-dddd-dddd-dddd-dddddddddd02', 'Test Analysis 2', '', 'Test App 2', 'Second synthetic app', + '/iplant/home/testuser01/analyses/test-analysis-2', '2024-01-16 09:00:00+00', '2024-01-16 09:05:00+00', + 'Failed', true, '11111111-1111-1111-1111-111111111101', '66666666-6666-6666-6666-666666666602', + (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), NULL, NULL, '77777777-7777-7777-7777-777777777702', NULL), + ('dddddddd-dddd-dddd-dddd-dddddddddd03', 'Test Analysis 3', '', 'Test App 3', 'Third synthetic app', + '/iplant/home/testuser02/analyses/test-analysis-3', '2024-02-01 14:00:00+00', '2024-02-01 14:02:00+00', + 'Canceled', true, '11111111-1111-1111-1111-111111111102', '66666666-6666-6666-6666-666666666603', + (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), NULL, NULL, '77777777-7777-7777-7777-777777777703', NULL), + ('dddddddd-dddd-dddd-dddd-dddddddddd04', 'Test Interactive Analysis 1', '', 'Test Interactive App', 'Synthetic interactive (VICE) app', + '/iplant/home/testuser02/analyses/test-interactive-1', '2024-02-10 08:00:00+00', NULL, + 'Running', true, '11111111-1111-1111-1111-111111111102', '66666666-6666-6666-6666-666666666605', + (SELECT id FROM job_types WHERE name='Interactive' AND system_id='interactive'), NULL, '2024-02-12 08:00:00+00', + '77777777-7777-7777-7777-777777777705', 'cccccccc-cccc-cccc-cccc-cccccccccc01'), + ('dddddddd-dddd-dddd-dddd-dddddddddd05', 'Test Analysis 5', '', 'Test App 1', 'First synthetic app', + '/iplant/home/testuser03/analyses/test-analysis-5', '2024-03-01 11:00:00+00', NULL, + 'Submitted', true, '11111111-1111-1111-1111-111111111103', '66666666-6666-6666-6666-666666666601', + (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), NULL, NULL, '77777777-7777-7777-7777-777777777701', NULL), + ('dddddddd-dddd-dddd-dddd-dddddddddd06', 'Test Analysis 6', '', 'Test App 4', 'Fourth synthetic app', + '/iplant/home/testuser03/analyses/test-analysis-6', '2024-03-02 11:00:00+00', NULL, + 'Queued', true, '11111111-1111-1111-1111-111111111103', '66666666-6666-6666-6666-666666666604', + (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), NULL, NULL, '77777777-7777-7777-7777-777777777704', NULL), + ('dddddddd-dddd-dddd-dddd-dddddddddd07', 'Test Analysis 7', '', 'Test App 2', 'Second synthetic app', + '/iplant/home/testuser04/analyses/test-analysis-7', '2024-03-05 13:00:00+00', '2024-03-05 13:30:00+00', + 'Completed', false, '11111111-1111-1111-1111-111111111104', '66666666-6666-6666-6666-666666666602', + (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), NULL, NULL, '77777777-7777-7777-7777-777777777702', NULL), + ('dddddddd-dddd-dddd-dddd-dddddddddd08', 'Test Interactive Analysis 2', '', 'Test Interactive App', 'Synthetic interactive (VICE) app', + '/iplant/home/testuser05/analyses/test-interactive-2', '2024-03-10 08:00:00+00', NULL, + 'Running', true, '11111111-1111-1111-1111-111111111105', '66666666-6666-6666-6666-666666666605', + (SELECT id FROM job_types WHERE name='Interactive' AND system_id='interactive'), NULL, '2024-03-12 08:00:00+00', + '77777777-7777-7777-7777-777777777705', 'cccccccc-cccc-cccc-cccc-cccccccccc02'), + ('dddddddd-dddd-dddd-dddd-dddddddddd09', 'Test Batch Analysis', '', 'Test App 1', 'First synthetic app', + '/iplant/home/testuser01/analyses/test-batch', '2024-04-01 10:00:00+00', '2024-04-01 10:40:00+00', + 'Completed', true, '11111111-1111-1111-1111-111111111101', '66666666-6666-6666-6666-666666666601', + (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), NULL, NULL, '77777777-7777-7777-7777-777777777701', NULL), + ('dddddddd-dddd-dddd-dddd-dddddddddd10', 'Test Batch Analysis - 1', '', 'Test App 1', 'First synthetic app', + '/iplant/home/testuser01/analyses/test-batch/1', '2024-04-01 10:00:00+00', '2024-04-01 10:20:00+00', + 'Completed', true, '11111111-1111-1111-1111-111111111101', '66666666-6666-6666-6666-666666666601', + (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), 'dddddddd-dddd-dddd-dddd-dddddddddd09', NULL, '77777777-7777-7777-7777-777777777701', NULL), + ('dddddddd-dddd-dddd-dddd-dddddddddd11', 'Test Batch Analysis - 2', '', 'Test App 1', 'First synthetic app', + '/iplant/home/testuser01/analyses/test-batch/2', '2024-04-01 10:20:00+00', '2024-04-01 10:40:00+00', + 'Failed', true, '11111111-1111-1111-1111-111111111101', '66666666-6666-6666-6666-666666666601', + (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), 'dddddddd-dddd-dddd-dddd-dddddddddd09', NULL, '77777777-7777-7777-7777-777777777701', NULL), + ('dddddddd-dddd-dddd-dddd-dddddddddd12', 'Test Analysis 12', '', 'Test App 3', 'Third synthetic app', + '/iplant/home/testuser06/analyses/test-analysis-12', '2024-04-10 16:00:00+00', '2024-04-10 16:15:00+00', + 'Completed', true, '11111111-1111-1111-1111-111111111106', '66666666-6666-6666-6666-666666666603', + (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), NULL, NULL, '77777777-7777-7777-7777-777777777703', NULL) +ON CONFLICT (id) DO NOTHING; + +-- One job step per non-parent job (the batch parent dd...09 has none; its children do). +INSERT INTO job_steps (job_id, step_number, external_id, start_date, end_date, status, job_type_id, app_step_number) VALUES + ('dddddddd-dddd-dddd-dddd-dddddddddd01', 1, 'extjob-01-0', '2024-01-15 10:00:00+00', '2024-01-15 10:20:00+00', 'Completed', (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), 0), + ('dddddddd-dddd-dddd-dddd-dddddddddd02', 1, 'extjob-02-0', '2024-01-16 09:00:00+00', '2024-01-16 09:05:00+00', 'Failed', (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), 0), + ('dddddddd-dddd-dddd-dddd-dddddddddd03', 1, 'extjob-03-0', '2024-02-01 14:00:00+00', '2024-02-01 14:02:00+00', 'Canceled', (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), 0), + ('dddddddd-dddd-dddd-dddd-dddddddddd04', 1, 'extjob-04-0', '2024-02-10 08:00:00+00', NULL, 'Running', (SELECT id FROM job_types WHERE name='Interactive' AND system_id='interactive'), 0), + ('dddddddd-dddd-dddd-dddd-dddddddddd05', 1, 'extjob-05-0', '2024-03-01 11:00:00+00', NULL, 'Submitted', (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), 0), + ('dddddddd-dddd-dddd-dddd-dddddddddd06', 1, 'extjob-06-0', '2024-03-02 11:00:00+00', NULL, 'Submitted', (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), 0), + ('dddddddd-dddd-dddd-dddd-dddddddddd07', 1, 'extjob-07-0', '2024-03-05 13:00:00+00', '2024-03-05 13:30:00+00', 'Completed', (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), 0), + ('dddddddd-dddd-dddd-dddd-dddddddddd08', 1, 'extjob-08-0', '2024-03-10 08:00:00+00', NULL, 'Running', (SELECT id FROM job_types WHERE name='Interactive' AND system_id='interactive'), 0), + ('dddddddd-dddd-dddd-dddd-dddddddddd10', 1, 'extjob-10-0', '2024-04-01 10:00:00+00', '2024-04-01 10:20:00+00', 'Completed', (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), 0), + ('dddddddd-dddd-dddd-dddd-dddddddddd11', 1, 'extjob-11-0', '2024-04-01 10:20:00+00', '2024-04-01 10:40:00+00', 'Failed', (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), 0), + ('dddddddd-dddd-dddd-dddd-dddddddddd12', 1, 'extjob-12-0', '2024-04-10 16:00:00+00', '2024-04-10 16:15:00+00', 'Completed', (SELECT id FROM job_types WHERE name='DE' AND system_id='de'), 0) +ON CONFLICT (job_id, step_number) DO NOTHING; + +-- Status update trail for the first two analyses. sent_from is an inet address and +-- sent_on is epoch milliseconds. +INSERT INTO job_status_updates (id, external_id, message, status, sent_from, sent_from_hostname, sent_on, propagated) VALUES + ('eeee0000-0000-0000-0000-000000000101', 'extjob-01-0', 'Job submitted', 'Submitted', '10.0.0.1', 'job-status-listener', 1705312800000, true), + ('eeee0000-0000-0000-0000-000000000102', 'extjob-01-0', 'Job running', 'Running', '10.0.0.1', 'job-status-listener', 1705312860000, true), + ('eeee0000-0000-0000-0000-000000000103', 'extjob-01-0', 'Job completed', 'Completed', '10.0.0.1', 'job-status-listener', 1705314000000, true), + ('eeee0000-0000-0000-0000-000000000201', 'extjob-02-0', 'Job submitted', 'Submitted', '10.0.0.1', 'job-status-listener', 1705395600000, true), + ('eeee0000-0000-0000-0000-000000000202', 'extjob-02-0', 'Job failed', 'Failed', '10.0.0.1', 'job-status-listener', 1705395900000, true) +ON CONFLICT (id) DO NOTHING; + +COMMIT; diff --git a/testdata/sql/60_launches.sql b/testdata/sql/60_launches.sql new file mode 100644 index 0000000..c89d65e --- /dev/null +++ b/testdata/sql/60_launches.sql @@ -0,0 +1,30 @@ +-- Quick launches (saved app configurations) and instant launches (quick launches +-- promoted to one-click buttons). A quick_launch points at a submissions row via +-- submission_id (NOT NULL), so the submissions are inserted first. +BEGIN; +SET search_path = public, pg_catalog; + +INSERT INTO submissions (id, submission) VALUES + ('a5a5a5a5-0000-0000-0000-000000000001', + '{"app_id":"66666666-6666-6666-6666-666666666601","app_version_id":"77777777-7777-7777-7777-777777777701","system_id":"de","name":"Test App 1 quick launch","description":"","notify":true,"debug":false,"create_output_subdir":true,"output_dir":"/iplant/home/testuser01/analyses","archive_logs":true,"config":{},"requirements":[]}'), + ('a5a5a5a5-0000-0000-0000-000000000002', + '{"app_id":"66666666-6666-6666-6666-666666666602","app_version_id":"77777777-7777-7777-7777-777777777702","system_id":"de","name":"Test App 2 quick launch","description":"","notify":true,"debug":false,"create_output_subdir":true,"output_dir":"/iplant/home/testuser01/analyses","archive_logs":true,"config":{},"requirements":[]}'), + ('a5a5a5a5-0000-0000-0000-000000000003', + '{"app_id":"66666666-6666-6666-6666-666666666605","app_version_id":"77777777-7777-7777-7777-777777777705","system_id":"interactive","name":"Interactive app quick launch","description":"","notify":true,"debug":false,"create_output_subdir":true,"output_dir":"/iplant/home/testuser03/analyses","archive_logs":true,"config":{},"requirements":[]}') +ON CONFLICT (id) DO NOTHING; + +INSERT INTO quick_launches (id, name, description, creator, app_id, app_version_id, submission_id, is_public) VALUES + ('f1f1f1f1-0000-0000-0000-000000000001', 'Test App 1 Quick Launch', 'Public quick launch for Test App 1', + '11111111-1111-1111-1111-111111111101', '66666666-6666-6666-6666-666666666601', '77777777-7777-7777-7777-777777777701', 'a5a5a5a5-0000-0000-0000-000000000001', true), + ('f1f1f1f1-0000-0000-0000-000000000002', 'Test App 2 Quick Launch', 'Private quick launch for Test App 2', + '11111111-1111-1111-1111-111111111101', '66666666-6666-6666-6666-666666666602', '77777777-7777-7777-7777-777777777702', 'a5a5a5a5-0000-0000-0000-000000000002', false), + ('f1f1f1f1-0000-0000-0000-000000000003', 'Interactive App Quick Launch', 'Public quick launch for the interactive app', + '11111111-1111-1111-1111-111111111103', '66666666-6666-6666-6666-666666666605', '77777777-7777-7777-7777-777777777705', 'a5a5a5a5-0000-0000-0000-000000000003', true) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO instant_launches (id, quick_launch_id, added_by) VALUES + ('f2f2f2f2-0000-0000-0000-000000000001', 'f1f1f1f1-0000-0000-0000-000000000001', '11111111-1111-1111-1111-111111111101'), + ('f2f2f2f2-0000-0000-0000-000000000002', 'f1f1f1f1-0000-0000-0000-000000000003', '11111111-1111-1111-1111-111111111103') +ON CONFLICT (id) DO NOTHING; + +COMMIT; diff --git a/testdata/sql/70_metadata.sql b/testdata/sql/70_metadata.sql new file mode 100644 index 0000000..d3bb998 --- /dev/null +++ b/testdata/sql/70_metadata.sql @@ -0,0 +1,58 @@ +-- App ratings and metadata. public.ratings feeds the app_listing average_rating +-- and the rating_listing view. The metadata schema holds AVUs, tags, comments, +-- favorites, and its own ratings, keyed by target_id + target_type. +BEGIN; + +-- public.ratings: numeric app ratings by user. +SET search_path = public, pg_catalog; +INSERT INTO ratings (id, user_id, app_id, rating) VALUES + ('a1a1a1a1-0000-0000-0000-000000000001', '11111111-1111-1111-1111-111111111102', '66666666-6666-6666-6666-666666666601', 5), + ('a1a1a1a1-0000-0000-0000-000000000002', '11111111-1111-1111-1111-111111111103', '66666666-6666-6666-6666-666666666601', 4), + ('a1a1a1a1-0000-0000-0000-000000000003', '11111111-1111-1111-1111-111111111104', '66666666-6666-6666-6666-666666666602', 3) +ON CONFLICT (id) DO NOTHING; + +SET search_path = metadata, public, pg_catalog; + +INSERT INTO metadata.avus (id, attribute, value, unit, target_id, target_type, created_by, modified_by) VALUES + ('a2a2a2a2-0000-0000-0000-000000000001', 'topic', 'genomics', '', '66666666-6666-6666-6666-666666666601', 'app', 'testuser01@example.org', 'testuser01@example.org'), + ('a2a2a2a2-0000-0000-0000-000000000002', 'topic', 'alignment', '', '66666666-6666-6666-6666-666666666602', 'app', 'testuser01@example.org', 'testuser01@example.org'), + ('a2a2a2a2-0000-0000-0000-000000000003', 'run-note', 'first run', '', 'dddddddd-dddd-dddd-dddd-dddddddddd01', 'analysis', 'testuser01@example.org', 'testuser01@example.org') +ON CONFLICT (id) DO NOTHING; + +INSERT INTO metadata.tags (id, value, description, owner_id) VALUES + ('14141414-0000-0000-0000-000000000001', 'genomics', 'Genomics-related apps', 'testuser01@example.org'), + ('14141414-0000-0000-0000-000000000002', 'favorites', 'Personal favorites', 'testuser02@example.org') +ON CONFLICT (id) DO NOTHING; + +INSERT INTO metadata.attached_tags (tag_id, target_id, target_type, attacher_id) VALUES + ('14141414-0000-0000-0000-000000000001', '66666666-6666-6666-6666-666666666601', 'app', 'testuser01@example.org'), + ('14141414-0000-0000-0000-000000000002', '66666666-6666-6666-6666-666666666602', 'app', 'testuser02@example.org') +ON CONFLICT DO NOTHING; + +INSERT INTO metadata.comments (id, value, owner_id, target_id, target_type) VALUES + ('c0c0c0c0-0000-0000-0000-000000000001', 'This app worked well for my data.', 'testuser02@example.org', '66666666-6666-6666-6666-666666666601', 'app') +ON CONFLICT (id) DO NOTHING; + +INSERT INTO metadata.favorites (target_id, target_type, owner_id) VALUES + ('66666666-6666-6666-6666-666666666601', 'app', 'testuser01@example.org'), + ('66666666-6666-6666-6666-666666666603', 'app', 'testuser02@example.org') +ON CONFLICT DO NOTHING; + +INSERT INTO metadata.ratings (id, owner_id, target_id, target_type, rating) VALUES + ('a3a3a3a3-0000-0000-0000-000000000001', 'testuser02@example.org', '66666666-6666-6666-6666-666666666601', 'app', 5) +ON CONFLICT (id) DO NOTHING; + +-- AVUs that drive metadata-service-backed apps features (Beta category, ontology +-- hierarchies, communities). These are NOT consulted by the apps service via the +-- database directly; they require the metadata service running against this DB. +-- Attribute IRIs/labels mirror the apps service config (apps.workspace.metadata.*): +-- Beta marker attr "n2t.net/ark:/99152/h1459" = "beta"; ontology category attrs +-- "rdf:type" and "http://edamontology.org/has_topic". See COVERAGE.md. +INSERT INTO metadata.avus (id, attribute, value, unit, target_id, target_type, created_by, modified_by) VALUES + ('a2a2a2a2-0000-0000-0000-000000000101', 'n2t.net/ark:/99152/h1459', 'beta', '', '66666666-6666-6666-6666-666666666602', 'app', 'testuser01@example.org', 'testuser01@example.org'), + ('a2a2a2a2-0000-0000-0000-000000000102', 'rdf:type', 'http://edamontology.org/topic_0091', '', '66666666-6666-6666-6666-666666666603', 'app', 'testuser02@example.org', 'testuser02@example.org'), + ('a2a2a2a2-0000-0000-0000-000000000103', 'http://edamontology.org/has_topic', 'http://edamontology.org/topic_3168', '', '66666666-6666-6666-6666-666666666610', 'app', 'testuser02@example.org', 'testuser02@example.org'), + ('a2a2a2a2-0000-0000-0000-000000000104', 'cyverse-internal-community', 'Test Community', '', '66666666-6666-6666-6666-666666666601', 'app', 'testuser01@example.org', 'testuser01@example.org') +ON CONFLICT (id) DO NOTHING; + +COMMIT; diff --git a/testdata/sql/72_metadata_templates.sql b/testdata/sql/72_metadata_templates.sql new file mode 100644 index 0000000..2190164 --- /dev/null +++ b/testdata/sql/72_metadata_templates.sql @@ -0,0 +1,69 @@ +-- Metadata templates and the attribute system that backs them. +-- +-- value_types is reference data seeded by migration 000025, so it is referenced +-- here by natural key (name) rather than re-inserted. The rest is synthetic: a +-- template whose attributes cover several value types, including an Enum attribute +-- with values, an attribute group with nested sub-attributes (attr_attrs), and a +-- synonym pair (attr_synonyms). Loaded with search_path = metadata, public so the +-- unqualified table/value_type names resolve to the metadata schema. +BEGIN; +SET search_path = metadata, public, pg_catalog; + +-- Attributes. Contact (a Grouping) parents two child attributes; Title and Name +-- are synonyms; Organism is an Enum with values defined below. description is +-- NOT NULL on this table. +INSERT INTO metadata.attributes (id, name, description, required, value_type_id, created_by, modified_by) VALUES + ('a7000000-0000-0000-0000-000000000001', 'Title', 'Title of the dataset', true, (SELECT id FROM value_types WHERE name='String'), 'testuser01@example.org', 'testuser01@example.org'), + ('a7000000-0000-0000-0000-000000000002', 'Description', 'Free-text description', false, (SELECT id FROM value_types WHERE name='Multiline Text'), 'testuser01@example.org', 'testuser01@example.org'), + ('a7000000-0000-0000-0000-000000000003', 'Organism', 'Source organism', false, (SELECT id FROM value_types WHERE name='Enum'), 'testuser01@example.org', 'testuser01@example.org'), + ('a7000000-0000-0000-0000-000000000004', 'Sample Count', 'Number of samples', false, (SELECT id FROM value_types WHERE name='Integer'), 'testuser01@example.org', 'testuser01@example.org'), + ('a7000000-0000-0000-0000-000000000005', 'Contact', 'Contact information group', false, (SELECT id FROM value_types WHERE name='Grouping'), 'testuser01@example.org', 'testuser01@example.org'), + ('a7000000-0000-0000-0000-000000000006', 'Contact Name', 'Name of the contact', false, (SELECT id FROM value_types WHERE name='String'), 'testuser01@example.org', 'testuser01@example.org'), + ('a7000000-0000-0000-0000-000000000007', 'Contact Email', 'Email of the contact', false, (SELECT id FROM value_types WHERE name='URL/URI'), 'testuser01@example.org', 'testuser01@example.org'), + ('a7000000-0000-0000-0000-000000000008', 'Name', 'Synonym of Title', false, (SELECT id FROM value_types WHERE name='String'), 'testuser01@example.org', 'testuser01@example.org') +ON CONFLICT (id) DO NOTHING; + +-- Enum values for the Organism attribute (Human is the default). +INSERT INTO metadata.attr_enum_values (id, attribute_id, value, is_default, display_order) VALUES + ('a8000000-0000-0000-0000-000000000001', 'a7000000-0000-0000-0000-000000000003', 'Human', true, 0), + ('a8000000-0000-0000-0000-000000000002', 'a7000000-0000-0000-0000-000000000003', 'Mouse', false, 1), + ('a8000000-0000-0000-0000-000000000003', 'a7000000-0000-0000-0000-000000000003', 'Arabidopsis', false, 2) +ON CONFLICT (id) DO NOTHING; + +-- Contact group's sub-attributes (attr_attrs: parent_id -> child_id; child_id is unique). +INSERT INTO metadata.attr_attrs (parent_id, child_id, display_order) VALUES + ('a7000000-0000-0000-0000-000000000005', 'a7000000-0000-0000-0000-000000000006', 0), + ('a7000000-0000-0000-0000-000000000005', 'a7000000-0000-0000-0000-000000000007', 1) +ON CONFLICT (child_id) DO NOTHING; + +-- Title and Name are synonyms (no unique constraint on this table, so guard with NOT EXISTS). +INSERT INTO metadata.attr_synonyms (attribute_id, synonym_id) +SELECT 'a7000000-0000-0000-0000-000000000001', 'a7000000-0000-0000-0000-000000000008' +WHERE NOT EXISTS ( + SELECT 1 FROM metadata.attr_synonyms + WHERE attribute_id = 'a7000000-0000-0000-0000-000000000001' + AND synonym_id = 'a7000000-0000-0000-0000-000000000008'); + +-- Templates: an active one wired to the top-level attributes, plus a deleted one +-- so listings can exercise the deleted filter. +INSERT INTO metadata.templates (id, name, description, deleted, created_by, modified_by) VALUES + ('7e000000-0000-0000-0000-000000000001', 'Test Metadata Template', 'A synthetic template', false, 'testuser01@example.org', 'testuser01@example.org'), + ('7e000000-0000-0000-0000-000000000002', 'Old Template', 'A deleted template', true, 'testuser01@example.org', 'testuser01@example.org') +ON CONFLICT (id) DO NOTHING; + +-- Top-level attributes on the active template (sub-attributes come via attr_attrs). +-- No unique constraint on template_attrs, so guard with NOT EXISTS. +INSERT INTO metadata.template_attrs (template_id, attribute_id, display_order) +SELECT v.template_id, v.attribute_id, v.display_order +FROM (VALUES + ('7e000000-0000-0000-0000-000000000001'::uuid, 'a7000000-0000-0000-0000-000000000001'::uuid, 0), + ('7e000000-0000-0000-0000-000000000001'::uuid, 'a7000000-0000-0000-0000-000000000002'::uuid, 1), + ('7e000000-0000-0000-0000-000000000001'::uuid, 'a7000000-0000-0000-0000-000000000003'::uuid, 2), + ('7e000000-0000-0000-0000-000000000001'::uuid, 'a7000000-0000-0000-0000-000000000004'::uuid, 3), + ('7e000000-0000-0000-0000-000000000001'::uuid, 'a7000000-0000-0000-0000-000000000005'::uuid, 4) +) AS v(template_id, attribute_id, display_order) +WHERE NOT EXISTS ( + SELECT 1 FROM metadata.template_attrs ta + WHERE ta.template_id = v.template_id AND ta.attribute_id = v.attribute_id); + +COMMIT; diff --git a/testdata/sql/74_metadata_ontologies.sql b/testdata/sql/74_metadata_ontologies.sql new file mode 100644 index 0000000..bec31df --- /dev/null +++ b/testdata/sql/74_metadata_ontologies.sql @@ -0,0 +1,28 @@ +-- A synthetic ontology with classes and a parent/child hierarchy. The metadata +-- service exposes these through the ontology/hierarchy endpoints, and the apps +-- service's app-hierarchy features classify apps against an active ontology. +-- ontologies is keyed by `version` (text PK) and requires non-null `xml`; +-- ontology_classes/ontology_hierarchies reference it by that version string. +-- ontology_hierarchies uses (class_iri = parent, subclass_iri = child). +BEGIN; +SET search_path = metadata, public, pg_catalog; + +INSERT INTO metadata.ontologies (version, iri, created_by, deleted, xml) VALUES + ('test-ontology-1.0', 'http://edamontology.org/test', 'testuser01@example.org', false, + '') +ON CONFLICT (version) DO NOTHING; + +-- Classes: a root topic with two child topics. +INSERT INTO metadata.ontology_classes (ontology_version, iri, label, description) VALUES + ('test-ontology-1.0', 'http://edamontology.org/topic_0003', 'Topic', 'Root topic'), + ('test-ontology-1.0', 'http://edamontology.org/topic_0091', 'Genomics', 'Genomics topic'), + ('test-ontology-1.0', 'http://edamontology.org/topic_3168', 'Sequencing', 'Sequencing topic') +ON CONFLICT (ontology_version, iri) DO NOTHING; + +-- Hierarchy: the two child topics are subclasses of the root topic. +INSERT INTO metadata.ontology_hierarchies (ontology_version, class_iri, subclass_iri) VALUES + ('test-ontology-1.0', 'http://edamontology.org/topic_0003', 'http://edamontology.org/topic_0091'), + ('test-ontology-1.0', 'http://edamontology.org/topic_0003', 'http://edamontology.org/topic_3168') +ON CONFLICT (ontology_version, class_iri, subclass_iri) DO NOTHING; + +COMMIT; diff --git a/testdata/sql/76_metadata_pid_requests.sql b/testdata/sql/76_metadata_pid_requests.sql new file mode 100644 index 0000000..b96689b --- /dev/null +++ b/testdata/sql/76_metadata_pid_requests.sql @@ -0,0 +1,28 @@ +-- Permanent ID (DOI) requests with status histories. +-- +-- permanent_id_request_types and permanent_id_request_status_codes are reference +-- data seeded by migration 000025, so they are referenced here by natural key +-- (DOI; status names Submitted/Approved/Completion/etc.) rather than re-inserted. +-- Requests target data folders (target_type 'folder'). +BEGIN; +SET search_path = metadata, public, pg_catalog; + +-- Two requests: one approved/completed (full trail), one still pending. The +-- `type` column is a FK to permanent_id_request_types.id. +INSERT INTO metadata.permanent_id_requests (id, requested_by, type, target_id, target_type, original_path, permanent_id) VALUES + ('44000000-0000-0000-0000-000000000001', 'testuser01@example.org', (SELECT id FROM permanent_id_request_types WHERE type='DOI'), + 'b1000000-0000-0000-0000-000000000001', 'folder', '/iplant/home/testuser01/dataset-1', '10.0000/test.0001'), + ('44000000-0000-0000-0000-000000000002', 'testuser02@example.org', (SELECT id FROM permanent_id_request_types WHERE type='DOI'), + 'b1000000-0000-0000-0000-000000000002', 'folder', '/iplant/home/testuser02/dataset-2', NULL) +ON CONFLICT (id) DO NOTHING; + +-- Status trails. Columns: permanent_id_request (FK), permanent_id_request_status_code (FK), updated_by. +INSERT INTO metadata.permanent_id_request_statuses (id, permanent_id_request, permanent_id_request_status_code, updated_by, comments) VALUES + ('45000000-0000-0000-0000-000000000001', '44000000-0000-0000-0000-000000000001', (SELECT id FROM permanent_id_request_status_codes WHERE name='Submitted'), 'testuser01@example.org', 'Request submitted'), + ('45000000-0000-0000-0000-000000000002', '44000000-0000-0000-0000-000000000001', (SELECT id FROM permanent_id_request_status_codes WHERE name='Approved'), 'admin@example.org', 'Approved by curators'), + ('45000000-0000-0000-0000-000000000003', '44000000-0000-0000-0000-000000000001', (SELECT id FROM permanent_id_request_status_codes WHERE name='Completion'), 'admin@example.org', 'DOI issued'), + ('45000000-0000-0000-0000-000000000004', '44000000-0000-0000-0000-000000000002', (SELECT id FROM permanent_id_request_status_codes WHERE name='Submitted'), 'testuser02@example.org', 'Request submitted'), + ('45000000-0000-0000-0000-000000000005', '44000000-0000-0000-0000-000000000002', (SELECT id FROM permanent_id_request_status_codes WHERE name='Pending'), 'admin@example.org', 'Awaiting response') +ON CONFLICT (id) DO NOTHING; + +COMMIT; diff --git a/testdata/sql/80_permissions.sql b/testdata/sql/80_permissions.sql new file mode 100644 index 0000000..08917e8 --- /dev/null +++ b/testdata/sql/80_permissions.sql @@ -0,0 +1,64 @@ +-- Permissions. subjects use the BARE username (no @domain); resources name apps +-- and analyses by their UUID. resource_types (app/analysis) and permission_levels +-- (own/write/read) are seeded by the migrations and referenced by natural key. +BEGIN; +SET search_path = permissions, public, pg_catalog; + +INSERT INTO permissions.subjects (id, subject_id, subject_type) VALUES + ('15151515-0000-0000-0000-000000000001', 'testuser01', 'user'), + ('15151515-0000-0000-0000-000000000002', 'testuser02', 'user'), + ('15151515-0000-0000-0000-000000000003', 'testuser03', 'user'), + ('15151515-0000-0000-0000-000000000004', 'testuser04', 'user'), + ('15151515-0000-0000-0000-000000000005', 'testuser05', 'user'), + ('15151515-0000-0000-0000-000000000006', 'testuser06', 'user') +ON CONFLICT (id) DO NOTHING; + +-- App resources. +INSERT INTO permissions.resources (id, name, resource_type_id) VALUES + ('16161616-0000-0000-0000-000000000601', '66666666-6666-6666-6666-666666666601', (SELECT id FROM permissions.resource_types WHERE name='app')), + ('16161616-0000-0000-0000-000000000602', '66666666-6666-6666-6666-666666666602', (SELECT id FROM permissions.resource_types WHERE name='app')), + ('16161616-0000-0000-0000-000000000603', '66666666-6666-6666-6666-666666666603', (SELECT id FROM permissions.resource_types WHERE name='app')), + ('16161616-0000-0000-0000-000000000604', '66666666-6666-6666-6666-666666666604', (SELECT id FROM permissions.resource_types WHERE name='app')), + ('16161616-0000-0000-0000-000000000605', '66666666-6666-6666-6666-666666666605', (SELECT id FROM permissions.resource_types WHERE name='app')), +-- Analysis resources. + ('16161616-0000-0000-0000-0000000d0d01', 'dddddddd-dddd-dddd-dddd-dddddddddd01', (SELECT id FROM permissions.resource_types WHERE name='analysis')), + ('16161616-0000-0000-0000-0000000d0d02', 'dddddddd-dddd-dddd-dddd-dddddddddd02', (SELECT id FROM permissions.resource_types WHERE name='analysis')), + ('16161616-0000-0000-0000-0000000d0d03', 'dddddddd-dddd-dddd-dddd-dddddddddd03', (SELECT id FROM permissions.resource_types WHERE name='analysis')) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO permissions.permissions (id, subject_id, resource_id, permission_level_id) VALUES + -- App ownership. + ('17171717-0000-0000-0000-000000000001', '15151515-0000-0000-0000-000000000001', '16161616-0000-0000-0000-000000000601', (SELECT id FROM permissions.permission_levels WHERE name='own')), + ('17171717-0000-0000-0000-000000000002', '15151515-0000-0000-0000-000000000001', '16161616-0000-0000-0000-000000000602', (SELECT id FROM permissions.permission_levels WHERE name='own')), + ('17171717-0000-0000-0000-000000000003', '15151515-0000-0000-0000-000000000002', '16161616-0000-0000-0000-000000000603', (SELECT id FROM permissions.permission_levels WHERE name='own')), + ('17171717-0000-0000-0000-000000000004', '15151515-0000-0000-0000-000000000002', '16161616-0000-0000-0000-000000000604', (SELECT id FROM permissions.permission_levels WHERE name='own')), + ('17171717-0000-0000-0000-000000000005', '15151515-0000-0000-0000-000000000003', '16161616-0000-0000-0000-000000000605', (SELECT id FROM permissions.permission_levels WHERE name='own')), + -- App sharing (read). + ('17171717-0000-0000-0000-000000000006', '15151515-0000-0000-0000-000000000002', '16161616-0000-0000-0000-000000000601', (SELECT id FROM permissions.permission_levels WHERE name='read')), + ('17171717-0000-0000-0000-000000000007', '15151515-0000-0000-0000-000000000003', '16161616-0000-0000-0000-000000000601', (SELECT id FROM permissions.permission_levels WHERE name='read')), + -- Analysis ownership. + ('17171717-0000-0000-0000-000000000008', '15151515-0000-0000-0000-000000000001', '16161616-0000-0000-0000-0000000d0d01', (SELECT id FROM permissions.permission_levels WHERE name='own')), + ('17171717-0000-0000-0000-000000000009', '15151515-0000-0000-0000-000000000001', '16161616-0000-0000-0000-0000000d0d02', (SELECT id FROM permissions.permission_levels WHERE name='own')), + ('17171717-0000-0000-0000-00000000000a', '15151515-0000-0000-0000-000000000002', '16161616-0000-0000-0000-0000000d0d03', (SELECT id FROM permissions.permission_levels WHERE name='own')), + -- Analysis sharing (write). + ('17171717-0000-0000-0000-00000000000b', '15151515-0000-0000-0000-000000000002', '16161616-0000-0000-0000-0000000d0d01', (SELECT id FROM permissions.permission_levels WHERE name='write')) +ON CONFLICT (id) DO NOTHING; + +-- A group subject and resources for the versioned and parameters apps, so the +-- permission-lister and sharing paths have group grants and more apps to report. +INSERT INTO permissions.subjects (id, subject_id, subject_type) VALUES + ('15151515-0000-0000-0000-0000000000f1', 'test-group-1', 'group') +ON CONFLICT (id) DO NOTHING; + +INSERT INTO permissions.resources (id, name, resource_type_id) VALUES + ('16161616-0000-0000-0000-000000000606', '66666666-6666-6666-6666-666666666606', (SELECT id FROM permissions.resource_types WHERE name='app')), + ('16161616-0000-0000-0000-000000000610', '66666666-6666-6666-6666-666666666610', (SELECT id FROM permissions.resource_types WHERE name='app')) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO permissions.permissions (id, subject_id, resource_id, permission_level_id) VALUES + ('17171717-0000-0000-0000-00000000000c', '15151515-0000-0000-0000-000000000001', '16161616-0000-0000-0000-000000000606', (SELECT id FROM permissions.permission_levels WHERE name='own')), + ('17171717-0000-0000-0000-00000000000d', '15151515-0000-0000-0000-000000000002', '16161616-0000-0000-0000-000000000610', (SELECT id FROM permissions.permission_levels WHERE name='own')), + ('17171717-0000-0000-0000-00000000000e', '15151515-0000-0000-0000-0000000000f1', '16161616-0000-0000-0000-000000000601', (SELECT id FROM permissions.permission_levels WHERE name='read')) +ON CONFLICT (id) DO NOTHING; + +COMMIT; diff --git a/testdata/sql/90_metadata_role.sql b/testdata/sql/90_metadata_role.sql new file mode 100644 index 0000000..ddae40b --- /dev/null +++ b/testdata/sql/90_metadata_role.sql @@ -0,0 +1,29 @@ +-- Test-only database login role for the metadata service. +-- +-- The metadata service (cyverse-de/metadata) references its tables unqualified +-- (:avus, :tags, :comments, :ratings, ...) and has no schema/search_path config — +-- it just picks a database name. In the consolidated DE schema those tables live +-- in the `metadata` schema of the `de` database, and some names (ratings, +-- comments) also exist in `public`, so the service must resolve `metadata` first. +-- +-- This role logs in to the `de` database with search_path = metadata, public so +-- unqualified queries hit the metadata schema. It is separate from the `de` role +-- (which the apps service uses with a public-first search) to avoid the name +-- collisions. Throwaway credentials for the public test image only. +DO $$ +BEGIN + IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'metadata') THEN + CREATE ROLE metadata LOGIN PASSWORD 'metadata'; + END IF; +END$$; + +ALTER ROLE metadata SET search_path = metadata, public, pg_catalog; + +GRANT USAGE ON SCHEMA metadata TO metadata; +GRANT USAGE ON SCHEMA public TO metadata; + +GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA metadata TO metadata; +GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA metadata TO metadata; + +-- Read-only access to public for any shared lookups / extension functions. +GRANT SELECT ON ALL TABLES IN SCHEMA public TO metadata; diff --git a/testdata/verify/apps_smoke.sql b/testdata/verify/apps_smoke.sql new file mode 100644 index 0000000..43f5b5a --- /dev/null +++ b/testdata/verify/apps_smoke.sql @@ -0,0 +1,96 @@ +-- Smoke checks for the apps-service test fixtures. Run against the test database: +-- psql 'postgres://de:de@localhost:5432/de?sslmode=disable' -f testdata/verify/apps_smoke.sql +-- Prints a short report, then a DO block that raises an exception if any core +-- invariant is wrong (so it can gate CI). +\pset pager off +SET search_path = public, pg_catalog; + +\echo '== app_listing rows for test apps (per version) ==' +SELECT id, name, version, deleted, disabled, step_count, task_count, tool_count, external_app_count, average_rating, total_ratings +FROM app_listing WHERE name LIKE 'Test %' ORDER BY name, version; + +\echo '== pipeline app step/task counts (expect 2/2) ==' +SELECT name, step_count, task_count FROM app_listing WHERE id = '66666666-6666-6666-6666-666666666609'; + +\echo '== versioned app versions (expect 1.0.0 deleted, 2.0.0 disabled, 3.0.0 active) ==' +SELECT version, version_order, deleted, disabled FROM app_versions WHERE app_id = '66666666-6666-6666-6666-666666666606' ORDER BY version_order; + +\echo '== parameter type coverage on the showcase task ==' +SELECT pt.name AS parameter_type, count(*) +FROM parameters p +JOIN parameter_groups pg ON pg.id = p.parameter_group_id +JOIN parameter_types pt ON pt.id = p.parameter_type +WHERE pg.task_id = '55555555-5555-5555-5555-555555555510' +GROUP BY pt.name ORDER BY pt.name; + +\echo '== favorites: Test App 1 in testuser01 favorites category ==' +SELECT u.username, c.name AS category +FROM app_category_app aca +JOIN app_categories c ON c.id = aca.app_category_id +JOIN workspace w ON w.id = c.workspace_id +JOIN users u ON u.id = w.user_id +WHERE aca.app_id = '66666666-6666-6666-6666-666666666601' AND c.name = 'Favorite Apps'; + +\echo '== tool_listing for test tools ==' +SELECT DISTINCT name, version, type FROM tool_listing WHERE name LIKE 'Test %' ORDER BY name; + +\echo '== tool requests with status history ==' +SELECT tr.tool_name, count(trs.id) AS status_count +FROM tool_requests tr LEFT JOIN tool_request_statuses trs ON trs.tool_request_id = tr.id +WHERE tr.tool_name LIKE 'Requested Tool%' GROUP BY tr.tool_name ORDER BY tr.tool_name; + +\echo '== publication requests ==' +SELECT count(*) AS publication_requests FROM app_publication_requests; + +\echo '== validation rules on showcase params ==' +SELECT rt.name AS rule_type, count(vra.id) AS arg_count +FROM validation_rules vr +JOIN rule_type rt ON rt.id = vr.rule_type +LEFT JOIN validation_rule_arguments vra ON vra.rule_id = vr.id +JOIN parameters p ON p.id = vr.parameter_id +JOIN parameter_groups pg ON pg.id = p.parameter_group_id +WHERE pg.task_id = '55555555-5555-5555-5555-555555555510' +GROUP BY rt.name ORDER BY rt.name; + +\echo '== ASSERTIONS ==' +DO $$ +DECLARE + n integer; +BEGIN + -- Pipeline app has two steps. + SELECT step_count INTO n FROM app_listing WHERE id = '66666666-6666-6666-6666-666666666609' LIMIT 1; + ASSERT n = 2, format('pipeline step_count expected 2, got %s', n); + + -- Versioned app: 3 versions, exactly one active (not deleted, not disabled). + SELECT count(*) INTO n FROM app_versions WHERE app_id = '66666666-6666-6666-6666-666666666606'; + ASSERT n = 3, format('versioned app expected 3 versions, got %s', n); + SELECT count(*) INTO n FROM app_versions WHERE app_id = '66666666-6666-6666-6666-666666666606' AND NOT deleted AND NOT disabled; + ASSERT n = 1, format('versioned app expected 1 active version, got %s', n); + + -- Showcase task exposes at least a dozen distinct parameter types. + SELECT count(DISTINCT p.parameter_type) INTO n + FROM parameters p JOIN parameter_groups pg ON pg.id = p.parameter_group_id + WHERE pg.task_id = '55555555-5555-5555-5555-555555555510'; + ASSERT n >= 12, format('showcase expected >=12 parameter types, got %s', n); + + -- Test App 1 is favorited by testuser01. + SELECT count(*) INTO n + FROM app_category_app aca JOIN app_categories c ON c.id = aca.app_category_id + WHERE aca.app_id = '66666666-6666-6666-6666-666666666601' + AND c.id = 'ca000000-0000-0000-0000-000000000201'; + ASSERT n = 1, 'Test App 1 should be in testuser01 favorites'; + + -- Documentation, references, tool requests, publication requests exist. + SELECT count(*) INTO n FROM app_documentation; ASSERT n >= 4, 'expected app_documentation rows'; + SELECT count(*) INTO n FROM app_references; ASSERT n >= 3, 'expected app_references rows'; + SELECT count(*) INTO n FROM tool_requests; ASSERT n >= 2, 'expected tool_requests'; + SELECT count(*) INTO n FROM app_publication_requests; ASSERT n >= 2, 'expected publication requests'; + + -- An external (Agave) task and an OSG tool exist. + SELECT count(*) INTO n FROM tasks WHERE external_app_id IS NOT NULL; + ASSERT n >= 1, 'expected an external task'; + SELECT count(*) INTO n FROM tools t JOIN tool_types tt ON tt.id = t.tool_type_id WHERE tt.name = 'osg'; + ASSERT n >= 1, 'expected an OSG tool'; + + RAISE NOTICE 'All apps smoke assertions passed.'; +END $$;