Live Trading Boundary의 남은 account-sync/audit-trail 작업을 완료해 운영자 headless workflow와 roadmap 완료 후보 상태를 함께 반영한다.
99 lines
2.9 KiB
Go
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")
|
|
}
|
|
}
|