mirror of
https://github.com/MengMengCode/VoCat.git
synced 2026-08-20 14:53:42 +08:00
145 lines
3.7 KiB
Go
145 lines
3.7 KiB
Go
package server
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"vocat/internal/device"
|
|
"vocat/internal/modem"
|
|
)
|
|
|
|
func TestValidateATCommandBlocksTrafficMessagingAndDialActions(t *testing.T) {
|
|
t.Parallel()
|
|
for _, command := range []string{
|
|
"AT+CGATT=1",
|
|
"AT+CGACT=1,1",
|
|
"AT+CGDATA=\"PPP\",1",
|
|
"AT+QNETDEVCTL=1,1,1",
|
|
"AT+QIACT=1",
|
|
"AT+CMGS=42",
|
|
"AT+CMSS=7",
|
|
"AT+CMGC=12",
|
|
"AT+QCMGS=42",
|
|
"AT+CUSD=1,\"*100#\"",
|
|
"ATD12345;",
|
|
"ATA",
|
|
"ATH",
|
|
"AT+CSQ; +CGACT = 1,1",
|
|
"AT+CSQ;+CMSS=7",
|
|
"AT+CSQ;D12345;",
|
|
} {
|
|
if err := validateATCommand(command, false); err == nil {
|
|
t.Errorf("validateATCommand(%q) permitted a guarded mutation", command)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValidateATCommandForceBypassesGuard(t *testing.T) {
|
|
t.Parallel()
|
|
for _, command := range []string{
|
|
"AT+CGATT=1",
|
|
"AT+CFUN=1",
|
|
"AT+CGACT=1,1",
|
|
"AT+CUSD=1,\"*100#\"",
|
|
"ATD12345;",
|
|
} {
|
|
if err := validateATCommand(command, true); err != nil {
|
|
t.Errorf("validateATCommand(%q, true): %v", command, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValidateATCommandForceKeepsSyntaxChecks(t *testing.T) {
|
|
t.Parallel()
|
|
for _, command := range []string{
|
|
"A",
|
|
"",
|
|
"AT\r",
|
|
"AT\n",
|
|
string(make([]byte, 513)),
|
|
} {
|
|
if err := validateATCommand(command, true); err == nil {
|
|
t.Errorf("validateATCommand(%q, true) skipped syntax check", command)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValidateATCommandAllowsReadOnlyStatusQueries(t *testing.T) {
|
|
t.Parallel()
|
|
for _, command := range []string{
|
|
"AT",
|
|
"AT+CPIN?",
|
|
"AT+CGATT?",
|
|
"AT+CGACT?",
|
|
"AT+CFUN?",
|
|
"AT+CIMI",
|
|
"AT+CCID",
|
|
} {
|
|
if err := validateATCommand(command, false); err != nil {
|
|
t.Errorf("validateATCommand(%q): %v", command, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// The AT terminal must present ERROR / +CME ERROR as a normal response, not as
|
|
// a 502. Before the CommandError branch was restored, every unsupported or
|
|
// SIM-less command was folded into "the device operation failed", hiding the
|
|
// real reason from the user.
|
|
func TestHandleATSurfacesCommandErrorAsResponse(t *testing.T) {
|
|
controller := fakeDeviceController{
|
|
entry: device.Device{ID: "dev1"},
|
|
atHandler: func(command string) (modem.Response, error) {
|
|
return modem.Response{}, &modem.CommandError{
|
|
Command: command,
|
|
Final: "+CME ERROR: 10",
|
|
Lines: []string{"+CME ERROR: 10"},
|
|
}
|
|
},
|
|
}
|
|
server := &Server{devices: controller, logger: regionTestLogger(), maxRequestBodyBytes: 1 << 20}
|
|
recorder := httptest.NewRecorder()
|
|
request := httptest.NewRequest(
|
|
http.MethodPost,
|
|
"/api/devices/dev1/actions/at",
|
|
strings.NewReader(`{"cmd":"AT+CPIN?","timeout_ms":5000}`),
|
|
)
|
|
request.Header.Set("Content-Type", "application/json")
|
|
|
|
if !server.handleAT(recorder, request, "dev1") {
|
|
t.Fatal("handleAT returned false")
|
|
}
|
|
if recorder.Code != http.StatusOK {
|
|
t.Fatalf("status = %d, want 200 (body=%s)", recorder.Code, recorder.Body.String())
|
|
}
|
|
data := decodeData(t, recorder)
|
|
response, _ := data["response"].(string)
|
|
if !strings.Contains(response, "+CME ERROR: 10") {
|
|
t.Fatalf("response = %q, want +CME ERROR text", response)
|
|
}
|
|
}
|
|
|
|
func TestHandleATMapsNonCommandErrorTo502(t *testing.T) {
|
|
controller := fakeDeviceController{
|
|
entry: device.Device{ID: "dev1"},
|
|
atErr: errors.New("transport wedged"),
|
|
}
|
|
server := &Server{devices: controller, logger: regionTestLogger(), maxRequestBodyBytes: 1 << 20}
|
|
recorder := httptest.NewRecorder()
|
|
request := httptest.NewRequest(
|
|
http.MethodPost,
|
|
"/api/devices/dev1/actions/at",
|
|
strings.NewReader(`{"cmd":"AT+CSQ"}`),
|
|
)
|
|
request.Header.Set("Content-Type", "application/json")
|
|
|
|
if !server.handleAT(recorder, request, "dev1") {
|
|
t.Fatal("handleAT returned false")
|
|
}
|
|
if recorder.Code != http.StatusBadGateway {
|
|
t.Fatalf("status = %d, want 502", recorder.Code)
|
|
}
|
|
}
|