def test_IOLoop_with_reader_become_writer_when_writer_failed(
        cache_dir, requests_mock, patch_FileCacheIOLoop, install_sigchld,
        deleter):
    IOLoop.set_lockpath(os.path.join(cache_dir, 'huskar.writer'))
    wr, ww = os.pipe()
    rr, rw = os.pipe()

    num = 20
    for _ in range(num):
        pid = os.fork()
        if pid == 0:
            os.close(wr)
            os.close(rr)

            requests_mock.set_result_file('test_data_changed.txt')
            IOLoop('test', 'test', cache_dir=cache_dir).install()
            if isinstance(IOLoop.current(), HuskarApiIOLoop):
                os.write(ww, ('{}'.format(os.getpid())).encode('utf-8'))
            elif isinstance(IOLoop.current(), FileCacheIOLoop):
                IOLoop.current().retry_acquire_gap = 0.3
                os.write(rw, b'1')
            IOLoop.current().run()

            gevent.sleep(2)

            if isinstance(IOLoop.current(), HuskarApiIOLoop):
                os.write(ww, ('{}'.format(os.getpid())).encode('utf-8'))
            elif isinstance(IOLoop.current(), FileCacheIOLoop):
                os.write(rw, b'1')

            os.close(ww)
            os.close(rw)
            time.sleep(2)
            os._exit(os.EX_OK)

    time.sleep(1)
    os.close(ww)
    os.close(rw)

    try:
        writerpid, readers = os.read(wr, 10), os.read(rr, 20)
        assert len(readers) == (num - 1)

        os.kill(int(writerpid), signal.SIGKILL)

        time.sleep(2)
        writerpid, readers = os.read(wr, 10), os.read(rr, 20)
        os.kill(int(writerpid), 0)
        assert len(readers) == (num - 2)
    finally:
        os.close(wr)
        os.close(rr)
        time.sleep(2)  # wait process die
def test_init_http_huskar(requests_mock, file_cache_client,
                          fake_config_with_file_cache_client,
                          wait_huskar_api_ioloop_connected, cache_dir):
    huskar = HttpHuskar('arch.test',
                        'alpha-stable',
                        url='test_url',
                        token='test_token',
                        cache_dir=cache_dir)
    assert huskar.config
    assert huskar.switch
    assert huskar.service_consumer

    huskar.start()
    wait_huskar_api_ioloop_connected(1)

    cache_config = fake_config_with_file_cache_client('arch.test',
                                                      'alpha-stable')
    file_cache_client.cache_dir = IOLoop.current().cache_dir
    file_cache_client.components_paths = {
        name: os.path.join(file_cache_client.cache_dir, name + '_cache.json')
        for name in file_cache_client.components.keys()
    }

    file_cache_client.run()

    assert huskar.config.get('test_config') == 'test_value'

    assert cache_config.get('test_config') == 'test_value'
    huskar.stop()
def test_register_huskar_event_handler(requests_mock,
                                       wait_huskar_api_ioloop_connected,
                                       cache_dir):
    huskar = HttpHuskar('arch.test',
                        'alpha-stable',
                        url='test_url',
                        token='test_token',
                        cache_dir=cache_dir)

    handler = Mock()
    huskar.register_ioloop_hook('polling_error', handler)

    assert handler in IOLoop.current().event_listeners['polling_error']
def test_IOLoop_with_one_writer_and_multiple_reader_processes(
        deleter, cache_dir):
    IOLoop.set_lockpath(os.path.join(cache_dir, 'huskar.writer'))
    wr, ww = os.pipe()
    rr, rw = os.pipe()

    num = 20
    for _ in range(num):
        pid = os.fork()
        if pid == 0:
            os.close(wr)
            os.close(rr)

            ioloop = IOLoop('test', 'test', cache_dir)
            if isinstance(ioloop, HuskarApiIOLoop):
                os.write(ww, b'1')
            elif isinstance(ioloop, FileCacheIOLoop):
                os.write(rw, b'1')

            os.close(ww)
            os.close(rw)

            time.sleep(3)  # do not release lock
            os._exit(os.EX_OK)

    os.close(ww)
    os.close(rw)

    time.sleep(1)
    writers, readers = os.read(wr, 20), os.read(rr, 20)

    os.close(wr)
    os.close(rr)

    try:
        assert len(writers) == 1
        assert len(readers) == (num - 1)
    finally:
        [os.wait() for _ in range(num)]
