예제 #1
0
    def test__notify_cluster_in(self, mock_get_root_auth, mock_post,
                                mock_get_now):
        mock_get_root_auth.return_value = 'auth'
        mock_post.side_effect = [
            ntwrk.Response(code=200,
                           msg={
                               'cluster':
                               [(1, now.strftime(defaults.DATEMARK_FORMAT),
                                 False),
                                (2, now.strftime(defaults.DATEMARK_FORMAT),
                                 False)],
                               'neighbours': [1, 2]
                           })
        ]
        mock_get_now.return_value = now

        s2 = Server('node2', port=5000)
        s2.set_route(None, gate=s2.gates[0], cost=0)

        db.session.add(s2)
        self.cm._route_initiated = mock.Mock()
        self.cm._notify_cluster_in()
        self.cm.main_func()
        self.assertDictEqual(
            {
                1: _Entry(id=1, keepalive=now, death=False),
                2: _Entry(id=2, keepalive=now, death=False)
            }, self.cm._registry)

        routes = [s2.route.to_json()]
        mock_post.assert_called_once_with(
            s2,
            'api_1_0.cluster_in',
            view_data=dict(server_id=str(self.s1.id)),
            json=dict(keepalive=now.strftime(defaults.DATEMARK_FORMAT),
                      routes=routes),
            timeout=10,
            auth='auth')
