From c2b4e7f62cdcb1c44621d4b49a25577c961e35da Mon Sep 17 00:00:00 2001 From: aler9 <46489434+aler9@users.noreply.github.com> Date: Sun, 20 Sep 2020 11:20:24 +0200 Subject: [PATCH] add ConnClient tests --- .travis.yml | 3 + Makefile | 6 +- connclient_test.go | 161 +++++++++++++++++++++++ testimages/ffmpeg/Dockerfile | 11 ++ testimages/ffmpeg/emptyvideo.ts | Bin 0 -> 65048 bytes testimages/ffmpeg/start.sh | 3 + testimages/rtsp-simple-server/Dockerfile | 1 + 7 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 connclient_test.go create mode 100644 testimages/ffmpeg/Dockerfile create mode 100644 testimages/ffmpeg/emptyvideo.ts create mode 100644 testimages/ffmpeg/start.sh create mode 100644 testimages/rtsp-simple-server/Dockerfile diff --git a/.travis.yml b/.travis.yml index 3ec52d21..8c81bc16 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,9 @@ go: - "1.14.x" - "1.15.x" +services: +- docker + env: - GO111MODULE=on diff --git a/Makefile b/Makefile index c77213e3..276c4a17 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ format: define DOCKERFILE_TEST FROM $(BASE_IMAGE) -RUN apk add --no-cache make git gcc musl-dev +RUN apk add --no-cache make docker-cli git gcc musl-dev WORKDIR /s COPY go.mod go.sum ./ RUN go mod download @@ -40,10 +40,14 @@ export DOCKERFILE_TEST test: echo "$$DOCKERFILE_TEST" | docker build -q . -f - -t temp docker run --rm -it \ + -v /var/run/docker.sock:/var/run/docker.sock:ro \ + --network=host \ --name temp \ temp \ make test-nodocker test-nodocker: + $(foreach IMG,$(shell echo testimages/*/ | xargs -n1 basename), \ + docker build -q testimages/$(IMG) -t gortsplib-test-$(IMG)$(NL)) go test -race -v . $(foreach f,$(shell ls examples/*),go build -o /dev/null $(f)$(NL)) diff --git a/connclient_test.go b/connclient_test.go new file mode 100644 index 00000000..7ee18137 --- /dev/null +++ b/connclient_test.go @@ -0,0 +1,161 @@ +package gortsplib + +import ( + "net/url" + "os" + "os/exec" + "strconv" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +type container struct { + name string +} + +func newContainer(image string, name string, args []string) (*container, error) { + c := &container{ + name: name, + } + + exec.Command("docker", "kill", "gortsplib-test-"+name).Run() + exec.Command("docker", "wait", "gortsplib-test-"+name).Run() + + cmd := []string{"docker", "run", + "--network=host", + "--name=gortsplib-test-" + name, + "gortsplib-test-" + image} + cmd = append(cmd, args...) + ecmd := exec.Command(cmd[0], cmd[1:]...) + ecmd.Stdout = nil + ecmd.Stderr = os.Stderr + + err := ecmd.Start() + if err != nil { + return nil, err + } + + time.Sleep(1 * time.Second) + + return c, nil +} + +func (c *container) close() { + exec.Command("docker", "kill", "gortsplib-test-"+c.name).Run() + exec.Command("docker", "wait", "gortsplib-test-"+c.name).Run() + exec.Command("docker", "rm", "gortsplib-test-"+c.name).Run() +} + +func (c *container) wait() int { + exec.Command("docker", "wait", "gortsplib-test-"+c.name).Run() + out, _ := exec.Command("docker", "inspect", "gortsplib-test-"+c.name, + "--format={{.State.ExitCode}}").Output() + code, _ := strconv.ParseInt(string(out[:len(out)-1]), 10, 64) + return int(code) +} + +func TestConnClientTCP(t *testing.T) { + cnt1, err := newContainer("rtsp-simple-server", "server", []string{}) + require.NoError(t, err) + defer cnt1.close() + + time.Sleep(1 * time.Second) + + cnt2, err := newContainer("ffmpeg", "publish", []string{ + "-re", + "-stream_loop", "-1", + "-i", "/emptyvideo.ts", + "-c", "copy", + "-f", "rtsp", + "-rtsp_transport", "udp", + "rtsp://localhost:8554/teststream", + }) + require.NoError(t, err) + defer cnt2.close() + + time.Sleep(1 * time.Second) + + u, err := url.Parse("rtsp://localhost:8554/teststream") + require.NoError(t, err) + + conn, err := NewConnClient(ConnClientConf{Host: u.Host}) + require.NoError(t, err) + defer conn.Close() + + _, err = conn.Options(u) + require.NoError(t, err) + + tracks, _, err := conn.Describe(u) + require.NoError(t, err) + + for _, track := range tracks { + _, err := conn.SetupTCP(u, track) + require.NoError(t, err) + } + + _, err = conn.Play(u) + require.NoError(t, err) + + frame := &InterleavedFrame{Content: make([]byte, 0, 128*1024)} + frame.Content = frame.Content[:cap(frame.Content)] + + err = conn.ReadFrame(frame) + require.NoError(t, err) +} + +func TestConnClientUDP(t *testing.T) { + cnt1, err := newContainer("rtsp-simple-server", "server", []string{}) + require.NoError(t, err) + defer cnt1.close() + + time.Sleep(1 * time.Second) + + cnt2, err := newContainer("ffmpeg", "publish", []string{ + "-re", + "-stream_loop", "-1", + "-i", "/emptyvideo.ts", + "-c", "copy", + "-f", "rtsp", + "-rtsp_transport", "udp", + "rtsp://localhost:8554/teststream", + }) + require.NoError(t, err) + defer cnt2.close() + + time.Sleep(1 * time.Second) + + u, err := url.Parse("rtsp://localhost:8554/teststream") + require.NoError(t, err) + + conn, err := NewConnClient(ConnClientConf{Host: u.Host}) + require.NoError(t, err) + defer conn.Close() + + _, err = conn.Options(u) + require.NoError(t, err) + + tracks, _, err := conn.Describe(u) + require.NoError(t, err) + + var rtpReads []UDPReadFunc + var rtcpReads []UDPReadFunc + + for _, track := range tracks { + rtpRead, rtcpRead, _, err := conn.SetupUDP(u, track, 9000+track.Id*2, 9001+track.Id*2) + require.NoError(t, err) + + rtpReads = append(rtpReads, rtpRead) + rtcpReads = append(rtcpReads, rtcpRead) + } + + _, err = conn.Play(u) + require.NoError(t, err) + + go conn.LoopUDP(u) + + buf := make([]byte, 2048) + _, err = rtpReads[0](buf) + require.NoError(t, err) +} diff --git a/testimages/ffmpeg/Dockerfile b/testimages/ffmpeg/Dockerfile new file mode 100644 index 00000000..1f380e26 --- /dev/null +++ b/testimages/ffmpeg/Dockerfile @@ -0,0 +1,11 @@ +FROM amd64/alpine:3.12 + +RUN apk add --no-cache \ + ffmpeg + +COPY emptyvideo.ts / + +COPY start.sh / +RUN chmod +x /start.sh + +ENTRYPOINT [ "/start.sh" ] diff --git a/testimages/ffmpeg/emptyvideo.ts b/testimages/ffmpeg/emptyvideo.ts new file mode 100644 index 0000000000000000000000000000000000000000..6693c037aa8cc233dd7a4f44803bef78b8cc53a5 GIT binary patch literal 65048 zcmeI54OmrGy2sZN5D*X+AL0kd*$Rq@3WA?Wx>HkcINE60loPXoqmm#9$JEJ5PgyfH zI@JtQQ<8SlzO6||r@GP2GckHct;Vt@i|%-?G)|+LmDN}%_g#4QU9ZnMP2SeKd!p++ z4Z`67zxO@=wf5Tkw--#AAd=X{$8#9>GuF=A8E;#aIyIShz2uVWTKD|eS?;>)D$CvZ z1xr^<+}-}|`rniZEQztF5<1u!Kh7@L61nx;h4`g3Q)U8tm#30D*aPf1>m%Q!JwN@5 zFa45l%_pXqEI)cCW7o&uz!>8P8C$iZTLFvx&?i{*o0fbm_PBgIzk=m%J}_Zfmx1r@ zn8a8FiMI8Hhg4} zYly47rq1mu7%{?CH+)RNC|ABUx~O8zX!yj`q40!Z(`QbeGNj05UNI4#S>Y~+PfV<- zU0&s$=Wz|s&o3M@JikCbdx6JOJ9gNxrBgT)OP3D4uCl^iQ)Mk0T2nWFnEXjY7kH|x z;CVH*p30g<^iiJw9Z;I z-(6fV(pA2ouBO^5g)c2|dFtF%Rh9Md-sokcE6P3aPWj^M;(R~=_GGK#$2E)G#ls8o z3JP5Fta?vrZT-T^TKTLq-(+!ZY0bQO^=?n`kl`-Rf;zWV0pD!6tE#4Ep|t=$DzzUR z?y9eXp{*XscP*;x_(A2B)s{!XR4($k>#8hx5?d)b`V#?V7RUp?|dW+jHOK zVk7^yH$R`6`}~zh|2%w&3_bcUBKh9ee^Jr%jhDt{2OsADl<&A{0;xr`@o)te)hk5>bLG`z&>(5`(~!SvtA+X zE=5Mc969QWB*xYk-9TLdB<^5v%1z8R1dDZZ29KSYa?N|QtIQdv-&g}7`g%20PXPAO zKLB?BTyl1JF%f=3w*cUO=tKDHFJ5+I*4IUk=#mKRV@iR&b+r@hXR;WqU{#dC;%+b% zJYR2lCPIB*ukVqKz&`e>B*vpRJHn0|f45gK=sspIzgC0&K48CaCa_9i z&g8uq^3E4$)3e(%FUou3Q+|cd*FUI}cbS=sWZoM}9AU?;-^~Ss{$uusb@DF9>Uf#= zr#*!1h&cUL1BiEXMQq-?8S-AGpLaRG=gYjm)kw%5n)kGtfM76gQ3>mJPfpX$dx6aR zsb+fiFnLcoWGZ~V{ym+%%ghXiymxUOb%Y(IC#}sZ81x^rAJNTwA>_Twq*Ow7MBL{& z9}u^B6|s5mahkl#`Mn78-evwcLiW(S_jK?%nU zRKkY4H1pma=194IkJz}0o;^(7jUW3JKHsoiC-3(9J!0oxN7zw%`ZsXFp#PZtX`Q@F zcDa6!c<%%uJ0c!5%K+jAu87TbO*DD8*YA-D8HDVic^^0?AQ+5WRKkY0H1jU6&&c(A zWd0<2_Aq(RdBRlqe8WkdyxZ&d$XQj6u%q-0-02kz`j6Sa(9L_{WzhHQ8YtNj@}R%^ z0ePoaA)D(?1p~jb{q&=EeckI~39;b$L?`xqq7!?*BJg~X_cWd5`36^6g2DWzUg>l7 zeD0s!$f902{n=~d_ijCUZ}#>>k9_vP`T?aAm*ntucQwC1cGcM#x%{oqlHP5u4V=Dd zNAMF__cIo?06yS5<(qi<@D};zcKFiU;Q#l@54OS^={}SO-gZW*0kI1H0%6X<^W=E6Fu=Q|gf*FUwW8~f=@?bnU zI~0KMhurKF42BWHC-NRq5k*e0pE2+y|2_U@KxW?;+Qb(tAWzZ6;(7F2Ya=1MeZ)0f;S+g}uHzdWVMpm1wbT?0 z`j6SQyob!Y^d4QynhDtvaq&n?Fu+#CWZpy0@6vm8z4<61duZM-%rpdpaf?dO_8v0t z(tC7$G?kt`Oy0-b;Z^uV-lOZ@agMN~^j!F;UohxDX4mo_GVjuRbp4=$kR1`53j#p= zs9zD2c@H_ikA}QQC$Ax756%1d89u>a+@cb+y@$-Z^d8Y8w$ZbP$$RmOT;UUWkLW8~ z9AQW48Q)?G2K~qETHZtEU3!n`6_JGOhS`dqn?XHa&ZoyqlkR6+V&oh<?GbJ=GT)b*%9)kS9t}SW||6_%6r6s_ek!<-Xpn_dyklBs?PErmmW6Ym3}Fp zUg>l99;;b8Y!KQ1^xmzX@*Zwdes4KE|fWLS~+Kltw!=CNz zf4|H{e3OsIEtls_;5}mAZlIiJI%-6d&1Jpd&;&D%iXg#$kB;*u*zXZ@x`~_}3PAWX zm<9NU4TP`hJ?!(QSfkYm_A?m^Rv@nfPp|hYcp~o+J2~DFcHH>2TrlW9W+(9;u?va_ z*%9&OB{12}Sj!bLx%Y_u`CLNw;Brm{0-5)SeR4HDd$0t1#LB#1_K>OY zHNA&C_mKNNV)t!!gdMm31+QSxf6PweJz`JnCuB#&Ke)jM#4mUiF}e5Xmfl9l9-8+# zZc8v2x2Obd?_u9B*6qSEm-{{9 z0+ICWVe(#HYbtzA?;$fI*YEL>d5*B7^tf;J3I_eh>?GbJe&B3Ec0{~zs!uS$R>b7q zBmUo35VD8ny>gf(7>rv~g0}at?^}wm-bBwHChzkf@GE>x?_sasBQb6rIUM)_`hVFK?3g~@1K#s=PDtyikuw^K=?J+ z8-l?wLin2A!#;0Hn9$$^`_voIonvfk4FF$Ds2H1+2%zMcBUGDejK5{c5 zduZO59yFkYodHw=nfK`agZ=dEVe-ComRI2ud5`WZ+8klW>8bJy2K~qETHZq*o22*X zet$M0J0e~=I3U>aD!(Eo^B(d(4!Pf>`->%n?4f!8NwN=0IBB60w7rMD-=q8AJoM~g z@_zj-T;UUWkHpwUN7zw%ezL(74Em4RwY-PSyYwE3dCi3Ei1?;!EFj)sDq=G4(XoDq zyeG~$O2{6Xckg6FFc`O}1a0qO-?x-lpGwajChses@hW^G?~!=dI7iq~dc6DmfmEHhT6jdB5ohSNKHUBdK4DBkVXmk)~kKf6T7sJ!IbH@3~64B$ALF5&!%}OR%3t znu?grd)Vvuq{=)(_RzfF`j`PF+z~(}ka>@!HM8m2!{q(eOs~Qx@*YXQUEv5jPR~fc zV965)@d5^U% zK6s^HwA3qo?%w14evhw`9r5#MdXWDD4en9O_F=S|{2n+Vy1i!fBeuX8QIV8o&lw7rLY-XxB+ z(z6Fkut%)S`>)pd6+V&oNKTA*gdMkjI~NT4kJ(AQNAmC@LUu&F&SL=acCLuYy+`up za|zi)^M21&0l{G0q7ulwNAj}O^z32se)r3!!q@a3a(?~xp6BV-TF`+aLI!C>5?612UCz274xDx01?Oy2Kf zeub~;J>;4|?)ON^Epdb$r>8d;4Em4RwY-NMtI~Uw7rMD-y^ke1wDJ1 zyg%snD|}7wA?J6w-y_vr;|M!S&%-OZV9Xo49>MUcRI*uUp0?W(=x>`(y0-%{%n z42BWHC-NR?KRMw9`WJknL zH^F4P<&>$2$-IZWe@5OfmUg&`kUh8vLnUnAXb1))7L}mwJ?!(Q9^D$~*@Gq6BUa{p zdk?R|*YqCtc~g%eO^&dm);~SWFBtS6vuk+|`@E^g%vM5nMEu;bfM9^Fh{?T24^KQH zduZODeccBoG+C$wGVjsj?jm~jFnND=8dvy4-lNCA&vk?yr>D#m4Em4RNxVmocUBX! zBVxZ{3HDr>sffwEhn(N#evfpvnUFm+?=Qp{P{OeQDuK*ikQrMbgbWH-q)58vWMpV z#j!rYVBDe-w7rMD-y{7g4?TOBy!)Tz3ZKY(q`%ha2s=v8i@Qw0p#PX%%X`SYOYf2X zX)_@^BL34Y77*_;6)~Cju-ETBdmSZY56%0oYC|v>x2Obd?_uA!)U!C1o;^(7|9H@= z@QJ)f&mWC*gdL@4*Ga!%(0|OXufn{uyvHlA8t_U#6Hu@8 zxqFZE`#t`Dc#mFJ%%+@YI%ak>*}NVJhbEYDR0K)9#{?nR#m93P_cPYc+Zk_Ll{z(< zcfI72>RR{w*jetn>nh9L`2|Z?Ox$fBY`!J`!u&3OM^~@qE6Do}6{6PfJ7PiWUo}wc zHJy!p&eyAPlN0P`UZ7wF@*4KOYvAQ&JodPJtLbdyaaHbB>Gi^1N7zy0Ut7ingYIK? z5@*xvzfTadBjN+2;6MS`ikRHl^zNEL$Q~TasD!^{1_XoI29-eOYmTz92K~qETF%Bk=j&b5K*)}W->LKg@nc>^Oy+Ft zbH3icY$9Y2&HLLkEx};iq7t;7jeXA7dwVNAdzic*c+s!$iJVRE1M!Zqqx8J}4i^mi zkJ(9_P4BiMLUu$PXf%NM9j=JUolT#txrFSYdH?H;0l{G0q7ulQO`nTb)3b-k`#YbS z3SZON$oXCFRq5m2>I!VSURy_hRva%YnF8@CLlk|6*8r>N$%bo#@G5vB?~(amD;#0RjsM6m7<3=AYk3d*ys0nW zM97YaPi}$9_T!KIikQrM$m_szuS(zSy@c$+MHnjKv)}jxgAt2LAoCu5r<|Z?50+q$ zSef_F;<>^n@*aH`W;nu*T7NRf6b$;0*-5-d-(O53WJkoOS}nl`Zfd)@kO zsUl<#&HER73@Bks0F|KaJ?!(QzWW>K*~8@hi;KJpU(!Nr<_RzeypYlNotrjYQ%zI>6MfB`p z^4`9fD|{mFk+piRBkU+W{5DfC=s#vB@g7+ZuO?(i#L?3%!2w$llX;Jh^*hY(S-UqA zvWMiIN97wrj$2d$nfJ(ge?L8YXx@3mMz6vr@*b|FHb>Y|dZL>ALiQiCYk3cOY?9u? zRg_K0j)>!~4*+qKUlEge4}1OYno~l^9-8;qGN0fuZcz!^-oxIj;`*_No;^(7qu<~P zpU8W-?rU^}9i=Ds15l99_RO}e7C)a z{X4phUu~nDXF6tfG})wm4u>X~aa05ey@&Dp7IJnd0O6+`3;_NvAHvu49`^lW##@n2 zu%9`y1}lK;z&vHPso*uehrG5V_j?$p@*H7DjZdrg3J%@J>?Gc!pKCTDJ0k9r2a_#e zD`Il*(Qo1kLiXSy43*F;#exz(H&6-M-orj`>Njr_J$tYOd&J7Tr{CgN_?q5BuEpej zkAAoAb%Y(a{(dev^dGa6c#nRYPY|*r;;d2wi0|i$nB05x`*Q{%duZM>CkF(Faf?bI z^B(;^ofR!TU#XMNIBJ`oA}qkUcc-IgbUP zggbqx1TycD9lx5MJxtzn`kD$~(|g$K_v~St9bw1m8RZom`j6R3yhrx;_Y<-s;=!N# z1RprctBA?HNA{97LiW(S4|>Of5}FNEg0}at_j_dDlTFVaChvo0`W3#W_psOR*-a&m zu;cVx%LRx2V|Fd?A;+rp9@&5O5V9lUfDj~NeaKCw!q@a3_WC_%>QP77QF?|odIg96V|Fd?A=#z($f-)DWJkya z+x>vt=vBy+-lJD1_8z@Dx%bGqecV~zqwr!&aG2lJD}C*^KhQp$TRj6+r^;A+Hn2{T?~5uOVlL0ucU)t9^pQFhcm6-a}p|ko)9w{<+Nw z_A^J;Uv zM^-q(j#__VZ@=Ksf6T7sJvz>tU>!MN&n8NCggpL0Kyctz$Vz++Y(KsIf>q~m1dRyu z9R4`uUGDc7aBMFn`&o12j&23Kc!v)vc-TS}ka>@R;siZ=n7kJkafMIhJqC`*aD*L) zXSyk5|1rD1_kg?)ymAsHJ3^iuZwWqrx~Y(r_|VV0^d1ARucBlR$-DWn0TmnwpbE6T zhrCW8y~n`y4fO0`@@~%aDtt}vA=d=*_goG1H#x$N!ZUHDUvTI@X4mo_a(*8r^WNG@ z$&QexT@(-;xD~PzANqM84SCOviKk=_$@`QXpWrZTQ3Yh)BX@8SJ$snEPripMd?N3W z`@Ol2u%qxy*=h<7{m1P3-UITUyLdGvJ3^km*aGCOrb1TYBS(8ZBiHY_4Vx+1L-Ky< zm4@IjY*7Vd-Xr(v{q*c%@;+^kSK$+RkKDJ~9AQV{xwO?UIP@R0Yk3cOY?9t1_jEQP zJ0iYpV*rR-{fbz552O9`W0!|nnX_=q^^gZ6<^a1~zYj7>2-$;SK_$$%%_levTU3I! z_ptYS44UMjXAhJ2>8H8EC-NSH<~KURj#__Nx+ysHAG2$D51DuAJqF#@Ov#RrXXSeZ M2X2K-