def setUp(self):
     try:
         os.unlink(UDS_PATH)
     except OSError:
         pass
     self.redis_server = TestProcess('redis-server', '--port', '0',
                                     '--unixsocket', UDS_PATH)
     self.wait_for_strings(self.redis_server.read, TIMEOUT, "Running")
Esempio n. 2
0
def test_pid():
    with TestProcess(sys.executable, HELPER, 'test_simple') as service:
        with dump_on_error(service.read):
            wait_for_strings(service.read, TIMEOUT, '/tmp/manhole-')
            with TestProcess('manhole-cli', str(service.proc.pid), bufsize=0, stdin=subprocess.PIPE) as client:
                with dump_on_error(client.read):
                    wait_for_strings(client.read, TIMEOUT, '(ManholeConsole)', '>>>')
                    client.proc.stdin.write(b"1234+2345\n")
                    wait_for_strings(client.read, TIMEOUT, '3579')
Esempio n. 3
0
def test_usr2():
    with TestProcess(sys.executable, '-u', HELPER, 'test_oneshot_on_usr2') as service:
        with dump_on_error(service.read):
            wait_for_strings(service.read, TIMEOUT,
                             'Not patching os.fork and os.forkpty. Oneshot activation is done by signal')
            with TestProcess('manhole-cli', '-USR2', str(service.proc.pid), bufsize=0, stdin=subprocess.PIPE) as client:
                with dump_on_error(client.read):
                    wait_for_strings(client.read, TIMEOUT, '(ManholeConsole)', '>>>')
                    client.proc.stdin.write(b"1234+2345\n")
                    wait_for_strings(client.read, TIMEOUT, '3579')
Esempio n. 4
0
    def test_oneshot_on_usr2_error(self):
        with TestProcess(sys.executable, '-u', __file__, 'daemon',
                         'test_oneshot_on_usr2') as proc:
            with self.dump_on_error(proc.read):
                self.wait_for_strings(
                    proc.read, TIMEOUT,
                    'Not patching os.fork and os.forkpty. Oneshot activation is done by signal 12'
                )
                self.assertRaises(AssertionError, self.wait_for_strings,
                                  proc.read, TIMEOUT, '/tmp/manhole-')
                proc.signal(signal.SIGUSR2)
                self.wait_for_strings(proc.read, TIMEOUT, '/tmp/manhole-')
                uds_path = re.findall("(/tmp/manhole-\d+)", proc.read())[0]
                self.wait_for_strings(proc.read, TIMEOUT,
                                      'Waiting for new connection')
                self.assertManholeRunning(
                    proc,
                    uds_path,
                    oneshot=True,
                    extra=lambda sock: sock.send(b"raise SystemExit()\n"))

                proc.reset()
                proc.signal(signal.SIGUSR2)
                self.wait_for_strings(proc.read, TIMEOUT, '/tmp/manhole-')
                uds_path = re.findall("(/tmp/manhole-\d+)", proc.read())[0]
                self.wait_for_strings(proc.read, TIMEOUT,
                                      'Waiting for new connection')
                self.assertManholeRunning(proc, uds_path, oneshot=True)
    def test_simple_break(self):
        with TestProcess(sys.executable, __file__, 'daemon', 'test_simple') as proc:
            with self.dump_on_error(proc.read):
                self.wait_for_strings(proc.read, TIMEOUT,
                    '{a1}',
                    '{b1}',
                    'RemotePdb session open at ',
                )
                host, port = re.findall("RemotePdb session open at (.+):(.+),", proc.read())[0]
                with closing(socket.create_connection((host, int(port)), timeout=TIMEOUT)) as conn:
                    if PY3:
                        fh = conn.makefile('rw', buffering=1)
                    else:
                        fh = conn.makefile(bufsize=0)
                    self.wait_for_strings(proc.read, TIMEOUT, 'accepted connection from')
                    fh.readline()
                    self.assertEqual("-> print('{b2}')", fh.readline().strip())
                    fh.write('break func_a\r\n')
                    fh.write('continue\r\n')
                    fh.readline()
                    fh.readline()
                    self.assertEqual("-> print('{a2}')", fh.readline().strip())
                    fh.write('continue\r\n')
                    try:
                        fh.readline()
                    except Exception as exc:
                        print("fh.readline() failed:", exc)

                self.wait_for_strings(proc.read, TIMEOUT,
                    'DIED.',
                )
                self.assertNotIn('Restoring streams', proc.read())
