##// END OF EJS Templates
wireprotov2: implement commands as a generator of objects...
wireprotov2: implement commands as a generator of objects Previously, wire protocol version 2 inherited version 1's model of having separate types to represent the results of different wire protocol commands. As I implemented more powerful commands in future commits, I found I was using a common pattern of returning a special type to hold a generator. This meant the command function required a closure to do most of the work. That made logic flow more difficult to follow. I also noticed that many commands were effectively a sequence of objects to be CBOR encoded. I think it makes sense to define version 2 commands as generators. This way, commands can simply emit the data structures they wish to send to the client. This eliminates the need for a closure in command functions and removes encoding from the bodies of commands. As part of this commit, the handling of response objects has been moved into the serverreactor class. This puts the reactor in the driver's seat with regards to CBOR encoding and error handling. Having error handling in the function that emits frames is particularly important because exceptions in that function can lead to things getting in a bad state: I'm fairly certain that uncaught exceptions in the frame generator were causing deadlocks. I also introduced a dedicated error type for explicit error reporting in command handlers. This will be used in subsequent commits. There's still a bit of work to be done here, especially around formalizing the error handling "protocol." I've added yet another TODO to track this so we don't forget. Test output changed because we're using generators and no longer know we are at the end of the data until we hit the end of the generator. This means we can't emit the end-of-stream flag until we've exhausted the generator. Hence the introduction of 0-sized end-of-stream frames. Differential Revision: https://phab.mercurial-scm.org/D4472

File last commit:

