feat: T1007 System Service Discovery - fixed allowlist probe in posture heartbeat
This commit is contained in:
208
server/internal/api/config_handler_test.go
Normal file
208
server/internal/api/config_handler_test.go
Normal file
@@ -0,0 +1,208 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"crypto-miner-server/internal/db"
|
||||
)
|
||||
|
||||
// stubConfigProvider implements ConfigProvider for handler unit tests.
|
||||
type stubConfigProvider struct {
|
||||
configJSON json.RawMessage
|
||||
updateErr error
|
||||
updated json.RawMessage
|
||||
}
|
||||
|
||||
func (s *stubConfigProvider) GetConfigJSON() json.RawMessage {
|
||||
if len(s.configJSON) == 0 {
|
||||
return json.RawMessage(`{"port":8989,"pool":{"host":"pool.example.com","port":3333,"use_tls":true}}`)
|
||||
}
|
||||
return s.configJSON
|
||||
}
|
||||
|
||||
func (s *stubConfigProvider) UpdateConfigFromJSON(data json.RawMessage) error {
|
||||
if s.updateErr != nil {
|
||||
return s.updateErr
|
||||
}
|
||||
s.updated = append(json.RawMessage(nil), data...)
|
||||
s.configJSON = append(json.RawMessage(nil), data...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func newTestConfigHandler(t *testing.T, cp ConfigProvider) *ConfigHandler {
|
||||
t.Helper()
|
||||
database, err := db.New(t.TempDir())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { database.Close() })
|
||||
return NewConfigHandler(database, cp)
|
||||
}
|
||||
|
||||
func TestNewConfigHandler(t *testing.T) {
|
||||
h := newTestConfigHandler(t, &stubConfigProvider{})
|
||||
if h == nil || h.config == nil || h.db == nil {
|
||||
t.Fatal("NewConfigHandler returned incomplete handler")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigHandlerServeHTTP_MethodNotAllowed(t *testing.T) {
|
||||
h := newTestConfigHandler(t, &stubConfigProvider{})
|
||||
for _, method := range []string{http.MethodPost, http.MethodDelete, http.MethodPatch} {
|
||||
req := httptest.NewRequest(method, "/api/v1/config", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusMethodNotAllowed {
|
||||
t.Fatalf("%s: expected 405, got %d", method, rec.Code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigHandlerGetConfig(t *testing.T) {
|
||||
stub := &stubConfigProvider{
|
||||
configJSON: json.RawMessage(`{"port":9001,"wallet":{"address":"48abc"}}`),
|
||||
}
|
||||
h := newTestConfigHandler(t, stub)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/config", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("GET status=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
if ct := rec.Header().Get("Content-Type"); !strings.Contains(ct, "application/json") {
|
||||
t.Fatalf("expected JSON content-type, got %q", ct)
|
||||
}
|
||||
var body map[string]interface{}
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if body["port"].(float64) != 9001 {
|
||||
t.Fatalf("unexpected config body: %v", body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigHandlerPutConfig_SuccessReturnsUpdated(t *testing.T) {
|
||||
stub := &stubConfigProvider{
|
||||
configJSON: json.RawMessage(`{"port":8989}`),
|
||||
}
|
||||
h := newTestConfigHandler(t, stub)
|
||||
|
||||
payload := `{"port":9100,"pool":{"host":"new.pool","port":4444,"use_tls":false}}`
|
||||
req := httptest.NewRequest(http.MethodPut, "/api/v1/config", strings.NewReader(payload))
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("PUT status=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
if string(stub.updated) != payload {
|
||||
t.Fatalf("provider did not receive payload: %q", stub.updated)
|
||||
}
|
||||
var body map[string]interface{}
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if body["port"].(float64) != 9100 {
|
||||
t.Fatalf("response not updated: %v", body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigHandlerPutConfig_InvalidJSON(t *testing.T) {
|
||||
h := newTestConfigHandler(t, &stubConfigProvider{})
|
||||
req := httptest.NewRequest(http.MethodPut, "/api/v1/config", strings.NewReader(`{not json`))
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusBadRequest {
|
||||
t.Fatalf("expected 400, got %d", rec.Code)
|
||||
}
|
||||
var errBody map[string]string
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &errBody); err != nil {
|
||||
t.Fatalf("error body not valid JSON: %s", rec.Body.String())
|
||||
}
|
||||
if errBody["error"] != "Invalid JSON" {
|
||||
t.Fatalf("unexpected error: %q", errBody["error"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigHandlerPutConfig_InvalidConfigBadRequest(t *testing.T) {
|
||||
stub := &stubConfigProvider{
|
||||
updateErr: fmt.Errorf("invalid config: unexpected EOF"),
|
||||
}
|
||||
h := newTestConfigHandler(t, stub)
|
||||
req := httptest.NewRequest(http.MethodPut, "/api/v1/config", strings.NewReader(`{"port":1}`))
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusBadRequest {
|
||||
t.Fatalf("expected 400 for invalid config, got %d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigHandlerPutConfig_SaveErrorInternalServerError(t *testing.T) {
|
||||
stub := &stubConfigProvider{
|
||||
updateErr: errors.New("failed to save config: disk full"),
|
||||
}
|
||||
h := newTestConfigHandler(t, stub)
|
||||
req := httptest.NewRequest(http.MethodPut, "/api/v1/config", strings.NewReader(`{"port":1}`))
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusInternalServerError {
|
||||
t.Fatalf("expected 500, got %d", rec.Code)
|
||||
}
|
||||
var errBody map[string]string
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &errBody); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(errBody["error"], "disk full") {
|
||||
t.Fatalf("unexpected error message: %q", errBody["error"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigHandlerPutConfig_ErrorJSONEscapesQuotes(t *testing.T) {
|
||||
stub := &stubConfigProvider{
|
||||
updateErr: errors.New(`failed: say "hello"`),
|
||||
}
|
||||
h := newTestConfigHandler(t, stub)
|
||||
req := httptest.NewRequest(http.MethodPut, "/api/v1/config", strings.NewReader(`{"port":1}`))
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusInternalServerError {
|
||||
t.Fatalf("expected 500, got %d", rec.Code)
|
||||
}
|
||||
var errBody map[string]string
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &errBody); err != nil {
|
||||
t.Fatalf("malformed JSON error response: %s", rec.Body.String())
|
||||
}
|
||||
if errBody["error"] != `failed: say "hello"` {
|
||||
t.Fatalf("unexpected escaped error: %q", errBody["error"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigHandlerPutConfig_EmptyBodyInvalidJSON(t *testing.T) {
|
||||
h := newTestConfigHandler(t, &stubConfigProvider{})
|
||||
req := httptest.NewRequest(http.MethodPut, "/api/v1/config", nil)
|
||||
req.Body = io.NopCloser(bytes.NewReader(nil))
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusBadRequest {
|
||||
t.Fatalf("expected 400 for empty body, got %d", rec.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigProviderInterface(t *testing.T) {
|
||||
var _ ConfigProvider = (*stubConfigProvider)(nil)
|
||||
}
|
||||
Reference in New Issue
Block a user