# frozen_string_literal: true require "rails_helper" RSpec.describe "HLS proxy", type: :request do let(:mediamtx_hls) { "http://mediamtx.test:8888" } let(:session_id) { "cc7e90b2-c672-4401-b5d3-51fdcdc7a214" } let(:playlist) do <<~M3U8 #EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:1 #EXTINF:1.0, /live/match_#{session_id}/segment0.ts M3U8 end def stub_hls_get(url, status:, body: "", headers: {}, location: nil) response_headers = headers.dup response_headers["location"] = location if location faraday_response = instance_double( Faraday::Response, status: status, body: body, headers: response_headers ) conn = instance_double(Faraday::Connection) allow_any_instance_of(HlsProxyController).to receive(:hls_conn).and_return(conn) allow(conn).to receive(:get) do |requested, &block| expect(requested).to start_with(url.split("?").first) block&.call(instance_double(Faraday::Request, headers: {})) faraday_response end end before do allow(MatchLiveTv).to receive(:mediamtx_hls_url).and_return(mediamtx_hls) end describe "GET /live/match_:session_id/*" do it "rewrites playlist paths to /hls/" do stub_hls_get( "#{mediamtx_hls}/live/match_#{session_id}/index.m3u8", status: 200, body: playlist, headers: { "content-type" => "application/vnd.apple.mpegurl" } ) get "/live/match_#{session_id}/index.m3u8" expect(response).to have_http_status(:ok) expect(response.body).to include("/hls/live/match_#{session_id}/segment0.ts") end end describe "GET /hls/live/match_:id on a lab node" do let!(:lab) do StreamNode.create!( slug: "ingest-lab-hls-spec", hostname: "ingest-lab-hls-spec.lab.mltv-stream.net", role: "lab", status: "ready", provider: "local", rtmp_base_url: "rtmp://127.0.0.1:11935", hls_base_url: "http://localhost:3000/hls", api_base_url: "http://mediamtx_lab:9997", internal_rtmp_url: "rtmp://mediamtx_lab:1935", internal_hls_url: "http://mediamtx_lab:8888" ) end before do user = User.create!(email: "hls-lab@test.com", name: "H", password: "Password123", role: "coach") club = Club.create!(name: "HlsLab", sport: "volleyball") team = club.teams.create!(name: "T", sport: "volleyball", slug: "hls-lab-t") match = team.matches.create!(opponent_name: "X") StreamSession.create!(id: session_id, match: match, user: user, platform: "matchlivetv", stream_node: lab) end it "proxies HLS to the session MediaMTX, not home" do requested = [] faraday_response = instance_double( Faraday::Response, status: 200, body: playlist, headers: { "content-type" => "application/vnd.apple.mpegurl" } ) conn = instance_double(Faraday::Connection) allow_any_instance_of(HlsProxyController).to receive(:hls_conn).and_return(conn) allow(conn).to receive(:get) do |url, &block| requested << url block&.call(instance_double(Faraday::Request, headers: {})) faraday_response end get "/hls/live/match_#{session_id}/index.m3u8" expect(response).to have_http_status(:ok) expect(requested.first).to eq("http://mediamtx_lab:8888/live/match_#{session_id}/index.m3u8") end end end