Smail/server/hooks/wechat_push/wechat_push_test.go

113 lines
3.1 KiB
Go

package main
import (
"encoding/json"
"io"
"net/http"
"strings"
"sync"
"sync/atomic"
"testing"
"time"
"unicode/utf8"
"git.pcux.cn/xuans/Smail/dto/parsemail"
)
type weChatRoundTripFunc func(*http.Request) (*http.Response, error)
func (f weChatRoundTripFunc) RoundTrip(request *http.Request) (*http.Response, error) {
return f(request)
}
func TestBuildWeChatMessageLimitsContent(t *testing.T) {
message := buildWeChatMessage(&parsemail.Email{
Subject: strings.Repeat("\u754c", maxWeChatMessageBytes),
Text: []byte(strings.Repeat("body", maxWeChatMessageBytes)),
})
if len(message) > maxWeChatMessageBytes {
t.Fatalf("message length = %d, want at most %d", len(message), maxWeChatMessageBytes)
}
if !utf8.ValidString(message) {
t.Fatal("message is not valid UTF-8")
}
if message := buildWeChatMessage(nil); message != "" {
t.Fatalf("nil email message = %q", message)
}
}
func TestSendUserMsgLimitsOutboundContent(t *testing.T) {
originalClient := weChatHTTPClient
t.Cleanup(func() { weChatHTTPClient = originalClient })
var captured sendMsgRequest
weChatHTTPClient = &http.Client{Transport: weChatRoundTripFunc(func(request *http.Request) (*http.Response, error) {
body, err := io.ReadAll(request.Body)
if err != nil {
t.Fatal(err)
}
if err := json.Unmarshal(body, &captured); err != nil {
t.Fatal(err)
}
return &http.Response{
StatusCode: http.StatusOK,
Header: make(http.Header),
Body: io.NopCloser(strings.NewReader(`{}`)),
}, nil
})}
hook := &WeChatPushHook{
token: "test-token",
tokenExpires: time.Now().Add(time.Minute).Unix(),
templateId: "template",
webDomain: "mail.example.com",
}
hook.sendUserMsg(nil, "user", strings.Repeat("x", maxWeChatMessageBytes+100))
if len(captured.Data.Content.Value) != maxWeChatMessageBytes {
t.Fatalf("outbound content length = %d, want %d", len(captured.Data.Content.Value), maxWeChatMessageBytes)
}
}
func TestGetWxAccessTokenConcurrentRefresh(t *testing.T) {
originalClient := weChatHTTPClient
t.Cleanup(func() { weChatHTTPClient = originalClient })
var requestCount atomic.Int32
weChatHTTPClient = &http.Client{Transport: weChatRoundTripFunc(func(request *http.Request) (*http.Response, error) {
requestCount.Add(1)
time.Sleep(20 * time.Millisecond)
return &http.Response{
StatusCode: http.StatusOK,
Header: make(http.Header),
Body: io.NopCloser(strings.NewReader(`{"access_token":"shared-token","expires_in":7200}`)),
}, nil
})}
hook := &WeChatPushHook{appId: "test-app-id", secret: "test-secret"}
const workerCount = 32
start := make(chan struct{})
results := make(chan string, workerCount)
var workers sync.WaitGroup
workers.Add(workerCount)
for range workerCount {
go func() {
defer workers.Done()
<-start
results <- hook.getWxAccessToken()
}()
}
close(start)
workers.Wait()
close(results)
for token := range results {
if token != "shared-token" {
t.Fatalf("token = %q, want shared-token", token)
}
}
if got := requestCount.Load(); got != 1 {
t.Fatalf("token request count = %d, want 1", got)
}
}