Esempio n. 6
0
def test_queue_collapse():
    with TestProcess(sys.executable, helper.__file__,
                     'queue_collapse') as proc:
        with dump_on_error(proc.read):
            wait_for_strings(proc.read, TIMEOUT, 'Queues =>')
            clients = []
            for _ in range(5):
                sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
                sock.settimeout(2)
                sock.connect(UDS_PATH)
                if PY3:
                    fh = sock.makefile("rwb", buffering=0)
                else:
                    fh = sock.makefile(bufsize=0)
                fh.write(b"queue_collapse\n")
                clients.append((fh, sock))
            try:
                t1 = time.time()
                for fh, _ in clients:
                    fh.readline()
                delta = time.time() - t1
                if delta > TIMEOUT:
                    raise AssertionError(
                        'Jobs took too much time (%0.2f sec)' % delta)
                wait_for_strings(
                    proc.read, TIMEOUT, 'queue_collapse OK',
                    '%s:%s' % (pwd.getpwuid(os.getuid())[0], os.getpid()))
            finally:
                [(fh.close(), sock.close()) for fh, sock in clients]
Esempio n. 7
0
def test_exit_with_grace():
    with TestProcess(sys.executable, '-u', HELPER, 'test_simple') as proc:
        with dump_on_error(proc.read):
            wait_for_strings(proc.read, TIMEOUT, '/tmp/manhole-')
            uds_path = re.findall(r"(/tmp/manhole-\d+)", proc.read())[0]
            wait_for_strings(proc.read, TIMEOUT, 'Waiting for new connection')

            sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
            sock.settimeout(0.05)
            sock.connect(uds_path)
            with TestSocket(sock) as client:
                with dump_on_error(client.read):
                    wait_for_strings(client.read, TIMEOUT, "ThreadID",
                                     "ProcessID", ">>>")
                    sock.send(b"print('FOOBAR')\n")
                    wait_for_strings(client.read, TIMEOUT, "FOOBAR")

                    wait_for_strings(proc.read, TIMEOUT,
                                     'UID:%s' % os.getuid())
                    sock.shutdown(socket.SHUT_WR)
                    select.select([sock], [], [], 5)
                    sock.recv(1024)
                    try:
                        sock.shutdown(socket.SHUT_RD)
                    except Exception as exc:
                        print("Failed to SHUT_RD: %s" % exc)
                    try:
                        sock.close()
                    except Exception as exc:
                        print("Failed to close socket: %s" % exc)
            wait_for_strings(proc.read, TIMEOUT, 'DONE.', 'Cleaned up.',
                             'Waiting for new connection')
Esempio n. 8
0
def app_server():
    with TestProcess("python", "app.py") as app_server:
        wait_for_strings(app_server.read, 10, "Running")
        print(app_server.read())
        yield app_server
        print("\n>>>>Teardown app_service")
        app_server.close()
 def setUp(self):
     try:
         os.unlink(UDS_PATH)
     except OSError:
         pass
     self.redis_server = TestProcess('redis-server', '--port', '0', '--unixsocket', UDS_PATH)
     self.wait_for_strings(self.redis_server.read, TIMEOUT, "Running")
Esempio n. 10
0
def test_trash_input():
    with TestProcess(sys.executable, __file__, 'daemon',
                     'test_simple') as proc:
        with dump_on_error(proc.read):
            wait_for_strings(proc.read, TIMEOUT, '{a1}', '{b1}',
                             'RemotePdb session open at ')
            host, port = re.findall("RemotePdb session open at (.+):(.+),",
                                    proc.read())[0]
            with TestSocket(
                    socket.create_connection((host, int(port)),
                                             timeout=TIMEOUT)) as client:
                with dump_on_error(client.read):
                    wait_for_strings(proc.read, TIMEOUT,
                                     'accepted connection from')
                    wait_for_strings(client.read, TIMEOUT, "-> print('{b2}')")
                    for i in range(100):
                        client.fh.write(b'\r\n'.join(b'print("[%d]")' %
                                                     (i * 10 + j)
                                                     for j in range(10)) +
                                        b'\r\n')
                    client.fh.write(b'continue\r\n')
                    wait_for_strings(client.read, TIMEOUT,
                                     *['[%s]' % i for i in range(1000)])

            wait_for_strings(proc.read, TIMEOUT, 'DIED.')
