def test_consume_from_balancer_should_transcode_to_audio(tmpdir): server = Server(M3U8_HOST, M3U8_PORT) playlist = 'real' uri = '/real_content.m3u8' playlists = {'streams': {playlist: {'input-path': uri, 'servers': [server]}}, 'actions': [{'type': 'transcode', 'input': playlist, 'output': {'audio': { "transcode": { "path": "transcode.m3u8", "audio-bitrate": "64000", "bandwidth": "65000" } }}}]} b = Balancer() b.update(get_servers(playlists)) hlsclient.consumer.consume_from_balancer(b, playlists, str(tmpdir)) expected_created = ['real_content.m3u8', 'sample.ts', 'transcode.m3u8', 'sample.aac'] resources_created = os.listdir(str(tmpdir)) assert sorted(expected_created) == sorted(resources_created) original_m3u8 = tmpdir.join('real_content.m3u8').read() expected_audio_m3u8 = original_m3u8.replace('.ts', '.aac') assert expected_audio_m3u8 == tmpdir.join('transcode.m3u8').read()
def test_paths_can_be_removed(): PATH = '/path' SERVERS = ['http://server1', 'http://server2', 'http://server3'] paths = {PATH: SERVERS} b = Balancer() b.update(paths) b.update({}) assert [] == list(b.actives)
def test_balancer_returns_active_server_if_its_the_only_one(): PATH = '/path' SERVER = FMS('http://server', port=80) paths = {PATH: [SERVER]} b = Balancer() b.update(paths) active_playlists = list(b.actives) assert 1 == len(active_playlists) assert PATH == active_playlists[0].key assert SERVER == active_playlists[0].server
def test_balancer_supports_multiple_paths(): PATH1 = '/path1' PATH2 = '/path2' SERVER = 'http://server' paths = {PATH1: [SERVER], PATH2: [SERVER]} b = Balancer() b.update(paths) paths = sorted(s.key for s in b.actives) assert 2 == len(paths) assert PATH1 == paths[0] assert PATH2 == paths[1]
def setup(self): helpers.setup_logging(self.config, "worker for {}".format(self.playlist)) logging.debug('HLS CLIENT Started for {}'.format(self.playlist)) self.destination = self.config.get('hlsclient', 'destination') self.encrypt = self.config.getboolean('hlsclient', 'encrypt') not_modified_tolerance = self.config.getint('hlsclient', 'not_modified_tolerance') self.balancer = Balancer(not_modified_tolerance) ttl = datetime.timedelta(seconds=random.randint(1, MAX_TTL_IN_SECONDS)) self.death_time = datetime.datetime.now() + ttl
def test_active_server_does_not_change_if_paths_updated(): PATH = '/path' SERVERS = ['http://server1', 'http://server2', 'http://server3'] paths = {PATH: SERVERS} b = Balancer() b.update(paths) # Notify that active server has failed b.notify_error() assert [SERVERS[1]] == [s.server for s in b.actives] b.update(paths) assert [SERVERS[1]] == [s.server for s in b.actives]
def test_consume_from_balancer_should_timeout(tmpdir, monkeypatch): server = Server(M3U8_HOST, M3U8_PORT) playlist = 'slow' uri = '/slow.m3u8' playlists = {'streams': {playlist: {'input-path': uri, 'servers': [server]}}} errors = [] b = Balancer() b.update(get_servers(playlists)) b.notify_error = lambda: errors.append("ERROR") monkeypatch.setattr(logging, 'warning', lambda warn: 0) # just to hide hlsclient warning hlsclient.consumer.consume_from_balancer(b, playlists, str(tmpdir)) assert errors == ["ERROR"]
def test_consume_from_balancer_should_not_report_content_modified_if_there_are_no_changes(tmpdir): server = Server(M3U8_HOST, M3U8_PORT) playlist = 'low' uri = '/low.m3u8' playlists = {'streams': {playlist: {'input-path': uri, 'servers': [server]}}} b = Balancer() b.update(get_servers(playlists)) hlsclient.consumer.consume_from_balancer(b, playlists, str(tmpdir)) modified = [] b.notify_modified = lambda: modified.append("MODIFIED") hlsclient.consumer.consume_from_balancer(b, playlists, str(tmpdir)) assert modified == []
def test_notify_error_should_rotate_servers_while_there_are_available_servers( ): PATH1 = '/path1' PATH2 = '/path2' SERVER1 = 'http://server1' SERVER2 = 'http://server2' SERVERS = [SERVER1, SERVER2] paths = {PATH1: SERVERS, PATH2: SERVERS} b = Balancer() b.update(paths) b.notify_error() b.notify_error() assert list(b.actives) == [ PlaylistResource(SERVER1, PATH1), PlaylistResource(SERVER1, PATH2) ]
def test_consume_from_balancer_should_report_content_modified(tmpdir): server = Server(M3U8_HOST, M3U8_PORT) playlist = 'low' uri = '/low.m3u8' playlists = {'streams': {playlist: {'input-path': uri, 'servers': [server]}}} modified = [] b = Balancer() b.update(get_servers(playlists)) b.notify_modified = lambda: modified.append("MODIFIED") hlsclient.consumer.consume_from_balancer(b, playlists, str(tmpdir)) assert modified == ["MODIFIED"] expected_created = ['low.m3u8', 'low1.ts', 'low2.ts'] resources_created = os.listdir(str(tmpdir)) assert sorted(expected_created) == sorted(resources_created) for filename in resources_created: assert stat.S_IMODE(os.stat(str(tmpdir.join(filename))).st_mode) == 0644
def test_active_server_changes_if_error_detected(): PATH = '/path' SERVERS = ['http://server1', 'http://server2', 'http://server3'] paths = {PATH: SERVERS} b = Balancer() b.update(paths) # Notify that the active server has failed assert [SERVERS[0]] == [s.server for s in b.actives] b.notify_error() # Assert that the backups assume assert [SERVERS[1]] == [s.server for s in b.actives] b.notify_error() assert [SERVERS[2]] == [s.server for s in b.actives] # Assert that the first server resumes if backup fails b.notify_error() assert [SERVERS[0]] == [s.server for s in b.actives]
def test_if_server_fails_for_any_stream_all_streams_should_switch_server(): PATH1 = '/path1' PATH2 = '/path2' SERVER1 = 'http://server1' SERVER2 = 'http://server2' SERVERS = [SERVER1, SERVER2] paths = {PATH1: SERVERS, PATH2: SERVERS} b = Balancer() b.update(paths) assert list(b.actives) == [ PlaylistResource(SERVER1, PATH1), PlaylistResource(SERVER1, PATH2) ] b.notify_error() assert list(b.actives) == [ PlaylistResource(SERVER2, PATH1), PlaylistResource(SERVER2, PATH2) ]
def test_active_server_changes_if_playlist_not_modified_for_a_while( monkeypatch): PATH = '/path' SERVERS = ['http://server1', 'http://server2'] paths = {PATH: SERVERS} b = Balancer() b.update(paths) now = datetime.datetime.now() assert [SERVERS[0]] == [s.server for s in b.actives] b.notify_modified() # 20 seconds later and playlist has not changed monkeypatch.setattr(b, '_now', lambda: now + datetime.timedelta(seconds=20)) assert [SERVERS[1]] == [s.server for s in b.actives] # more 20 seconds later but backup is being updated monkeypatch.setattr(b, '_now', lambda: now + datetime.timedelta(seconds=40)) b.notify_modified() assert [SERVERS[1]] == [s.server for s in b.actives]