class TestMessage(unittest.TestCase):

    def setUp(self):
        m = AmsMessage()
        self.message_callable = m(attributes={'foo': 'bar'}, data='baz')
        self.message_callable_memoization = m(attributes={'foo1': 'bar1'})
        self.message_callable_memoization_two = m(data='baz1')
        self.message_send = AmsMessage(attributes={'foo': 'bar'}, data='baz')
        self.message_send_no_payload = AmsMessage()
        self.message_send_onlyattr = AmsMessage(attributes={'foo': 'bar'})
        self.message_send_onlydata = AmsMessage(data='baz')
        self.message_unicode = AmsMessage(data='ùňĭćőđĕ')

        self.message_recv = AmsMessage(b64enc=False, attributes={'foo': 'bar'},
                                       data='YmF6', messageId='1',
                                       publishTime='2017-03-15T17:11:34.035345612Z')
        self.message_recv_faulty = AmsMessage(b64enc=False, attributes={'foo': 'bar'},
                                              data='123456789thiswillfail',
                                              messageId='1',
                                              publishTime='2017-03-15T17:11:34.035345612Z')

    def test_MsgReadyToSend(self):
        self.assertEqual(self.message_send.dict(), {'attributes': {'foo': 'bar'},
                                                    'data': 'YmF6'})
        self.assertEqual(self.message_callable, {'attributes': {'foo': 'bar'},
                                                 'data': 'YmF6'})
        self.assertEqual(self.message_callable_memoization, {'attributes': {'foo1': 'bar1'},
                                                 'data': 'YmF6'})
        self.assertEqual(self.message_callable_memoization_two, {'attributes': {'foo1': 'bar1'},
                                                 'data': 'YmF6MQ=='})
        self.assertEqual(self.message_send_onlyattr.dict(), {'attributes': {'foo': 'bar'}})
        self.assertEqual(self.message_send_onlydata.dict(), {'data': 'YmF6'})
        self.assertEqual(self.message_unicode.dict(), {'data': 'w7nFiMStxIfFkcSRxJU='})
        self.assertEqual(self.message_unicode.get_data(), 'ùňĭćőđĕ')

        self.message_send.set_data('baz')
        self.assertEqual(self.message_send.get_data(), 'baz')

    def test_MsgReadyToRecv(self):
        self.assertEqual(self.message_recv.get_data(), 'baz')
        self.assertEqual(self.message_recv.get_msgid(), '1')
        self.assertEqual(self.message_recv.get_publishtime(),
                         '2017-03-15T17:11:34.035345612Z')
        self.assertEqual(self.message_recv.get_attr(), {'foo': 'bar'})

    def test_MsgFaulty(self):
        self.assertRaises(AmsMessageException, self.message_recv_faulty.get_data)
        self.assertRaises(AmsMessageException, self.message_send_no_payload.get_data)
        self.assertRaises(AmsMessageException, self.message_send_no_payload.get_attr)