Esempio n. 11
0
def test_oneshot_on_usr2_error():
    with TestProcess(sys.executable, '-u', HELPER,
                     'test_oneshot_on_usr2') as proc:
        with dump_on_error(proc.read):
            wait_for_strings(
                proc.read, TIMEOUT,
                'Not patching os.fork and os.forkpty. Oneshot activation is done by signal'
            )
            pytest.raises(AssertionError, wait_for_strings, proc.read, TIMEOUT,
                          '/tmp/manhole-')
            proc.signal(signal.SIGUSR2)
            wait_for_strings(proc.read, TIMEOUT, '/tmp/manhole-')
            uds_path = re.findall(r"(/tmp/manhole-\d+)", proc.read())[0]
            wait_for_strings(proc.read, TIMEOUT, 'Waiting for new connection')
            assert_manhole_running(
                proc,
                uds_path,
                oneshot=True,
                extra=lambda client: client.sock.send(b"raise SystemExit()\n"))

            proc.reset()
            proc.signal(signal.SIGUSR2)
            wait_for_strings(proc.read, TIMEOUT, '/tmp/manhole-')
            uds_path = re.findall(r"(/tmp/manhole-\d+)", proc.read())[0]
            wait_for_strings(proc.read, TIMEOUT, 'Waiting for new connection')
            assert_manhole_running(proc, uds_path, oneshot=True)
Esempio n. 12
0
def test_sample():
    with TestProcess('coverage', 'run', 'tests/nosetests.py', '--verbose',
                     '--with-html', '--html-file=sample.html',
                     'tests/test_sample.py') as proc:
        with dump_on_error(proc.read):
            wait_for_strings(proc.read, TIMEOUT, 'Ran 9 tests in')
    output = open('sample.html').read()

    assert """<tr>
                    <td>test_sample</td>
                    <td class="failed">1</td>
                    <td class="failed">1</td>
                    <td>1</td>
                    <td>1</td>
                    <td>4</td>
                </tr>""" in output
    assert """<tr>
                    <td>test_sample.MainTestCase</td>
                    <td class="failed">1</td>
                    <td>0</td>
                    <td>0</td>
                    <td>1</td>
                    <td>2</td>
                </tr>""" in output
    assert """<tr>
                    <td>test_sample.FailedSetupTestCase</td>
                    <td>0</td>
                    <td class="failed">1</td>
                    <td>0</td>
                    <td>0</td>
                    <td>1</td>
                </tr>""" in output
    assert """<tr>
                    <td>test_sample.SecondTestCase</td>
                    <td>0</td>
                    <td>0</td>
                    <td>0</td>
                    <td>2</td>
                    <td>2</td>
                </tr>""" in output
    assert """<tr>
                <td><strong>Total</strong></td>
                <td class="failed">2</td>
                <td class="failed">2</td>
                <td>1</td>
                <td>4</td>
                <td>9</td>
            </tr>""" in output

    assert "<h2>test_sample.MainTestCase (1 failures, 0 errors)</h2>" in output
    assert '<section id="test_sample.MainTestCase:test_b">' in output
    assert '<h3>test_b: <strong>' in output
    assert '<section id="test_sample:test_b">' in output
    assert '<h3>test_b: <strong>' in output
    assert '<li><a class="success">test_a</a></li>' in output
    assert '<li><a class="failed" href="#test_sample.MainTestCase:test_b">test_b</a></li>' in output
    assert '<h2>test_sample (1 failures, 1 errors)</h2>' in output
    assert '<li><a class="success">test_a</a></li>' in output
    assert '<li><a class="failed" href="#test_sample:test_b">test_b</a></li>' in output
    assert "<h2>test_sample.FailedSetupTestCase (0 failures, 1 errors)</h2>" in output
