{"id":19873969,"url":"https://github.com/bose/minisentinel","last_synced_at":"2025-10-09T06:52:23.100Z","repository":{"id":54418467,"uuid":"193893833","full_name":"Bose/minisentinel","owner":"Bose","description":"Pure Go Redis Sentinel server for Go unittests","archived":false,"fork":false,"pushed_at":"2023-01-04T10:16:21.000Z","size":17,"stargazers_count":26,"open_issues_count":3,"forks_count":11,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-08-14T01:41:26.805Z","etag":null,"topics":["go","golang","redis","redis-sentinel"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Bose.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-06-26T11:46:12.000Z","updated_at":"2025-05-25T14:43:11.000Z","dependencies_parsed_at":"2023-02-02T08:00:56.967Z","dependency_job_id":null,"html_url":"https://github.com/Bose/minisentinel","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Bose/minisentinel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Bose%2Fminisentinel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Bose%2Fminisentinel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Bose%2Fminisentinel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Bose%2Fminisentinel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Bose","download_url":"https://codeload.github.com/Bose/minisentinel/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Bose%2Fminisentinel/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279000859,"owners_count":26082951,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","redis","redis-sentinel"],"created_at":"2024-11-12T16:20:44.632Z","updated_at":"2025-10-09T06:52:23.066Z","avatar_url":"https://github.com/Bose.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Minisentinel\n\nPure Go Redis Sentinel server\n\n##\n\nSometimes you want to test code which uses Redis with Sentinel, without making it a full-blown\nintegration test.  Minisentinel implements (parts of) the Sentinel protocol to be used in unittests.  Used together with [Miniredis](https://github.com/alicebob/miniredis), they enable a simple, cheap, in-memory, Redis with Sentinel replacement, with a real TCP interface. Think of it as the Sentinel+Redis version of `net/http/httptest`.\n\nIt saves you from using mock code, and since both the sentinel and redis servers live within the\ntest process you can query for values directly, without going through the server\nstack.\n\nThere are no dependencies on external binaries, so you can easily integrate it in automated build processes.\n\n\n## Sentinel Commands\n\nImplemented commands:\n\n- Connection \n    - AUTH -- see RequireAuth()\n    - PING \n- Sentinel\n    - MASTERS\n    - GET-MASTER-ADDR-BY-NAME\n    - SLAVES\n\n## Redis Commands\n\nSee the Miniredis documentation: https://github.com/alicebob/miniredis/blob/master/README.md\n\n## Example\n\n```go\n\npackage minisentinel\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/FZambia/sentinel\"\n\t\"github.com/alicebob/miniredis\"\n\t\"github.com/gomodule/redigo/redis\"\n\t\"github.com/matryer/is\"\n)\n\n// TestSomething - shows how-to start up sentinel + redis in your unittest\nfunc TestSomething(t *testing.T) {\n\tis := is.New(t)\n\tm := miniredis.NewMiniRedis()\n\terr := m.StartAddr(\":6379\")\n\tis.NoErr(err)\n\tdefer m.Close()\n\ts := NewSentinel(m, WithReplica(m))\n\terr = s.StartAddr(\":26379\")\n\tis.NoErr(err)\n\tdefer s.Close()\n\t// all the setup is done.. now just use sentinel/redis like you\n\t// would normally in your tests via a redis client\n}\n\n// TestRedisWithSentinel - an example of combining miniRedis with miniSentinel for unittests\nfunc TestRedisWithSentinel(t *testing.T) {\n\tis := is.New(t)\n\tm, err := miniredis.Run()\n\tm.RequireAuth(\"super-secret\") // not required, but demonstrates how-to\n\tis.NoErr(err)\n\tdefer m.Close()\n\ts := NewSentinel(m, WithReplica(m))\n\ts.Start()\n\tdefer s.Close()\n\n\t// use redigo to create a sentinel pool\n\tsntnl := \u0026sentinel.Sentinel{\n\t\tAddrs:      []string{s.Addr()},\n\t\tMasterName: s.MasterInfo().Name,\n\t\tDial: func(addr string) (redis.Conn, error) {\n\t\t\tconnTimeout := time.Duration(50 * time.Millisecond)\n\t\t\treadWriteTimeout := time.Duration(50 * time.Millisecond)\n\t\t\tc, err := redis.DialTimeout(\"tcp\", addr, connTimeout, readWriteTimeout, readWriteTimeout)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn c, nil\n\t\t},\n\t}\n\tredisPassword := []byte(\"super-secret\") // required because of m.RequireAuth()\n\tpool := redis.Pool{\n\t\tMaxIdle:     3,\n\t\tMaxActive:   64,\n\t\tWait:        true,\n\t\tIdleTimeout: 240 * time.Second,\n\t\tDial: func() (redis.Conn, error) {\n\t\t\tredisHostAddr, errHostAddr := sntnl.MasterAddr()\n\t\t\tif errHostAddr != nil {\n\t\t\t\treturn nil, errHostAddr\n\t\t\t}\n\t\t\t\tc, err := redis.Dial(\"tcp\", redisHostAddr)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif redisPassword != nil { // auth first, before doing anything else\n\t\t\t\tif _, err := c.Do(\"AUTH\", string(redisPassword)); err != nil {\n\t\t\t\t\tc.Close()\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn c, nil\n\t\t},\n\t\tTestOnBorrow: func(c redis.Conn, t time.Time) error {\n\t\t\tif time.Since(t) \u003c time.Minute {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif !sentinel.TestRole(c, \"master\") {\n\t\t\t\treturn errors.New(\"Role check failed\")\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\n\t// Optionally set some keys your code expects:\n\tm.Set(\"foo\", \"not-bar\")\n\tm.HSet(\"some\", \"other\", \"key\")\n\n\t// Run your code and see if it behaves.\n\t// An example using the redigo library from \"github.com/gomodule/redigo/redis\":\n\tc := pool.Get()\n\tdefer c.Close() //release connection back to the pool\n\t// use the pool connection to do things via TCP to our miniRedis\n\t_, err = c.Do(\"SET\", \"foo\", \"bar\")\n\n\t// Optionally check values in redis...\n\tgot, err := m.Get(\"foo\")\n\tis.NoErr(err)\n\tis.Equal(got, \"bar\")\n\n\t// ... or use a miniRedis helper for that:\n\tm.CheckGet(t, \"foo\", \"bar\")\n\n\t// TTL and expiration:\n\tm.Set(\"foo\", \"bar\")\n\tm.SetTTL(\"foo\", 10*time.Second)\n\tm.FastForward(11 * time.Second)\n\tis.True(m.Exists(\"foo\") == false) // it shouldn't be there anymore\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbose%2Fminisentinel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbose%2Fminisentinel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbose%2Fminisentinel/lists"}