def test_IOLoop_replacement(cache_dir):
    def func():
        pass

    ioloop = FileCacheIOLoop('test_url', 'test_token', cache_dir=cache_dir)
    ioloop.install()

    ioloop.watched_configs.set_default_fail_strategy_to_raise()

    ioloop.watched_configs.add_watch('foo', 'bar')
    ioloop.watched_configs.add_listener_for_app_id_at_cluster(
        'app_foo', 'cluster_foo', func)
    ioloop.watched_services.add_watch('bar', 'baz')
    ioloop.watched_services.add_listener_for_app_id_at_cluster(
        'app_bar', 'cluster_bar', func)
    ioloop.watched_switches.add_watch('baz', 'foo')
    ioloop.watched_switches.add_listener_for_app_id_at_cluster(
        'app_baz', 'cluster_baz', func)

    assert isinstance(IOLoop.current(), FileCacheIOLoop)

    HuskarApiIOLoop(ioloop.url, ioloop.token, ioloop.cache_dir).install()
    ioloop = IOLoop.current()

    assert isinstance(ioloop, HuskarApiIOLoop)
    configs = ioloop.watched_configs
    services = ioloop.watched_services
    switches = ioloop.watched_switches
    assert 'foo' in configs.app_id_cluster_map
    assert 'bar' in services.app_id_cluster_map
    assert 'baz' in switches.app_id_cluster_map
    assert ('app_foo', 'cluster_foo') in configs.event_listeners
    assert ('app_bar', 'cluster_bar') in services.event_listeners
    assert ('app_baz', 'cluster_baz') in switches.event_listeners
    assert configs.default_fail_strategy == configs.FAIL_STRATEGY_RAISE
    IOLoop.clear_instance()
    def new_process():
        r, w = os.pipe()
        r, w = os.fdopen(r, 'r'), os.fdopen(w, 'w')
        set_non_blocking(r)
        set_non_blocking(w)
        pid = os.fork()
        if pid < 0:
            return
        elif pid == 0:  # child
            r.close()

            requests_mock.set_result_file('test_data_changed.txt')
            IOLoop('test', 'test', cache_dir=cache_dir).install()
            if isinstance(IOLoop.current(), FileCacheIOLoop):
                IOLoop.current().retry_acquire_gap = 0.5

            stoped = Event()

            # simulate framework behavior
            def _exit(signum, frame):
                stoped.set()
                IOLoop.current().stop()
                IOLoop.clear_instance()
                os._exit(os.EX_OK)

            signal.signal(signal.SIGTERM, _exit)

            IOLoop.current().run()

            while not stoped.is_set():
                if isinstance(IOLoop.current(), HuskarApiIOLoop):
                    w.write('{}\n'.format(os.getpid()))
                else:
                    w.write('0\n')
                w.flush()
                gevent.sleep(0.5)

            w.close()
            os._exit(os.EX_OK)
        else:
            w.close()
            processes[pid] = r
Ejemplo n.º 7
0
 def _(timeout):
     ioloop = IOLoop.current()
     assert isinstance(ioloop, HuskarApiIOLoop)
     assert ioloop.connected.wait(timeout)
def deleter(request):
    IOLoop.clear_configure()
    request.addfinalizer(IOLoop.clear_instance)
 def _exit(signum, frame):
     stoped.set()
     IOLoop.current().stop()
     IOLoop.clear_instance()
     os._exit(os.EX_OK)
def test_IOLoop_with_only_one_writer_exists_no_matter_what_happens(
        cache_dir, requests_mock, patch_FileCacheIOLoop, install_sigchld,
        deleter):
    IOLoop.set_lockpath(os.path.join(cache_dir, 'huskar.writer'))
    processes = {}

    def new_process():
        r, w = os.pipe()
        r, w = os.fdopen(r, 'r'), os.fdopen(w, 'w')
        set_non_blocking(r)
        set_non_blocking(w)
        pid = os.fork()
        if pid < 0:
            return
        elif pid == 0:  # child
            r.close()

            requests_mock.set_result_file('test_data_changed.txt')
            IOLoop('test', 'test', cache_dir=cache_dir).install()
            if isinstance(IOLoop.current(), FileCacheIOLoop):
                IOLoop.current().retry_acquire_gap = 0.5

            stoped = Event()

            # simulate framework behavior
            def _exit(signum, frame):
                stoped.set()
                IOLoop.current().stop()
                IOLoop.clear_instance()
                os._exit(os.EX_OK)

            signal.signal(signal.SIGTERM, _exit)

            IOLoop.current().run()

            while not stoped.is_set():
                if isinstance(IOLoop.current(), HuskarApiIOLoop):
                    w.write('{}\n'.format(os.getpid()))
                else:
                    w.write('0\n')
                w.flush()
                gevent.sleep(0.5)

            w.close()
            os._exit(os.EX_OK)
        else:
            w.close()
            processes[pid] = r

    def kill_process(pid):
        os.kill(pid, signal.SIGTERM)
        processes[pid].close()
        del processes[pid]

    def ensure_one():
        writers = set()
        for _ in range(10):
            for pid, r in processes.items():
                try:
                    data = r.readline()
                except IOError as e:
                    if e.errno == errno.EWOULDBLOCK:
                        continue
                if not data:
                    continue
                if int(data.strip()) == pid:
                    try:
                        os.kill(pid, 0)
                        writers.add(pid)
                    except OSError:
                        if pid in writers:
                            writers.remove(pid)
            time.sleep(0.5)

        assert len(writers) == 1
        return list(writers)[0]

    num = 20
    for _ in range(num):
        new_process()

    writer = ensure_one()

    for _ in range(12):
        if random.random() <= 0.5:
            kill_process(writer)
            num -= 1
        else:
            nkill = random.randint(2, 6)
            for _ in range(nkill):
                kill_process(random.choice(list(processes.keys())))  # Py3
            num -= nkill

        writer = ensure_one()

        if num < 10:
            nlaunch = random.randint(11 - num, 10)
            for _ in range(nlaunch):
                new_process()
            num += nlaunch
        elif num < 20 and random.random() >= 0.5:
            new_process()
            num += 1

        same_writer = ensure_one()
        assert writer == same_writer

    for pid in list(processes.keys()):  # Py3
        kill_process(pid)
        if len(processes) > 0:
            ensure_one()