Esempio n. 13
0
def test_cli(entrypoint, tmpdir):
    args = ['127.0.0.1:0', '--password', 'foobar', '--storage', str(tmpdir)]
    with TestProcess(*entrypoint.split() + args) as process:
        wait_for_strings(process.read, TIMEOUT, "server at http://")
        print(process.read())
        t = time.time()
        port = None
        while time.time() - t < TIMEOUT and port is None:
            for conn in psutil.Process(process.proc.pid).connections():
                print(conn)
                if conn.status == psutil.CONN_LISTEN and conn.laddr[
                        0] == '127.0.0.1':
                    port = conn.laddr[1]
                    break
        if port is None:
            pytest.fail("Didn't find the listen port!")
        session = requests.Session()
        resp = session.get('http://127.0.0.1:%s/' % port)
        csrftoken, = re.findall(
            'name=[\'"]csrfmiddlewaretoken[\'"] value=[\'"](.*?)[\'"]',
            resp.text)
        resp = session.post(
            'http://127.0.0.1:%s/login/?next=/redisboard/redisserver/' % port,
            data={
                'csrfmiddlewaretoken': csrftoken,
                'username': '******',
                'password': '******',
            })
        assert '<a href="/redisboard/redisserver/1/inspect/"' in resp.text
Esempio n. 14
0
def test_gdb():
    with TestProcess('python', '-mtarget',
                     'manhole') as target, dump_on_error(target.read):
        with TestProcess('hunter-trace', '-p', str(target.proc.pid), '--gdb',
                         'stdlib=False') as tracer, dump_on_error(tracer.read):
            wait_for_strings(
                tracer.read,
                TIMEOUT,
                'WARNING: Using GDB may deadlock the process or create unpredictable results!',
                'Output stream active. Starting tracer',
                'call      => stuff()',
                'line         time.sleep(1)',
                'return    <= stuff: None',
            )
        wait_for_strings(target.read, TIMEOUT, 'Broken pipe',
                         'Stopping tracer.')
Esempio n. 15
0
def test_no_overlap(redis_server):
    """
    This test tries to simulate contention: lots of clients trying to acquire at the same time.

    If there would be a bug that would allow two clients to hold the lock at the same time it
    would most likely regress this test.

    The code here mostly tries to parse out the pid of the process and the time when it got and
    released the lock. If there's is overlap (eg: pid1.start < pid2.start < pid1.end) then we
    got a very bad regression on our hands ...

    The subprocess being run (check helper.py) will fork bunch of processes and will try to
    syncronize them (using the builting sched) to try to acquire the lock at the same time.
    """
    with TestProcess(sys.executable, HELPER, 'test_no_overlap') as proc:
        with dump_on_error(proc.read):
            name = 'lock:foobar'
            wait_for_strings(proc.read, 10 * TIMEOUT, 'Getting %r ...' % name)
            wait_for_strings(proc.read, 10 * TIMEOUT,
                             'Got lock for %r.' % name)
            wait_for_strings(proc.read, 10 * TIMEOUT, 'Releasing %r.' % name)
            wait_for_strings(proc.read, 10 * TIMEOUT,
                             'UNLOCK_SCRIPT not cached.')
            wait_for_strings(proc.read, 10 * TIMEOUT, 'DIED.')

            class Event(object):
                pid = start = end = '?'

                def __str__(self):
                    return "Event(%s; %r => %r)" % (self.pid, self.start,
                                                    self.end)

            events = defaultdict(Event)
            for line in proc.read().splitlines():
                try:
                    pid, time, junk = line.split(' ', 2)
                    pid = int(pid)
                except ValueError:
                    continue
                if 'Got lock for' in junk:
                    events[pid].pid = pid
                    events[pid].start = time
                if 'Releasing' in junk:
                    events[pid].pid = pid
                    events[pid].end = time
            assert len(events) == 125

            # not very smart but we don't have millions of events so it's
            # ok - compare all the events with all the other events:
            for event in events.values():
                for other in events.values():
                    if other is not event:
                        try:
                            if (other.start < event.start < other.end
                                    or other.start < event.end < other.end):
                                pytest.fail('%s overlaps %s' % (event, other))
                        except Exception:
                            print("[%s/%s]" % (event, other))
                            raise
