1#! /usr/bin/env python
2# -*- coding: utf-8 -*-
3# vi:ts=4:et
4
5from . import localhost
6import pycurl
7import unittest
8
9from . import appmanager
10from . import util
11
12setup_module_1, teardown_module_1 = appmanager.setup(('app', 8380))
13setup_module_2, teardown_module_2 = appmanager.setup(('app', 8381))
14setup_module_3, teardown_module_3 = appmanager.setup(('app', 8382))
15
16def setup_module(mod):
17    setup_module_1(mod)
18    setup_module_2(mod)
19    setup_module_3(mod)
20
21def teardown_module(mod):
22    teardown_module_3(mod)
23    teardown_module_2(mod)
24    teardown_module_1(mod)
25
26class MultiSocketTest(unittest.TestCase):
27    def test_multi_socket(self):
28        urls = [
29            # not sure why requesting /success produces no events.
30            # see multi_socket_select_test.py for a longer explanation
31            # why short wait is used there.
32            'http://%s:8380/short_wait' % localhost,
33            'http://%s:8381/short_wait' % localhost,
34            'http://%s:8382/short_wait' % localhost,
35        ]
36
37        socket_events = []
38
39        # socket callback
40        def socket(event, socket, multi, data):
41            #print(event, socket, multi, data)
42            socket_events.append((event, multi))
43
44        # init
45        m = pycurl.CurlMulti()
46        m.setopt(pycurl.M_SOCKETFUNCTION, socket)
47        m.handles = []
48        for url in urls:
49            c = util.DefaultCurl()
50            # save info in standard Python attributes
51            c.url = url
52            c.body = util.BytesIO()
53            c.http_code = -1
54            m.handles.append(c)
55            # pycurl API calls
56            c.setopt(c.URL, c.url)
57            c.setopt(c.WRITEFUNCTION, c.body.write)
58            m.add_handle(c)
59
60        # get data
61        num_handles = len(m.handles)
62        while num_handles:
63            while 1:
64                ret, num_handles = m.socket_all()
65                if ret != pycurl.E_CALL_MULTI_PERFORM:
66                    break
67            # currently no more I/O is pending, could do something in the meantime
68            # (display a progress bar, etc.)
69            m.select(0.1)
70
71        for c in m.handles:
72            # save info in standard Python attributes
73            c.http_code = c.getinfo(c.HTTP_CODE)
74
75        # at least in and remove events per socket
76        assert len(socket_events) >= 6
77
78        # print result
79        for c in m.handles:
80            self.assertEqual('success', c.body.getvalue().decode())
81            self.assertEqual(200, c.http_code)
82
83            # multi, not curl handle
84            self.check(pycurl.POLL_IN, m, socket_events)
85            self.check(pycurl.POLL_REMOVE, m, socket_events)
86
87        # close handles
88        for c in m.handles:
89            # pycurl API calls
90            m.remove_handle(c)
91            c.close()
92        m.close()
93
94    def check(self, event, multi, socket_events):
95        for event_, multi_ in socket_events:
96            if event == event_ and multi == multi_:
97                return
98        assert False, '%d %s not found in socket events' % (event, multi)
99