# # Copyright 2008 The ndb Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Tests for blobstore.py.""" import cgi import cStringIO import datetime import pickle from .google_imports import namespace_manager from .google_imports import datastore_types from .google_test_imports import unittest from . import blobstore from . import model from . import tasklets from . import test_utils class BlobstoreTests(test_utils.NDBTest): def setUp(self): super(BlobstoreTests, self).setUp() self.testbed.init_blobstore_stub() the_module = blobstore def testConstants(self): # This intentionally hardcodes the values. I'd like to know when # they change. self.assertEqual(blobstore.BLOB_INFO_KIND, '__BlobInfo__') self.assertEqual(blobstore.BLOB_MIGRATION_KIND, '__BlobMigration__') self.assertEqual(blobstore.BLOB_KEY_HEADER, 'X-AppEngine-BlobKey') self.assertEqual(blobstore.BLOB_RANGE_HEADER, 'X-AppEngine-BlobRange') self.assertEqual(blobstore.UPLOAD_INFO_CREATION_HEADER, 'X-AppEngine-Upload-Creation') self.assertEqual(blobstore.MAX_BLOB_FETCH_SIZE, 1015808) def testExceptions(self): self.assertTrue(issubclass(blobstore.Error, Exception)) self.assertTrue(issubclass(blobstore.InternalError, blobstore.Error)) self.assertTrue(issubclass(blobstore.BlobFetchSizeTooLargeError, blobstore.Error)) self.assertTrue(issubclass(blobstore.BlobNotFoundError, blobstore.Error)) self.assertTrue(issubclass(blobstore.DataIndexOutOfRangeError, blobstore.Error)) self.assertTrue(issubclass(blobstore.PermissionDeniedError, blobstore.Error)) self.assertTrue(issubclass(blobstore.BlobInfoParseError, blobstore.Error)) def create_blobinfo(self, blobkey): """Handcraft a dummy BlobInfo.""" b = blobstore.BlobInfo(key=model.Key(blobstore.BLOB_INFO_KIND, blobkey), content_type='text/plain', creation=datetime.datetime(2012, 1, 24, 8, 15, 0), filename='hello.txt', size=42, md5_hash='xxx') model.Model._put_async(b).check_success() return b def testBlobInfo(self): b = self.create_blobinfo('dummy') self.assertEqual(b._get_kind(), blobstore.BLOB_INFO_KIND) self.assertEqual(b.key(), blobstore.BlobKey('dummy')) self.assertEqual(b.content_type, 'text/plain') self.assertEqual(b.creation, datetime.datetime(2012, 1, 24, 8, 15, 0)) self.assertEqual(b.filename, 'hello.txt') self.assertEqual(b.md5_hash, 'xxx') def testBlobInfo_PutErrors(self): b = self.create_blobinfo('dummy') self.assertRaises(Exception, b.put) self.assertRaises(Exception, b.put_async) self.assertRaises(Exception, model.put_multi, [b]) self.assertRaises(Exception, model.put_multi_async, [b]) def testBlobInfo_Get(self): b = self.create_blobinfo('dummy') c = blobstore.BlobInfo.get(b.key()) self.assertEqual(c, b) self.assertTrue(c is not b) c = blobstore.BlobInfo.get('dummy') self.assertEqual(c, b) self.assertTrue(c is not b) def testBlobInfo_GetAsync(self): b = self.create_blobinfo('dummy') cf = blobstore.BlobInfo.get_async(b.key()) self.assertTrue(isinstance(cf, tasklets.Future)) c = cf.get_result() self.assertEqual(c, b) self.assertTrue(c is not b) df = blobstore.BlobInfo.get_async(str(b.key())) self.assertTrue(isinstance(df, tasklets.Future)) d = df.get_result() self.assertEqual(d, b) self.assertTrue(d is not b) def testBlobInfo_GetMulti(self): b = self.create_blobinfo('b') c = self.create_blobinfo('c') d, e = blobstore.BlobInfo.get_multi([b.key(), str(c.key())]) self.assertEqual(d, b) self.assertEqual(e, c) def testBlobInfo_GetMultiAsync(self): b = self.create_blobinfo('b') c = self.create_blobinfo('c') df, ef = blobstore.BlobInfo.get_multi_async([str(b.key()), c.key()]) self.assertTrue(isinstance(df, tasklets.Future)) self.assertTrue(isinstance(ef, tasklets.Future)) d, e = df.get_result(), ef.get_result() self.assertEqual(d, b) self.assertEqual(e, c) def testBlobInfo_Delete(self): b = self.create_blobinfo('dummy') c = blobstore.get(b._key.id()) self.assertEqual(c, b) b.delete() d = blobstore.get(b.key()) self.assertEqual(d, None) def testBlobInfo_DeleteAsync(self): b = self.create_blobinfo('dummy') df = b.delete_async() self.assertTrue(isinstance(df, tasklets.Future), df) df.get_result() d = blobstore.get(b.key()) self.assertEqual(d, None) def testBlobstore_Get(self): b = self.create_blobinfo('dummy') c = blobstore.get(b.key()) self.assertEqual(c, b) self.assertTrue(c is not b) c = blobstore.get('dummy') self.assertEqual(c, b) self.assertTrue(c is not b) def testBlobstore_GetAsync(self): b = self.create_blobinfo('dummy') cf = blobstore.get_async(b.key()) self.assertTrue(isinstance(cf, tasklets.Future)) c = cf.get_result() self.assertEqual(c, b) self.assertTrue(c is not b) cf = blobstore.get_async('dummy') c = cf.get_result() self.assertEqual(c, b) self.assertTrue(c is not b) def testBlobstore_Delete(self): b = self.create_blobinfo('dummy') blobstore.delete(b.key()) d = blobstore.get(b.key()) self.assertEqual(d, None) def testBlobstore_DeleteAsync(self): b = self.create_blobinfo('dummy') df = blobstore.delete_async(b.key()) self.assertTrue(isinstance(df, tasklets.Future), df) df.get_result() d = blobstore.get(b.key()) self.assertEqual(d, None) def testBlobstore_DeleteMulti(self): b = self.create_blobinfo('b') c = self.create_blobinfo('c') blobstore.delete_multi([b.key(), str(c.key())]) d, e = blobstore.get_multi([b.key(), str(c.key())]) self.assertEqual(d, None) self.assertEqual(e, None) def testBlobstore_DeleteMultiAsync(self): b = self.create_blobinfo('b') c = self.create_blobinfo('c') f = blobstore.delete_multi_async([b.key(), str(c.key())]) self.assertTrue(isinstance(f, tasklets.Future), f) f.get_result() d, e = blobstore.get_multi([b.key(), str(c.key())]) self.assertEqual(d, None) self.assertEqual(e, None) def testBlobstore_CreateUploadUrl(self): url = blobstore.create_upload_url('/foo') self.assertTrue('/_ah/upload/' in url, url) def testBlobstore_CreateUploadUrlAsync(self): urlf = blobstore.create_upload_url_async('/foo') self.assertTrue(isinstance(urlf, tasklets.Future), urlf) url = urlf.get_result() self.assertTrue('/_ah/upload/' in url, url) def testBlobstore_ParseBlobInfo_Errors(self): nope = blobstore.parse_blob_info(None) self.assertEqual(nope, None) env = {'REQUEST_METHOD': 'POST'} hdrs = {'content-disposition': 'blah; filename=hello.txt; name=hello', 'content-type': 'text/plain; blob-key=xxx'} fd = cStringIO.StringIO( 'Content-length: 42\n' 'X-AppEngine-Upload-Creation: 2012-01-24 17:35:00.000000\n' 'Content-MD5: eHh4\n' '\n' ) fs = cgi.FieldStorage(fd, headers=hdrs, environ=env) self.assertRaises(blobstore.BlobInfoParseError, blobstore.parse_blob_info, fs) fd = cStringIO.StringIO( 'Content-type: image/jpeg\n' 'Content-length: hello\n' 'X-AppEngine-Upload-Creation: 2012-01-24 17:35:00.000000\n' 'Content-MD5: eHh4\n' '\n' ) fs = cgi.FieldStorage(fd, headers=hdrs, environ=env) self.assertRaises(blobstore.BlobInfoParseError, blobstore.parse_blob_info, fs) fd = cStringIO.StringIO( 'Content-type: image/jpeg\n' 'Content-length: 42\n' 'X-AppEngine-Upload-Creation: BLAH-01-24 17:35:00.000000\n' 'Content-MD5: eHh4\n' '\n' ) fs = cgi.FieldStorage(fd, headers=hdrs, environ=env) self.assertRaises(blobstore.BlobInfoParseError, blobstore.parse_blob_info, fs) def testBlobstore_ParseBlobInfo(self): env = {'REQUEST_METHOD': 'POST'} hdrs = {'content-disposition': 'blah; filename=hello.txt; name=hello', 'content-type': 'text/plain; blob-key=xxx'} fd = cStringIO.StringIO( 'Content-type: image/jpeg\n' 'Content-length: 42\n' 'X-AppEngine-Upload-Creation: 2012-01-24 17:35:00.000000\n' 'Content-MD5: eHh4\n' '\n' ) fs = cgi.FieldStorage(fd, headers=hdrs, environ=env) bi = blobstore.parse_blob_info(fs) self.assertTrue(isinstance(bi, blobstore.BlobInfo)) self.assertEqual( bi, blobstore.BlobInfo(key=model.Key(blobstore.BlobInfo, 'xxx'), content_type='image/jpeg', creation=datetime.datetime(2012, 1, 24, 17, 35), filename='hello.txt', md5_hash='xxx', size=42)) def testBlobstore_FetchData(self): self.create_blobinfo('xxx') stub = self.testbed.get_stub('blobstore') storage = stub.storage storage._blobs['xxx'] = 'abcde' result = blobstore.fetch_data('xxx', 0, 3) # Range is inclusive! self.assertEqual(result, 'abcd') def testBlobstore_FetchDataAsync(self): b = self.create_blobinfo('xxx') stub = self.testbed.get_stub('blobstore') storage = stub.storage storage._blobs['xxx'] = 'abcde' fut = blobstore.fetch_data_async(b, 0, 2) self.assertTrue(isinstance(fut, tasklets.Future), fut) result = fut.get_result() self.assertEqual(result, 'abc') def testBlobInfo_Open(self): b = self.create_blobinfo('xxx') stub = self.testbed.get_stub('blobstore') storage = stub.storage storage._blobs['xxx'] = 'abcde' f = b.open() self.assertEqual(f.read(3), 'abc') self.assertEqual(f.read(3), 'de') self.assertEqual(f.blob_info, b) def testBlobReader(self): b = self.create_blobinfo('xxx') stub = self.testbed.get_stub('blobstore') storage = stub.storage storage._blobs['xxx'] = 'abcde' f = blobstore.BlobReader('xxx') self.assertEqual(f.read(), 'abcde') self.assertEqual(f.blob_info, b) if __name__ == '__main__': unittest.main()