Esempio n. 16
0
 def test_activate_on_with_oneshot_on(self):
     with TestProcess(sys.executable, '-u', __file__, 'daemon',
                      'test_activate_on_with_oneshot_on') as proc:
         with self.dump_on_error(proc.read):
             self.wait_for_strings(
                 proc.read, TIMEOUT,
                 "RuntimeError('You cannot do activation of the Manhole thread on the same signal that you want to do oneshot activation !')"
             )
Esempio n. 17
0
def redis_server(scope='module'):
    try:
        os.unlink(UDS_PATH)
    except OSError:
        pass
    with TestProcess('redis-server', '--port', '0', '--unixsocket', UDS_PATH) as process:
        wait_for_strings(process.read, TIMEOUT, "Running")
        yield process
Esempio n. 18
0
def test_activate_on_with_oneshot_on():
    with TestProcess(sys.executable, '-u', HELPER,
                     'test_activate_on_with_oneshot_on') as proc:
        with dump_on_error(proc.read):
            wait_for_strings(
                proc.read, TIMEOUT,
                "You cannot do activation of the Manhole thread on the same signal that you want to do "
                "oneshot activation !")
Esempio n. 19
0
def test_sigprocmask_negative():
    with TestProcess(sys.executable, '-u', HELPER,
                     'test_signalfd_weirdness_negative') as proc:
        with dump_on_error(proc.read):
            wait_for_strings(proc.read, TIMEOUT, '/tmp/manhole-')
            uds_path = re.findall(r"(/tmp/manhole-\d+)", proc.read())[0]
            wait_for_strings(proc.read, TIMEOUT, 'Waiting for new connection')
            wait_for_strings(proc.read, TIMEOUT, 'signalled=True')
            assert_manhole_running(proc, uds_path)
Esempio n. 20
0
def test_manhole():
    with TestProcess('python', '-mtarget',
                     'manhole') as target, dump_on_error(target.read):
        wait_for_strings(target.read, TIMEOUT,
                         'Oneshot activation is done by signal')

        with TestProcess('hunter-trace', '-p', str(target.proc.pid),
                         'stdlib=False') as tracer, dump_on_error(tracer.read):
            wait_for_strings(
                tracer.read,
                TIMEOUT,
                'Output stream active. Starting tracer',
                'call      => stuff()',
                'line         time.sleep(1)',
                'return    <= stuff: None',
            )
        wait_for_strings(target.read, TIMEOUT, 'Broken pipe',
                         'Stopping tracer.')
Esempio n. 21
0
def test_locmem():
    with TestProcess('django-admin.py',
                     'runserver', '127.0.0.1:0', '--traceback', '--noreload', '--nothreading',
                     env=dict(os.environ, UWSGI_CACHE_FALLBACK='y')) as proc:
        with dump_on_error(proc.read):
            wait_for_strings(proc.read, TIMEOUT, '127.0.0.1')
            port = get_ports(proc.proc.pid)
            url = "http://127.0.0.1:%s" % port
            assertions(url)
Esempio n. 22
0
def test_locals_after_fork():
    with TestProcess(sys.executable, HELPER, 'test_locals_after_fork') as proc:
        with dump_on_error(proc.read):
            wait_for_strings(proc.read, TIMEOUT, 'Fork detected')
            proc.reset()
            wait_for_strings(proc.read, TIMEOUT, '/tmp/manhole-')
            child_uds_path = re.findall(r"(/tmp/manhole-\d+)", proc.read())[0]
            wait_for_strings(proc.read, TIMEOUT, 'Waiting for new connection')
            check_locals(child_uds_path)
Esempio n. 23
0
def test_custom_exit_code():
    with TestProcess(sys.executable, helper.__file__,
                     'custom_exit_code') as proc:
        with dump_on_error(proc.read):
            wait_for_strings(proc.read, TIMEOUT, 'Queues =>')
            with connection(3) as fh:
                fh.write(b"asdf\n")
                line = fh.readline()
                json.loads(line.decode('ascii'))["exit_code"] == 123
Esempio n. 24
0
def test_simple():
    with TestProcess(sys.executable, HELPER, 'test_simple') as proc:
        with dump_on_error(proc.read):
            wait_for_strings(proc.read, TIMEOUT, '/tmp/manhole-')
            uds_path = re.findall(r"(/tmp/manhole-\d+)", proc.read())[0]
            wait_for_strings(proc.read, TIMEOUT, 'Waiting for new connection')
            for _ in range(20):
                proc.reset()
                assert_manhole_running(proc, uds_path)
