95 lines
2.9 KiB
Go
95 lines
2.9 KiB
Go
package mediamtx
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
type roundTripFunc func(*http.Request) (*http.Response, error)
|
|
|
|
func (f roundTripFunc) RoundTrip(request *http.Request) (*http.Response, error) { return f(request) }
|
|
|
|
func TestApplyBuildsCredentialSourceOnlyInTransientBody(t *testing.T) {
|
|
var body map[string]any
|
|
var appliedPath string
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if strings.Contains(r.URL.String(), "password") {
|
|
t.Fatal("credential leaked in control URL")
|
|
}
|
|
if r.Method == http.MethodGet {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
appliedPath = r.URL.Path
|
|
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer server.Close()
|
|
client := NewHTTPController(server.URL)
|
|
if err := client.Apply(context.Background(), Source{Path: "sense_test", URI: "rtsp://camera.invalid/main", Username: "fixture-user", Password: "fixture-password"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if body["source"] != "rtsp://fixture-user:fixture-password@camera.invalid/main" {
|
|
t.Fatalf("body=%#v", body)
|
|
}
|
|
if appliedPath != "/v3/config/paths/add/sense_test" {
|
|
t.Fatalf("applied path = %q", appliedPath)
|
|
}
|
|
}
|
|
|
|
func TestApplyReplacesExistingPath(t *testing.T) {
|
|
var appliedPath string
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == http.MethodGet {
|
|
w.WriteHeader(http.StatusOK)
|
|
return
|
|
}
|
|
appliedPath = r.URL.Path
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer server.Close()
|
|
if err := NewHTTPController(server.URL).Apply(context.Background(), Source{Path: "sense_test", URI: "rtsp://camera.invalid/main"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if appliedPath != "/v3/config/paths/replace/sense_test" {
|
|
t.Fatalf("applied path = %q", appliedPath)
|
|
}
|
|
}
|
|
|
|
func TestApplyWaitsForNewlyStartedControlAPI(t *testing.T) {
|
|
attempts := 0
|
|
client := NewHTTPController("http://127.0.0.1:9997")
|
|
client.client.Transport = roundTripFunc(func(request *http.Request) (*http.Response, error) {
|
|
attempts++
|
|
if attempts < 3 {
|
|
return nil, errors.New("connection refused")
|
|
}
|
|
status := http.StatusNotFound
|
|
if request.Method == http.MethodPost {
|
|
status = http.StatusOK
|
|
}
|
|
return &http.Response{StatusCode: status, Body: io.NopCloser(strings.NewReader("")), Header: make(http.Header)}, nil
|
|
})
|
|
if err := client.Apply(context.Background(), Source{Path: "sense_test", URI: "rtsp://camera.invalid/main"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if attempts != 4 {
|
|
t.Fatalf("attempts = %d", attempts)
|
|
}
|
|
}
|
|
func TestApplyRejectsCredentialURI(t *testing.T) {
|
|
client := NewHTTPController("http://127.0.0.1")
|
|
if err := client.Apply(context.Background(), Source{Path: "x", URI: "rtsp://user:pass@camera.invalid/main"}); err == nil {
|
|
t.Fatal("credential URI accepted")
|
|
}
|
|
}
|
|
|