package services import ( "database/sql" "testing" "quyun/v2/app/commands/testx" "quyun/v2/database" "quyun/v2/database/models" . "github.com/smartystreets/goconvey/convey" "github.com/stretchr/testify/suite" "go.ipao.vip/atom/contracts" "go.uber.org/dig" ) type AuditTestSuiteInjectParams struct { dig.In DB *sql.DB Initials []contracts.Initial `group:"initials"` } type AuditTestSuite struct { suite.Suite AuditTestSuiteInjectParams } func Test_Audit(t *testing.T) { providers := testx.Default().With(Provide) testx.Serve(providers, t, func(p AuditTestSuiteInjectParams) { suite.Run(t, &AuditTestSuite{AuditTestSuiteInjectParams: p}) }) } func (s *AuditTestSuite) Test_Log() { Convey("Audit.Log", s.T(), func() { ctx := s.T().Context() database.Truncate(ctx, s.DB, models.TableNameAuditLog) Convey("should persist audit log with all fields", func() { tenantID := int64(1) operatorID := int64(100) action := "review_content" targetID := "123" detail := "approved content for publishing" Audit.Log(ctx, tenantID, operatorID, action, targetID, detail) q := models.AuditLogQuery entry, err := q.WithContext(ctx). Where(q.TenantID.Eq(tenantID), q.OperatorID.Eq(operatorID), q.Action.Eq(action)). First() So(err, ShouldBeNil) So(entry.TenantID, ShouldEqual, tenantID) So(entry.OperatorID, ShouldEqual, operatorID) So(entry.Action, ShouldEqual, action) So(entry.TargetID, ShouldEqual, targetID) So(entry.Detail, ShouldEqual, detail) }) Convey("should persist audit log with operatorID=0 for platform-level action", func() { Audit.Log(ctx, 0, 0, "system_init", "", "system initialization") q := models.AuditLogQuery entry, err := q.WithContext(ctx). Where(q.Action.Eq("system_init")). First() So(err, ShouldBeNil) So(entry.TenantID, ShouldEqual, 0) So(entry.OperatorID, ShouldEqual, 0) }) Convey("should persist multiple audit logs for same action type", func() { Audit.Log(ctx, 1, 10, "update_settings", "s1", "changed theme") Audit.Log(ctx, 1, 20, "update_settings", "s2", "changed logo") q := models.AuditLogQuery entries, err := q.WithContext(ctx). Where(q.Action.Eq("update_settings")). Find() So(err, ShouldBeNil) So(len(entries), ShouldEqual, 2) }) Convey("should query audit logs by tenant", func() { Audit.Log(ctx, 100, 1, "action_a", "t1", "tenant 100 action") Audit.Log(ctx, 200, 2, "action_b", "t2", "tenant 200 action") q := models.AuditLogQuery entries, err := q.WithContext(ctx). Where(q.TenantID.Eq(100)). Find() So(err, ShouldBeNil) So(len(entries), ShouldEqual, 1) So(entries[0].Action, ShouldEqual, "action_a") }) Convey("should query audit logs by operator", func() { Audit.Log(ctx, 1, 500, "op_action_1", "t1", "operator 500 first") Audit.Log(ctx, 1, 500, "op_action_2", "t2", "operator 500 second") Audit.Log(ctx, 1, 600, "op_action_3", "t3", "operator 600") q := models.AuditLogQuery entries, err := q.WithContext(ctx). Where(q.OperatorID.Eq(500)). Find() So(err, ShouldBeNil) So(len(entries), ShouldEqual, 2) }) Convey("should query audit logs by action", func() { Audit.Log(ctx, 1, 1, "freeze_coupon", "c1", "frozen") Audit.Log(ctx, 2, 2, "freeze_coupon", "c2", "frozen again") Audit.Log(ctx, 3, 3, "unfreeze_coupon", "c3", "unfrozen") q := models.AuditLogQuery entries, err := q.WithContext(ctx). Where(q.Action.Eq("freeze_coupon")). Find() So(err, ShouldBeNil) So(len(entries), ShouldEqual, 2) }) }) }