class TestTopic(unittest.TestCase):
    def setUp(self):
        self.ams = ArgoMessagingService(endpoint="localhost",
                                        token="s3cr3t",
                                        project="TEST")
        self.msg = AmsMessage(attributes={'foo': 'bar'}, data='baz')
        self.submocks = SubMocks()
        self.topicmocks = TopicMocks()

    def testPublish(self):
        # Mock response for POST publish to topic
        @urlmatch(netloc="localhost",
                  path="/v1/projects/TEST/topics/topic1:publish",
                  method="POST")
        def publish_mock(url, request):
            # Check request produced by ams client
            req_body = json.loads(request.body)
            self.assertEqual(req_body["messages"][0]["data"], 'YmF6')
            self.assertEqual(req_body["messages"][0]["attributes"]["foo"],
                             "bar")
            return '{"msgIds":["1"]}'

        # Execute ams client with mocked response
        with HTTMock(self.topicmocks.has_topic_mock, publish_mock):
            topic = self.ams.topic('topic1')
            resp = topic.publish(self.msg.dict())
            # Assert that ams client handled the json response correctly
            self.assertEqual(resp["msgIds"][0], "1")
            self.assertEqual(topic.name, 'topic1')
            self.assertEqual(topic.fullname, '/projects/TEST/topics/topic1')

    def testSubscription(self):
        # Execute ams client with mocked response
        with HTTMock(self.topicmocks.create_topic_mock,
                     self.submocks.create_subscription_mock,
                     self.topicmocks.get_topic_mock,
                     self.submocks.has_subscription_mock):
            topic = self.ams.topic('topic1')
            sub = topic.subscription('subscription1')
            # Assert that ams client handled the json response correctly
            self.assertEqual(topic.name, 'topic1')
            self.assertEqual(topic.fullname, '/projects/TEST/topics/topic1')
            assert isinstance(sub, AmsSubscription)
            self.assertEqual(sub.topic, topic)
            self.assertEqual(sub.name, 'subscription1')
            self.assertEqual(sub.fullname,
                             '/projects/TEST/subscriptions/subscription1')

    def testIterSubscriptions(self):
        # Mock response for GET Subscriptions request
        @urlmatch(netloc="localhost",
                  path="/v1/projects/TEST/subscriptions",
                  method="GET")
        def iter_subs_mock(url, request):
            assert url.path == "/v1/projects/TEST/subscriptions"
            # Return two topics in json format
            return response(
                200,
                '{"subscriptions":[{"name": "/projects/TEST/subscriptions/subscription1",\
                                  "topic": "/projects/TEST/topics/topic1","pushConfig": \
                                  {"pushEndpoint": "","retryPolicy": {}},"ackDeadlineSeconds": 10},\
                                  {"name": "/projects/TEST/subscriptions/subscription2", \
                                  "topic": "/projects/TEST/topics/topic1", \
                                  "pushConfig": {"pushEndpoint": "","retryPolicy": {}},\
                                  "ackDeadlineSeconds": 10}]}', None, None, 5,
                request)

        # Execute ams client with mocked response
        with HTTMock(iter_subs_mock, self.topicmocks.create_topic_mock,
                     self.topicmocks.has_topic_mock):
            topic = self.ams.topic('topic1')
            resp = topic.iter_subs()
            obj1 = next(resp)
            obj2 = next(resp)
            assert isinstance(obj1, AmsSubscription)
            assert isinstance(obj2, AmsSubscription)
            if sys.version_info < (3, ):
                self.assertRaises(StopIteration, resp.next)
            else:
                self.assertRaises(StopIteration, resp.__next__)
            self.assertEqual(obj1.name, 'subscription1')
            self.assertEqual(obj2.name, 'subscription2')

    def testDelete(self):
        # Mock response for DELETE topic request
        @urlmatch(netloc="localhost",
                  path="/v1/projects/TEST/topics/topic1",
                  method="DELETE")
        def delete_topic(url, request):
            return response(200, '{}', None, None, 5, request)

        # Execute ams client with mocked response
        with HTTMock(delete_topic, self.topicmocks.create_topic_mock,
                     self.topicmocks.has_topic_mock):
            topic = self.ams.topic('topic1')
            self.assertTrue(topic.delete())

    def testAcl(self):
        # Mock response for GET topic request
        @urlmatch(netloc="localhost",
                  path="/v1/projects/TEST/topics/topic1:modifyAcl",
                  method="POST")
        def modifyacl_topic_mock(url, request):
            self.assertEqual(url.path,
                             "/v1/projects/TEST/topics/topic1:modifyAcl")
            self.assertEqual(request.body,
                             '{"authorized_users": ["user1", "user2"]}')
            # Return the details of a topic in json format
            return response(200, '{}', None, None, 5, request)

        # Mock response for GET topic request
        @urlmatch(netloc="localhost",
                  path="/v1/projects/TEST/topics/topic1:acl",
                  method="GET")
        def getacl_topic_mock(url, request):
            assert url.path == "/v1/projects/TEST/topics/topic1:acl"
            # Return the details of a topic in json format
            return response(200, '{"authorized_users": ["user1", "user2"]}',
                            None, None, 5, request)

        # Execute ams client with mocked response
        with HTTMock(getacl_topic_mock, self.topicmocks.get_topic_mock,
                     modifyacl_topic_mock):
            topic = self.ams.topic('topic1')
            ret = topic.acl(['user1', 'user2'])
            self.assertTrue(ret)
            resp_users = topic.acl()
            self.assertEqual(resp_users['authorized_users'],
                             ['user1', 'user2'])