api: add tests

This commit is contained in:
aler9 2021-08-07 16:07:08 +02:00 committed by Alessandro Ros
parent 5943660ab3
commit 0535ab8e9c
5 changed files with 312 additions and 19 deletions

View File

@ -137,7 +137,6 @@ func loadConfPathData(ctx *gin.Context) (interface{}, error) {
}
type apiPathsItem struct {
Name string `json:"name"`
ConfName string `json:"confName"`
Conf *conf.PathConf `json:"conf"`
Source interface{} `json:"source"`
@ -146,7 +145,7 @@ type apiPathsItem struct {
}
type apiPathsListData struct {
Items []apiPathsItem `json:"items"`
Items map[string]apiPathsItem `json:"items"`
}
type apiPathsListRes1 struct {
@ -167,13 +166,12 @@ type apiPathsListReq2 struct {
Res chan apiPathsListRes2
}
type apiRTSPSessionsItem struct {
ID string `json:"id"`
type apiRTSPSessionsListItem struct {
RemoteAddr string `json:"remoteAddr"`
}
type apiRTSPSessionsListData struct {
Items []apiRTSPSessionsItem `json:"items"`
Items map[string]apiRTSPSessionsListItem `json:"items"`
}
type apiRTSPSessionsListRes struct {
@ -193,12 +191,11 @@ type apiRTSPSessionsKickReq struct {
}
type apiRTMPConnsListItem struct {
ID string `json:"id"`
RemoteAddr string `json:"remoteAddr"`
}
type apiRTMPConnsListData struct {
Items []apiRTMPConnsListItem `json:"items"`
Items map[string]apiRTMPConnsListItem `json:"items"`
}
type apiRTMPConnsListRes struct {
@ -357,6 +354,10 @@ func (a *api) onConfigSet(ctx *gin.Context) {
return
}
a.mutex.Lock()
a.conf = &newConf
a.mutex.Unlock()
// since reloading the configuration can cause the shutdown of the API,
// call it in a goroutine
go a.parent.OnAPIConfigSet(&newConf)
@ -393,6 +394,10 @@ func (a *api) onConfigPathsAdd(ctx *gin.Context) {
return
}
a.mutex.Lock()
a.conf = &newConf
a.mutex.Unlock()
// since reloading the configuration can cause the shutdown of the API,
// call it in a goroutine
go a.parent.OnAPIConfigSet(&newConf)
@ -428,6 +433,10 @@ func (a *api) onConfigPathsEdit(ctx *gin.Context) {
return
}
a.mutex.Lock()
a.conf = &newConf
a.mutex.Unlock()
// since reloading the configuration can cause the shutdown of the API,
// call it in a goroutine
go a.parent.OnAPIConfigSet(&newConf)
@ -456,6 +465,10 @@ func (a *api) onConfigPathsDelete(ctx *gin.Context) {
return
}
a.mutex.Lock()
a.conf = &newConf
a.mutex.Unlock()
// since reloading the configuration can cause the shutdown of the API,
// call it in a goroutine
go a.parent.OnAPIConfigSet(&newConf)
@ -465,7 +478,7 @@ func (a *api) onConfigPathsDelete(ctx *gin.Context) {
func (a *api) onPathsList(ctx *gin.Context) {
data := apiPathsListData{
Items: []apiPathsItem{},
Items: make(map[string]apiPathsItem),
}
res := a.pathManager.OnAPIPathsList(apiPathsListReq1{})
@ -488,7 +501,7 @@ func (a *api) onRTSPSessionsList(ctx *gin.Context) {
}
data := apiRTSPSessionsListData{
Items: []apiRTSPSessionsItem{},
Items: make(map[string]apiRTSPSessionsListItem),
}
if a.rtspServer != nil {
@ -544,7 +557,7 @@ func (a *api) onRTMPConnsList(ctx *gin.Context) {
}
data := apiRTMPConnsListData{
Items: []apiRTMPConnsListItem{},
Items: make(map[string]apiRTMPConnsListItem),
}
res := a.rtmpServer.OnAPIRTMPConnsList(apiRTMPConnsListReq{Data: &data})

283
internal/core/api_test.go Normal file
View File

@ -0,0 +1,283 @@
package core
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"testing"
"time"
"github.com/aler9/gortsplib"
"github.com/stretchr/testify/require"
)
func httpRequest(method string, ur string, in interface{}, out interface{}) error {
buf, err := func() (io.Reader, error) {
if in == nil {
return nil, nil
}
byts, err := json.Marshal(in)
if err != nil {
return nil, err
}
return bytes.NewBuffer(byts), nil
}()
if err != nil {
return err
}
req, err := http.NewRequest(method, ur, buf)
if err != nil {
return err
}
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return fmt.Errorf("bad status code: %d", res.StatusCode)
}
if out == nil {
return nil
}
return json.NewDecoder(res.Body).Decode(out)
}
func TestAPIConfigGet(t *testing.T) {
p, ok := newInstance("api: yes\n")
require.Equal(t, true, ok)
defer p.close()
var out map[string]interface{}
err := httpRequest(http.MethodGet, "http://localhost:9997/config/get", nil, &out)
require.NoError(t, err)
require.Equal(t, true, out["api"])
}
func TestAPIConfigSet(t *testing.T) {
p, ok := newInstance("api: yes\n")
require.Equal(t, true, ok)
defer p.close()
err := httpRequest(http.MethodPost, "http://localhost:9997/config/set", map[string]interface{}{
"rtmpDisable": true,
}, nil)
require.NoError(t, err)
time.Sleep(500 * time.Millisecond)
var out map[string]interface{}
err = httpRequest(http.MethodGet, "http://localhost:9997/config/get", nil, &out)
require.NoError(t, err)
require.Equal(t, true, out["rtmpDisable"])
}
func TestAPIConfigPathsAdd(t *testing.T) {
p, ok := newInstance("api: yes\n")
require.Equal(t, true, ok)
defer p.close()
err := httpRequest(http.MethodPost, "http://localhost:9997/config/paths/add/mypath", map[string]interface{}{
"source": "rtsp://127.0.0.1:9999/mypath",
"sourceOnDemand": true,
}, nil)
require.NoError(t, err)
var out map[string]interface{}
err = httpRequest(http.MethodGet, "http://localhost:9997/config/get", nil, &out)
require.NoError(t, err)
require.Equal(t, "rtsp://127.0.0.1:9999/mypath", out["paths"].(map[string]interface{})["mypath"].(map[string]interface{})["source"])
}
func TestAPIConfigPathsEdit(t *testing.T) {
p, ok := newInstance("api: yes\n")
require.Equal(t, true, ok)
defer p.close()
err := httpRequest(http.MethodPost, "http://localhost:9997/config/paths/add/mypath", map[string]interface{}{
"source": "rtsp://127.0.0.1:9999/mypath",
"sourceOnDemand": true,
}, nil)
require.NoError(t, err)
err = httpRequest(http.MethodPost, "http://localhost:9997/config/paths/edit/mypath", map[string]interface{}{
"source": "rtsp://127.0.0.1:9998/mypath",
"sourceOnDemand": true,
}, nil)
require.NoError(t, err)
var out struct {
Paths map[string]struct {
Source string `json:"source"`
} `json:"paths"`
}
err = httpRequest(http.MethodGet, "http://localhost:9997/config/get", nil, &out)
require.NoError(t, err)
require.Equal(t, "rtsp://127.0.0.1:9998/mypath", out.Paths["mypath"].Source)
}
func TestAPIConfigPathsDelete(t *testing.T) {
p, ok := newInstance("api: yes\n")
require.Equal(t, true, ok)
defer p.close()
err := httpRequest(http.MethodPost, "http://localhost:9997/config/paths/add/mypath", map[string]interface{}{
"source": "rtsp://127.0.0.1:9999/mypath",
"sourceOnDemand": true,
}, nil)
require.NoError(t, err)
err = httpRequest(http.MethodPost, "http://localhost:9997/config/paths/delete/mypath", nil, nil)
require.NoError(t, err)
var out struct {
Paths map[string]interface{} `json:"paths"`
}
err = httpRequest(http.MethodGet, "http://localhost:9997/config/get", nil, &out)
require.NoError(t, err)
_, ok = out.Paths["mypath"]
require.Equal(t, false, ok)
}
func TestAPIPathsList(t *testing.T) {
p, ok := newInstance("api: yes\n" +
"paths:\n" +
" mypath:\n")
require.Equal(t, true, ok)
defer p.close()
var out struct {
Items map[string]interface{} `json:"items"`
}
err := httpRequest(http.MethodGet, "http://localhost:9997/paths/list", nil, &out)
require.NoError(t, err)
_, ok = out.Items["mypath"]
require.Equal(t, true, ok)
}
func TestAPIRTSPSessionsList(t *testing.T) {
p, ok := newInstance("api: yes\n")
require.Equal(t, true, ok)
defer p.close()
track, err := gortsplib.NewTrackH264(96, []byte("123456"), []byte("123456"))
require.NoError(t, err)
source, err := gortsplib.DialPublish("rtsp://localhost:8554/mypath",
gortsplib.Tracks{track})
require.NoError(t, err)
defer source.Close()
var out struct {
Items map[string]struct{} `json:"items"`
}
err = httpRequest(http.MethodGet, "http://localhost:9997/rtspsessions/list", nil, &out)
require.NoError(t, err)
require.Equal(t, 1, len(out.Items))
}
func TestAPIRTSPSessionsKick(t *testing.T) {
p, ok := newInstance("api: yes\n")
require.Equal(t, true, ok)
defer p.close()
track, err := gortsplib.NewTrackH264(96, []byte("123456"), []byte("123456"))
require.NoError(t, err)
source, err := gortsplib.DialPublish("rtsp://localhost:8554/mypath",
gortsplib.Tracks{track})
require.NoError(t, err)
defer source.Close()
var out1 struct {
Items map[string]struct{} `json:"items"`
}
err = httpRequest(http.MethodGet, "http://localhost:9997/rtspsessions/list", nil, &out1)
require.NoError(t, err)
var firstID string
for k := range out1.Items {
firstID = k
}
err = httpRequest(http.MethodPost, "http://localhost:9997/rtspsessions/kick/"+firstID, nil, nil)
require.NoError(t, err)
var out2 struct {
Items map[string]struct{} `json:"items"`
}
err = httpRequest(http.MethodGet, "http://localhost:9997/rtspsessions/list", nil, &out2)
require.NoError(t, err)
require.Equal(t, 0, len(out2.Items))
}
func TestAPIRTMPConnsList(t *testing.T) {
p, ok := newInstance("api: yes\n")
require.Equal(t, true, ok)
defer p.close()
cnt1, err := newContainer("ffmpeg", "source", []string{
"-re",
"-stream_loop", "-1",
"-i", "emptyvideo.mkv",
"-c", "copy",
"-f", "flv",
"rtmp://localhost:1935/test1/test2",
})
require.NoError(t, err)
defer cnt1.close()
var out struct {
Items map[string]struct{} `json:"items"`
}
err = httpRequest(http.MethodGet, "http://localhost:9997/rtmpconns/list", nil, &out)
require.NoError(t, err)
require.Equal(t, 1, len(out.Items))
}
func TestAPIRTSPConnsKick(t *testing.T) {
p, ok := newInstance("api: yes\n")
require.Equal(t, true, ok)
defer p.close()
cnt1, err := newContainer("ffmpeg", "source", []string{
"-re",
"-stream_loop", "-1",
"-i", "emptyvideo.mkv",
"-c", "copy",
"-f", "flv",
"rtmp://localhost:1935/test1/test2",
})
require.NoError(t, err)
defer cnt1.close()
var out1 struct {
Items map[string]struct{} `json:"items"`
}
err = httpRequest(http.MethodGet, "http://localhost:9997/rtmpconns/list", nil, &out1)
require.NoError(t, err)
var firstID string
for k := range out1.Items {
firstID = k
}
err = httpRequest(http.MethodPost, "http://localhost:9997/rtmpconns/kick/"+firstID, nil, nil)
require.NoError(t, err)
var out2 struct {
Items map[string]struct{} `json:"items"`
}
err = httpRequest(http.MethodGet, "http://localhost:9997/rtmpconns/list", nil, &out2)
require.NoError(t, err)
require.Equal(t, 0, len(out2.Items))
}

View File

@ -426,8 +426,7 @@ outer:
pa.onReaderPause(req)
case req := <-pa.apiPathsList:
req.Data.Items = append(req.Data.Items, apiPathsItem{
Name: pa.name,
req.Data.Items[pa.name] = apiPathsItem{
ConfName: pa.confName,
Conf: pa.conf,
Source: func() interface{} {
@ -444,7 +443,7 @@ outer:
}
return ret
}(),
})
}
req.Res <- apiPathsListRes2{}
case <-pa.ctx.Done():

View File

@ -159,10 +159,9 @@ outer:
case req := <-s.apiRTMPConnsList:
for c := range s.conns {
req.Data.Items = append(req.Data.Items, apiRTMPConnsListItem{
ID: c.ID(),
req.Data.Items[c.ID()] = apiRTMPConnsListItem{
RemoteAddr: c.RemoteAddr().String(),
})
}
}
req.Res <- apiRTMPConnsListRes{}

View File

@ -352,10 +352,9 @@ func (s *rtspServer) OnAPIRTSPSessionsList(req apiRTSPSessionsListReq) apiRTSPSe
s.mutex.RLock()
for _, s := range s.sessions {
req.Data.Items = append(req.Data.Items, apiRTSPSessionsItem{
ID: s.ID(),
req.Data.Items[s.ID()] = apiRTSPSessionsListItem{
RemoteAddr: s.RemoteAddr().String(),
})
}
}
s.mutex.RUnlock()