Esempio n. 25
0
def test_gdb_clean_exit():
    with TestProcess(sys.executable, '-mtarget',
                     'manhole') as target, dump_on_error(target.read):
        with TestProcess('hunter-trace', '-p', str(target.proc.pid),
                         'stdlib=False',
                         '--gdb') as tracer, dump_on_error(tracer.read):
            wait_for_strings(
                tracer.read,
                TIMEOUT,
                'WARNING: Using GDB may deadlock the process or create unpredictable results!',
                'Output stream active. Starting tracer',
                'call      => stuff()',
                'line         time.sleep(1)',
                'return    <= stuff: None',
            )
            target.reset()
            tracer.proc.send_signal(signal.SIGINT)
        wait_for_strings(target.read, TIMEOUT, 'Doing stuff', 'Doing stuff',
                         'Doing stuff')
Esempio n. 26
0
def test_interrupt_on_accept():
    with TestProcess(sys.executable, '-u', __file__, 'daemon',
                     'test_interrupt_on_accept') as proc:
        with dump_on_error(proc.read):
            wait_for_strings(proc.read, TIMEOUT, '/tmp/manhole-')
            uds_path = re.findall(r"(/tmp/manhole-\d+)", proc.read())[0]
            wait_for_strings(proc.read, TIMEOUT, 'Waiting for new connection',
                             'Sending signal to manhole thread',
                             'Waiting for new connection')
            assert_manhole_running(proc, uds_path)
Esempio n. 27
0
def test_simple(redis_server):
    with TestProcess(sys.executable, HELPER, 'test_simple') as proc:
        with dump_on_error(proc.read):
            name = 'lock:foobar'
            wait_for_strings(proc.read, TIMEOUT,
                'Getting %r ...' % name,
                'Got lock for %r.' % name,
                'Releasing %r.' % name,
                'UNLOCK_SCRIPT not cached.',
                'DIED.',
            )
Esempio n. 28
0
def test_no_block(redis_server):
    with Lock(StrictRedis(unix_socket_path=UDS_PATH), "foobar"):
        with TestProcess(sys.executable, HELPER, 'test_no_block') as proc:
            with dump_on_error(proc.read):
                name = 'lock:foobar'
                wait_for_strings(proc.read, TIMEOUT,
                    'Getting %r ...' % name,
                    'Failed to get %r.' % name,
                    'acquire=>False',
                    'DIED.',
                )
Esempio n. 29
0
def test_timeout_acquired(conn):
    with TestProcess(sys.executable, HELPER, 'test_timeout') as proc:
        with dump_on_error(proc.read):
            name = 'lock:foobar'
            wait_for_strings(
                proc.read, TIMEOUT,
                'Getting %r ...' % name,
                'Got lock for %r.' % name,
            )
            lock = Lock(conn, "foobar")
            assert lock.acquire(timeout=2)
Esempio n. 30
0
def test_manhole_clean_exit():
    with TestProcess('python', '-mtarget',
                     'manhole') as target, dump_on_error(target.read):
        wait_for_strings(target.read, TIMEOUT,
                         'Oneshot activation is done by signal')

        with TestProcess('hunter-trace', '-p', str(target.proc.pid),
                         'stdlib=False') as tracer, dump_on_error(tracer.read):
            wait_for_strings(
                tracer.read,
                TIMEOUT,
                'Output stream active. Starting tracer',
                'call      => stuff()',
                'line         time.sleep(1)',
                'return    <= stuff: None',
            )
            target.reset()
            tracer.proc.send_signal(signal.SIGINT)
        wait_for_strings(target.read, TIMEOUT, 'remote.deactivate()',
                         'Doing stuff', 'Doing stuff', 'Doing stuff')
Esempio n. 31
0
def test_prespawned():
    with TestProcess(sys.executable, helper.__file__, 'simple') as proc:
        with dump_on_error(proc.read):
            wait_for_strings(proc.read, TIMEOUT, 'Queues =>')
            response = client.request(helper.PATH, b"foobar")
            assert response.exit_code == 0
            wait_for_strings(proc.read, TIMEOUT,
                             '%s:%s' % (pwd.getpwuid(os.getuid())[0], os.getpid()),
                             'JOB foobar EXECUTED',
                             'completed. Passing back results to',
                             'Queues => 0 workspaces')
