Skip to content
cccskills
FreePublished on GitHub

simba-testing

Guide for testing code built on Simba 5 (leader election and distributed locks). Use when writing or reviewing tests for LeadershipListener callbacks, runWhileLeader / schedule work, partition groups, locks, @SimbaScheduled / @SimbaPartitioned beans, fencing-token resources (FencingSpec), LeaseBackend implementations (LeaseBackendSpec), or deterministic failover tests with InMemoryLeaseBackend and VirtualScheduler.

The English summary is being prepared. Showing the original description.

See how to install

Files included (2)

  • SKILL.md4.1 KB
  • agents/openai.yaml182 B

SKILL.md (original)

Review the instructions the agent will receive before you install.

Testing Simba-Based Code

Choose the Layer

You testUse
Application code that takes a SimbaInMemoryLeaseBackend (module simba-testing) on real time
Failover, expiry, timingInMemoryLeaseBackend + VirtualScheduler (virtual time, opt-in API)
A resource that checks fencing tokensFencingSpec (module simba-tck)
A LeaseBackend implementationLeaseBackendSpec (module simba-tck)
Real infrastructureTestcontainers (MySQL, PostgreSQL, Redis) or Curator TestingServer (Zookeeper)
testImplementation("me.ahoo.simba:simba-testing")
testImplementation("me.ahoo.simba:simba-tck")

The examples use FluentAssert's .assert() (me.ahoo.test:fluent-assert-core, brought in by simba-tck); with simba-testing alone, add it or use any assertion library.

Do not mock Simba, Election or Term when the in-memory backend can drive the real engine.

In-Memory Backend

val backend = InMemoryLeaseBackend()
val config = SimbaConfig.builder().leaseDuration(Duration.ofSeconds(3)).renewInterval(Duration.ofSeconds(1)).build()
Simba.builder().backend(backend).config(config).build().use { simba ->
    val elected = LinkedBlockingQueue<Term>()
    simba.election("job").start(object : LeadershipListener {
        override fun onElected(term: Term) { elected += term }
        override fun onRevoked(term: Term, reason: RevokeReason) = Unit
    })
    val term = elected.poll(5, TimeUnit.SECONDS)!!
    backend.owner(term.name)!!.token.assert().isEqualTo(term.token)
}

backend.owner(name) and backend.token(name) inspect the backend. In Spring Boot tests, declare @Bean fun leaseBackend(): LeaseBackend = InMemoryLeaseBackend(); the starter builds Simba over it.

Virtual Time

@OptIn(InternalSimbaApi::class)
val scheduler = VirtualScheduler()
val backend = InMemoryLeaseBackend(scheduler)
val simba = Simba.builder()
    .backend(backend)
    .config(config)
    .scheduler(scheduler)
    .ioExecutor(Runnable::run)
    .callbackExecutor(Runnable::run)
    .seed(0)
    .build()

scheduler.advance(Duration.ofSeconds(4)) { simba.awaitIdle() }   // fire due timers, settle between them

Leader work still runs on virtual threads: wait for it through queues. scheduler, awaitIdle and Scheduler are @InternalSimbaApi (opt-in, no compatibility guarantee).

FencingSpec

class LedgerFencingTest : FencingSpec() {
    override fun write(resource: String, fencingToken: Long) = ledger.settle(resource, fencingToken)
    override fun highestToken(resource: String) = ledger.fencingToken(resource)
    override fun leaseBackend(): LeaseBackend = InMemoryLeaseBackend()   // optional: real lock terms
}

Checks increasing and equal tokens accepted, lower rejected, racing writers, and a stale lock term rejected.

LeaseBackendSpec

class MyLeaseBackendTest : LeaseBackendSpec() {
    override fun createBackend(): LeaseBackend = MyLeaseBackend(store)
    // override val clock: ClockControl? — when the backend's clock is injectable
    // override val shortLease, lease, timeout
}

Every test uses fresh names, so the store can be shared.

Pitfalls

  • Never sleep; wait on queues, latches or futures (or advance virtual time).
  • Assert on the Term the callback/work received, never on shared "current leader" state.
  • Close clients (use {}) so sessions and virtual threads end with the test.
  • renewInterval × 2 ≤ leaseDuration and leaseDuration × (1 − drift) − margin > renewInterval, or SimbaConfig throws.
  • Simba's own engine changes must keep SimulationSpec green; replay with ./gradlew simba-testing:test -Psimba.simulation.seed=N.

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

simba

Free

Guide for using Simba 5, the JVM leader-election and distributed-lock library, in applications. Use when adding leader election, leader-only work (runWhileLeader, schedule, @SimbaScheduled), partitioned work (group, @SimbaPartitioned), distributed locks (lock / LockTerm), configuring the JDBC (MySQL, PostgreSQL), Redis or Zookeeper backend, integrating with Spring Boot, using fencing tokens, tuning session timing, or migrating from Simba 4.x. For test-focused work, use the simba-testing skill as well.

The English summary is being prepared. Showing the original description.

Ahoo-Wang/Simba33Updated Oct 20, 2026

See all skills by Ahoo-Wang

Report a problem with this skill