Files
chis_osi/handler/health_record_upsert_test.go
T

115 lines
4.8 KiB
Go
Raw Normal View History

package handler
import (
"context"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"strings"
"testing"
"chis_osi/pipeline"
"chis_osi/source"
)
func TestHealthRecordUpsertReturnsStructuredOutcome(t *testing.T) {
tests := []struct {
name string
outcome pipeline.Outcome
wantStatus int
}{
{name: "create", outcome: pipeline.Outcome{Status: pipeline.StatusDone, Action: pipeline.ActionCreate, ServiceID: "JKDA00001", ResponseCode: "01", PHRIDHint: "****0001"}, wantStatus: http.StatusOK},
{name: "update", outcome: pipeline.Outcome{Status: pipeline.StatusDone, Action: pipeline.ActionUpdate, ServiceID: "JKDA00003", ResponseCode: "01", PHRIDHint: "****0001"}, wantStatus: http.StatusOK},
{name: "manual review", outcome: pipeline.Outcome{Status: pipeline.StatusManualReview, Action: pipeline.ActionNone, Reason: "multiple CHIS health records found"}, wantStatus: http.StatusConflict},
{name: "retry", outcome: pipeline.Outcome{Status: pipeline.StatusRetry, Action: pipeline.ActionNone, Reason: "CHIS query failed"}, wantStatus: http.StatusServiceUnavailable},
{name: "validation failed", outcome: pipeline.Outcome{Status: pipeline.StatusFailed, Action: pipeline.ActionNone, Reason: "mapping validation failed: idCard"}, wantStatus: http.StatusUnprocessableEntity},
{name: "upstream failed", outcome: pipeline.Outcome{Status: pipeline.StatusFailed, Action: pipeline.ActionCreate, Reason: "CHIS create failed", ServiceID: "JKDA00001"}, wantStatus: http.StatusBadGateway},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
upserter := &fakeHealthRecordUpserter{outcome: tt.outcome}
h := NewHealthRecordUpsertHandler(upserter)
req := httptest.NewRequest(http.MethodPost, "/api/health-record/upsert", strings.NewReader(testPHISEnvelope()))
rec := httptest.NewRecorder()
h.Upsert(rec, req)
if rec.Code != tt.wantStatus {
t.Fatalf("status = %d, want %d; body=%s", rec.Code, tt.wantStatus, rec.Body.String())
}
var got pipeline.Outcome
if err := json.Unmarshal(rec.Body.Bytes(), &got); err != nil {
t.Fatalf("decode outcome: %v; body=%s", err, rec.Body.String())
}
if got.Status != tt.outcome.Status || got.Action != tt.outcome.Action || upserter.task.ArchID != "ARCH-HTTP-1" {
t.Fatalf("outcome=%#v task=%#v", got, upserter.task)
}
})
}
}
func TestHealthRecordUpsertHidesInternalError(t *testing.T) {
h := NewHealthRecordUpsertHandler(&fakeHealthRecordUpserter{err: errors.New("proxy secret detail")})
req := httptest.NewRequest(http.MethodPost, "/api/health-record/upsert", strings.NewReader(testPHISEnvelope()))
rec := httptest.NewRecorder()
h.Upsert(rec, req)
if rec.Code != http.StatusBadGateway || strings.Contains(rec.Body.String(), "secret") {
t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String())
}
}
func TestHealthRecordUpsertPreservesDoneOutcomeOnFinalizationError(t *testing.T) {
h := NewHealthRecordUpsertHandler(&fakeHealthRecordUpserter{
outcome: pipeline.Outcome{Status: pipeline.StatusDone, Action: pipeline.ActionCreate, ServiceID: "JKDA00001", ResponseCode: "01"},
err: errors.New("idempotency complete failed"),
})
req := httptest.NewRequest(http.MethodPost, "/api/health-record/upsert", strings.NewReader(testPHISEnvelope()))
rec := httptest.NewRecorder()
h.Upsert(rec, req)
if rec.Code != http.StatusBadGateway || !strings.Contains(rec.Body.String(), `"retrySafe":false`) || !strings.Contains(rec.Body.String(), `"status":"done"`) {
t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String())
}
}
func TestHealthRecordUpsertRejectsInvalidEnvelopeAndMethod(t *testing.T) {
t.Run("invalid envelope", func(t *testing.T) {
h := NewHealthRecordUpsertHandler(&fakeHealthRecordUpserter{})
req := httptest.NewRequest(http.MethodPost, "/api/health-record/upsert", strings.NewReader(`{"code":500,"msg":"failed"}`))
rec := httptest.NewRecorder()
h.Upsert(rec, req)
if rec.Code != http.StatusBadRequest {
t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String())
}
})
t.Run("method", func(t *testing.T) {
h := NewHealthRecordUpsertHandler(nil)
req := httptest.NewRequest(http.MethodGet, "/api/health-record/upsert", nil)
rec := httptest.NewRecorder()
h.Upsert(rec, req)
if rec.Code != http.StatusMethodNotAllowed || rec.Header().Get("Allow") != http.MethodPost {
t.Fatalf("status=%d allow=%q", rec.Code, rec.Header().Get("Allow"))
}
})
}
type fakeHealthRecordUpserter struct {
outcome pipeline.Outcome
err error
task source.HealthRecordTask
}
func (f *fakeHealthRecordUpserter) Upsert(_ context.Context, task source.HealthRecordTask) (pipeline.Outcome, error) {
f.task = task
return f.outcome, f.err
}
func testPHISEnvelope() string {
return `{"code":200,"msg":"ok","compress":false,"data":{"archId":"ARCH-HTTP-1","businessId":"BUS-HTTP-1","record":{"idCard":"440000********1234"}}}`
}