Skip to content

Commit

Permalink
create: unlink new file on any IOError types
Browse files Browse the repository at this point in the history
  • Loading branch information
jraby committed Jan 12, 2015
1 parent b9c9ae2 commit c21cdb8
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 12 deletions.
28 changes: 19 additions & 9 deletions test_whisper.py
Expand Up @@ -187,45 +187,55 @@ def test_aggregate(self):
with AssertRaisesException(whisper.InvalidAggregationMethod('Unrecognized aggregation method derp')):
whisper.aggregate('derp', [12, 2, 3123, 1])

def _test_create_IOError(self, ioerror_method='write', e=errno.ENOSPC):
def _test_create_exception(self, exception_method='write', e=None):
"""
Behaviour when creating a whisper file on a full filesystem
"""
m_open = mock_open()
# Get the mocked file object and override interresting attributes
m_file = m_open.return_value
m_file.name = self.filename
method = getattr(m_file, ioerror_method)
method.side_effect = IOError(e, "Mocked IOError - ENOSPC")
method = getattr(m_file, exception_method)

if not e:
e = IOError(errno.ENOSPC, "Mocked IOError")
method.side_effect = e

with patch('whisper.open', m_open, create=True):
with patch('os.unlink') as m_unlink:
self.assertRaises(IOError, whisper.create, self.filename, self.retention)
self.assertRaises(e.__class__, whisper.create, self.filename, self.retention)

return (m_file, m_unlink)

def test_create_write_ENOSPC(self):
"""
Behaviour when creating a whisper file on a full filesystem (write)
"""
(m_file, m_unlink) = self._test_create_IOError('write')
(m_file, m_unlink) = self._test_create_exception('write')
m_unlink.assert_called_with(self.filename)

def test_create_close_ENOSPC(self):
"""
Behaviour when creating a whisper file on a full filesystem (close)
"""
(m_file, m_unlink) = self._test_create_IOError('close')
(m_file, m_unlink) = self._test_create_exception('close')
m_unlink.assert_called_with(self.filename)

def test_create_close_EIO(self):
"""
Behaviour when creating a whisper file and getting an I/O error
Behaviour when creating a whisper file and getting an I/O error (EIO)
"""
(m_file, m_unlink) = self._test_create_exception('close', e=IOError(errno.EIO))
self.assertTrue(m_unlink.called)

def test_create_close_exception(self):
"""
Behaviour when creating a whisper file and getting a generic exception
"""
(m_file, m_unlink) = self._test_create_IOError('close', e=errno.EIO)
(m_file, m_unlink) = self._test_create_exception('close', e=Exception("boom!"))
# Must not call os.unlink on exception other than IOError
self.assertFalse(m_unlink.called)


def test_create_and_info(self):
"""
Create a db and use info() to validate
Expand Down
6 changes: 3 additions & 3 deletions whisper.py
Expand Up @@ -420,9 +420,9 @@ def create(path,archiveList,xFilesFactor=None,aggregationMethod=None,sparse=Fals
# Explicitly close the file to catch IOError on close()
fh.close()
except IOError, e:
# Cleanup after ourself if there's no space left on device
if e.errno == ENOSPC:
os.unlink(fh.name)
# if we got an IOError above, the file is either empty or half created.
# Better off deleting it to avoid surprises later
os.unlink(fh.name)
raise


Expand Down

0 comments on commit c21cdb8

Please sign in to comment.