Files
mediamtx/internal/api/api_admin_test.go
T
QiuSW 6465a11074
lint / go (push) Canceled after 0s
lint / go_mod (push) Canceled after 0s
lint / conf (push) Canceled after 0s
lint / docslinks (push) Canceled after 0s
lint / docsorder (push) Canceled after 0s
lint / apidocs (push) Canceled after 0s
lint / other (push) Canceled after 0s
test / test_64 (push) Canceled after 0s
test / test_32 (push) Canceled after 0s
test / test_e2e (push) Canceled after 0s
feat: add embedded RTSP admin console (#3)
2026-08-28 11:24:47 +08:00

123 lines
4.1 KiB
Go

package api //nolint:revive
import (
"fmt"
"io"
"net/http"
"strings"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/bluenviron/mediamtx/internal/auth"
"github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/test"
)
const adminTestAddress = "localhost:9996"
func newAdminTestAPI(t *testing.T, authManager apiAuthManager) *API {
t.Helper()
api := &API{
Address: adminTestAddress,
ReadTimeout: conf.Duration(10 * time.Second),
WriteTimeout: conf.Duration(10 * time.Second),
AuthManager: authManager,
Parent: &testParent{},
}
require.NoError(t, api.Initialize())
t.Cleanup(api.Close)
return api
}
func readAdminResponse(t *testing.T, client *http.Client, url string) (*http.Response, string) {
t.Helper()
res, err := client.Get(url)
require.NoError(t, err)
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
require.NoError(t, res.Body.Close())
return res, string(body)
}
func TestAdminAssets(t *testing.T) {
newAdminTestAPI(t, test.NilAuthManager)
transport := &http.Transport{}
t.Cleanup(transport.CloseIdleConnections)
client := &http.Client{Transport: transport}
res, body := readAdminResponse(t, client, "http://"+adminTestAddress+"/admin/")
require.Equal(t, http.StatusOK, res.StatusCode)
require.Equal(t, "text/html; charset=utf-8", res.Header.Get("Content-Type"))
require.Equal(t, "no-store", res.Header.Get("Cache-Control"))
require.Contains(t, res.Header.Get("Content-Security-Policy"), "object-src 'none'")
require.Equal(t, "nosniff", res.Header.Get("X-Content-Type-Options"))
require.Contains(t, body, "MediaMTX Stream Console")
require.Contains(t, body, "./app.css")
require.Contains(t, body, "./app.js")
require.NotContains(t, body, "https://")
res, body = readAdminResponse(t, client, "http://"+adminTestAddress+"/admin/app.css")
require.Equal(t, http.StatusOK, res.StatusCode)
require.Equal(t, "text/css; charset=utf-8", res.Header.Get("Content-Type"))
require.Contains(t, body, "prefers-reduced-motion")
require.Contains(t, body, "@media (max-width: 700px)")
res, body = readAdminResponse(t, client, "http://"+adminTestAddress+"/admin/app.js")
require.Equal(t, http.StatusOK, res.StatusCode)
require.Equal(t, "text/javascript; charset=utf-8", res.Header.Get("Content-Type"))
require.Contains(t, body, "sourceMasked")
require.Contains(t, body, "encodePathName")
require.Contains(t, body, "if (source) payload.source = source")
require.Contains(t, body, "redactSensitiveText")
require.Contains(t, body, "state.global.webrtcAddress")
require.NotContains(t, body, ".innerHTML")
require.NotContains(t, body, "localStorage")
res, _ = readAdminResponse(t, client, "http://"+adminTestAddress+"/admin/missing.js")
require.Equal(t, http.StatusNotFound, res.StatusCode)
}
func TestAdminRedirect(t *testing.T) {
newAdminTestAPI(t, test.NilAuthManager)
transport := &http.Transport{}
t.Cleanup(transport.CloseIdleConnections)
client := &http.Client{
Transport: transport,
CheckRedirect: func(_ *http.Request, _ []*http.Request) error {
return http.ErrUseLastResponse
},
}
res, _ := readAdminResponse(t, client, "http://"+adminTestAddress+"/admin")
require.Equal(t, http.StatusMovedPermanently, res.StatusCode)
require.Equal(t, "/admin/", res.Header.Get("Location"))
}
func TestAdminUsesAPIAuthentication(t *testing.T) {
var got *auth.Request
newAdminTestAPI(t, &test.AuthManager{
AuthenticateImpl: func(req *auth.Request) (string, *auth.Error) {
got = req
return "", &auth.Error{AskCredentials: true, Wrapped: fmt.Errorf("denied")}
},
})
transport := &http.Transport{}
t.Cleanup(transport.CloseIdleConnections)
client := &http.Client{Transport: transport}
res, body := readAdminResponse(t, client, "http://"+adminTestAddress+"/admin/")
require.Equal(t, http.StatusUnauthorized, res.StatusCode)
require.Equal(t, `Basic realm="mediamtx"`, res.Header.Get("WWW-Authenticate"))
require.NotNil(t, got)
require.Equal(t, conf.AuthActionAPI, got.Action)
require.True(t, got.EnableAskCredentials)
require.True(t, strings.Contains(body, "authentication error"))
}