TestLuaScriptReadOnlyError tests that READONLY errors from Lua scripts are correctly detected by IsReadOnlyError and ShouldRetry.
(t *testing.T)
| 314 | // TestLuaScriptReadOnlyError tests that READONLY errors from Lua scripts |
| 315 | // are correctly detected by IsReadOnlyError and ShouldRetry. |
| 316 | func TestLuaScriptReadOnlyError(t *testing.T) { |
| 317 | luaReadOnlyMsg := "ERR Error running script (call to f_abc123): @user_script:1: -READONLY You can't write against a read only replica." |
| 318 | |
| 319 | t.Run("IsReadOnlyError detects Lua script READONLY", func(t *testing.T) { |
| 320 | err := proto.ParseErrorReply([]byte("-" + luaReadOnlyMsg)) |
| 321 | if !redis.IsReadOnlyError(err) { |
| 322 | t.Errorf("IsReadOnlyError should detect Lua script READONLY error: %v", err) |
| 323 | } |
| 324 | }) |
| 325 | |
| 326 | t.Run("ShouldRetry retries Lua script READONLY", func(t *testing.T) { |
| 327 | err := proto.ParseErrorReply([]byte("-" + luaReadOnlyMsg)) |
| 328 | if !redis.ShouldRetry(err, false) { |
| 329 | t.Errorf("ShouldRetry should retry Lua script READONLY error: %v", err) |
| 330 | } |
| 331 | }) |
| 332 | |
| 333 | t.Run("wrapped Lua script READONLY detected", func(t *testing.T) { |
| 334 | err := proto.ParseErrorReply([]byte("-" + luaReadOnlyMsg)) |
| 335 | wrappedErr := fmt.Errorf("hook wrapper: %w", err) |
| 336 | if !redis.IsReadOnlyError(wrappedErr) { |
| 337 | t.Errorf("IsReadOnlyError should detect wrapped Lua script READONLY error: %v", wrappedErr) |
| 338 | } |
| 339 | if !redis.ShouldRetry(wrappedErr, false) { |
| 340 | t.Errorf("ShouldRetry should retry wrapped Lua script READONLY error: %v", wrappedErr) |
| 341 | } |
| 342 | }) |
| 343 | |
| 344 | t.Run("false positive: non-script error with -READONLY not matched", func(t *testing.T) { |
| 345 | err := proto.ParseErrorReply([]byte("-ERR something-READONLY-key")) |
| 346 | if redis.IsReadOnlyError(err) { |
| 347 | t.Errorf("IsReadOnlyError should NOT match non-script error containing -READONLY: %v", err) |
| 348 | } |
| 349 | }) |
| 350 | |
| 351 | t.Run("false positive: script error without -READONLY not matched", func(t *testing.T) { |
| 352 | err := proto.ParseErrorReply([]byte("-ERR Error running script (call to f_abc): @user_script:1: some other error")) |
| 353 | if redis.IsReadOnlyError(err) { |
| 354 | t.Errorf("IsReadOnlyError should NOT match script error without -READONLY: %v", err) |
| 355 | } |
| 356 | }) |
| 357 | } |
| 358 | |
| 359 | // TestSetErrWithWrappedError tests that when a hook wraps an error and sets it |
| 360 | // via cmd.SetErr(), the underlying typed error can still be detected |
nothing calls this directly
no test coverage detected