integration_tests

package
v0.0.0-...-89bdeea Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 8, 2026 License: MIT Imports: 33 Imported by: 0

README

Integration tests

Run from the repository root:

bash integration_tests/run.sh

Requirements: Docker with Compose, Bash and Git. Go and database clients run inside the image; no local Go installation, database setup, production dumps, validator, Discord connection or external submission/image collection is required. The small tracked archive and mock validator supply the file fixtures.

Select cases using Go test flags:

bash integration_tests/run.sh -run '^TestHarness'
bash integration_tests/run.sh -run '^TestSubmissionStateMachine_MainFlow$'

Each invocation builds a snapshot of the test inputs, starts a uniquely named Compose project with fresh MariaDB and PostgreSQL volumes, waits for database health, applies both complete migration chains, and runs the tests. Migrations and tests use the same image snapshot. The default invocation runs serially, uncached, with a 20-minute Go test timeout and fail-fast enabled. A selection matching no tests is an error. Arguments are passed to go test, so explicit flags can change these defaults.

The build allows only source/test inputs: local .env, backups, existing test_data, results and the validator submodule are excluded. Runtime containers have an internal network with service-name addressing, no published ports, and no Docker socket. The only host bind mount is the invocation's output directory. The outer script performs all provisioning and cleanup; Go helpers cannot run Docker or recreate databases.

Before every fixture reset, the helpers verify both generated database identities and both clean migration versions against the image's migration files. They refuse ordinary developer connection settings and do not fall back to recreating a reachable database. MariaDB cleanup uses one reserved connection for foreign-key settings and resets. Each top-level setup gets temporary writable paths, temporary fixture/template symlinks, and environment restoration through Go test cleanup. Nested subtests retain their parent's data where the existing scenarios require it. Do not add t.Parallel() to this suite; t.Setenv/t.Chdir intentionally reject it.

Results are saved under integration_tests/results/run-XXXXXXXX/ (gitignored):

  • manifest.txt, runtime.txt, image-metadata.json, source.sha256 and migrations.sha256: run identity, source revision/dirty status, runtime/images and exact input checksums.
  • tests.jsonl, coverage.out, coverage.txt: machine-readable test events and application-package statement coverage. Statement coverage is not SQL branch coverage.
  • Build, startup, migration, runner, container and cleanup logs; exit-code.txt.

The script returns a failing status for test/provisioning failures, preserves logs, and removes only its own containers, network, database volumes and built image. It retains shared Docker build caches and database images. Ctrl+C/termination also triggers cleanup; if the process is forcibly killed, use the project recorded in manifest.txt to identify leftover resources. Do not run broad Docker prune commands.

For unit tests without Docker, use:

go test ./database ./types ./service ./transport ./utils -count=1
go test ./integration_tests -run '^TestHarness(RejectsUnsafeTargets|MigrationValidation|TemporaryEnvironment)$' -count=1

Running the database-backed cases directly on the host is intentionally unsupported; use the runner. Old absolute.env, test_data and developer database containers are neither used nor deleted by this setup. make -C integration_tests test is an alias for the full containerized run; the old rebuild/migrate targets are removed.

bash integration_tests/run.sh -run '^TestSubmission(SearchComments|QuickFilter|FilterLayoutSwitch)'

comment-partial matches a literal, case-insensitive substring within any one non-deleted comment message, including review actions and bot messages across upload versions. Accents and punctuation remain significant. An empty value disables the filter; legacy entries have no comments and cannot match. It combines with the other submission filters using AND. Action/state filters still apply to the submission, not necessarily to the comment containing the matching text.

Coverage includes Unicode, literal SQL/wildcard punctuation, deleted comments and submissions, multiple matching comments, separate messages that must not form a phrase, edits/deletions without cache rebuilds, pagination/counts, both HTTP search endpoints, HTML escaping, and form reset/layout switching. These fixtures verify correctness, not production-scale search latency. The query materializes distinct matching submission IDs before pagination and uses the existing comment-to-submission index for constrained searches. Arbitrary substring matching still requires examining message text and has no ordinary text-index lookup. Expensive filter totals are computed before pagination in the same query, with a transaction-local fallback for pages past the end.

