Skip to content

Commit

Permalink
Fix disk usage calculations when too large file is created
Browse files Browse the repository at this point in the history
Previously if you created file having larger initial contents than the
free space in the fake filesystem, the disk usage counter was decreased
by the size of the initial contents possibly resulting in negative usage.

Basically the issue was that when ChangeDiskUsage is called with size
larger than the amount of free space, space usage is not changed but
an error is raised. Due to an exception, CreateFile removes the created
object that results in new call to ChangeDiskUsage with negative size
of the object.

Previously the object's size was set before ChangeDiskUsage was called
and then when the object was being removed the object's already set size
was used to reduce the filesystem usage (even though that size was never
added to the usage).
  • Loading branch information
janneronkko committed Feb 2, 2017
1 parent 1ab5e47 commit a125519
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 2 deletions.
16 changes: 16 additions & 0 deletions fake_filesystem_test.py
Expand Up @@ -4203,29 +4203,45 @@ def testFileSystemSizeAfterDirectoryRemoval(self):
self.assertEqual((100, 40, 60), self.filesystem.GetDiskUsage())

def testCreatingFileWithFittingContent(self):
initial_usage = self.filesystem.GetDiskUsage()

try:
self.filesystem.CreateFile('!foo!bar', contents=b'a' * 100)
except IOError:
self.fail('File with contents fitting into disk space could not be written.')

self.assertEqual(initial_usage.used + 100, self.filesystem.GetDiskUsage().used)

def testCreatingFileWithContentTooLarge(self):
def create_large_file():
self.filesystem.CreateFile('!foo!bar', contents=b'a' * 101)

initial_usage = self.filesystem.GetDiskUsage()

self.assertRaises(IOError, create_large_file)

self.assertEqual(initial_usage, self.filesystem.GetDiskUsage())

def testCreatingFileWithFittingSize(self):
initial_usage = self.filesystem.GetDiskUsage()

try:
self.filesystem.CreateFile('!foo!bar', st_size=100)
except IOError:
self.fail('File with size fitting into disk space could not be written.')

self.assertEqual(initial_usage.used + 100, self.filesystem.GetDiskUsage().used)

def testCreatingFileWithSizeTooLarge(self):
initial_usage = self.filesystem.GetDiskUsage()

def create_large_file():
self.filesystem.CreateFile('!foo!bar', st_size=101)

self.assertRaises(IOError, create_large_file)

self.assertEqual(initial_usage, self.filesystem.GetDiskUsage())

def testResizeFileWithFittingSize(self):
file_object = self.filesystem.CreateFile('!foo!bar', st_size=50)
try:
Expand Down
16 changes: 16 additions & 0 deletions fake_filesystem_unittest_test.py
Expand Up @@ -141,6 +141,22 @@ def test_fakepathlib(self):
else:
self.assertTrue(self.fs.Exists('/fake_file.txt'))

def test_disk_usage_on_file_creation(self):
total_size = 100
self.fs.AddMountPoint('mount', total_size)
def create_too_large_file():
with open('/mount/file', 'w') as dest:
dest.write('a' * (total_size + 1))

self.assertRaises(OSError, create_too_large_file)

self.assertEqual(0, self.fs.GetDiskUsage('/mount').used)

with open('/mount/file', 'w') as dest:
dest.write('a' * total_size)

self.assertEqual(total_size, self.fs.GetDiskUsage('/mount').used)

import math as path


Expand Down
4 changes: 2 additions & 2 deletions pyfakefs/fake_filesystem.py
Expand Up @@ -308,10 +308,10 @@ def _SetInitialContents(self, contents, encoding):
if self.byte_contents:
self.SetSize(0)
current_size = self.st_size or 0
if self.filesystem:
self.filesystem.ChangeDiskUsage(st_size - current_size, self.name, self.st_dev)
self.byte_contents = contents
self.st_size = st_size
if self.filesystem:
self.filesystem.ChangeDiskUsage(self.st_size - current_size, self.name, self.st_dev)
self.epoch += 1

def SetContents(self, contents, encoding=None):
Expand Down

0 comments on commit a125519

Please sign in to comment.