sync: 同步 v1.0.4 开源代码并脱敏

This commit is contained in:
MiFaZhan
2026-10-29 14:52:43 +08:00
parent 32e4316ee4
commit 6893e21f07
136 changed files with 9851 additions and 436 deletions
+161
View File
@@ -0,0 +1,161 @@
package rolesync
import (
"context"
"encoding/json"
"errors"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcfg"
"git.5iot.com/iotlcm-public/iotlcm-worker-svr/internal/library/rabbitmq"
"git.5iot.com/iotlcm-public/iotlcm-worker-svr/internal/model"
"testing"
"time"
)
func TestMessageRetryAndDeadLetter(t *testing.T) {
originalSync, originalRetry, originalDead := syncRoleMessage, publishRoleRetry, publishRoleDeadLetter
t.Cleanup(func() {
syncRoleMessage, publishRoleRetry, publishRoleDeadLetter = originalSync, originalRetry, originalDead
})
syncRoleMessage = func(_ context.Context, message *model.AgentRoleSyncMessage) error {
message.ChildDeptIds = []int64{200}
return errors.New("child failed")
}
for attempt := 0; attempt <= 5; attempt++ {
retries, deadLetters := 0, 0
publishRoleRetry = func(_ context.Context, delay time.Duration, body []byte) error {
retries++
var message model.AgentRoleSyncMessage
if err := json.Unmarshal(body, &message); err != nil {
t.Fatal(err)
}
if message.RetryCount != attempt+1 || len(message.ChildDeptIds) != 1 || message.ChildDeptIds[0] != 200 || delay != time.Duration(1<<uint(attempt))*5*time.Second {
t.Fatalf("invalid retry: %+v, delay=%s", message, delay)
}
return nil
}
publishRoleDeadLetter = func(_ context.Context, body []byte) error {
deadLetters++
var dead model.AgentRoleSyncDeadLetterMessage
if err := json.Unmarshal(body, &dead); err != nil {
t.Fatal(err)
}
if dead.Error != "child failed" || dead.FailedAt == "" || dead.Message.RetryCount != 6 {
t.Fatalf("invalid dead letter: %+v", dead)
}
return nil
}
if err := handleMessage(context.Background(), model.AgentRoleSyncMessage{RetryCount: attempt}); err != nil {
t.Fatal(err)
}
if (attempt < 5 && (retries != 1 || deadLetters != 0)) || (attempt == 5 && (retries != 0 || deadLetters != 1)) {
t.Fatalf("unexpected destinations: retry=%d, dead=%d", retries, deadLetters)
}
}
brokerError := errors.New("broker offline")
publishRoleRetry = func(context.Context, time.Duration, []byte) error { return brokerError }
publishRoleDeadLetter = func(context.Context, []byte) error { return brokerError }
for _, attempt := range []int{0, 5} {
if err := handleMessage(context.Background(), model.AgentRoleSyncMessage{RetryCount: attempt}); err == nil {
t.Fatal("publication failure must prevent acknowledgement")
}
}
syncRoleMessage = func(context.Context, *model.AgentRoleSyncMessage) error { return nil }
if err := handleMessage(context.Background(), model.AgentRoleSyncMessage{}); err != nil {
t.Fatalf("successful sync should not publish retries: %v", err)
}
}
func TestRuntimeConfiguration(t *testing.T) {
original := g.Cfg().GetAdapter()
t.Cleanup(func() { g.Cfg().SetAdapter(original) })
for _, test := range []struct {
content string
wantError bool
}{
{"roleSync:\n enabled: false\n", false},
{"roleSync:\n enabled: true\nrabbitmq:\n enabled: false\n", true},
} {
adapter, err := gcfg.NewAdapterContent(test.content)
if err != nil {
t.Fatal(err)
}
g.Cfg().SetAdapter(adapter)
stop, err := Start(context.Background())
if (err != nil) != test.wantError {
t.Fatalf("unexpected initialization: %v", err)
}
if stop != nil {
stop()
}
}
}
func TestConsumerReconnectsAfterConnectionFailureAndChannelClose(t *testing.T) {
original := consumeRoleSync
t.Cleanup(func() { consumeRoleSync = original })
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
reconnected := make(chan struct{})
calls := 0
consumeRoleSync = func(context.Context, string, string, rabbitmq.Handler) (<-chan struct{}, error) {
calls++
if calls == 1 {
return nil, errors.New("broker offline")
}
if calls == 2 {
closed := make(chan struct{})
close(closed)
return closed, nil
}
close(reconnected)
return make(chan struct{}), nil
}
finished := make(chan struct{})
go func() { defer close(finished); superviseConsumer(ctx) }()
select {
case <-reconnected:
case <-time.After(10 * time.Second):
cancel()
<-finished
t.Fatal("consumer did not reconnect")
}
cancel()
<-finished
if calls != 3 {
t.Fatalf("unexpected restarts: %d", calls)
}
}
func TestInvalidMessagesAreQuarantinedAndPublicationFailureIsRetried(t *testing.T) {
originalConsume, originalQuarantine := consumeRoleSync, quarantineRoleSync
t.Cleanup(func() { consumeRoleSync = originalConsume; quarantineRoleSync = originalQuarantine })
for _, body := range []string{`broken json`, `{"sourceRoleId":18}`} {
for _, publishFails := range []bool{false, true} {
ctx, cancel := context.WithCancel(context.Background())
calls := 0
quarantineRoleSync = func(context.Context, []byte) error {
calls++
if publishFails {
return errors.New("broker offline")
}
return nil
}
consumeRoleSync = func(ctx context.Context, queue, consumer string, handler rabbitmq.Handler) (<-chan struct{}, error) {
cancel()
err := handler(ctx, []byte(body))
if (err != nil) != publishFails {
t.Fatalf("unexpected quarantine result: %v", err)
}
done := make(chan struct{})
close(done)
return done, nil
}
superviseConsumer(ctx)
cancel()
if calls != 1 {
t.Fatalf("invalid message not isolated: %d", calls)
}
}
}
}