Repository: garnaat/placebo

Issue:
StreamingBody Issue in Record Mode
Today I had the problem with the following code in **record** mode:

``` python
            stdout_key = self._s3.Object(bucket_name='somebucket',
                                         key='{}/stdout'.format(location))
            result_output = stdout_key.get()['Body'].read()
```

No matter what, `result_output` was always `''`.  After some digging, I was able to determine that the stream was already read.

``` python
(Pdb) test = stdout_key.get()['Body']
(Pdb) test._raw_stream.tell()
5
```

Important note: the tests run fine and work as expected when in **playback** mode, and the content of the StreamingBody is saved correctly to the cassette.

My assumption: Placebo is `read()`ing the StreamingBody while in record mode so that it can save it to the cassette.

Is there any way we can still present the results correctly? I'd like to avoid having my tests fail in record mode and then pass during playback mode. :-P


Comments:

Patch:
diff --git a/placebo/serializer.py b/placebo/serializer.py
index 5e87c39..cb18e99 100644
--- a/placebo/serializer.py
+++ b/placebo/serializer.py
@@ -12,10 +12,23 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import datetime
+from datetime import datetime, timedelta, tzinfo
 from botocore.response import StreamingBody
 from six import StringIO
 
+class UTC(tzinfo):
+    """UTC"""
+
+    def utcoffset(self, dt):
+        return timedelta(0)
+
+    def tzname(self, dt):
+        return "UTC"
+
+    def dst(self, dt):
+        return timedelta(0)
+
+utc = UTC()
 
 def deserialize(obj):
     """Convert JSON dicts back into objects."""
@@ -28,7 +41,7 @@ def deserialize(obj):
         module_name = obj.pop('__module__')
     # Use getattr(module, class_name) for custom types if needed
     if class_name == 'datetime':
-        return datetime.datetime(**target)
+        return datetime(tzinfo=utc, **target)
     if class_name == 'StreamingBody':
         return StringIO(target['body'])
     # Return unrecognized structures as-is
@@ -44,7 +57,7 @@ def serialize(obj):
     except AttributeError:
         pass
     # Convert objects to dictionary representation based on type
-    if isinstance(obj, datetime.datetime):
+    if isinstance(obj, datetime):
         result['year'] = obj.year
         result['month'] = obj.month
         result['day'] = obj.day
@@ -55,6 +68,8 @@ def serialize(obj):
         return result
     if isinstance(obj, StreamingBody):
         result['body'] = obj.read()
+        obj._raw_stream = StringIO(result['body'])
+        obj._amount_read = 0
         return result
     # Raise a TypeError if the object isn't recognized
     raise TypeError("Type not serializable")


Test patch:
diff --git a/tests/unit/test_serializers.py b/tests/unit/test_serializers.py
index ff1081c..7dfc55a 100644
--- a/tests/unit/test_serializers.py
+++ b/tests/unit/test_serializers.py
@@ -16,13 +16,13 @@ import datetime
 import unittest
 import json
 
-from placebo.serializer import serialize, deserialize
+from placebo.serializer import serialize, deserialize, utc
 
 
 date_sample = {
     "LoginProfile": {
         "UserName": "baz",
-        "CreateDate": datetime.datetime(2015, 1, 4, 9, 1, 2, 0),
+        "CreateDate": datetime.datetime(2015, 1, 4, 9, 1, 2, 0, tzinfo=utc),
     }
 }