//go:build smoke

package smoketest

import "testing"

// TestSmoke is the single top-level test that pins run-order across
// scenario classes:
//
//   - "pool" runs pure scenarios concurrently (each calls t.Parallel)
//     alongside the repodir chain, which runs its own subtests
//     sequentially. The pool subtest only returns once every t.Parallel
//     child has finished.
//   - "global" runs after pool, serially, in registry order. These
//     scenarios assert host-wide state (iptables, vm row counts,
//     ssh-config under a fake HOME, the update / rollback flow, daemon
//     stop) and would race with the parallel pool.
//
// `go test -parallel N` controls fan-out within the pool. `-run
// TestSmoke/pool/bare_run` runs a single scenario without changing
// the install preamble path.
func TestSmoke(t *testing.T) {
	t.Run("pool", func(t *testing.T) {
		// Pure scenarios — t.Parallel inside each, fan out under -parallel.
		t.Run("bare_run", testBareRun)
		t.Run("exit_code", testExitCode)
		t.Run("concurrent_run", testConcurrentRun)
		t.Run("detach_run", testDetachRun)
		t.Run("bootstrap_precondition", testBootstrapPrecondition)
		t.Run("vm_lifecycle", testVMLifecycle)
		t.Run("vm_set", testVMSet)
		t.Run("vm_restart", testVMRestart)
		t.Run("vm_kill", testVMKill)
		t.Run("vm_ports", testVMPorts)
		t.Run("ssh_config", testSSHConfig)

		// Repodir chain — single virtual job in the pool. Subtests run
		// sequentially because they share the throwaway git repo at
		// repoDir and mutate it; t.Parallel() is intentionally absent.
		// The chain itself competes with the pure scenarios for a
		// parallel slot at this outer level.
		t.Run("repodir_chain", func(t *testing.T) {
			t.Parallel()
			t.Run("workspace_run", testWorkspaceRun)
			t.Run("workspace_dryrun", testWorkspaceDryrun)
			t.Run("include_untracked", testIncludeUntracked)
			t.Run("workspace_export", testWorkspaceExport)
			t.Run("workspace_full_copy", testWorkspaceFullCopy)
			t.Run("workspace_basecommit", testWorkspaceBasecommit)
			t.Run("workspace_restart", testWorkspaceRestart)
			t.Run("vm_exec", testVMExec)
		})
	})

	// Global scenarios — serial, after the pool drains. Order matters:
	// daemon_admin tears the installed services down and must be LAST.
	// The order otherwise mirrors scripts/smoke.sh's SMOKE_SCENARIOS
	// registry so the run shape is comparable.
	t.Run("global", func(t *testing.T) {
		t.Run("vm_prune", testVMPrune)
		t.Run("nat", testNAT)
		t.Run("invalid_spec", testInvalidSpec)
		t.Run("invalid_name", testInvalidName)
		t.Run("update_check", testUpdateCheck)
		t.Run("update_to_unknown", testUpdateToUnknown)
		t.Run("update_no_root", testUpdateNoRoot)
		t.Run("update_dry_run", testUpdateDryRun)
		t.Run("update_keeps_vm_alive", testUpdateKeepsVMAlive)
		t.Run("update_rollback_keeps_vm_alive", testUpdateRollbackKeepsVMAlive)
		t.Run("daemon_admin", testDaemonAdmin)
	})
}
