//// Reference integration stacks with reproducible setup/teardown (M26).
import gleam/list
import lightspeed/integration/data
import lightspeed/integration/jobs
import lightspeed/integration/mail
import lightspeed/integration/ops
/// Setup actions for integration fixtures.
pub type SetupStep {
PrepareDataLayer
StartJobWorkers
StartMailer
EnableTelemetryPipelines
SeedReferenceData
}
/// Teardown actions for integration fixtures.
pub type TeardownStep {
DrainJobs
FlushOutbox
DisableTelemetryPipelines
CleanupDataFixtures
}
/// One production-like reference stack.
pub type ReferenceStack {
ReferenceStack(
name: String,
data_pattern: data.Pattern,
jobs_pattern: jobs.Pattern,
mail_pattern: mail.Pattern,
ops_pattern: ops.Pattern,
setup_steps: List(SetupStep),
teardown_steps: List(TeardownStep),
)
}
/// Commerce-oriented stack.
pub fn commerce_stack() -> ReferenceStack {
ReferenceStack(
name: "commerce_stack",
data_pattern: data.crud_pattern(),
jobs_pattern: jobs.critical_path_pattern(),
mail_pattern: mail.transactional_pattern(),
ops_pattern: ops.production_pattern(),
setup_steps: default_setup_steps(),
teardown_steps: default_teardown_steps(),
)
}
/// Collaboration/chat-oriented stack.
pub fn collaboration_stack() -> ReferenceStack {
ReferenceStack(
name: "collaboration_stack",
data_pattern: data.event_stream_pattern(),
jobs_pattern: jobs.mixed_runtime_pattern(),
mail_pattern: mail.digest_pattern(),
ops_pattern: ops.mixed_runtime_pattern(),
setup_steps: default_setup_steps(),
teardown_steps: default_teardown_steps(),
)
}
/// Mixed-runtime baseline stack.
pub fn mixed_runtime_stack() -> ReferenceStack {
ReferenceStack(
name: "mixed_runtime_stack",
data_pattern: data.crud_pattern(),
jobs_pattern: jobs.mixed_runtime_pattern(),
mail_pattern: mail.digest_pattern(),
ops_pattern: ops.mixed_runtime_pattern(),
setup_steps: default_setup_steps(),
teardown_steps: default_teardown_steps(),
)
}
/// Validate stack-level integration constraints.
pub fn valid(stack: ReferenceStack) -> Bool {
data.valid(stack.data_pattern)
&& jobs.valid(stack.jobs_pattern)
&& mail.valid(stack.mail_pattern)
&& ops.valid(stack.ops_pattern)
&& contains_setup(stack.setup_steps, PrepareDataLayer)
&& contains_setup(stack.setup_steps, StartJobWorkers)
&& contains_setup(stack.setup_steps, StartMailer)
&& contains_setup(stack.setup_steps, EnableTelemetryPipelines)
&& contains_setup(stack.setup_steps, SeedReferenceData)
&& contains_teardown(stack.teardown_steps, DrainJobs)
&& contains_teardown(stack.teardown_steps, FlushOutbox)
&& contains_teardown(stack.teardown_steps, DisableTelemetryPipelines)
&& contains_teardown(stack.teardown_steps, CleanupDataFixtures)
}
/// Stable stack signature for fixtures and docs.
pub fn signature(stack: ReferenceStack) -> String {
"stack:"
<> stack.name
<> "|"
<> data.signature(stack.data_pattern)
<> "|"
<> jobs.signature(stack.jobs_pattern)
<> "|"
<> mail.signature(stack.mail_pattern)
<> "|"
<> ops.signature(stack.ops_pattern)
}
/// Stable setup signature.
pub fn setup_signature(stack: ReferenceStack) -> String {
"setup=" <> join_with(",", list.map(stack.setup_steps, setup_step_label))
}
/// Stable teardown signature.
pub fn teardown_signature(stack: ReferenceStack) -> String {
"teardown="
<> join_with(",", list.map(stack.teardown_steps, teardown_step_label))
}
/// Stable lifecycle signature.
pub fn lifecycle_signature(stack: ReferenceStack) -> String {
signature(stack)
<> "|"
<> setup_signature(stack)
<> "|"
<> teardown_signature(stack)
}
/// Stack name.
pub fn name(stack: ReferenceStack) -> String {
stack.name
}
/// Setup-step label.
pub fn setup_step_label(step: SetupStep) -> String {
case step {
PrepareDataLayer -> "prepare_data_layer"
StartJobWorkers -> "start_job_workers"
StartMailer -> "start_mailer"
EnableTelemetryPipelines -> "enable_telemetry_pipelines"
SeedReferenceData -> "seed_reference_data"
}
}
/// Teardown-step label.
pub fn teardown_step_label(step: TeardownStep) -> String {
case step {
DrainJobs -> "drain_jobs"
FlushOutbox -> "flush_outbox"
DisableTelemetryPipelines -> "disable_telemetry_pipelines"
CleanupDataFixtures -> "cleanup_data_fixtures"
}
}
/// Setup steps.
pub fn setup_steps(stack: ReferenceStack) -> List(SetupStep) {
stack.setup_steps
}
/// Teardown steps.
pub fn teardown_steps(stack: ReferenceStack) -> List(TeardownStep) {
stack.teardown_steps
}
fn default_setup_steps() -> List(SetupStep) {
[
PrepareDataLayer,
StartJobWorkers,
StartMailer,
EnableTelemetryPipelines,
SeedReferenceData,
]
}
fn default_teardown_steps() -> List(TeardownStep) {
[DrainJobs, FlushOutbox, DisableTelemetryPipelines, CleanupDataFixtures]
}
fn contains_setup(steps: List(SetupStep), expected: SetupStep) -> Bool {
case steps {
[] -> False
[step, ..rest] ->
case step == expected {
True -> True
False -> contains_setup(rest, expected)
}
}
}
fn contains_teardown(
steps: List(TeardownStep),
expected: TeardownStep,
) -> Bool {
case steps {
[] -> False
[step, ..rest] ->
case step == expected {
True -> True
False -> contains_teardown(rest, expected)
}
}
}
fn join_with(separator: String, values: List(String)) -> String {
case values {
[] -> ""
[value] -> value
[value, ..rest] -> value <> separator <> join_with(separator, rest)
}
}