예제 #2
0
class TestForwardOrDispatch(TestCase, ValidateResponseMixin):

    # def run(self, result=None):
    #     with patch('dimensigon.web.scopefunc') as mock_scopefunc:
    #         mock_scopefunc.side_effect = lambda: threading.get_ident()
    #         super().run(result)

    def setUp(self):
        """Create and configure a new self.app instance for each test."""
        # create a temporary file to isolate the database for each test
        # create the self.app with common test config
        self.app = Flask(__name__)

        @self.app.route('/', methods=['GET', 'POST'])
        @forward_or_dispatch()
        def hello():
            return {'msg': 'default response'}

        self.app_context = self.app.app_context()
        self.app_context.push()
        self.client = self.app.test_client()
        db.init_app(self.app)
        db.create_all()

        self.srv1 = Server(id='bbbbbbbb-1234-5678-1234-56781234bbb1', name='server1',
                           dns_or_ip='192.168.1.9', port=7123)
        Route(self.srv1, cost=0)
        self.srv2 = Server(id='bbbbbbbb-1234-5678-1234-56781234bbb2', name='server2',
                           dns_or_ip='192.168.1.10', port=7124)
        Route(self.srv2, self.srv1, cost=1)
        db.session.add_all([self.srv1, self.srv2])
        db.session.commit()

    def tearDown(self) -> None:
        db.session.remove()
        db.drop_all()
        self.app_context.pop()

    @patch('dimensigon.web.decorators.g')
    @responses.activate
    def test_forward_or_dispatch_in_content(self, mock_g):
        mock_g.server = MagicMock(id=self.srv1.id)
        responses.add(responses.POST, 'https://192.168.1.9:7123/', json={'msg': 'response'})

        # check if request is forwarded to the server
        response = self.client.post('/', json={'destination': self.srv2.id, 'data': None})
        self.assertEqual({'msg': 'response'}, response.json)

        self.assertEqual(1, len(responses.calls))
        self.assertEqual('https://192.168.1.9:7123/', responses.calls[0].request.url)

        # check if request is forwarded to the server
        response = self.client.post('/', json={'destination': self.srv1.id, 'data': None})
        self.assertEqual({'msg': 'default response'}, response.json)

        self.assertEqual(1, len(responses.calls))

    @patch('dimensigon.web.decorators.g')
    @responses.activate
    def test_forward_or_dispatch(self, mock_g):
        mock_g.server = MagicMock(id=self.srv1.id)
        responses.add(responses.POST, 'https://192.168.1.9:7123/', json={'msg': 'response'})

        # check if request is forwarded to the server
        response = self.client.post('/', json={'data': None},
                                    headers={'D-Destination': self.srv2.id})
        self.assertEqual({'msg': 'response'}, response.json)

        self.assertEqual(1, len(responses.calls))
        self.assertEqual('https://192.168.1.9:7123/', responses.calls[0].request.url)

        # check if request is forwarded to the server
        response = self.client.post('/', json={'data': None},
                                    headers={'D-Destination': self.srv1.id})
        self.assertEqual({'msg': 'default response'}, response.json)

        self.assertEqual(1, len(responses.calls))

    # @patch('dimensigon.web.decorators.g')
    # def test_forward_or_dispatch_hidden_ip(self, mock_g):
    #     mock_g.server = MagicMock(id=self.srv1.id)
    #
    #     response = self.client.post('/', json={'data': None},
    #                                 headers={'D-Destination': self.srv1.id,
    #                                          'D-Source': self.srv2.id},
    #                                 environ_base={'REMOTE_ADDR': '10.1.2.3'})
    #     self.assertEqual({'msg': 'default response'}, response.json)
    #
    #     self.assertEqual(1, len(self.srv2.hidden_gates))
    #     hg = self.srv2.hidden_gates[0]
    #     self.assertEqual('10.1.2.3', str(hg.ip))
    #     self.assertEqual(7124, hg.port)
    #
    #     response = self.client.post('/', json={'data': None},
    #                                 headers={'D-Destination': self.srv1.id,
    #                                          'D-Source': self.srv2.id},
    #                                 environ_base={'REMOTE_ADDR': '10.1.2.3'})
    #     self.assertEqual({'msg': 'default response'}, response.json)
    #
    #     self.assertEqual(1, len(self.srv2.hidden_gates))
    #     self.assertEqual('10.1.2.3', str(hg.ip))
    #     self.assertEqual(7124, hg.port)
    #
    #     response = self.client.post('/', json={'data': None},
    #                                 headers={'D-Destination': self.srv1.id,
    #                                          'D-Source': self.srv2.id},
    #                                 environ_base={'REMOTE_ADDR': '10.1.2.4'})
    #     self.assertEqual({'msg': 'default response'}, response.json)
    #
    #     db.session.refresh(self.srv2)
    #     self.assertEqual(1, len(self.srv2.hidden_gates))
    #     self.assertEqual('10.1.2.4', str(hg.ip))
    #     self.assertEqual(7124, hg.port)

    # @patch('dimensigon.web.decorators.g')
    # def test_forward_or_dispatch_hidden_ip_multiple_ports(self, mock_g):
    #     mock_g.server = MagicMock(id=self.srv1.id)
    #
    #     g = self.srv2.add_new_gate('127.0.0.1', 7125)
    #
    #     db.session.add(g)
    #     db.session.commit()
    #
    #     response = self.client.post('/', json={'data': None},
    #                                 headers={'D-Destination': self.srv1.id,
    #                                          'D-Source': self.srv2.id},
    #                                 environ_base={'REMOTE_ADDR': '10.1.2.3'})
    #
    #     self.assertEqual({'msg': 'default response'}, response.json)
    #
    #     db.session.refresh(self.srv2)
    #
    #     self.assertEqual(2, len(self.srv2.hidden_gates))
    #     hg = self.srv2.hidden_gates
    #     self.assertEqual('10.1.2.3', str(hg[0].ip))
    #     self.assertEqual(7124, hg[0].port)
    #     self.assertEqual('10.1.2.3', str(hg[1].ip))
    #     self.assertEqual(7125, hg[1].port)
    #
    #     response = self.client.post('/', json={'data': None},
    #                                 headers={'D-Destination': self.srv1.id,
    #                                          'D-Source': self.srv2.id},
    #                                 environ_base={'REMOTE_ADDR': '10.1.2.3'})
    #     self.assertEqual({'msg': 'default response'}, response.json)
    #
    #     db.session.refresh(self.srv2)
    #
    #     self.assertEqual(2, len(self.srv2.hidden_gates))
    #     hg = self.srv2.hidden_gates
    #     self.assertEqual('10.1.2.3', str(hg[0].ip))
    #     self.assertEqual(7124, hg[0].port)
    #     self.assertEqual('10.1.2.3', str(hg[1].ip))
    #     self.assertEqual(7125, hg[1].port)
    #
    #     response = self.client.post('/', json={'data': None},
    #                                 headers={'D-Destination': self.srv1.id,
    #                                          'D-Source': self.srv2.id},
    #                                 environ_base={'REMOTE_ADDR': '10.1.2.4'})
    #
    #     self.assertEqual({'msg': 'default response'}, response.json)
    #
    #     db.session.refresh(self.srv2)
    #
    #     self.assertEqual(2, len(self.srv2.hidden_gates))
    #     hg = self.srv2.hidden_gates
    #     self.assertEqual('10.1.2.4', str(hg[0].ip))
    #     self.assertIn(hg[0].port, (7124, 7125))
    #     self.assertEqual('10.1.2.4', str(hg[1].ip))
    #     self.assertIn(hg[1].port, (7124, 7125))

    # @patch('dimensigon.web.decorators.g')
    # def test_forward_or_dispatch_using_proxy_server(self, mock_g):
    #     me = Server(id='bbbbbbbb-1234-5678-1234-56781234bbb0', name='server0',
    #                 dns_or_ip='192.168.1.8', port=7123, me=True)
    #     db.session.add(me)
    #     db.session.commit()
    #     mock_g.server = MagicMock(id='bbbbbbbb-1234-5678-1234-56781234bbb0')
    #
    #     response = self.client.post('/', json={'data': None},
    #                                 headers={'D-Destination': 'bbbbbbbb-1234-5678-1234-56781234bbb0',
    #                                          'D-Source': 'bbbbbbbb-1234-5678-1234-56781234bbb2:bbbbbbbb-1234-5678-1234-56781234bbb1'},
    #                                 environ_base={'REMOTE_ADDR': '192.168.1.9'})
    #     self.assertEqual({'msg': 'default response'}, response.json)
    #
    #     db.session.refresh(self.srv2)
    #     self.assertEqual(0, len(self.srv2.hidden_gates))
    #
    #     response = self.client.post('/', json={'data': None},
    #                                 headers={'D-Destination': 'bbbbbbbb-1234-5678-1234-56781234bbb0',
    #                                          'D-Source': 'bbbbbbbb-1234-5678-1234-56781234bbb2:bbbbbbbb-1234-5678-1234-56781234bbb1'},
    #                                 environ_base={'REMOTE_ADDR': '10.1.2.3'})
    #     self.assertEqual({'msg': 'default response'}, response.json)
    #
    #     db.session.refresh(self.srv1)
    #     self.assertEqual(1, len(self.srv1.hidden_gates))
    #     hg = self.srv1.hidden_gates[0]
    #     self.assertEqual('10.1.2.3', str(hg.ip))
    #     self.assertEqual(7123, hg.port)

    @patch('dimensigon.web.decorators.g')
    def test_server_not_found(self, mock_g):
        mock_g.server = MagicMock(id=self.srv1.id)

        resp = self.client.post('/', json={'data': None},
                                headers={'D-Destination': 'bbbbbbbb-1234-5678-1234-56781234bbb5'})

        self.validate_error_response(resp, errors.EntityNotFound('Server', 'bbbbbbbb-1234-5678-1234-56781234bbb5'))

    @patch('dimensigon.web.decorators.socket.gethostbyname')
    @patch('dimensigon.web.decorators.g')
    def test_forward_or_dispatch_dns(self, mock_g, mock_gethostbyname):
        mock_g.server = MagicMock(id=self.srv1.id)

        def gethostbyname(dns: str):
            if dns == 'server2':
                return '10.1.2.3'
            else:
                return None

        mock_gethostbyname.side_effect = gethostbyname
        self.srv2.add_new_gate('server2', 7124)
        db.session.commit()

        response = self.client.post('/', json={'data': None},
                                    headers={'D-Destination': self.srv1.id,
                                             'D-Source': self.srv2.id},
                                    environ_base={'REMOTE_ADDR': '10.1.2.3'})
        self.assertEqual({'msg': 'default response'}, response.json)

        self.assertEqual(0, len(self.srv2.hidden_gates))

    @patch('dimensigon.web.decorators.requests.request', autospec=True)
    @patch('dimensigon.web.decorators.g')
    def test_forward_or_dispatch_proxy_request(self, mock_g, mock_request):
        mock_g.server = MagicMock(id=self.srv1.id)

        def request(*args, **kwargs):
            r = requests.Response()
            r._content = kwargs['headers'].get('d-source')
            r.status_code = 222
            return r

        mock_request.side_effect = request

        # check if request is forwarded to the server without d-source header
        resp = self.client.post('/', json={'data': None},
                                headers={'D-Destination': self.srv2.id})

        self.assertEqual(':bbbbbbbb-1234-5678-1234-56781234bbb1', resp.get_data(True))

        # check if request is forwarded to the server with d-source header
        resp = self.client.post('/', json={'data': None},
                                headers={'D-Destination': self.srv2.id,
                                         'D-Source': 'bbbbbbbb-1234-5678-1234-56781234bbb0'})

        self.assertEqual('bbbbbbbb-1234-5678-1234-56781234bbb0:bbbbbbbb-1234-5678-1234-56781234bbb1',
                             resp.get_data(True))

    @patch('dimensigon.web.decorators.g')
    def test_forward_or_dispatch_unreachable_destination(self, mock_g):
        type(mock_g).server = mock.PropertyMock(return_value=self.srv1)
        self.srv2.set_route(None, None, None)
        resp = self.client.post('/', json={'data': None},
                            headers={'D-Destination': self.srv2.id})

        self.validate_error_response(resp, errors.UnreachableDestination(self.srv2, self.srv1))

    @patch('dimensigon.web.decorators.requests.request', autospec=True)
    @patch('dimensigon.web.decorators.g')
    def test_forward_or_dispatch_error_proxying(self, mock_g, mock_request):
        mock_g.server = MagicMock(id=self.srv1.id)
        mock_request.side_effect = requests.exceptions.ConnectionError('error')

        # check if request is forwarded to the server
        resp = self.client.post('/', json={'data': None},
                                headers={'D-Destination': self.srv2.id})

        self.validate_error_response(resp, errors.ProxyForwardingError(self.srv2,
                                                                       requests.exceptions.ConnectionError('error')))