192 lines
7.8 KiB
Go
192 lines
7.8 KiB
Go
package http
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"primaya-api/cpone-middleware/internal/repository"
|
|
)
|
|
|
|
type fakePatientRepository struct {
|
|
outcome repository.MedrecOutcome
|
|
err error
|
|
params repository.MedrecParams
|
|
}
|
|
|
|
func (f *fakePatientRepository) StoreMedrec(_ context.Context, params repository.MedrecParams) (repository.MedrecOutcome, error) {
|
|
f.params = params
|
|
return f.outcome, f.err
|
|
}
|
|
|
|
func TestStoreMedrecValidPayloadAndCreatedResponseParity(t *testing.T) {
|
|
name := "BUDI SANTOS"
|
|
birthDate := "1990-01-15"
|
|
identityType := "KTP"
|
|
identityNumber := "3174011501900001"
|
|
phone := "081234567890"
|
|
repo := &fakePatientRepository{outcome: repository.MedrecOutcome{
|
|
HTTPStatus: http.StatusCreated,
|
|
Success: true,
|
|
Status: "created",
|
|
Message: "Pasien berhasil disimpan",
|
|
Data: repository.MedrecData{
|
|
Patient: repository.MedrecPatient{
|
|
MEDRECID: "00001235",
|
|
Nama: &name,
|
|
TanggalLahir: &birthDate,
|
|
JenisNomerSosial: &identityType,
|
|
NomerSosial: &identityNumber,
|
|
Telepon: &phone,
|
|
Ponsel: &phone,
|
|
},
|
|
IsNewPatient: true,
|
|
},
|
|
}}
|
|
handler := Handler{patientRepo: repo}
|
|
body := `{
|
|
"rs":" primaya ",
|
|
"nama":" Budi Santos ",
|
|
"jenis_kelamin":"l",
|
|
"tgl_lahir":"1990-01-15",
|
|
"jenis_nomer_sosial":"ktp",
|
|
"nomer_sosial":"3174-0115-0190-0001",
|
|
"telepon":"+62 812-3456-7890",
|
|
"ponsel":"0812 3456 7890",
|
|
"email":" BUDI@Example.COM ",
|
|
"tempat_lahir":" jakarta ",
|
|
"alamat":" JL. CONTOH NO. 1 ",
|
|
"propinsi":" DKI JAKARTA ",
|
|
"kabupaten":" JAKARTA ",
|
|
"kecamatan":" KECAMATAN CONTOH ",
|
|
"kelurahan":" KELURAHAN CONTOH ",
|
|
"kode_pos":" 12345 ",
|
|
"channel":" cpone "
|
|
}`
|
|
|
|
request := httptest.NewRequest(http.MethodPost, "/api/cpone/patients/medrec", strings.NewReader(body))
|
|
recorder := httptest.NewRecorder()
|
|
handler.StoreMedrec(recorder, request)
|
|
|
|
if recorder.Code != http.StatusCreated {
|
|
t.Fatalf("status = %d, want %d; body=%s", recorder.Code, http.StatusCreated, recorder.Body.String())
|
|
}
|
|
const expected = `{"success":true,"status":"created","message":"Pasien berhasil disimpan","data":{"patient":{"MEDRECID":"00001235","Nama":"BUDI SANTOS","TanggalLahir":"1990-01-15","JenisNomerSosial":"KTP","NomerSosial":"3174011501900001","Telepon":"081234567890","Ponsel":"081234567890"},"is_new_patient":true}}` + "\n"
|
|
if recorder.Body.String() != expected {
|
|
t.Fatalf("body mismatch\n got: %s\nwant: %s", recorder.Body.String(), expected)
|
|
}
|
|
|
|
if repo.params.HospitalCode != "PRIMAYA" || repo.params.Name != "BUDI SANTOS" || repo.params.Gender != "L" {
|
|
t.Fatalf("basic normalization mismatch: %+v", repo.params)
|
|
}
|
|
if repo.params.IdentityType != "KTP" || repo.params.IdentityNumber != "3174011501900001" {
|
|
t.Fatalf("identity normalization mismatch: %+v", repo.params)
|
|
}
|
|
if repo.params.Phone != "081234567890" || repo.params.Mobile != "081234567890" {
|
|
t.Fatalf("phone normalization mismatch: %+v", repo.params)
|
|
}
|
|
if repo.params.Email != "budi@example.com" || repo.params.PlaceOfBirth != "JAKARTA" || repo.params.Channel != "CPONE" {
|
|
t.Fatalf("text normalization mismatch: %+v", repo.params)
|
|
}
|
|
if repo.params.DateOfBirth.Format("2006-01-02") != "1990-01-15" {
|
|
t.Fatalf("birth date mismatch: %s", repo.params.DateOfBirth)
|
|
}
|
|
}
|
|
|
|
func TestStoreMedrecValidationParity(t *testing.T) {
|
|
baseline := map[string]any{
|
|
"rs": "PRIMAYA",
|
|
"nama": "BUDI SANTOS",
|
|
"jenis_kelamin": "L",
|
|
"tgl_lahir": "1990-01-15",
|
|
"jenis_nomer_sosial": "KTP",
|
|
"nomer_sosial": "3174011501900001",
|
|
"telepon": "081234567890",
|
|
}
|
|
|
|
tomorrow := time.Now().AddDate(0, 0, 1).Format("2006-01-02")
|
|
tests := []struct {
|
|
name string
|
|
mutate func(map[string]any)
|
|
message string
|
|
}{
|
|
{name: "missing rs", mutate: func(p map[string]any) { delete(p, "rs") }, message: "Kode RS wajib diisi"},
|
|
{name: "missing name", mutate: func(p map[string]any) { delete(p, "nama") }, message: "Nama pasien wajib diisi"},
|
|
{name: "invalid gender", mutate: func(p map[string]any) { p["jenis_kelamin"] = "M" }, message: "Jenis kelamin harus L atau P"},
|
|
{name: "invalid date format", mutate: func(p map[string]any) { p["tgl_lahir"] = "15-01-1990" }, message: "Tanggal lahir harus format Y-m-d"},
|
|
{name: "future birth date", mutate: func(p map[string]any) { p["tgl_lahir"] = tomorrow }, message: "Tanggal lahir tidak boleh lebih dari hari ini"},
|
|
{name: "missing identity", mutate: func(p map[string]any) { delete(p, "nomer_sosial") }, message: "NIK/nomer_sosial wajib diisi"},
|
|
{name: "invalid ktp", mutate: func(p map[string]any) { p["nomer_sosial"] = "123" }, message: "NIK/KTP harus 16 digit angka"},
|
|
{name: "missing phone", mutate: func(p map[string]any) { delete(p, "telepon") }, message: "Telepon atau ponsel wajib diisi"},
|
|
{name: "invalid email", mutate: func(p map[string]any) { p["email"] = "invalid" }, message: "The email must be a valid email address."},
|
|
{name: "long hospital code", mutate: func(p map[string]any) { p["rs"] = strings.Repeat("X", 21) }, message: "The rs must not be greater than 20 characters."},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
payload := make(map[string]any, len(baseline))
|
|
for key, value := range baseline {
|
|
payload[key] = value
|
|
}
|
|
test.mutate(payload)
|
|
body, err := json.Marshal(payload)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
handler := Handler{patientRepo: &fakePatientRepository{}}
|
|
request := httptest.NewRequest(http.MethodPost, "/api/cpone/patients/medrec", strings.NewReader(string(body)))
|
|
recorder := httptest.NewRecorder()
|
|
handler.StoreMedrec(recorder, request)
|
|
|
|
if recorder.Code != http.StatusUnprocessableEntity {
|
|
t.Fatalf("status = %d; body=%s", recorder.Code, recorder.Body.String())
|
|
}
|
|
expected := `{"success":false,"status":"validation_error","message":` + strconvQuote(test.message) + `,"data":null}` + "\n"
|
|
if recorder.Body.String() != expected {
|
|
t.Fatalf("body mismatch\n got: %s\nwant: %s", recorder.Body.String(), expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStoreMedrecNikFallbackAndOutcomeForwarding(t *testing.T) {
|
|
data := repository.PossibleDuplicateData{Candidates: []repository.MedrecPatient{}}
|
|
repo := &fakePatientRepository{outcome: repository.MedrecOutcome{
|
|
HTTPStatus: http.StatusConflict,
|
|
Success: false,
|
|
Status: "possible_duplicate",
|
|
Message: "Ditemukan pasien dengan nama, tanggal lahir, dan nomor telepon yang sama atau sangat mirip",
|
|
Data: data,
|
|
}}
|
|
handler := Handler{patientRepo: repo}
|
|
body := `{"rs":"PRIMAYA","nama":"BUDI","jenis_kelamin":"P","tgl_lahir":"1990-01-15","nik":"3174011501900001","ponsel":"08123"}`
|
|
request := httptest.NewRequest(http.MethodPost, "/api/cpone/patients/medrec", strings.NewReader(body))
|
|
recorder := httptest.NewRecorder()
|
|
handler.StoreMedrec(recorder, request)
|
|
|
|
if recorder.Code != http.StatusConflict || repo.params.IdentityType != "KTP" || repo.params.IdentityNumber != "3174011501900001" {
|
|
t.Fatalf("unexpected result: status=%d params=%+v body=%s", recorder.Code, repo.params, recorder.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestStoreMedrecRepositoryErrorParity(t *testing.T) {
|
|
handler := Handler{patientRepo: &fakePatientRepository{err: errors.New("database unavailable")}}
|
|
body := `{"rs":"PRIMAYA","nama":"BUDI","jenis_kelamin":"L","tgl_lahir":"1990-01-15","nomer_sosial":"3174011501900001","telepon":"08123"}`
|
|
request := httptest.NewRequest(http.MethodPost, "/api/cpone/patients/medrec", strings.NewReader(body))
|
|
recorder := httptest.NewRecorder()
|
|
handler.StoreMedrec(recorder, request)
|
|
|
|
if recorder.Code != http.StatusInternalServerError {
|
|
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
|
|
}
|
|
const expected = `{"success":false,"status":"error","message":"database unavailable","data":null}` + "\n"
|
|
if recorder.Body.String() != expected {
|
|
t.Fatalf("body mismatch\n got: %s\nwant: %s", recorder.Body.String(), expected)
|
|
}
|
|
}
|