alt/packages/domain/trading/audit_test.go
toki c0db4b24c1 feat(live-trading): 계좌 동기화와 감사 추적을 추가한다
Live Trading Boundary의 남은 account-sync/audit-trail 작업을 완료해 운영자 headless workflow와 roadmap 완료 후보 상태를 함께 반영한다.
2026-06-08 11:18:41 +09:00

99 lines
2.9 KiB
Go

package trading_test
import (
"testing"
"time"
"git.toki-labs.com/toki/alt/packages/domain/trading"
)
func TestAuditEventTypeStability(t *testing.T) {
// AuditEventType strings are stored in the database; they must remain stable
// across versions.
cases := []struct {
typ trading.AuditEventType
want string
}{
{trading.AuditEventTypeSubmitConfirmed, "submit_confirmed"},
{trading.AuditEventTypeBrokerAccepted, "broker_accepted"},
{trading.AuditEventTypeBrokerRejected, "broker_rejected"},
{trading.AuditEventTypeCancelConfirmed, "cancel_confirmed"},
{trading.AuditEventTypeRiskBlocked, "risk_blocked"},
{trading.AuditEventTypeKillSwitchSet, "kill_switch_set"},
{trading.AuditEventTypeAccountSyncSuccess, "account_sync_success"},
{trading.AuditEventTypeAccountSyncFailure, "account_sync_failure"},
}
for _, c := range cases {
if string(c.typ) != c.want {
t.Errorf("AuditEventType changed: got %q, want %q", string(c.typ), c.want)
}
}
}
func TestHasRawSecretKeyBlocksForbiddenKeys(t *testing.T) {
blockedPayloads := []map[string]string{
{"token": "abc123"},
{"access_token": "xyz"},
{"secret": "shh"},
{"password": "hunter2"},
{"raw_account_number": "123456"},
{"api_key": "key"},
{"authorization": "Bearer tok"},
{"raw_body": `{"raw":true}`},
}
for _, p := range blockedPayloads {
if !trading.HasRawSecretKey(p) {
t.Errorf("expected HasRawSecretKey=true for payload %v", p)
}
}
}
func TestHasRawSecretKeyAllowsSafePayload(t *testing.T) {
safe := map[string]string{
"order_id": "lo-acct-1",
"status": "submitted",
"instrument_id": "005930.KS",
}
if trading.HasRawSecretKey(safe) {
t.Error("expected HasRawSecretKey=false for safe payload")
}
if trading.HasRawSecretKey(nil) {
t.Error("expected HasRawSecretKey=false for nil payload")
}
}
func TestAuditFilterDefaults(t *testing.T) {
var f trading.AuditFilter
if f.AccountID != "" || f.OrderID != "" || f.EventType != "" || f.Limit != 0 {
t.Error("zero-value AuditFilter must have empty/zero fields")
}
}
func TestAuditEventFields(t *testing.T) {
now := time.Now().UTC()
ev := trading.AuditEvent{
EventID: "evt-1",
Type: trading.AuditEventTypeSubmitConfirmed,
Timestamp: now,
Broker: trading.BrokerKIS,
AccountID: "acct-1",
OrderID: "lo-acct-1-1",
Status: "submitted",
Reason: "operator confirmed",
Actor: "op-001",
CorrelationID: "corr-001",
Payload: map[string]string{"instrument_id": "005930.KS"},
}
if ev.EventID == "" {
t.Error("expected non-empty EventID")
}
if ev.Type != trading.AuditEventTypeSubmitConfirmed {
t.Errorf("expected AuditEventTypeSubmitConfirmed, got %q", ev.Type)
}
if ev.Timestamp != now {
t.Error("Timestamp does not match")
}
if trading.HasRawSecretKey(ev.Payload) {
t.Error("safe payload must not be flagged as containing raw secret key")
}
}