2
from epsilon import hotfix
3
hotfix.require('twisted', 'delayedcall_seconds')
4
hotfix.require('twisted', 'timeoutmixin_calllater')
8
from twisted.trial import unittest
9
from twisted.internet import error, base
10
from twisted.python import failure, filepath
12
from epsilon.scripts import benchmark
14
from epsilon import juice
17
class DiskstatTestCase(unittest.TestCase):
18
def testDiskLineParser(self):
20
Test the parsing of a single line into a single diststat instance.
22
s = ("3 0 hda 267481 3913 3944418 1625467 3392405 3781877 58210592 "
23
"150845143 0 6136300 153333793")
24
device, stat = benchmark.parseDiskStatLine(s)
25
self.assertEquals(device, 'hda')
26
self.assertEquals(stat.readCount, 267481)
27
self.assertEquals(stat.mergedReadCount, 3913)
28
self.assertEquals(stat.readSectorCount, 3944418)
29
self.assertEquals(stat.readMilliseconds, 1625467)
30
self.assertEquals(stat.writeCount, 3392405)
31
self.assertEquals(stat.mergedWriteCount, 3781877)
32
self.assertEquals(stat.writeSectorCount, 58210592)
33
self.assertEquals(stat.writeMilliseconds, 150845143)
34
self.assertEquals(stat.outstandingIOCount, 0)
35
self.assertEquals(stat.ioMilliseconds, 6136300)
36
self.assertEquals(stat.weightedIOMilliseconds, 153333793)
39
def testPartitionLineParser(self):
41
Test parsing the other kind of line that can show up in the diskstats
44
s = "3 1 hda1 2 5 7 9"
45
device, stat = benchmark.parseDiskStatLine(s)
46
self.assertEquals(device, 'hda1')
47
self.assertEquals(stat.readCount, 2)
48
self.assertEquals(stat.readSectorCount, 5)
49
self.assertEquals(stat.writeCount, 7)
50
self.assertEquals(stat.writeSectorCount, 9)
53
def testFileParser(self):
55
Test the parsing of multiple lines into a dict mapping device names and
56
numbers to diststat instances.
58
s = StringIO.StringIO(
59
"1 2 abc 3 4 5 6 7 8 9 10 11 12 13\n"
60
"14 15 def 16 17 18 19 20 21 22 23 24 25 26\n")
61
ds = list(benchmark.parseDiskStats(s))
63
self.assertEquals(ds[0][0], "abc")
64
self.assertEquals(ds[0][1].readCount, 3)
65
self.assertEquals(ds[0][1].mergedReadCount, 4)
66
self.assertEquals(ds[0][1].readSectorCount, 5)
67
self.assertEquals(ds[0][1].readMilliseconds, 6)
68
self.assertEquals(ds[0][1].writeCount, 7)
69
self.assertEquals(ds[0][1].mergedWriteCount, 8)
70
self.assertEquals(ds[0][1].writeSectorCount, 9)
71
self.assertEquals(ds[0][1].writeMilliseconds, 10)
72
self.assertEquals(ds[0][1].outstandingIOCount, 11)
73
self.assertEquals(ds[0][1].ioMilliseconds, 12)
74
self.assertEquals(ds[0][1].weightedIOMilliseconds, 13)
76
self.assertEquals(ds[1][0], "def")
77
self.assertEquals(ds[1][1].readCount, 16)
78
self.assertEquals(ds[1][1].mergedReadCount, 17)
79
self.assertEquals(ds[1][1].readSectorCount, 18)
80
self.assertEquals(ds[1][1].readMilliseconds, 19)
81
self.assertEquals(ds[1][1].writeCount, 20)
82
self.assertEquals(ds[1][1].mergedWriteCount, 21)
83
self.assertEquals(ds[1][1].writeSectorCount, 22)
84
self.assertEquals(ds[1][1].writeMilliseconds, 23)
85
self.assertEquals(ds[1][1].outstandingIOCount, 24)
86
self.assertEquals(ds[1][1].ioMilliseconds, 25)
87
self.assertEquals(ds[1][1].weightedIOMilliseconds, 26)
90
def testCaptureStats(self):
92
Test that captureStats reads out of /proc/diskstats, if it is
95
stats = benchmark.captureStats()
96
self.failUnless(isinstance(stats, dict), "Expected dictionary, got %r" % (stats,))
100
class ReporterTestCase(unittest.TestCase):
101
def testFormatter(self):
102
[msg] = juice.parseString(benchmark.formatResults(
105
benchmark.ResourceSnapshot(
107
benchmark.diskstat(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
108
benchmark.partitionstat(1, 2, 3, 4),
110
benchmark.ResourceSnapshot(
112
benchmark.diskstat(11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21),
113
benchmark.partitionstat(5, 7, 9, 11),
116
self.assertEquals(msg['_command'], 'Result')
118
self.assertEquals(msg['version'], '0')
119
self.assertEquals(msg['error'], 'False')
120
self.assertEquals(msg['timeout'], 'False')
121
self.assertEquals(msg['name'], 'frunk')
122
self.failIfEqual(msg['host'], 'localhost')
124
self.assertIn('sector_size', msg)
125
self.assertIn('python_version', msg)
126
self.assertIn('twisted_version', msg)
127
self.assertIn('divmod_version', msg)
129
self.assertEquals(msg['elapsed'], '4')
130
self.assertEquals(msg['filesystem_growth'], '44')
131
self.assertEquals(msg['read_count'], '4')
132
self.assertEquals(msg['read_sectors'], '5')
133
self.assertEquals(msg['write_count'], '6')
134
self.assertEquals(msg['write_sectors'], '7')
135
self.assertEquals(msg['read_ms'], '10')
136
self.assertEquals(msg['write_ms'], '10')
139
def testFormatterWithoutDiskStats(self):
141
Sometimes it is not possible to find diskstats. In these cases, None
142
should be reported as the value for all fields which are derived from
143
the diskstats object.
145
[msg] = juice.parseString(benchmark.formatResults(
148
benchmark.ResourceSnapshot(
151
benchmark.partitionstat(1, 2, 3, 4),
153
benchmark.ResourceSnapshot(
156
benchmark.partitionstat(5, 7, 9, 11),
159
self.assertEquals(msg['_command'], 'Result')
161
self.assertEquals(msg['version'], '0')
162
self.assertEquals(msg['error'], 'False')
163
self.assertEquals(msg['timeout'], 'False')
164
self.assertEquals(msg['name'], 'frunk')
165
self.failIfEqual(msg['host'], 'localhost')
167
self.assertIn('sector_size', msg)
168
self.assertIn('python_version', msg)
169
self.assertIn('twisted_version', msg)
170
self.assertIn('divmod_version', msg)
172
self.assertEquals(msg['elapsed'], '4')
173
self.assertEquals(msg['filesystem_growth'], '44')
174
self.assertEquals(msg['read_count'], '4')
175
self.assertEquals(msg['read_sectors'], '5')
176
self.assertEquals(msg['write_count'], '6')
177
self.assertEquals(msg['write_sectors'], '7')
179
self.failIfIn('read_ms', msg)
180
self.failIfIn('write_ms', msg)
183
def testFormatterWithoutPartitionStats(self):
185
Sometimes it is not possible to find partitionstats. In these cases,
186
None should be reported as the value for all fields which are derived
187
from the partitionstats object.
189
[msg] = juice.parseString(benchmark.formatResults(
192
benchmark.ResourceSnapshot(
194
benchmark.diskstat(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
197
benchmark.ResourceSnapshot(
199
benchmark.diskstat(11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21),
203
self.assertEquals(msg['_command'], 'Result')
205
self.assertEquals(msg['version'], '0')
206
self.assertEquals(msg['error'], 'False')
207
self.assertEquals(msg['timeout'], 'False')
208
self.assertEquals(msg['name'], 'frunk')
209
self.failIfEqual(msg['host'], 'localhost')
211
self.assertIn('sector_size', msg)
212
self.assertIn('python_version', msg)
213
self.assertIn('twisted_version', msg)
214
self.assertIn('divmod_version', msg)
216
self.assertEquals(msg['elapsed'], '4')
217
self.assertEquals(msg['filesystem_growth'], '44')
219
self.failIfIn('read_count', msg)
220
self.failIfIn('read_sectors', msg)
221
self.failIfIn('write_count', msg)
222
self.failIfIn('write_sectors', msg)
224
self.assertEquals(msg['read_ms'], '10')
225
self.assertEquals(msg['write_ms'], '10')
228
def testGetSize(self):
231
fObj = file(os.path.join(path, 'foo'), 'wb')
235
benchmark.getSize(filepath.FilePath(path)),
236
os.path.getsize(path) + os.path.getsize(os.path.join(path, 'foo')))
239
def test_getOneSizeBrokenSymlink(self):
241
Test that a broken symlink inside a directory passed to getOneSize doesn't
242
cause it to freak out.
244
path = filepath.FilePath(self.mktemp())
246
link = path.child('foo')
247
os.symlink('abcdefg', link.path)
249
benchmark.getOneSize(link),
254
class MockSpawnProcess(object):
256
A fake partial ITransport implementation for use in testing
262
def __init__(self, proto, executable, args, path, env, childFDs):
264
self.executable = executable
268
self.childFDs = childFDs
272
def signalProcess(self, signal):
273
self.signals.append(signal)
276
self.proto.processEnded(failure.Failure(error.ProcessTerminated()))
284
def spawnProcess(*a, **kw):
285
mock.append(MockSpawnProcess(*a, **kw))
287
self.workingDirectory = self.mktemp()
288
os.makedirs(self.workingDirectory)
289
self.spawnDeferred = self.processProtocol.spawn(
290
'executable', ['args'], self.workingDirectory, {'env': 'stuff'},
298
return self.currentTime
304
self.sched.sort(key=lambda d: d.getTime())
306
def callLater(n, f, *a, **kw):
307
c = base.DelayedCall(self.currentTime + n, f, a, kw, canceller, resetter, seconds)
311
self.mock.proto.callLater = callLater
312
self.mock.proto.makeConnection(self.mock)
316
class BasicProcessTestCase(SpawnMixin, unittest.TestCase):
317
processProtocol = benchmark.BasicProcess
319
def testCorrectArgs(self):
320
self.assertEquals(self.mock.executable, 'executable')
321
self.assertEquals(self.mock.args, ['executable', 'args'])
322
self.assertEquals(self.mock.path, self.workingDirectory)
323
self.assertEquals(self.mock.env, {'env': 'stuff'})
326
def testChildDataReceived(self):
327
self.mock.proto.childDataReceived(1, 'stdout bytes')
328
self.mock.proto.childDataReceived(2, 'stderr bytes')
329
self.mock.proto.childDataReceived(1, 'more stdout bytes')
331
def cbProcessFinished((proto, status, output)):
332
self.assertIdentical(proto, self.mock.proto)
333
self.assertEquals(status, 0)
336
[(1, 'stdout bytes'),
338
(1, 'more stdout bytes')])
339
self.spawnDeferred.addCallback(cbProcessFinished)
340
self.mock.proto.processEnded(failure.Failure(error.ProcessDone(0)))
341
return self.spawnDeferred
344
def testTimeout(self):
346
Assert that a timeout call is created as soon as the process is started
347
and that if it expires, the spawn call's Deferred fails.
349
self.assertEquals(len(self.sched), 1)
350
self.assertEquals(self.sched[0].getTime(), 900.0)
351
self.sched[0].func(*self.sched[0].args, **self.sched[0].kw)
354
self.assertEquals(self.mock.signals, ['KILL'])
356
d = self.assertFailure(self.spawnDeferred, error.TimeoutError)
357
d.addCallback(cbTimedOut)
361
def testTimeoutExtended(self):
363
Assert that input or connection-lost events reset the timeout.
366
self.mock.proto.childDataReceived(1, 'bytes')
367
self.assertEquals(len(self.sched), 1)
368
self.assertEquals(self.sched[0].getTime(), 901.0)
371
self.mock.proto.childConnectionLost(1)
372
self.assertEquals(len(self.sched), 1)
373
self.assertEquals(self.sched[0].getTime(), 902.0)
376
def testProcessKilled(self):
378
Assert that the spawn call's Deferred fails appropriately if someone
379
else gets involved and kills the child process.
382
self.assertEquals(exc.exitCode, 1)
383
self.assertEquals(exc.signal, 2)
384
self.assertEquals(exc.status, 3)
385
self.assertEquals(exc.output, [(1, 'bytes')])
387
self.mock.proto.childDataReceived(1, 'bytes')
388
self.mock.proto.processEnded(failure.Failure(error.ProcessTerminated(1, 2, 3)))
389
d = self.assertFailure(self.spawnDeferred, benchmark.ProcessDied)
390
d.addCallback(cbKilled)
395
class SnapshotTestCase(unittest.TestCase):
397
c = benchmark.Change()
398
c.start(filepath.FilePath('.'), 'hda', 'hda1')
399
self.failUnless(isinstance(c.before, benchmark.ResourceSnapshot))
403
c = benchmark.Change()
404
c.stop(filepath.FilePath('.'), 'hda', 'hda1')
405
self.failUnless(isinstance(c.after, benchmark.ResourceSnapshot))
409
class BenchmarkProcessTestCase(SpawnMixin, unittest.TestCase):
411
processProtocol = benchmark.BenchmarkProcess
413
def testProcessStartTimingCommand(self):
416
p.startTiming = lambda: started.append(None)
417
self.mock.proto.childDataReceived(p.BACKCHANNEL_OUT, p.START)
418
self.assertEquals(started, [None])
421
def testProcessStopTimingCommand(self):
424
p.stopTiming = lambda: stopped.append(None)
425
self.mock.proto.childDataReceived(p.BACKCHANNEL_OUT, p.STOP)
426
self.assertEquals(stopped, [None])