package main import ( "context" "errors" "net/http" "net/http/httptest" "os" "strings" "testing" "chis_osi/contract" "chis_osi/osi" "chis_osi/pipeline" "chis_osi/source" ) func TestServerHealthRecordUpserterLoadsMasterDataAndCreates(t *testing.T) { task := loadRuntimeHealthRecordTask(t) client := &fakeRuntimeHealthRecordClient{ doctors: []osi.Doctor{{PersonID: task.Record.ManaDoctorID, PersonName: "测试医生"}}, orgs: []osi.Org{{OrganizCode: task.Record.ManaUnitID, OrganizName: "测试机构"}}, records: []contract.FindHealthRecord{}, } upserter := newServerHealthRecordUpserter(client) outcome, err := upserter.Upsert(context.Background(), task) if err != nil || outcome.Status != pipeline.StatusDone || outcome.Action != pipeline.ActionCreate { t.Fatalf("outcome=%#v err=%v", outcome, err) } if client.doctorQueries != 1 || client.orgQueries != 1 || client.createCalls != 1 { t.Fatalf("doctorQueries=%d orgQueries=%d create=%d", client.doctorQueries, client.orgQueries, client.createCalls) } } func TestServerHealthRecordUpserterStopsWhenMasterDataFails(t *testing.T) { task := loadRuntimeHealthRecordTask(t) client := &fakeRuntimeHealthRecordClient{masterErr: errors.New("dictionary unavailable")} upserter := newServerHealthRecordUpserter(client) _, err := upserter.Upsert(context.Background(), task) if err == nil || client.findCalls != 0 || client.createCalls != 0 { t.Fatalf("err=%v find=%d create=%d", err, client.findCalls, client.createCalls) } } func TestServerHealthRecordUpserterValidatesBeforeMasterDataCalls(t *testing.T) { client := &fakeRuntimeHealthRecordClient{masterErr: errors.New("must not be called")} upserter := newServerHealthRecordUpserter(client) outcome, err := upserter.Upsert(context.Background(), source.HealthRecordTask{ArchID: "ARCH-INVALID"}) if err != nil || outcome.Status != pipeline.StatusFailed || client.doctorQueries != 0 || client.orgQueries != 0 { t.Fatalf("outcome=%#v err=%v doctorQueries=%d orgQueries=%d", outcome, err, client.doctorQueries, client.orgQueries) } } func TestServerMuxRegistersHealthRecordUpsert(t *testing.T) { upserter := &fakeServerUpserter{outcome: pipeline.Outcome{Status: pipeline.StatusDone, Action: pipeline.ActionCreate}} mux := newServerMux(nil, upserter) raw, err := os.ReadFile("source/testdata/health_record.json") if err != nil { t.Fatalf("ReadFile: %v", err) } req := httptest.NewRequest(http.MethodPost, "/api/health-record/upsert", strings.NewReader(string(raw))) rec := httptest.NewRecorder() mux.ServeHTTP(rec, req) if rec.Code != http.StatusOK || upserter.calls != 1 { t.Fatalf("status=%d calls=%d body=%s", rec.Code, upserter.calls, rec.Body.String()) } } func loadRuntimeHealthRecordTask(t *testing.T) source.HealthRecordTask { t.Helper() raw, err := os.ReadFile("source/testdata/health_record.json") if err != nil { t.Fatalf("ReadFile: %v", err) } task, err := source.DecodeHealthRecordTask(raw) if err != nil { t.Fatalf("DecodeHealthRecordTask: %v", err) } return task } type fakeRuntimeHealthRecordClient struct { doctors []osi.Doctor orgs []osi.Org records []contract.FindHealthRecord masterErr error doctorQueries, orgQueries int findCalls, createCalls int } func (f *fakeRuntimeHealthRecordClient) QueryDoctors(context.Context, osi.DoctorQuery) ([]osi.Doctor, osi.Result, error) { f.doctorQueries++ return f.doctors, osi.Result{Success: f.masterErr == nil, Code: "01"}, f.masterErr } func (f *fakeRuntimeHealthRecordClient) QueryOrgs(context.Context, osi.OrgQuery) ([]osi.Org, osi.Result, error) { f.orgQueries++ return f.orgs, osi.Result{Success: f.masterErr == nil, Code: "01"}, f.masterErr } func (f *fakeRuntimeHealthRecordClient) FindHealthRecord(context.Context, osi.FindHealthRecordQuery) ([]contract.FindHealthRecord, osi.Result, error) { f.findCalls++ return f.records, osi.Result{Success: true, Code: "01"}, nil } func (f *fakeRuntimeHealthRecordClient) CreateHealthRecord(context.Context, contract.HealthRecordCreate) (contract.HealthRecordSaveResult, osi.Result, error) { f.createCalls++ return contract.HealthRecordSaveResult{PhrID: "PHR-RUNTIME"}, osi.Result{Success: true, Code: "01"}, nil } func (f *fakeRuntimeHealthRecordClient) UpdateHealthRecord(context.Context, contract.HealthRecordCreate) (contract.HealthRecordSaveResult, osi.Result, error) { return contract.HealthRecordSaveResult{}, osi.Result{Success: true, Code: "01"}, nil } type fakeServerUpserter struct { outcome pipeline.Outcome calls int } func (f *fakeServerUpserter) Upsert(context.Context, source.HealthRecordTask) (pipeline.Outcome, error) { f.calls++ return f.outcome, nil }