125 lines
4.9 KiB
Go
125 lines
4.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
type fakeReader struct {
|
|
status ReaderStatus
|
|
readResult DLLResult
|
|
readErr error
|
|
readPanic any
|
|
hmacResult DLLResult
|
|
hmacErr error
|
|
lastType string
|
|
lastNoPIN bool
|
|
}
|
|
|
|
func (f *fakeReader) Status() ReaderStatus { return f.status }
|
|
func (f *fakeReader) ReadCard(readerType string, noPIN bool) (DLLResult, error) {
|
|
f.lastType, f.lastNoPIN = readerType, noPIN
|
|
if f.readPanic != nil {
|
|
panic(f.readPanic)
|
|
}
|
|
return f.readResult, f.readErr
|
|
}
|
|
func (f *fakeReader) HMACSM3(_, _, _, _ string) (DLLResult, error) {
|
|
return f.hmacResult, f.hmacErr
|
|
}
|
|
|
|
func testHandler(reader *fakeReader) http.Handler {
|
|
cfg := defaultConfig(".")
|
|
return newHandler(cfg, reader, discardLogger())
|
|
}
|
|
|
|
func TestHealth(t *testing.T) {
|
|
reader := &fakeReader{status: ReaderStatus{Loaded: true, DLLDir: `C:\\dll`, Arch: "386", Platform: "windows"}}
|
|
recorder := httptest.NewRecorder()
|
|
testHandler(reader).ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/health", nil))
|
|
if recorder.Code != http.StatusOK {
|
|
t.Fatalf("status = %d, body = %s", recorder.Code, recorder.Body.String())
|
|
}
|
|
var response apiResponse
|
|
if err := json.Unmarshal(recorder.Body.Bytes(), &response); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if response.Code != 0 {
|
|
t.Fatalf("unexpected response: %#v", response)
|
|
}
|
|
}
|
|
|
|
func TestReadNoPINRequiresReaderType(t *testing.T) {
|
|
recorder := httptest.NewRecorder()
|
|
testHandler(&fakeReader{}).ServeHTTP(recorder, httptest.NewRequest(http.MethodPost, "/api/card/read-nopin", strings.NewReader(`{}`)))
|
|
if recorder.Code != http.StatusBadRequest {
|
|
t.Fatalf("status = %d, body = %s", recorder.Code, recorder.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestReadNoPINSuccess(t *testing.T) {
|
|
reader := &fakeReader{readResult: DLLResult{Code: 0, Success: true, Data: map[string]any{"Success": true, "Name": "测试"}}}
|
|
recorder := httptest.NewRecorder()
|
|
request := httptest.NewRequest(http.MethodPost, "/api/card/read-nopin", strings.NewReader(`{"reader_type":" ZJ_HZ_310000 "}`))
|
|
testHandler(reader).ServeHTTP(recorder, request)
|
|
if recorder.Code != http.StatusOK || reader.lastType != "ZJ_HZ_310000" || !reader.lastNoPIN {
|
|
t.Fatalf("status=%d type=%q noPIN=%v body=%s", recorder.Code, reader.lastType, reader.lastNoPIN, recorder.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestReadFailure(t *testing.T) {
|
|
reader := &fakeReader{readResult: DLLResult{Code: -1, Success: false, Raw: `{"Success":false,"Message":"未检测到卡"}`, Data: map[string]any{"Success": false, "Message": "未检测到卡"}}}
|
|
recorder := httptest.NewRecorder()
|
|
testHandler(reader).ServeHTTP(recorder, httptest.NewRequest(http.MethodPost, "/api/card/read-nopin", strings.NewReader(`{"reader_type":"ZJ_HZ_310000"}`)))
|
|
if recorder.Code != http.StatusInternalServerError || !strings.Contains(recorder.Body.String(), "未检测到卡") {
|
|
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestReadError(t *testing.T) {
|
|
reader := &fakeReader{readErr: errors.New("DLL unavailable")}
|
|
recorder := httptest.NewRecorder()
|
|
testHandler(reader).ServeHTTP(recorder, httptest.NewRequest(http.MethodPost, "/api/card/read-nopin", strings.NewReader(`{"reader_type":"ZJ_HZ_310000"}`)))
|
|
if recorder.Code != http.StatusInternalServerError {
|
|
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestReadPanicIsRecovered(t *testing.T) {
|
|
reader := &fakeReader{readPanic: "driver panic"}
|
|
recorder := httptest.NewRecorder()
|
|
testHandler(reader).ServeHTTP(recorder, httptest.NewRequest(http.MethodPost, "/api/card/read-nopin", strings.NewReader(`{"reader_type":"ZJ_HZ_310000"}`)))
|
|
if recorder.Code != http.StatusInternalServerError || !strings.Contains(recorder.Body.String(), "服务内部异常") {
|
|
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestWithPINRejectsOtherCity(t *testing.T) {
|
|
recorder := httptest.NewRecorder()
|
|
testHandler(&fakeReader{}).ServeHTTP(recorder, httptest.NewRequest(http.MethodPost, "/api/card/read", strings.NewReader(`{"reader_type":"ZJ_HZ_310000"}`)))
|
|
if recorder.Code != http.StatusBadRequest {
|
|
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestHMACSuccess(t *testing.T) {
|
|
reader := &fakeReader{hmacResult: DLLResult{Code: 0, Success: true, Data: "123:ABC"}}
|
|
recorder := httptest.NewRecorder()
|
|
testHandler(reader).ServeHTTP(recorder, httptest.NewRequest(http.MethodPost, "/api/hmac-sm3", strings.NewReader(`{"key":"k","secret":"1234","request_body":"{}"}`)))
|
|
if recorder.Code != http.StatusOK || !strings.Contains(recorder.Body.String(), "123:ABC") {
|
|
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestInvalidJSON(t *testing.T) {
|
|
recorder := httptest.NewRecorder()
|
|
testHandler(&fakeReader{}).ServeHTTP(recorder, httptest.NewRequest(http.MethodPost, "/api/card/read-nopin", strings.NewReader(`{`)))
|
|
if recorder.Code != http.StatusBadRequest {
|
|
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
|
|
}
|
|
}
|