### Start TLS Server with RunTLS Source: https://context7.com/alicebob/miniredis/llms.txt Configure and start a miniredis server over TLS using `RunTLS` for testing encrypted connections. Ensure you load the appropriate TLS certificates. ```go import ( "crypto/tls" "testing" "github.com/alicebob/miniredis/v2" ) func TestTLSConnection(t *testing.T) { cert, err := tls.LoadX509KeyPair("server.crt", "server.key") if err != nil { t.Fatal(err) } cfg := &tls.Config{Certificates: []tls.Certificate{cert}} s, err := miniredis.RunTLS(cfg) if err != nil { t.Fatal(err) } defer s.Close() t.Logf("TLS server at %s", s.Addr()) // Connect your Redis client with matching TLS config } ``` -------------------------------- ### Start Server with RunT for Automatic Cleanup Source: https://context7.com/alicebob/miniredis/llms.txt Use `RunT` to start the miniredis server within a test. It automatically registers a cleanup function with `t.Cleanup` to close the server when the test ends, simplifying test setup. ```go import ( "testing" "github.com/alicebob/miniredis/v2" "github.com/redis/go-redis/v9" "context" ) func TestMyService(t *testing.T) { s := miniredis.RunT(t) // starts server; auto-closed when test ends rdb := redis.NewClient(&redis.Options{ Addr: s.Addr(), // e.g. "127.0.0.1:54321" }) ctx := context.Background() if err := rdb.Set(ctx, "greeting", "hello", 0).Err(); err != nil { t.Fatal(err) } val, err := rdb.Get(ctx, "greeting").Result() if err != nil { t.Fatal(err) } t.Logf("got: %s", val) // got: hello } ``` -------------------------------- ### Start Server on a Fixed Address with StartAddr Source: https://context7.com/alicebob/miniredis/llms.txt Utilize `StartAddr` to bind the miniredis server to a specific host and port, rather than an ephemeral one. This is useful when clients need to connect to a predictable address. ```go func TestFixedAddr(t *testing.T) { m := miniredis.NewMiniRedis() if err := m.StartAddr("127.0.0.1:6399"); err != nil { t.Fatal(err) } defer m.Close() // Any Redis client can now connect to 127.0.0.1:6399 t.Logf("server at %s", m.Addr()) } ``` -------------------------------- ### Run miniredis Mock Server in Go Tests Source: https://github.com/alicebob/miniredis/blob/master/README.md Use miniredis.RunT to start a mock Redis server within your Go tests. You can optionally pre-populate it with keys and values that your application expects. This is useful for testing interactions with Redis without a live instance. ```Go import ( ... "github.com/alicebob/miniredis/v2" ... ) func TestSomething(t *testing.T) { ss := miniredis.RunT(t) // Optionally set some keys your code expects: ss.Set("foo", "bar") ss.HSet("some", "other", "key") // Run your code and see if it behaves. // An example using the redigo library from "github.com/gomodule/redigo/redis": c, err := redis.Dial("tcp", ss.Addr()) _, err = c.Do("SET", "foo", "bar") // Optionally check values in redis... if got, err := ss.Get("foo"); err != nil || got != "bar" { t.Error("'foo' has the wrong value") } // ... or use a helper for that: ss.CheckGet(t, "foo", "bar") // TTL and expiration: ss.Set("foo", "bar") ss.SetTTL("foo", 10*time.Second) ss.FastForward(11 * time.Second) if ss.Exists("foo") { t.Fatal("'foo' should not have existed anymore") } } ``` -------------------------------- ### Direct String Key Operations: Set, Get, Del, Exists Source: https://context7.com/alicebob/miniredis/llms.txt Perform direct read/write operations on string keys using methods like `Set`, `Get`, `Del`, and `Exists`. These operations bypass the TCP stack and operate on the currently selected database (default DB 0). `Set` removes any existing TTL. ```go func TestStringOps(t *testing.T) { s := miniredis.RunT(t) // Set a string key (removes any existing TTL) if err := s.Set("username", "alice"); err != nil { t.Fatal(err) } // Get it back val, err := s.Get("username") if err != nil { // ErrKeyNotFound if missing t.Fatal(err) } t.Logf("username=%s", val) // username=alice // Check existence if !s.Exists("username") { t.Fatal("key should exist") } // Integer increment (INCRBY) s.Set("hits", "100") newVal, _ := s.Incr("hits", 5) t.Logf("hits=%d", newVal) // hits=105 // Float increment (INCRBYFLOAT) s.Set("price", "9.99") newFloat, _ := s.Incrfloat("price", 0.01) t.Logf("price=%f", newFloat) // price=10.000000 // Delete s.Del("username") t.Logf("exists=%v", s.Exists("username")) // exists=false } ``` -------------------------------- ### Sorted Set Operations Source: https://context7.com/alicebob/miniredis/llms.txt Manipulate sorted sets by score. Functions include adding members with scores using `ZAdd`, retrieving members ordered by score with `ZMembers`, getting a member's score with `ZScore`, retrieving all members as a map with `SortedSet`, removing members with `ZRem`, and getting multiple scores with `ZMScore`. ```APIDOC ## Sorted Set Operations: `ZAdd` / `ZMembers` / `ZScore` / `ZRem` / `SortedSet` Manipulate sorted sets by score directly. ```go func TestSortedSetOps(t *testing.T) { s := miniredis.RunT(t) // Add members with scores s.ZAdd("leaderboard", 1500.0, "alice") s.ZAdd("leaderboard", 2300.0, "bob") s.ZAdd("leaderboard", 800.0, "charlie") // Members ordered by score (ascending) members, _ := s.ZMembers("leaderboard") t.Logf("by score=%v", members) // by score=[charlie alice bob] // Get a member's score score, _ := s.ZScore("leaderboard", "bob") t.Logf("bob's score=%.1f", score) // bob's score=2300.0 // Get all members as a map all, _ := s.SortedSet("leaderboard") t.Logf("alice=%.1f", all["alice"]) // alice=1500.0 // Remove a member removed, _ := s.ZRem("leaderboard", "charlie") t.Logf("removed=%v", removed) // removed=true // Get multiple scores at once scores, _ := s.ZMScore("leaderboard", "alice", "bob", "ghost") t.Logf("scores=%v", scores) // scores=[1500 2300 0] } ``` ``` -------------------------------- ### Manipulate Hash Keys with HSet, HGet, HDel, HIncr Source: https://context7.com/alicebob/miniredis/llms.txt Directly set, get, delete, and increment fields within hash keys. `HSet` can set multiple fields at once. `HIncr` and `HIncrByFloat` are used for numeric field manipulation. ```go func TestHashOps(t *testing.T) { s := miniredis.RunT(t) // Set multiple fields in one call s.HSet("user:1", "name", "Bob", "email", "bob@example.com", "age", "30") // Read a single field name := s.HGet("user:1", "name") t.Logf("name=%s", name) // name=Bob // List all fields (sorted) fields, _ := s.HKeys("user:1") t.Logf("fields=%v", fields) // fields=[age email name] // Increment an integer field newAge, err := s.HIncr("user:1", "age", 1) if err != nil { t.Fatal(err) } t.Logf("age=%d", newAge) // age=31 // Float increment s.HSet("product", "price", "9.99") newPrice, _ := s.HIncrByFloat("product", "price", 0.51) t.Logf("price=%f", newPrice) // price=10.500000 // Delete a field s.HDel("user:1", "email") t.Logf("email=%q", s.HGet("user:1", "email")) // email="" } ``` -------------------------------- ### Set Key Operations Source: https://context7.com/alicebob/miniredis/llms.txt Perform operations on Redis Set data structures. Includes adding members with `SAdd`, retrieving all members with `SMembers`, checking membership with `SIsMember`, getting the count of members with `SCard`, and removing members with `SRem`. ```APIDOC ## Set Key Operations: `SAdd` / `SMembers` / `SIsMember` / `SRem` / `SCard` Work directly with Redis Set data structures. ```go func TestSetOps(t *testing.T) { s := miniredis.RunT(t) // Add members added, _ := s.SAdd("tags", "go", "redis", "testing", "go") // "go" is a dupe t.Logf("new members added=%d", added) // new members added=3 // Get sorted members members, _ := s.SMembers("tags") t.Logf("members=%v", members) // members=[go redis testing] // Membership test ok, _ := s.SIsMember("tags", "redis") t.Logf("redis in tags: %v", ok) // redis in tags: true // Cardinality count, _ := s.SCard("tags") t.Logf("count=%d", count) // count=3 // Remove removed, _ := s.SRem("tags", "testing") t.Logf("removed=%d", removed) // removed=1 } ``` ``` -------------------------------- ### Manipulate Sorted Set Operations with ZAdd, ZMembers, ZScore, ZRem Source: https://context7.com/alicebob/miniredis/llms.txt Add members with scores using `ZAdd`, retrieve members ordered by score with `ZMembers`, get a specific member's score with `ZScore`, and remove members with `ZRem`. `SortedSet` retrieves all members as a map. ```go func TestSortedSetOps(t *testing.T) { s := miniredis.RunT(t) // Add members with scores s.ZAdd("leaderboard", 1500.0, "alice") s.ZAdd("leaderboard", 2300.0, "bob") s.ZAdd("leaderboard", 800.0, "charlie") // Members ordered by score (ascending) members, _ := s.ZMembers("leaderboard") t.Logf("by score=%v", members) // by score=[charlie alice bob] // Get a member's score score, _ := s.ZScore("leaderboard", "bob") t.Logf("bob's score=%.1f", score) // bob's score=2300.0 // Get all members as a map all, _ := s.SortedSet("leaderboard") t.Logf("alice=%.1f", all["alice"]) // alice=1500.0 // Remove a member removed, _ := s.ZRem("leaderboard", "charlie") t.Logf("removed=%v", removed) // removed=true // Get multiple scores at once scores, _ := s.ZMScore("leaderboard", "alice", "bob", "ghost") t.Logf("scores=%v", scores) // scores=[1500 2300 0] } ``` -------------------------------- ### Manual Server Lifecycle Management with Run/Close/Restart Source: https://context7.com/alicebob/miniredis/llms.txt Employ `Run` for explicit control over the server's lifecycle, allowing for operations like restarting the server mid-test while preserving in-memory data. Remember to manually call `Close` using `defer`. ```go func TestManualLifecycle(t *testing.T) { s, err := miniredis.Run() if err != nil { t.Fatal(err) } defer s.Close() t.Logf("listening on %s (host=%s port=%s)", s.Addr(), s.Host(), s.Port()) // Pre-load some data s.Set("counter", "10") // Restart preserves in-memory data s.Close() if err := s.Restart(); err != nil { t.Fatal(err) } val, _ := s.Get("counter") t.Logf("after restart: %s", val) // after restart: 10 } ``` -------------------------------- ### Import Miniredis v2 Source: https://github.com/alicebob/miniredis/blob/master/README.md Import the miniredis package for use in your Go project. Ensure you are using the correct version. ```go import "github.com/alicebob/miniredis/v2" ``` -------------------------------- ### Multi-Database Operations in Redis Source: https://context7.com/alicebob/miniredis/llms.txt Demonstrates managing multiple Redis databases using `Select`, `DB`, and `SwapDB`. `Select` changes the current database, `DB(n)` accesses a specific database without changing the current context, and `SwapDB` exchanges the contents of two databases. `Copy` can copy keys between databases. ```go func TestMultipleDBs(t *testing.T) { s := miniredis.RunT(t) // Write to DB 0 (default) s.Set("color", "red") // Switch selected DB for direct commands s.Select(1) s.Set("color", "blue") // Confirm isolation s.Select(0) v0, _ := s.Get("color") t.Logf("DB0 color=%s", v0) // DB0 color=red // Access a DB object directly (without changing selected DB) v1, _ := s.DB(1).Get("color") t.Logf("DB1 color=%s", v1) // DB1 color=blue // Swap databases s.SwapDB(0, 1) v, _ := s.Get("color") // still in DB 0 context t.Logf("after swap, DB0 color=%s", v) // after swap, DB0 color=blue // Copy a key between databases s.Select(0) s.Set("src", "hello") s.Copy(0, "src", 2, "dst") v2, _ := s.DB(2).Get("dst") t.Logf("DB2 dst=%s", v2) // DB2 dst=hello } ``` -------------------------------- ### Add and Read Redis Stream Entries Source: https://context7.com/alicebob/miniredis/llms.txt Demonstrates adding entries to a Redis stream using `XAdd` with auto-generated IDs and reading all entries directly using `Stream`. Ensure the stream key and field-value pairs are correctly formatted. ```go func TestStreamOps(t *testing.T) { s := miniredis.RunT(t) // Add entries (id="" or "*" for auto-generated ID) id1, err := s.XAdd("events", "*", []string{"type", "login", "user", "alice"}) if err != nil { t.Fatal(err) } t.Logf("entry id=%s", id1) // entry id= s.XAdd("events", "*", []string{"type", "purchase", "user", "bob", "amount", "42.50"}) // Read all entries directly entries, _ := s.Stream("events") for _, e := range entries { t.Logf("id=%s values=%v", e.ID, e.Values) } // id=... values=[type login user alice] // id=... values=[type purchase user bob amount 42.50] t.Logf("total entries=%d", len(entries)) // total entries=2 } ``` -------------------------------- ### Manage List Key Operations with Push, Pop, List Source: https://context7.com/alicebob/miniredis/llms.txt Append elements to the tail (`Push`) or head (`Lpush`) of a list, retrieve the entire list (`List`), or remove elements from the head (`Lpop`) or tail (`Pop`). ```go func TestListOps(t *testing.T) { s := miniredis.RunT(t) // RPush (append to tail) length, _ := s.Push("queue", "job1", "job2", "job3") t.Logf("queue length=%d", length) // queue length=3 // LPush (prepend to head) s.Lpush("queue", "job0") // Read full list items, _ := s.List("queue") t.Logf("queue=%v", items) // queue=[job0 job1 job2 job3] // LPop (remove from head) head, _ := s.Lpop("queue") t.Logf("lpop=%s", head) // lpop=job0 // RPop (remove from tail) tail, _ := s.Pop("queue") t.Logf("rpop=%s", tail) // rpop=job3 items, _ = s.List("queue") t.Logf("remaining=%v", items) // remaining=[job1 job2] } ``` -------------------------------- ### HyperLogLog Operations: PfAdd, PfCount, PfMerge Source: https://context7.com/alicebob/miniredis/llms.txt Illustrates approximate cardinality counting using HyperLogLog operations. `PfAdd` adds elements, `PfCount` returns the approximate count, and `PfMerge` combines multiple HyperLogLogs. Note that `PfAdd` returns 1 if the internal representation changed. ```go func TestHLL(t *testing.T) { s := miniredis.RunT(t) // Add elements (returns 1 if internal representation changed) changed, _ := s.PfAdd("visitors", "user1", "user2", "user3", "user1") t.Logf("changed=%d", changed) // changed=1 // Approximate count count, _ := s.PfCount("visitors") t.Logf("approx visitors=%d", count) // approx visitors=3 // Merge multiple HLLs s.PfAdd("visitors:us", "user1", "user4") s.PfAdd("visitors:eu", "user2", "user5") s.PfMerge("visitors:all", "visitors:us", "visitors:eu") total, _ := s.PfCount("visitors:all") t.Logf("total merged=%d", total) // total merged=4 } ``` -------------------------------- ### Manage TTL and Key Expiration with FastForward Source: https://context7.com/alicebob/miniredis/llms.txt Use `SetTTL` to set expiration times and `FastForward` to advance time deterministically in tests. `TTL` retrieves remaining time, and `Exists` checks key presence. Absolute time can be controlled with `SetTime`. ```go func TestExpiration(t *testing.T) { s := miniredis.RunT(t) s.Set("session", "abc123") s.SetTTL("session", 30*time.Second) ttl := s.TTL("session") t.Logf("TTL remaining: %s", ttl) // TTL remaining: 30s // Advance time by 20 seconds — key still alive s.FastForward(20 * time.Second) if !s.Exists("session") { t.Fatal("should still exist") } // Advance past expiry s.FastForward(11 * time.Second) if s.Exists("session") { t.Fatal("key should have expired") } // Control absolute time for EXPIREAT / PEXPIREAT base := time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC) s.SetTime(base) s.Set("token", "xyz") s.SetTTL("token", 5*time.Minute) s.FastForward(6 * time.Minute) t.Logf("token expired: %v", !s.Exists("token")) // token expired: true } ``` -------------------------------- ### Perform Set Key Operations with SAdd, SMembers, SIsMember, SRem Source: https://context7.com/alicebob/miniredis/llms.txt Add members to a set using `SAdd`, retrieve all members with `SMembers`, check for membership using `SIsMember`, and remove members with `SRem`. Duplicates are ignored on addition. ```go func TestSetOps(t *testing.T) { s := miniredis.RunT(t) // Add members added, _ := s.SAdd("tags", "go", "redis", "testing", "go") // "go" is a dupe t.Logf("new members added=%d", added) // new members added=3 // Get sorted members members, _ := s.SMembers("tags") t.Logf("members=%v", members) // members=[go redis testing] // Membership test ok, _ := s.SIsMember("tags", "redis") t.Logf("redis in tags: %v", ok) // redis in tags: true // Cardinality count, _ := s.SCard("tags") t.Logf("count=%d", count) // count=3 // Remove removed, _ := s.SRem("tags", "testing") t.Logf("removed=%d", removed) // removed=1 } ``` -------------------------------- ### Redis Authentication Testing Source: https://context7.com/alicebob/miniredis/llms.txt Shows how to test Redis authentication using `RequireAuth` for single-password mode and `RequireUserAuth` for multi-user mode. Clients must authenticate correctly to avoid `NOAUTH` errors. An empty password disables authentication for a user. ```go func TestAuth(t *testing.T) { s := miniredis.RunT(t) // Single-password mode (Redis 5 AUTH ) s.RequireAuth("supersecret") // A client that doesn't authenticate will get NOAUTH errors. // A correctly authenticated client works normally: rdb := redis.NewClient(&redis.Options{ Addr: s.Addr(), Password: "supersecret", }) defer rdb.Close() ctx := context.Background() if err := rdb.Set(ctx, "key", "val", 0).Err(); err != nil { t.Fatal(err) } // Multi-user mode (Redis 6 AUTH ) s.RequireUserAuth("alice", "alice_pw") s.RequireUserAuth("bob", "bob_pw") // Remove auth for a user s.RequireUserAuth("bob", "") // empty password disables bob } ``` -------------------------------- ### Redis Pub/Sub Testing Source: https://context7.com/alicebob/miniredis/llms.txt Tests publish/subscribe functionality without a real Redis broker. `NewSubscriber` creates a direct subscriber, `Subscribe` subscribes to channels, `Publish` sends messages, and `PubSubChannels`, `PubSubNumSub`, and `PubSubNumPat` inspect channel and subscription status. ```go func TestPubSub(t *testing.T) { s := miniredis.RunT(t) // Create a direct subscriber (not via TCP) sub := s.NewSubscriber() defer sub.Close() sub.Subscribe("news") sub.Subscribe("alerts") // Publish a message and count receivers n := s.Publish("news", "breaking: miniredis rocks") t.Logf("receivers=%d", n) // receivers=1 // Inspect active channels channels := s.PubSubChannels("*") t.Logf("channels=%v", channels) // channels=[alerts news] // Subscriber counts per channel counts := s.PubSubNumSub("news", "alerts", "weather") t.Logf("news=%d alerts=%d weather=%d", counts["news"], counts["alerts"], counts["weather"]) // news=1 alerts=1 weather=0 // Pattern subscriptions count t.Logf("num_pat=%d", s.PubSubNumPat()) // num_pat=0 } ``` -------------------------------- ### Inspect Redis Server State with Introspection Helpers in Go Source: https://context7.com/alicebob/miniredis/llms.txt Programmatically inspect the state of the miniredis server during tests using introspection helpers like Dump, CommandCount, and Keys. This is useful for verifying server contents and statistics. ```go func TestIntrospection(t *testing.T) { s := miniredis.RunT(t) s.Set("name", "miniredis") s.HSet("config", "host", "localhost", "port", "6379") s.Push("queue", "task1", "task2") s.ZAdd("scores", 100.0, "alice") // Dump a human-readable view of the selected DB t.Logf("DB state:\n%s", s.Dump()) // - config // host: "localhost" // port: "6379" // - name // "miniredis" // - queue // "task1" // "task2" // - scores // 100.000000: "alice" // All keys in selected DB (sorted) keys := s.Keys() t.Logf("keys=%v", keys) // keys=[config name queue scores] // Command / connection statistics t.Logf("connections=%d", s.TotalConnectionCount()) t.Logf("commands=%d", s.CommandCount()) t.Logf("current_clients=%d", s.CurrentConnectionCount()) } ``` -------------------------------- ### Register Custom Redis Commands in Go Source: https://context7.com/alicebob/miniredis/llms.txt Extend or override Redis commands by registering custom handlers on the underlying server using Server().Register. This is useful for testing non-standard Redis extensions or specific command behaviors. ```go import "github.com/alicebob/miniredis/v2/server" func TestCustomCommand(t *testing.T) { s := miniredis.RunT(t) // Register a custom command s.Server().Register("HELLO_WORLD", func(c *server.Peer, cmd string, args []string) { c.WriteBulk("Hello, World!") }) rdb := redis.NewClient(&redis.Options{Addr: s.Addr()}) defer rdb.Close() res, err := rdb.Do(context.Background(), "HELLO_WORLD").Text() if err != nil { t.Fatal(err) } t.Logf("response=%s", res) // response=Hello, World! } ``` -------------------------------- ### Simulate Redis Server Errors with SetError in Go Source: https://context7.com/alicebob/miniredis/llms.txt Test application error handling by simulating Redis server errors using SetError. This allows verification of how your application responds to conditions like LOADING or MASTERDOWN. ```go func TestErrorHandling(t *testing.T) { s := miniredis.RunT(t) rdb := redis.NewClient(&redis.Options{Addr: s.Addr()}) defer rdb.Close() ctx := context.Background() // Normal operation works rdb.Set(ctx, "k", "v", 0) // Simulate a Redis server being unavailable / loading s.SetError("LOADING Redis is loading the dataset in memory") _, err := rdb.Get(ctx, "k").Result() if err == nil { t.Fatal("expected error") } t.Logf("got expected error: %v", err) // Clear the error — server resumes normal operation s.SetError("") val, _ := rdb.Get(ctx, "k").Result() t.Logf("recovered: %s", val) // recovered: v } ``` -------------------------------- ### List Key Operations Source: https://context7.com/alicebob/miniredis/llms.txt Manage list keys by pushing and popping elements from either end, or retrieving the entire list. Supports `Push` (RPush), `Lpush`, `Pop` (RPop), `Lpop`, and `List`. ```APIDOC ## List Key Operations: `Push` / `Lpush` / `Pop` / `Lpop` / `List` Push and pop list elements directly, or retrieve the full list. ```go func TestListOps(t *testing.T) { s := miniredis.RunT(t) // RPush (append to tail) length, _ := s.Push("queue", "job1", "job2", "job3") t.Logf("queue length=%d", length) // queue length=3 // LPush (prepend to head) s.Lpush("queue", "job0") // Read full list items, _ := s.List("queue") t.Logf("queue=%v", items) // queue=[job0 job1 job2 job3] // LPop (remove from head) head, _ := s.Lpop("queue") t.Logf("lpop=%s", head) // lpop=job0 // RPop (remove from tail) tail, _ := s.Pop("queue") t.Logf("rpop=%s", tail) // rpop=job3 items, _ = s.List("queue") t.Logf("remaining=%v", items) // remaining=[job1 job2] } ``` ``` -------------------------------- ### TTL and Key Expiration Source: https://context7.com/alicebob/miniredis/llms.txt Manage Time-To-Live (TTL) for keys and control time progression deterministically. Functions include `SetTTL`, `TTL`, and `FastForward` for advancing time, and `SetTime` for absolute time control. ```APIDOC ## TTL and Key Expiration: `SetTTL` / `TTL` / `FastForward` TTLs do not decrement automatically in miniredis — they are advanced explicitly using `FastForward`, giving tests full deterministic control over time. ```go func TestExpiration(t *testing.T) { s := miniredis.RunT(t) s.Set("session", "abc123") s.SetTTL("session", 30*time.Second) ttl := s.TTL("session") t.Logf("TTL remaining: %s", ttl) // TTL remaining: 30s // Advance time by 20 seconds — key still alive s.FastForward(20 * time.Second) if !s.Exists("session") { t.Fatal("should still exist") } // Advance past expiry s.FastForward(11 * time.Second) if s.Exists("session") { t.Fatal("key should have expired") } // Control absolute time for EXPIREAT / PEXPIREAT base := time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC) s.SetTime(base) s.Set("token", "xyz") s.SetTTL("token", 5*time.Minute) s.FastForward(6 * time.Minute) t.Logf("token expired: %v", !s.Exists("token")) // token expired: true } ``` ``` -------------------------------- ### Use Test Assertion Helpers in Go Source: https://context7.com/alicebob/miniredis/llms.txt Utilize built-in assertion helpers like CheckGet, CheckList, and CheckSet to simplify test assertions and reduce boilerplate code. These helpers automatically call t.Errorf on failure. ```go func TestCheckHelpers(t *testing.T) { s := miniredis.RunT(t) // String key assertion s.Set("name", "alice") s.CheckGet(t, "name", "alice") // passes // s.CheckGet(t, "name", "bob") would call t.Errorf // List assertion (exact order matters) s.Push("colors", "red", "green", "blue") s.CheckList(t, "colors", "red", "green", "blue") // passes // Set assertion (order-insensitive, values are sorted internally) s.SAdd("fruits", "banana", "apple", "cherry") s.CheckSet(t, "fruits", "apple", "banana", "cherry") // passes } ``` -------------------------------- ### Hash Key Operations Source: https://context7.com/alicebob/miniredis/llms.txt Directly manipulate hash keys. Supports setting multiple fields with `HSet`, retrieving a single field with `HGet`, listing all fields with `HKeys`, incrementing integer fields with `HIncr`, floating-point increments with `HIncrByFloat`, and deleting fields with `HDel`. ```APIDOC ## Hash Key Operations: `HSet` / `HGet` / `HKeys` / `HDel` / `HIncr` Directly manipulate hash keys without a Redis client. ```go func TestHashOps(t *testing.T) { s := miniredis.RunT(t) // Set multiple fields in one call s.HSet("user:1", "name", "Bob", "email", "bob@example.com", "age", "30") // Read a single field name := s.HGet("user:1", "name") t.Logf("name=%s", name) // name=Bob // List all fields (sorted) fields, _ := s.HKeys("user:1") t.Logf("fields=%v", fields) // fields=[age email name] // Increment an integer field newAge, err := s.HIncr("user:1", "age", 1) if err != nil { t.Fatal(err) } t.Logf("age=%d", newAge) // age=31 // Float increment s.HSet("product", "price", "9.99") newPrice, _ := s.HIncrByFloat("product", "price", 0.51) t.Logf("price=%f", newPrice) // price=10.500000 // Delete a field s.HDel("user:1", "email") t.Logf("email=%q", s.HGet("user:1", "email")) // email="" } ``` ``` -------------------------------- ### Ensure Reproducible Randomness with Seed in Go Source: https://context7.com/alicebob/miniredis/llms.txt Use the Seed function to fix the random number generator for commands like RANDOMKEY, SPOP, or SRANDMEMBER, ensuring reproducible test results. Tests with the same seed will yield identical random outputs. ```go func TestDeterministicRandom(t *testing.T) { s := miniredis.RunT(t) s.Seed(42) // fixes RNG for RANDOMKEY, SPOP, SRANDMEMBER s.SAdd("letters", "a", "b", "c", "d", "e") // With a fixed seed, the random member is always the same m1, _ := s.SRandMember("letters") t.Logf("random member (seed=42): %s", m1) // Another server with the same seed returns the same result s2 := miniredis.RunT(t) s2.Seed(42) s2.SAdd("letters", "a", "b", "c", "d", "e") m2, _ := s2.SRandMember("letters") if m1 != m2 { t.Errorf("expected same result with same seed: %s != %s", m1, m2) } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.