# frozen_string_literal: true require "rails_helper" RSpec.describe Streams::NodeProvisioner do def with_env(vars) previous = vars.keys.index_with { |k| ENV[k] } vars.each { |k, v| ENV[k] = v } yield ensure previous.each { |k, v| v.nil? ? ENV.delete(k) : ENV[k] = v } end let(:redis) { Redis.new(url: ENV.fetch("REDIS_URL", "redis://redis:6379/0")) } before do redis.del(Streams::DnsProviders::Lab::REDIS_KEY) StreamSession.where.not(stream_node_id: nil).update_all(stream_node_id: nil, status: "ended", ended_at: Time.current) StreamNode.where.not(slug: Streams::NodeRegistry::HOME_SLUG).delete_all end it "provisions and decommissions a simulated lab node" do with_env( "STREAM_CLOUD_PROVIDER" => "local_lab", "STREAM_DNS_PROVIDER" => "lab", "STREAM_LAB_DNS_SUFFIX" => "lab.mltv-stream.net", "MEDIAMTX_API_URL" => "http://mtx-home:9997", "MEDIAMTX_RTMP_URL" => "rtmp://ingest-home.example:1935", "HLS_PUBLIC_URL" => "https://ingest-home.example/hls", "STREAM_LAB_MAX_PUBLISHERS" => "2" ) do provisioner = described_class.new node = provisioner.provision_lab! expect(node.slug).to eq("ingest-lab-01") expect(node.role).to eq("lab") expect(node.status).to eq("ready") expect(node.hostname).to eq("ingest-lab-01.lab.mltv-stream.net") expect(node.api_base_url).to eq("http://mtx-home:9997") expect(Streams::DnsProviders::Lab.new.resolve(node.hostname)).to eq("127.0.0.1") provisioner.decommission!(node) expect(StreamNode.find_by(slug: "ingest-lab-01")).to be_nil expect(Streams::DnsProviders::Lab.new.resolve("ingest-lab-01.lab.mltv-stream.net")).to be_nil end end it "refuses to decommission a busy node" do with_env( "STREAM_CLOUD_PROVIDER" => "local_lab", "STREAM_DNS_PROVIDER" => "lab", "MEDIAMTX_API_URL" => "http://mtx-home:9997", "MEDIAMTX_RTMP_URL" => "rtmp://ingest-home.example:1935", "HLS_PUBLIC_URL" => "https://ingest-home.example/hls" ) do node = described_class.new.provision_lab! user = User.create!(email: "lab@example.com", name: "L", password: "Password123", role: "coach") club = Club.create!(name: "LabClub", sport: "volleyball") team = club.teams.create!(name: "T", sport: "volleyball", slug: "lab-t") match = team.matches.create!(opponent_name: "X", scheduled_at: 1.hour.from_now) StreamSession.create!(match: match, user: user, platform: "matchlivetv", status: "live", stream_node: node) expect { described_class.new.decommission!(node) }.to raise_error(Streams::NodeProvisioner::BusyError) end end end