r36799:ffa3026d default
r39595:07b58266 default
Show More
test-atomictempfile.py
125 lines | 4.2 KiB | text/x-python | PythonLexer
/ tests / test-atomictempfile.py
Pulkit Goyal
py3: make tests/test-atomictempfile.py use absolute_import
r29194 from __future__ import absolute_import
import glob
Greg Ward
atomictempfile: avoid infinite recursion in __del__()....
r14007 import os
Martijn Pieters
atomictempfile: use a tempdir to keep the test environment clean...
r29391 import shutil
Augie Fackler
cleanup: use stat_result[stat.ST_MTIME] instead of stat_result.st_mtime...
r36799 import stat
Martijn Pieters
atomictempfile: use a tempdir to keep the test environment clean...
r29391 import tempfile
Idan Kamara
test-atomictempfile: convert to unit test
r18666 import unittest
Pulkit Goyal
py3: make tests/test-atomictempfile.py use absolute_import
r29194 from mercurial import (
Pulkit Goyal
py3: use range instead on xrange on py3 in tests/test-atomictempfile.py...
r36299 pycompat,
Pulkit Goyal
py3: make tests/test-atomictempfile.py use absolute_import
r29194 util,
)
atomictempfile = util.atomictempfile
Greg Ward
atomictempfile: avoid infinite recursion in __del__()....
r14007
Pulkit Goyal
py3: use range instead on xrange on py3 in tests/test-atomictempfile.py...
r36299 if pycompat.ispy3:
xrange = range
Idan Kamara
test-atomictempfile: convert to unit test
r18666 class testatomictempfile(unittest.TestCase):
Martijn Pieters
atomictempfile: use a tempdir to keep the test environment clean...
r29391 def setUp(self):
Augie Fackler
tests: add missing b prefixes in test-atomictempfile.py...
r36634 self._testdir = tempfile.mkdtemp(b'atomictempfiletest')
self._filename = os.path.join(self._testdir, b'testfilename')
Martijn Pieters
atomictempfile: use a tempdir to keep the test environment clean...
r29391
def tearDown(self):
shutil.rmtree(self._testdir, True)
Martijn Pieters
atomictempfile: remove test ordering...
r29392 def testsimple(self):
Martijn Pieters
atomictempfile: use a tempdir to keep the test environment clean...
r29391 file = atomictempfile(self._filename)
self.assertFalse(os.path.isfile(self._filename))
tempfilename = file._tempname
self.assertTrue(tempfilename in glob.glob(
Augie Fackler
tests: add missing b prefixes in test-atomictempfile.py...
r36634 os.path.join(self._testdir, b'.testfilename-*')))
Greg Ward
atomictempfile: avoid infinite recursion in __del__()....
r14007
timeless
tests: mark test-atomictempfile.py write as binary
r29188 file.write(b'argh\n')
Idan Kamara
test-atomictempfile: convert to unit test
r18666 file.close()
Greg Ward
atomictempfile: avoid infinite recursion in __del__()....
r14007
Martijn Pieters
atomictempfile: use a tempdir to keep the test environment clean...
r29391 self.assertTrue(os.path.isfile(self._filename))
self.assertTrue(tempfilename not in glob.glob(
Augie Fackler
tests: add missing b prefixes in test-atomictempfile.py...
r36634 os.path.join(self._testdir, b'.testfilename-*')))
Greg Ward
atomictempfile: avoid infinite recursion in __del__()....
r14007
Idan Kamara
test-atomictempfile: convert to unit test
r18666 # discard() removes the temp file without making the write permanent
Martijn Pieters
atomictempfile: remove test ordering...
r29392 def testdiscard(self):
Martijn Pieters
atomictempfile: use a tempdir to keep the test environment clean...
r29391 file = atomictempfile(self._filename)
Idan Kamara
test-atomictempfile: convert to unit test
r18666 (dir, basename) = os.path.split(file._tempname)
Greg Ward
atomictempfile: avoid infinite recursion in __del__()....
r14007
timeless
tests: mark test-atomictempfile.py write as binary
r29188 file.write(b'yo\n')
Idan Kamara
test-atomictempfile: convert to unit test
r18666 file.discard()
Greg Ward
atomictempfile: avoid infinite recursion in __del__()....
r14007
Martijn Pieters
atomictempfile: use a tempdir to keep the test environment clean...
r29391 self.assertFalse(os.path.isfile(self._filename))
Augie Fackler
tests: add missing b prefixes in test-atomictempfile.py...
r36634 self.assertTrue(basename not in os.listdir(b'.'))
Idan Kamara
test-atomictempfile: convert to unit test
r18666
# if a programmer screws up and passes bad args to atomictempfile, they
# get a plain ordinary TypeError, not infinite recursion
Martijn Pieters
atomictempfile: remove test ordering...
r29392 def testoops(self):
Gregory Szorc
tests: use context manager form of assertRaises...
r32279 with self.assertRaises(TypeError):
atomictempfile()
Greg Ward
atomictempfile: avoid infinite recursion in __del__()....
r14007
FUJIWARA Katsunori
util: make atomictempfile avoid ambiguity of file stat if needed...
r29201 # checkambig=True avoids ambiguity of timestamp
Martijn Pieters
atomictempfile: remove test ordering...
r29392 def testcheckambig(self):
FUJIWARA Katsunori
util: make atomictempfile avoid ambiguity of file stat if needed...
r29201 def atomicwrite(checkambig):
Martijn Pieters
atomictempfile: use a tempdir to keep the test environment clean...
r29391 f = atomictempfile(self._filename, checkambig=checkambig)
Augie Fackler
tests: add missing b prefixes in test-atomictempfile.py...
r36634 f.write(b'FOO')
FUJIWARA Katsunori
util: make atomictempfile avoid ambiguity of file stat if needed...
r29201 f.close()
# try some times, because reproduction of ambiguity depends on
# "filesystem time"
for i in xrange(5):
atomicwrite(False)
Martijn Pieters
atomictempfile: use a tempdir to keep the test environment clean...
r29391 oldstat = os.stat(self._filename)
Augie Fackler
cleanup: use stat_result[stat.ST_MTIME] instead of stat_result.st_mtime...
r36799 if oldstat[stat.ST_CTIME] != oldstat[stat.ST_MTIME]:
FUJIWARA Katsunori
util: make atomictempfile avoid ambiguity of file stat if needed...
r29201 # subsequent changing never causes ambiguity
continue
repetition = 3
# repeat atomic write with checkambig=True, to examine
Mads Kiilerich
spelling: fixes of non-dictionary words
r30332 # whether st_mtime is advanced multiple times as expected
FUJIWARA Katsunori
util: make atomictempfile avoid ambiguity of file stat if needed...
r29201 for j in xrange(repetition):
atomicwrite(True)
Martijn Pieters
atomictempfile: use a tempdir to keep the test environment clean...
r29391 newstat = os.stat(self._filename)
Augie Fackler
cleanup: use stat_result[stat.ST_MTIME] instead of stat_result.st_mtime...
r36799 if oldstat[stat.ST_CTIME] != newstat[stat.ST_CTIME]:
FUJIWARA Katsunori
util: make atomictempfile avoid ambiguity of file stat if needed...
r29201 # timestamp ambiguity was naturally avoided while repetition
continue
# st_mtime should be advanced "repetition" times, because
Mads Kiilerich
spelling: fixes of non-dictionary words
r30332 # all atomicwrite() occurred at same time (in sec)
Augie Fackler
cleanup: use stat_result[stat.ST_MTIME] instead of stat_result.st_mtime...
r36799 oldtime = (oldstat[stat.ST_MTIME] + repetition) & 0x7fffffff
self.assertTrue(newstat[stat.ST_MTIME] == oldtime)
FUJIWARA Katsunori
util: make atomictempfile avoid ambiguity of file stat if needed...
r29201 # no more examination is needed, if assumption above is true
break
else:
# This platform seems too slow to examine anti-ambiguity
# of file timestamp (or test happened to be executed at
# bad timing). Exit silently in this case, because running
# on other faster platforms can detect problems
pass
Martijn Pieters
atomictempfile: add read to the supported file operations
r29393 def testread(self):
with open(self._filename, 'wb') as f:
f.write(b'foobar\n')
Augie Fackler
tests: add missing b prefixes in test-atomictempfile.py...
r36634 file = atomictempfile(self._filename, mode=b'rb')
Martijn Pieters
atomictempfile: add read to the supported file operations
r29393 self.assertTrue(file.read(), b'foobar\n')
file.discard()
Martijn Pieters
atomictempfile: add context manager support...
r29394 def testcontextmanagersuccess(self):
"""When the context closes, the file is closed"""
Augie Fackler
tests: add missing b prefixes in test-atomictempfile.py...
r36634 with atomictempfile(b'foo') as f:
self.assertFalse(os.path.isfile(b'foo'))
Martijn Pieters
atomictempfile: add context manager support...
r29394 f.write(b'argh\n')
Augie Fackler
tests: add missing b prefixes in test-atomictempfile.py...
r36634 self.assertTrue(os.path.isfile(b'foo'))
Martijn Pieters
atomictempfile: add context manager support...
r29394
def testcontextmanagerfailure(self):
"""On exception, the file is discarded"""
try:
Augie Fackler
tests: add missing b prefixes in test-atomictempfile.py...
r36634 with atomictempfile(b'foo') as f:
self.assertFalse(os.path.isfile(b'foo'))
Martijn Pieters
atomictempfile: add context manager support...
r29394 f.write(b'argh\n')
raise ValueError
except ValueError:
pass
Augie Fackler
tests: add missing b prefixes in test-atomictempfile.py...
r36634 self.assertFalse(os.path.isfile(b'foo'))
Martijn Pieters
atomictempfile: add context manager support...
r29394
Greg Ward
atomictempfile: avoid infinite recursion in __del__()....
r14007 if __name__ == '__main__':
Pulkit Goyal
py3: make tests/test-atomictempfile.py use absolute_import
r29194 import silenttestrunner
Idan Kamara
test-atomictempfile: convert to unit test
r18666 silenttestrunner.main(__name__)