#!/usr/bin/env python
from __future__ import with_statement
import os
import time
import stat
import errno
import datetime
import mock
import unittest2 as unittest
import zope.interface
import atom.data
import gdata.blogger.data
import gdata.blogger.client
try:
import rst2atom
from docutils.core import publish_string
except ImportError:
rst2atom = None
from pkg_resources import resource_string
from bloggerfs import bloggerfs
TEST_REMOTE = os.environ.get('BLOGGERFS_TEST_REMOTE', False)
def read(filename):
fn = os.path.join(os.path.dirname(os.path.abspath(__file__)), filename)
with open(fn) as fp:
return fp.read()
class TestUtils(unittest.TestCase):
def test_getType(self):
obj = object()
self.assertEqual(stat.S_IFREG, bloggerfs.getType(obj))
d = bloggerfs.DirNode(None, None, None)
self.assertEqual(stat.S_IFDIR, bloggerfs.getType(d))
def test_dirEntry(self):
de1 = bloggerfs.DirEntry('test', type=stat.S_IFDIR)
de2 = bloggerfs.DirEntry('test2', type=stat.S_IFDIR)
self.failIfEqual(de1, de2)
de2.name = 'test'
self.assertEqual(de1, de2)
self.assertFalse(de1 == object())
self.assertFalse(de1 != de2)
def test_timeoutmixin(self):
class Test(bloggerfs.TimeOutMixin, bloggerfs.DirNode):
def __init__(self, a, b, c):
super(Test, self).__init__(a, b, c)
self._fake_children = {}
def getChildren(self):
return self._fake_children
m = Test(None, None, None)
self.assertEqual(m.children, {})
di = {'test': 'asdf'}
m._fake_children = di
self.assertEqual(m.children, {})
m._tick = m._tick - datetime.timedelta(seconds=m.seconds + 1)
self.assertEqual(m.children, di)
class PublishedStub:
zope.interface.implements(bloggerfs.IPublished)
def __init__(self, time):
self.published = time
class UpdatedStub:
zope.interface.implements(bloggerfs.IUpdated)
def __init__(self, time):
self.updated = time
class TestUpdatedPublished(unittest.TestCase):
def setUp(self):
self.t = time.time()
self.pstub = PublishedStub(self.t)
self.ustub = UpdatedStub(self.t)
def test_publishedInterface(self):
self.assertEqual(bloggerfs.IPublished(self.pstub).published, self.t)
self.failUnlessRaises(TypeError, bloggerfs.IPublished, self.ustub)
def test_publishedHierarchy(self):
node = bloggerfs.Node(None, self.pstub, None)
self.assertEqual(bloggerfs.IPublished(node).published, self.t)
def test_updatedInterface(self):
self.assertEqual(bloggerfs.IUpdated(self.ustub).updated, self.t)
self.failUnlessRaises(TypeError, bloggerfs.IUpdated, self.pstub)
def test_updatedHierarchy(self):
node = bloggerfs.Node(None, self.ustub, None)
self.assertEqual(bloggerfs.IUpdated(node).updated, self.t)
class TestNodeBase(unittest.TestCase):
def setUp(self):
self.parentCtx = self.getParentCtx()
self.parent = self.getParent(self.parentCtx)
self.nodeCtx = self.getNodeCtx()
self.node = self.getNode(self.nodeCtx, self.parent)
def getParent(self, ctx):
return bloggerfs.Node(ctx, None, None)
def getNode(self, ctx, parent):
return bloggerfs.Node(ctx, parent, None)
def getNodeCtx(self):
return object()
getParentCtx = getNodeCtx
class TestNode(TestNodeBase):
def test_locate(self):
self.failUnlessRaises(NotImplementedError, self.node.locate, [])
def test_time(self):
self.assertEqual(0, self.node.mtime)
self.assertEqual(0, self.node.ctime)
class TestFileNode(TestNodeBase):
def getParent(self, ctx, parent=None):
return bloggerfs.FileNode(ctx, parent, None)
getNode = getParent
def getParentCtx(self):
return 'parent'
def getNodeCtx(self):
return 'node'
def test_locate(self):
for node in self.parent, self.node:
self.assertEqual(node, node.locate([]))
self.failUnlessRaises(AssertionError, node.locate, ['1234'])
def test_textProperty(self):
for node, text in ((self.parent, self.getParentCtx()),
(self.node, self.getNodeCtx())):
self.assertEqual(text, node.text)
def test_getattr(self):
for node, text in ((self.parent, self.getParentCtx()),
(self.node, self.getNodeCtx())):
st = node.getattr()
self.assertEqual(st.st_mode, stat.S_IFREG | 0440)
self.assertEqual(st.st_size, len(text))
self.assertEqual(st.st_ctime, 0)
self.assertEqual(st.st_mtime, 0)
def test_read(self):
self.assertEqual('node', self.node.read(1024, 0))
self.assertEqual('nod', self.node.read(3, 0))
self.assertEqual('ode', self.node.read(1024, 1))
def test_write(self):
self.failUnlessRaises(IOError, self.node.write, 'asdf', 0)
@unittest.expectedFailure
def test_adaptation(self):
s = 'node'
node = bloggerfs.IFileNode(s)
self.assertTrue(isinstance(node, bloggerfs.FileNode),
'Adaptetion error, unexpected class returned')
self.node = node
self.test_read()
self.test_write()
class TestTextNode(TestNodeBase):
def getParent(self, ctx, parent=None):
return bloggerfs.TextNode(ctx, parent, None)
getNode = getParent
def getParentCtx(self):
return atom.data.Text('parent')
def getNodeCtx(self):
return atom.data.Text('node')
@unittest.expectedFailure
def test_textProperty(self):
self.assertEqual(self.node.text, 'node')
self.assertEqual(self.parent.text, 'parent')
node = bloggerfs.INode(atom.data.Text())
self.assertEqual('', node.text)
def getTextClasses(self):
from atom.data import (Text, Date, Id, Draft, Name, Email, Uri)
return Text, Date, Id, Draft, Name, Email, Uri
@unittest.expectedFailure
def test_adapters(self):
s = 'test'
for klass in self.getTextClasses():
obj = klass(s)
node = bloggerfs.IFileNode(obj)
self.assertEqual(s, node.text)
class UpdatedPublishedStub(bloggerfs.DirNode):
zope.interface.implements(bloggerfs.IPublished, bloggerfs.IUpdated,
bloggerfs.INode)
published = time.time()
updated = time.time()
def getChildren(self):
return {'test': self}
class MockDirNode(bloggerfs.DirNode):
def getChildren(self):
self.getChildren.called = 1
return bloggerfs.DirNode.getChildren()
class TestDirNode(unittest.TestCase):
def getNode(self, ctx, parent):
pass
def setUp(self):
self.node = UpdatedPublishedStub(None, None, None)
self.ln = bloggerfs.ListNode(['a', ['b', 'c']], self.node, None)
def test_readdir1(self):
dir1 = list(self.node.readdir(0))
self.assertEqual(len(dir1), 3)
dir2 = [bloggerfs.DirEntry('.', type=stat.S_IFDIR),
bloggerfs.DirEntry('..', type=stat.S_IFDIR),
bloggerfs.DirEntry('test', type=stat.S_IFDIR)]
self.assertEqual(dir1, dir2)
def test_readdir2(self):
c = bloggerfs.DirEntry('.', type=stat.S_IFDIR)
p = bloggerfs.DirEntry('..', type=stat.S_IFDIR)
d = bloggerfs.DirEntry('0', type=stat.S_IFREG)
f = bloggerfs.DirEntry('1', type=stat.S_IFDIR)
dir1 = list(self.ln.readdir(0))
self.assertEqual(len(dir1), 4)
dir2 = [c, p, f, d]
self.assertEqual(dir1, dir2)
def test_getattr(self):
st = self.node.getattr()
self.assertEqual(st.st_mode, stat.S_IFDIR | 0550)
def test_getChild(self):
self.failUnlessRaises(IOError, self.node.getChild, 'qwerty')
self.assertEqual(self.node.getChild('test'), self.node)
def test_locate(self):
self.assertEqual(self.node, self.node.locate([]))
self.failUnlessRaises(IOError, self.node.locate, ['non exists'])
self.assertEqual(self.node.locate(['test']), self.node)
def test_rmdir(self):
self.failUnlessRaises(IOError, self.node.rmdir)
class FakePostNode:
def __init__(self):
self.children = {}
self.original = gdata.blogger.data.BlogPost()
def addPost(self, post):
self.children['posts'] = post
def get_blog_id(self):
return '123'
def get_post_id(self):
return '456'
@property
def blogId(self):
return self.get_blog_id()
# class MockClient(gdata.blogger.client.BloggerClient):
# buggy = False
# def __init__(self):
# self.requests = {}
# def request(self, method=None, **kwargs):
# if self.buggy:
# raise gdata.client.RequestError('buggybuggybuggy')
# li = self.requests.setdefault(method, [])
# li.append(kwargs)
# def get_posts(self, blog_id, auth_token=None,
# desired_class=gdata.blogger.data.BlogPostFeed, query=None,
# **kwargs):
# feed = read('postfeed.xml')
# return desired_class(feed)
class TestClientBase(unittest.TestCase):
def setUp(self):
self.client = gdata.blogger.client.BloggerClient()
self.client.request = self.mock = mock.Mock()
# self.client = bloggerfs.client = MockClient()
# def get_request(self, method):
# self.assertTrue(method in self.client.requests)
# reqs = self.client.requests[method]
# self.assertEqual(1, len(reqs))
# return reqs[0]
def el_to_string(self, el):
return el.to_string(gdata.client.get_xml_version('2'))
# class TestAdd(TestClientBase):
# def setUp(self):
# TestClientBase.setUp(self)
# self.addcomment = AddCommentNode('', FakePostNode())
# self.addhtmlcomment = AddHtmlCommentNode('', FakePostNode())
# self.addlabel = AddLabelNode('', FakePostNode())
# def test_writeOnly(self):
# for node in self.addcomment, self.addlabel:
# self.assertEqual(node.mode, 0220)
# self.failUnlessRaises(IOError, node.read, 10, 0)
# def test_addComment(self):
# s = '1234'
# self.addcomment.write(s, 0)
# req = self.get_request('POST')
# c = gdata.blogger.data.Comment(
# content=atom.data.Content(text=s, type='text'))
# self.assertEqual(req['http_request']._body_parts[0],
# self.el_to_string(c))
# def test_addHtmlComment(self):
# s = 'hello <b>world</b>'
# self.addhtmlcomment.write(s, 0)
# req = self.get_request('POST')
# c = gdata.blogger.data.Comment(
# content=atom.data.Content(text=s, type='html'))
# self.assertEqual(req['http_request']._body_parts[0],
# self.el_to_string(c))
# def test_addLabel(self):
# s = 'label'
# self.addlabel.write(s, 0)
# req = self.get_request('PUT')
# def test_requestError(self):
# self.client.buggy = True
# for method in self.test_addComment, self.test_addLabel:
# self.failUnlessRaises(IOError, method)
class BaseClient(unittest.TestCase):
def setUp(self):
self.client = gdata.blogger.client.BloggerClient()
self.client.request = self.requests = mock.Mock()
self.feed = gdata.blogger.data.BlogFeed()
self.client.get_posts = self.pmock = mock.Mock(return_value=self.feed)
self.commentfeed = gdata.blogger.data.CommentFeed()
self.client.get_post_comments = self.cmock = \
mock.Mock(return_value=self.commentfeed)
class TestAddPost(BaseClient):
def setUp(self):
BaseClient.setUp(self)
# self.client = gdata.blogger.client.BloggerClient()
# self.client.request = self.mock = mock.Mock()
# blogfeed = gdata.blogger.data.BlogFeed()
# self.client.get_posts = mock.Mock(return_value=blogfeed)
self.blogfeed = atom.core.parse(read('blogfeed.xml'),
gdata.blogger.data.BlogFeed, 2)
self.blog = self.blogfeed.entry[0]
node = bloggerfs.BlogNode(self.blog, None, self.client)
self.addpostnode = bloggerfs.AddPostNode('', node, self.client)
self.postfeed = atom.core.parse(read('postfeed.xml'),
gdata.blogger.data.BlogPostFeed, 2)
def write(self, node, s, offset=0):
node.open(os.O_WRONLY)
node.write(s, offset)
node.flush()
node.release(None)
def test_invalidxml(self):
xml = '<b>xml not well formed</i>'
with self.assertRaises(IOError) as e:
self.write(self.addpostnode, xml)
self.assertTrue('SyntaxError' in e.exception.strerror)
def test_write(self):
entry = self.postfeed.entry[0]
self.assertIsInstance(entry, gdata.blogger.data.BlogPost)
s = entry.to_string()
self.write(self.addpostnode, s)
request = self.client.request
self.assertTrue(request.called)
args, kwds = request.call_args
self.assertSequenceEqual(args, ())
uri = 'http://www.blogger.com/feeds/6453341579591288887/posts/default'
klass = gdata.blogger.data.BlogPost
self.assertDictContainsSubset(dict(method='POST', uri=uri,
auth_token=None, converter=None,
desired_class=klass), kwds)
@unittest.skipIf(rst2atom is None, "rst2atom not installed")
def test_atom2rst(self):
source = resource_string(__name__, 'simple.txt')
feed = publish_string(source, writer_name='rst2atom',
settings_overrides={'output_encoding': 'utf8'})
element = atom.core.parse(feed, gdata.blogger.data.BlogFeed, 2)
self.assertIsInstance(element, gdata.blogger.data.BlogFeed)
entry = element.entry[0]
self.write(self.addpostnode, entry.to_string(2))
request = self.client.request
self.assertTrue(request.called)
args, kwds = request.call_args
self.assertSequenceEqual(args, ())
uri = 'http://www.blogger.com/feeds/6453341579591288887/posts/default'
klass = gdata.blogger.data.BlogPost
self.assertDictContainsSubset(dict(method='POST', uri=uri,
auth_token=None, converter=None,
desired_class=klass), kwds)
@unittest.expectedFailure
def test_writeoffset(self):
node = self.addpostnode
node.open(os.O_WRONLY)
node.write('123', 0)
node.write('45', 0)
node.flush()
node.release(None)
def test_flushing0bytes(self):
node = self.addpostnode
node.open(os.O_WRONLY)
node.flush() # flushing 0 bytes should not raise Exception
class TestPostNode(BaseClient):
def setUp(self):
BaseClient.setUp(self)
self.post = gdata.blogger.data.BlogPost()
self.post.get_post_id = self.post.get_blog_id = \
mock.Mock(return_value='123')
self.node = bloggerfs.PostNode(self.post, None, self.client)
def test_addLabelFlush0bytes(self):
add_label = self.node.children['add_label']
add_label.open(os.O_WRONLY)
add_label.flush() # flushing 0 bytes
add_label.release(0)
self.assertEqual(1, len(self.post.category))
self.assertIsNone(self.post.category[0].text)
def test_addCommentFlush0bytes(self):
add_text_comment = self.node.children['add_comment']
add_html_comment = self.node.children['add_html_comment']
for add_comment in add_text_comment, add_html_comment:
add_comment.open(os.O_WRONLY)
add_comment.flush() # flushing 0 bytes
add_comment.release(0)
args, kwds = self.requests.call_args
self.assertSequenceEqual(args, ())
uri = 'http://www.blogger.com/feeds/123/123/comments/default'
klass = gdata.blogger.data.Comment
self.assertDictContainsSubset(dict(method='POST', uri=uri,
auth_token=None, converter=None,
desired_class=klass), kwds)
def test_attributes(self):
self.assertIn('add_label', self.node.children)
self.assertIn('add_html_comment', self.node.children)
self.assertIn('add_comment', self.node.children)
class TestFeedEntryNode(unittest.TestCase):
def setUp(self):
feed = read('feed.xml')
self.blogfeed = atom.core.parse(feed, gdata.blogger.data.BlogFeed)
self.fe = bloggerfs.FeedEntryNode(self.blogfeed, None, None)
def test_children(self):
self.fe.stale = False
children = ['category', 'updated', 'generator', 'author', 'text',
'title', 'etag', 'link', 'contributor', 'entry', 'id']
self.assertEqual(children, self.fe.children.keys())
self.fe.stale = True
self.failUnlessRaises(NotImplementedError, lambda: self.fe.children)
class TestWriteOnlyMixin(unittest.TestCase):
def setUp(self):
self.mixin = bloggerfs.WriteOnlyMixin()
self.m = mock.Mock()
self.mixin._sio = self.m
def test_open(self):
for mode in os.O_RDWR, os.O_RDONLY:
with self.assertRaises(IOError):
self.mixin.open(mode)
self.mixin.open(os.O_WRONLY)
self.assertTrue(self.mixin._sio is not None)
def test_read(self):
with self.assertRaises(IOError):
self.mixin.read(1, 0)
def test__flush(self):
with self.assertRaises(NotImplementedError):
self.mixin._flush()
def test_write(self):
self.mixin.write('123', 0)
self.mixin.write('456', 3)
calls = [('seek', (0,), {}), ('write', ('123',), {}),
('seek', (3,), {}), ('write', ('456',), {})]
self.assertListEqual(calls, self.m.method_calls)
def test_release(self):
self.mixin.release(None)
self.assertTrue(self.m.close.called)
def test_flush(self):
side_effects = [
IOError(errno.EIO, 'Input/Output error'),
gdata.client.RequestError(),
Exception(),
]
self.mixin._flush = self.m
for side_effect in side_effects:
self.m.side_effect=side_effect
with self.assertRaises(IOError):
self.mixin.flush()
if __name__ == '__main__':
unittest.main()
|