Search quick filters

bash integration_tests/run.sh -run '^TestSubmission(QuickFilter|UploaderFilter|FilterLayoutSwitch|Search)'

The image includes Node and a locked, test-only jsdom dependency. These tests render the production filter template, execute the actual quick-filter JavaScript in a DOM, serialize its form, and pass that query through authenticated search requests. Multi-user histories upload real fixture archives with a mock validator and check review requests as well as search rows and counts. All seven presets are checked in both layouts; the original-submitter and latest-uploader options are checked separately and together. jsdom checks form behavior, not visual layout. Layout-switch tests cover shared edits, cleared selections, retained advanced drafts, reset, URL preservation, and switching without submitting a search.

Run the additional metadata search cases with:

bash integration_tests/run.sh -run '^TestSubmissionSearchMetadata'

These cover every new text field, case-insensitive partial matching, Tags include/exclude combinations, legacy metadata, current versus historical/deleted versions, NULL/empty metadata, additional-application lists, combined filters, and pagination counts. Form tests serialize the rendered advanced controls and send them through authenticated submissions and my-submissions HTTP requests. The quick-filter and layout-switch cases also check clearing the new dropdown and retaining metadata drafts without changing basic-search scope.

Scope limits: this is a correctness harness, not the production-dump replay or performance harness. Lookup seed rows are preserved rather than reconstructed after every test, so tests that mutate those rows must restore them. Successful uploads wait for persisted processing results, but failed asynchronous uploads do not yet have an explicit worker-drain API. Fail-fast limits subsequent contamination; worker lifecycle coverage is follow-up work before introducing parallel fixtures or injected upload-worker failures.

Generated state histories

The generated tests complement the hand-written histories and real-service tests. They use an independent Go replay model to check evolving cache/search state across several users and submissions. Default histories stay within 50 comments and four upload versions per submission; this is correctness coverage, not a load test.

Run the pure model/corpus tests without databases:

go test ./integration_tests -run '^Test(SubmissionHistoryModel|SubmissionGeneratedHistoryCorpus)$' -count=1

Run the default SQL corpus or replay one seed:

bash integration_tests/run.sh -run '^TestSubmissionGeneratedHistories$'
bash integration_tests/run.sh -run '^TestSubmissionGeneratedHistories$' -args -history-seed=42

A failure logs the seed, operation index and HISTORY_TRACE_JSON containing the exact operation prefix in tests.jsonl. In Docker it also saves a history-failure-seed-N-step-N.json file alongside the run artifacts. Copy that JSON array under integration_tests/testdata/histories/ to replay it independently of future RNG or generator changes, and reduce it into a focused regression when diagnosing a bug:

bash integration_tests/run.sh -run '^TestSubmissionGeneratedHistories$' -args -history-replay=integration_tests/testdata/histories/example.json

That narrow JSON directory is included in the Docker build; arbitrary host paths and the ignored results directories are not. Replay traces use the test fixture's three submissions and four human user IDs plus the validator. Preserve any source operations that later deletions refer to when reducing a trace.

Notifications and controlled concurrency

Run notification SQL contracts and controlled mutation overlaps with:

bash integration_tests/run.sh -run '^TestNotificationQueries'
bash integration_tests/run.sh -race -count=3 -run '^TestSubmissionConcurrency'
bash integration_tests/run.sh -race -run '^TestSubmissionQuota'

The trigger barriers use MariaDB named locks to control arrival and release. A separate observer checks waiting parent-lock statements in PROCESSLIST. Cleanup releases locks and joins workers before closing pools. Go race detection checks memory access; history/cache/search assertions check SQL behavior.

