Repository: googleapis/google-cloud-python

Issue:
Pubsub message getting wrong attribute for publishTime
According the [REST docs](https://cloud.google.com/pubsub/docs/reference/rest/v1/PubsubMessage), a `PubsubMessage` has the field `publishTime`

In [message.py](https://github.com/GoogleCloudPlatform/google-cloud-python/blob/master/pubsub/google/cloud/pubsub/message.py), `from_api_repr` is getting the field `publishTimestamp` below:

```
instance._service_timestamp = api_repr.get('publishTimestamp')
```

The current tests are self-confirming of this issue as they simply set up the api_repr with `publishTimestamp`

A quick fix seems to adjust the following:
**message.py**

``` python
    @classmethod
    def from_api_repr(cls, api_repr):
        """Factory:  construct message from API representation.

        :type api_repr: dict or None
        :param api_repr: The API representation of the message

        :rtype: :class:`Message`
        :returns: The message created from the response.
        """
        data = base64.b64decode(api_repr.get('data', b''))
        instance = cls(
            data=data, message_id=api_repr['messageId'],
            attributes=api_repr.get('attributes'))
        instance._service_timestamp = api_repr.get('publishTime')
        return instance
```

**test_message.py**

``` python
    def test_from_api_repr_no_attributes(self):
        from base64 import b64encode as b64
        DATA = b'DEADBEEF'
        B64_DATA = b64(DATA)
        MESSAGE_ID = '12345'
        TIMESTAMP = '2016-03-18-19:38:22.001393427Z'
        api_repr = {
            'data': B64_DATA,
            'messageId': MESSAGE_ID,
            'publishTime': TIMESTAMP,
        }
        message = self._getTargetClass().from_api_repr(api_repr)
        self.assertEqual(message.data, DATA)
        self.assertEqual(message.message_id, MESSAGE_ID)
        self.assertEqual(message.attributes, {})
        self.assertEqual(message.service_timestamp, TIMESTAMP)

    def test_from_api_repr_w_attributes(self):
        from base64 import b64encode as b64
        DATA = b'DEADBEEF'
        B64_DATA = b64(DATA)
        MESSAGE_ID = '12345'
        ATTRS = {'a': 'b'}
        TIMESTAMP = '2016-03-18-19:38:22.001393427Z'
        api_repr = {
            'data': B64_DATA,
            'messageId': MESSAGE_ID,
            'publishTime': TIMESTAMP,
            'attributes': ATTRS,
        }
        message = self._getTargetClass().from_api_repr(api_repr)
        self.assertEqual(message.data, DATA)
        self.assertEqual(message.message_id, MESSAGE_ID)
        self.assertEqual(message.service_timestamp, TIMESTAMP)
        self.assertEqual(message.attributes, ATTRS)
```

I don't currently have a contributor license signed, but will work on that.  In the meantime, hoping that someone can pick this up.



Discussion:
See #1623 and #2243 for previous iterations on the server-side timestamp feature.


Resolving patch:
diff --git a/pubsub/google/cloud/pubsub/message.py b/pubsub/google/cloud/pubsub/message.py
--- a/pubsub/google/cloud/pubsub/message.py
+++ b/pubsub/google/cloud/pubsub/message.py
@@ -89,5 +89,5 @@ def from_api_repr(cls, api_repr):
         instance = cls(
             data=data, message_id=api_repr['messageId'],
             attributes=api_repr.get('attributes'))
-        instance._service_timestamp = api_repr.get('publishTimestamp')
+        instance._service_timestamp = api_repr.get('publishTime')
         return instance


Test patch:
diff --git a/pubsub/unit_tests/test_message.py b/pubsub/unit_tests/test_message.py
--- a/pubsub/unit_tests/test_message.py
+++ b/pubsub/unit_tests/test_message.py
@@ -98,7 +98,7 @@ def test_from_api_repr_no_attributes(self):
         api_repr = {
             'data': B64_DATA,
             'messageId': MESSAGE_ID,
-            'publishTimestamp': TIMESTAMP,
+            'publishTime': TIMESTAMP,
         }
         message = self._getTargetClass().from_api_repr(api_repr)
         self.assertEqual(message.data, DATA)
@@ -116,7 +116,7 @@ def test_from_api_repr_w_attributes(self):
         api_repr = {
             'data': B64_DATA,
             'messageId': MESSAGE_ID,
-            'publishTimestamp': TIMESTAMP,
+            'publishTime': TIMESTAMP,
             'attributes': ATTRS,
         }
         message = self._getTargetClass().from_api_repr(api_repr)
diff --git a/system_tests/pubsub.py b/system_tests/pubsub.py
--- a/system_tests/pubsub.py
+++ b/system_tests/pubsub.py
@@ -198,10 +198,14 @@ def suction(self):
 
         message1, message2 = sorted(hoover.received,
                                     key=operator.attrgetter('timestamp'))
+
         self.assertEqual(message1.data, MESSAGE_1)
         self.assertEqual(message1.attributes['extra'], EXTRA_1)
+        self.assertIsNotNone(message1.service_timestamp)
+
         self.assertEqual(message2.data, MESSAGE_2)
         self.assertEqual(message2.attributes['extra'], EXTRA_2)
+        self.assertIsNotNone(message2.service_timestamp)
 
     def _maybe_emulator_skip(self):
         # NOTE: This method is necessary because ``Config.IN_EMULATOR``