9e6e95f431
- internal/m2mcore/fsm.go: конечный автомат с переходами Draft → Validated → SubmittedToNSD → AwaitingDecision → Confirmed → AwaitingSUB16 → Done, ветки Rejected/TimedOut/ManualApproval - internal/m2mcore/deal.go: доменная модель Deal с методами Validate/Submit/ReceiveDecision/Timeout/SendToManualApproval/ApproveManually/RejectManually/CompleteSUB16, журнал событий - internal/m2mcore/uuid.go: генератор UUID v4 без внешних зависимостей (crypto/rand) - internal/m2mcore/repo.go: порт Repository + MemoryRepository с идемпотентным Create по GUID - internal/m2mcore/ports.go: порты NSDSender/LKCallbackClient/CryptoVerifier/FansyStore с no-op заглушками для M1 - internal/m2mcore/enrich.go: EnrichRequest — сборка M2MTransferRequest из ClaimInput + Fansy, генерация ReferenceID по каждой ЦБ - internal/m2mcore/metrics.go: порт Recorder + MemoryRecorder в Prometheus-text формате - cmd/m2m-core/main.go: HTTP-сервер с /healthz и /metrics, graceful shutdown - migrations/m2m-core/001__deals.sql: схема для PostgreSQL-Repository (для M2) Покрытие: 63.1%. make ci зелёный. Без внешних Go-зависимостей (pgx и prometheus подключим в M2, когда прокси zetit откроет Go-модули). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
45 lines
1.2 KiB
Go
45 lines
1.2 KiB
Go
package m2mcore_test
|
|
|
|
import (
|
|
"bytes"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/m2mcore"
|
|
)
|
|
|
|
func TestMemoryRecorderPrometheus(t *testing.T) {
|
|
r := m2mcore.NewMemoryRecorder()
|
|
r.StageDuration(m2mcore.StateAwaitingDecision, 12*time.Second)
|
|
r.StageDuration(m2mcore.StateAwaitingDecision, 8*time.Second)
|
|
r.IncDeal(m2mcore.StateConfirmed)
|
|
r.IncDeal(m2mcore.StateConfirmed)
|
|
r.IncDeal(m2mcore.StateRejected)
|
|
r.IncSLABreach(m2mcore.StateAwaitingDecision, "5m")
|
|
|
|
var buf bytes.Buffer
|
|
if err := r.WritePrometheus(&buf); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
out := buf.String()
|
|
for _, want := range []string{
|
|
`m2m_stage_duration_seconds_count{stage="awaiting_decision"} 2`,
|
|
`m2m_stage_duration_seconds_sum{stage="awaiting_decision"} 20`,
|
|
`m2m_deals_total{state="confirmed"} 2`,
|
|
`m2m_deals_total{state="rejected"} 1`,
|
|
`m2m_sla_breaches_total{stage="awaiting_decision",budget="5m"} 1`,
|
|
} {
|
|
if !strings.Contains(out, want) {
|
|
t.Errorf("в выводе нет %q\n---\n%s", want, out)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNoopRecorder(t *testing.T) {
|
|
var r m2mcore.Recorder = m2mcore.NoopRecorder{}
|
|
r.StageDuration(m2mcore.StateConfirmed, time.Second)
|
|
r.IncDeal(m2mcore.StateConfirmed)
|
|
r.IncSLABreach(m2mcore.StateAwaitingDecision, "5m")
|
|
}
|