Esempio n. 32
0
class RedisLockTestCase(ProcessTestCase):
    def setUp(self):
        try:
            os.unlink(UDS_PATH)
        except OSError:
            pass
        self.redis_server = TestProcess('redis-server', '--port', '0', '--unixsocket', UDS_PATH)
        self.wait_for_strings(self.redis_server.read, TIMEOUT, "Running")

    def tearDown(self):
        self.redis_server.close()

    def test_simple(self):
        with TestProcess(sys.executable, __file__, 'daemon', 'test_simple') as proc:
            with self.dump_on_error(proc.read):
                name = 'lock:foobar'
                self.wait_for_strings(proc.read, TIMEOUT,
                    'Getting %r ...' % name,
                    'Got lock for %r.' % name,
                    'Releasing %r.' % name,
                    'UNLOCK_SCRIPT not cached.',
                    'DIED.',
                )

    def test_no_block(self):
        with Lock(StrictRedis(unix_socket_path=UDS_PATH), "foobar"):
            with TestProcess(sys.executable, __file__, 'daemon', 'test_no_block') as proc:
                with self.dump_on_error(proc.read):
                    name = 'lock:foobar'
                    self.wait_for_strings(proc.read, TIMEOUT,
                        'Getting %r ...' % name,
                        'Failed to get %r.' % name,
                        'acquire=>False',
                        'DIED.',
                    )

    def test_expire(self):
        conn = StrictRedis(unix_socket_path=UDS_PATH)
        with Lock(conn, "foobar", expire=TIMEOUT/4):
            with TestProcess(sys.executable, __file__, 'daemon', 'test_expire') as proc:
                with self.dump_on_error(proc.read):
                    name = 'lock:foobar'
                    self.wait_for_strings(proc.read, TIMEOUT,
                        'Getting %r ...' % name,
                        'Got lock for %r.' % name,
                        'Releasing %r.' % name,
                        'UNLOCK_SCRIPT not cached.',
                        'DIED.',
                    )
        lock = Lock(conn, "foobar")
        try:
            self.assertEqual(lock.acquire(blocking=False), True)
        finally:
            lock.release()

    def test_double_acquire(self):
        lock = Lock(StrictRedis(unix_socket_path=UDS_PATH), "foobar")
        with lock:
            self.assertRaises(RuntimeError, lock.acquire)

    def test_plain(self):
        with Lock(StrictRedis(unix_socket_path=UDS_PATH), "foobar"):
            time.sleep(0.01)

    def test_no_overlap(self):
        with TestProcess(sys.executable, __file__, 'daemon', 'test_no_overlap') as proc:
            with self.dump_on_error(proc.read):
                name = 'lock:foobar'
                self.wait_for_strings(proc.read, TIMEOUT, 'Getting %r ...' % name)
                self.wait_for_strings(proc.read, TIMEOUT, 'Got lock for %r.' % name)
                self.wait_for_strings(proc.read, TIMEOUT, 'Releasing %r.' % name)
                self.wait_for_strings(proc.read, TIMEOUT, 'UNLOCK_SCRIPT not cached.')
                self.wait_for_strings(proc.read, 10*TIMEOUT, 'DIED.')

                class Event(object):
                    def __str__(self):
                        return "Event(%s; %r => %r)" % (self.pid, self.start, self.end)

                events = defaultdict(Event)
                for line in proc.read().splitlines():
                    pid, time, junk = line.split(' ', 2)
                    if 'Got lock for' in junk:
                        events[pid].pid = pid
                        events[pid].start = time
                    if 'Releasing' in junk:
                        events[pid].pid = pid
                        events[pid].end = time
                self.assertEqual(len(events), 125)

                for event in events.values():
                    for other in events.values():
                        if other is not event:
                            try:
                                if other.start < event.start < other.end or \
                                   other.start < event.end < other.end:
                                    self.fail('%s overlaps %s' % (event, other))
                            except:
                                print("[%s/%s]" %(event, other))
                                raise