Tests named CurrentBehavior document remaining MariaDB limitations, including repeated subscription/settings rows. Passing these witnesses does not mean the behavior is desirable. The runner always uses MariaDB for submissions and the existing separate PostgreSQL database for launcher metadata.

The MariaDB fixture uses production's utf8mb4_unicode_ci defaults and the historical OAuth columns' utf8mb4_general_ci exception. Every reset checks these collations as well as database identities and migration versions.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DiscordServerRoles = []types.DiscordRole{
	{
		ID:    432708847304704010,
		Name:  "@everyone",
		Color: "#000000",
	},
	{
		ID:    441043545735036929,
		Name:  "Administrator",
		Color: "#3498db",
	},
	{
		ID:    roleIDModerator,
		Name:  "Moderator",
		Color: "#9b59b6",
	},
	{
		ID:    roleIDCurator,
		Name:  "Curator",
		Color: "#f1c40f",
	},
	{
		ID:    442987546046103562,
		Name:  "Hacker",
		Color: "#b11515",
	},
	{
		ID:    roleIDTester,
		Name:  "Tester",
		Color: "#e67e22",
	},
	{
		ID:    451454116393254912,
		Name:  "The Moe",
		Color: "#e0a4f1",
	},
	{
		ID:    453048638646648833,
		Name:  "VIP",
		Color: "#d6047f",
	},
	{
		ID:    454640479317917696,
		Name:  "The Blue",
		Color: "#385f84",
	},
	{
		ID:    475413811394904074,
		Name:  "Archivist",
		Color: "#fa8072",
	},
	{
		ID:    477773789724409861,
		Name:  "Mechanic",
		Color: "#748e9a",
	},
	{
		ID:    478369603622273024,
		Name:  "Notification Squad",
		Color: "#000000",
	},
	{
		ID:    546894295962222622,
		Name:  "Hunter",
		Color: "#1f8b4c",
	},
	{
		ID:    roleIDTrialCurator,
		Name:  "Trial Curator",
		Color: "#000000",
	},
	{
		ID:    581828606502764565,
		Name:  "Nitro Booster",
		Color: "#f47fff",
	},
	{
		ID:    602334900623900672,
		Name:  "Virus Destroyer",
		Color: "#71368a",
	},
	{
		ID:    636078914493480960,
		Name:  "MOTAS Finder",
		Color: "#3498db",
	},
	{
		ID:    643230868768423976,
		Name:  "Archiver",
		Color: "#000000",
	},
	{
		ID:    666444964120494080,
		Name:  "Former Staff",
		Color: "#607d8b",
	},
	{
		ID:    703740452385325136,
		Name:  "Translator",
		Color: "#01e8fc",
	},
	{
		ID:    810221698179792897,
		Name:  "BlueBot",
		Color: "#000000",
	},
	{
		ID:    830110904561041428,
		Name:  "Bunnyposter",
		Color: "#2ecc71",
	},
	{
		ID:    852181478044598273,
		Name:  "PF Scrape",
		Color: "#000000",
	},
	{
		ID:    855487139029319681,
		Name:  "FPFSS Notification Service",
		Color: "#ff00ec",
	},
	{
		ID:    855488531802750996,
		Name:  "The D",
		Color: "#008080",
	},
	{
		ID:    871819872408055828,
		Name:  "Developer",
		Color: "#7477ce",
	},
	{
		ID:    880181541089738844,
		Name:  "Guardian",
		Color: "#000000",
	},
	{
		ID:    880203664822775829,
		Name:  "Bot",
		Color: "#ff0000",
	},
	{
		ID:    914324576434028574,
		Name:  "Helper",
		Color: "#00ff8d",
	},
	{
		ID:    921852025904435251,
		Name:  "Donator",
		Color: "#ffe4a8",
	},
	{
		ID:    1007648354437693581,
		Name:  "Forbidden knowledge",
		Color: "#000000",
	},
	{
		ID:    1008934569547927693,
		Name:  "Linux",
		Color: "#000000",
	},
	{
		ID:    1008934759679922267,
		Name:  "Mac (Intel)",
		Color: "#000000",
	},
	{
		ID:    1008934935492558869,
		Name:  "Mac (Apple Silicon)",
		Color: "#000000",
	},
	{
		ID:    1021367134623907844,
		Name:  "Flashpoint Mail",
		Color: "#000000",
	},
	{
		ID:    1058518177140711526,
		Name:  "CredBot",
		Color: "#000000",
	},
	{
		ID:    1058757300967448680,
		Name:  "Flashpoint GOTD",
		Color: "#000000",
	},
	{
		ID:    1084270358321963078,
		Name:  "The Mentioner",
		Color: "#000000",
	},
	{
		ID:    roleIDTrialEditor,
		Name:  "Trial Editor",
		Color: "#1abc9c",
	},
	{
		ID:    1126109274418987048,
		Name:  "International Manager",
		Color: "#e74c3c",
	},
	{
		ID:    1128307753459392513,
		Name:  "Editor",
		Color: "#1abc9c",
	},
	{
		ID:    1133654438729494532,
		Name:  "Doomposter",
		Color: "#000001",
	},
	{
		ID:    1133654698600181770,
		Name:  "Hopeposter",
		Color: "#c27c0e",
	},
	{
		ID:    1133852834991972444,
		Name:  "Flashpoint Ultimate",
		Color: "#000000",
	},
	{
		ID:    1136910341603856427,
		Name:  "deleted-role",
		Color: "#858585",
	},
	{
		ID:    1136941292031594587,
		Name:  "Donator",
		Color: "#ffe4a8",
	},
	{
		ID:    1148134067137695777,
		Name:  "CredBot",
		Color: "#000000",
	},
	{
		ID:    1153356678843093244,
		Name:  "9o3o",
		Color: "#000000",
	},
	{
		ID:    1158439542420951153,
		Name:  "DJ Kakabus",
		Color: "#000000",
	},
	{
		ID:    1159895585336328245,
		Name:  "Craig",
		Color: "#000000",
	},
	{
		ID:    1172153393544962100,
		Name:  "NGAU",
		Color: "#000000",
	},
	{
		ID:    1203384090733056000,
		Name:  "Interviewer",
		Color: "#000000",
	},
	{
		ID:    1203384239341572186,
		Name:  "new role",
		Color: "#000000",
	},
	{
		ID:    1403105517194313859,
		Name:  "Media Poster",
		Color: "#000000",
	},
	{
		ID:    1410724183876571157,
		Name:  "new role",
		Color: "#000000",
	},
	{
		ID:    1410724266164359259,
		Name:  "Raven",
		Color: "#e8acc7",
	},
}

Functions

This section is empty.

Types

type MockDiscordNotificationSender

type MockDiscordNotificationSender struct{}

func (*MockDiscordNotificationSender) SendCurationFeedMessage

func (m *MockDiscordNotificationSender) SendCurationFeedMessage(msg string) error

func (*MockDiscordNotificationSender) SendNotification

func (m *MockDiscordNotificationSender) SendNotification(msg, notificationType string) error

type MockDiscordRoleReader

type MockDiscordRoleReader struct{}

func (*MockDiscordRoleReader) GetFlashpointRoleIDsForUser

func (m *MockDiscordRoleReader) GetFlashpointRoleIDsForUser(uid int64) ([]string, error)

func (*MockDiscordRoleReader) GetFlashpointRoles

func (m *MockDiscordRoleReader) GetFlashpointRoles() ([]types.DiscordRole, error)

func (*MockDiscordRoleReader) GetFlashpointUserInfo

func (m *MockDiscordRoleReader) GetFlashpointUserInfo(uid int64, roles []types.DiscordRole) (*types.FlashpointDiscordUser, error)

func (*MockDiscordRoleReader) GetJoinedAtForUser

func (m *MockDiscordRoleReader) GetJoinedAtForUser(uid int64) (time.Time, error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL