aliyun_captcha_verifier_test.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. package repository
  2. import (
  3. "context"
  4. "errors"
  5. "net/http"
  6. "net/http/httptest"
  7. "strings"
  8. "testing"
  9. "github.com/stretchr/testify/require"
  10. "github.com/Wei-Shaw/sub2api/internal/service"
  11. )
  12. // newAliyunCaptchaTestTarget 起一个假的阿里云端点,让真实 SDK 走完整的签名/序列化链路。
  13. func newAliyunCaptchaTestTarget(t *testing.T, handler http.HandlerFunc) (*aliyunCaptchaVerifier, service.AliyunCaptchaCredentials) {
  14. t.Helper()
  15. server := httptest.NewServer(handler)
  16. t.Cleanup(server.Close)
  17. verifier := &aliyunCaptchaVerifier{protocol: "HTTP", timeoutMillis: 2_000}
  18. cred := service.AliyunCaptchaCredentials{
  19. AccessKeyID: "test-ak-id",
  20. AccessKeySecret: "test-ak-secret",
  21. SceneID: "scene-1",
  22. Endpoint: strings.TrimPrefix(server.URL, "http://"),
  23. }
  24. return verifier, cred
  25. }
  26. func TestAliyunCaptchaVerifier_VerifySuccess(t *testing.T) {
  27. var capturedParam, capturedSceneID string
  28. verifier, cred := newAliyunCaptchaTestTarget(t, func(w http.ResponseWriter, r *http.Request) {
  29. require.NoError(t, r.ParseForm())
  30. capturedParam = r.Form.Get("CaptchaVerifyParam")
  31. capturedSceneID = r.Form.Get("SceneId")
  32. w.Header().Set("Content-Type", "application/json")
  33. _, _ = w.Write([]byte(`{"Code":"Success","Message":"success","RequestId":"req-1","Success":true,"Result":{"VerifyResult":true,"VerifyCode":"T001"}}`))
  34. })
  35. result, err := verifier.VerifyCaptcha(context.Background(), cred, "the-verify-param")
  36. require.NoError(t, err)
  37. require.True(t, result.VerifyResult)
  38. require.Equal(t, "T001", result.VerifyCode)
  39. require.Equal(t, "the-verify-param", capturedParam)
  40. require.Equal(t, "scene-1", capturedSceneID)
  41. }
  42. func TestAliyunCaptchaVerifier_VerifyResultFalse(t *testing.T) {
  43. verifier, cred := newAliyunCaptchaTestTarget(t, func(w http.ResponseWriter, _ *http.Request) {
  44. w.Header().Set("Content-Type", "application/json")
  45. _, _ = w.Write([]byte(`{"Code":"Success","RequestId":"req-2","Success":true,"Result":{"VerifyResult":false,"VerifyCode":"F002"}}`))
  46. })
  47. result, err := verifier.VerifyCaptcha(context.Background(), cred, "bad-param")
  48. require.NoError(t, err)
  49. require.False(t, result.VerifyResult)
  50. require.Equal(t, "F002", result.VerifyCode)
  51. }
  52. func TestAliyunCaptchaVerifier_APIErrorNormalized(t *testing.T) {
  53. verifier, cred := newAliyunCaptchaTestTarget(t, func(w http.ResponseWriter, _ *http.Request) {
  54. w.Header().Set("Content-Type", "application/json")
  55. w.WriteHeader(http.StatusForbidden)
  56. _, _ = w.Write([]byte(`{"Code":"SignatureDoesNotMatch","Message":"Specified signature is not matched with our calculation.","RequestId":"req-3"}`))
  57. })
  58. _, err := verifier.VerifyCaptcha(context.Background(), cred, "param")
  59. require.Error(t, err)
  60. var apiErr *service.AliyunCaptchaAPIError
  61. require.ErrorAs(t, err, &apiErr)
  62. require.Equal(t, "SignatureDoesNotMatch", apiErr.Code)
  63. }
  64. func TestAliyunCaptchaVerifier_TransportError(t *testing.T) {
  65. server := httptest.NewServer(http.NotFoundHandler())
  66. endpoint := strings.TrimPrefix(server.URL, "http://")
  67. server.Close() // 立即关闭,制造连接失败
  68. verifier := &aliyunCaptchaVerifier{protocol: "HTTP", timeoutMillis: 2_000}
  69. cred := service.AliyunCaptchaCredentials{
  70. AccessKeyID: "test-ak-id",
  71. AccessKeySecret: "test-ak-secret",
  72. SceneID: "scene-1",
  73. Endpoint: endpoint,
  74. }
  75. _, err := verifier.VerifyCaptcha(context.Background(), cred, "param")
  76. require.Error(t, err)
  77. var apiErr *service.AliyunCaptchaAPIError
  78. require.False(t, errors.As(err, &apiErr), "transport errors must not be normalized to API errors")
  79. }