Make decorators thread-safe.

Reviewed in https://codereview.appspot.com/9363044/.
diff --git a/tests/test_oauth2client_appengine.py b/tests/test_oauth2client_appengine.py
index b6541ba..b99bd8c 100644
--- a/tests/test_oauth2client_appengine.py
+++ b/tests/test_oauth2client_appengine.py
@@ -441,20 +441,31 @@
 
   def _finish_setup(self, decorator, user_mock):
     self.decorator = decorator
+    self.had_credentials = False
+    self.found_credentials = None
+    self.should_raise = False
+    parent = self
 
     class TestRequiredHandler(webapp2.RequestHandler):
-
       @decorator.oauth_required
       def get(self):
-        pass
+        if decorator.has_credentials():
+          parent.had_credentials = True
+          parent.found_credentials = decorator.credentials
+        if parent.should_raise:
+          raise Exception('')
 
     class TestAwareHandler(webapp2.RequestHandler):
-
       @decorator.oauth_aware
       def get(self, *args, **kwargs):
         self.response.out.write('Hello World!')
         assert(kwargs['year'] == '2012')
         assert(kwargs['month'] == '01')
+        if decorator.has_credentials():
+          parent.had_credentials = True
+          parent.found_credentials = decorator.credentials
+        if parent.should_raise:
+          raise Exception('')
 
 
     application = webapp2.WSGIApplication([
@@ -507,6 +518,9 @@
       response = parse_qs(parts[1])[self.decorator._token_response_param][0]
       self.assertEqual(Http2Mock.content,
                        simplejson.loads(urllib.unquote(response)))
+    self.assertEqual(self.decorator.flow, self.decorator._tls.flow)
+    self.assertEqual(self.decorator.credentials,
+                     self.decorator._tls.credentials)
 
     m.UnsetStubs()
     m.VerifyAll()
@@ -514,15 +528,26 @@
     # Now requesting the decorated path should work.
     response = self.app.get('/foo_path')
     self.assertEqual('200 OK', response.status)
-    self.assertEqual(True, self.decorator.has_credentials())
+    self.assertEqual(True, self.had_credentials)
     self.assertEqual('foo_refresh_token',
-                     self.decorator.credentials.refresh_token)
+                     self.found_credentials.refresh_token)
     self.assertEqual('foo_access_token',
-                     self.decorator.credentials.access_token)
+                     self.found_credentials.access_token)
+    self.assertEqual(None, self.decorator.credentials)
+
+    # Raising an exception still clears the Credentials.
+    self.should_raise = True
+    try:
+      response = self.app.get('/foo_path')
+      self.fail('Should have raised an exception.')
+    except Exception:
+      pass
+    self.assertEqual(None, self.decorator.credentials)
+    self.should_raise = False
 
     # Invalidate the stored Credentials.
-    self.decorator.credentials.invalid = True
-    self.decorator.credentials.store.put(self.decorator.credentials)
+    self.found_credentials.invalid = True
+    self.found_credentials.store.put(self.found_credentials)
 
     # Invalid Credentials should start the OAuth dance again.
     response = self.app.get('/foo_path')
@@ -553,8 +578,13 @@
     # Now requesting the decorated path should work.
     response = self.app.get('/foo_path')
 
+    self.assertTrue(self.had_credentials)
+
+    # Credentials should be cleared after each call.
+    self.assertEqual(None, self.decorator.credentials)
+
     # Invalidate the stored Credentials.
-    self.decorator.credentials.store.delete()
+    self.found_credentials.store.delete()
 
     # Invalid Credentials should start the OAuth dance again.
     response = self.app.get('/foo_path')
@@ -600,11 +630,25 @@
     response = self.app.get('/bar_path/2012/01')
     self.assertEqual('200 OK', response.status)
     self.assertEqual('Hello World!', response.body)
-    self.assertEqual(True, self.decorator.has_credentials())
+    self.assertEqual(True, self.had_credentials)
     self.assertEqual('foo_refresh_token',
-                     self.decorator.credentials.refresh_token)
+                     self.found_credentials.refresh_token)
     self.assertEqual('foo_access_token',
-                     self.decorator.credentials.access_token)
+                     self.found_credentials.access_token)
+
+    # Credentials should be cleared after each call.
+    self.assertEqual(None, self.decorator.credentials)
+
+    # Raising an exception still clears the Credentials.
+    self.should_raise = True
+    try:
+      response = self.app.get('/bar_path/2012/01')
+      self.fail('Should have raised an exception.')
+    except Exception:
+      pass
+    self.assertEqual(None, self.decorator.credentials)
+    self.should_raise = False
+
 
   def test_error_in_step2(self):
     # An initial request to an oauth_aware decorated path should not redirect.
@@ -634,6 +678,7 @@
     self.assertEqual('foo_user_agent', decorator.flow.user_agent)
     self.assertEqual('dummy_revoke_uri', decorator.flow.revoke_uri)
     self.assertEqual(None, decorator.flow.params.get('user_agent', None))
+    self.assertEqual(decorator.flow, decorator._tls.flow)
 
   def test_token_response_param(self):
     self.decorator._token_response_param = 'foobar'