~divmod-dev/divmod.org/trunk

« back to all changes in this revision

Viewing changes to Epsilon/epsilon/test/test_benchmark.py

  • Committer: Jean-Paul Calderone
  • Date: 2014-06-29 20:33:04 UTC
  • mfrom: (2749.1.1 remove-epsilon-1325289)
  • Revision ID: exarkun@twistedmatrix.com-20140629203304-gdkmbwl1suei4m97
mergeĀ lp:~exarkun/divmod.org/remove-epsilon-1325289

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
from epsilon import hotfix
3
 
hotfix.require('twisted', 'delayedcall_seconds')
4
 
hotfix.require('twisted', 'timeoutmixin_calllater')
5
 
 
6
 
import os, StringIO
7
 
 
8
 
from twisted.trial import unittest
9
 
from twisted.internet import error, base
10
 
from twisted.python import failure, filepath
11
 
 
12
 
from epsilon.scripts import benchmark
13
 
 
14
 
from epsilon import juice
15
 
 
16
 
 
17
 
class DiskstatTestCase(unittest.TestCase):
18
 
    def testDiskLineParser(self):
19
 
        """
20
 
        Test the parsing of a single line into a single diststat instance.
21
 
        """
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)
37
 
 
38
 
 
39
 
    def testPartitionLineParser(self):
40
 
        """
41
 
        Test parsing the other kind of line that can show up in the diskstats
42
 
        file.
43
 
        """
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)
51
 
 
52
 
 
53
 
    def testFileParser(self):
54
 
        """
55
 
        Test the parsing of multiple lines into a dict mapping device names and
56
 
        numbers to diststat instances.
57
 
        """
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))
62
 
        ds.sort()
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)
75
 
 
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)
88
 
 
89
 
 
90
 
    def testCaptureStats(self):
91
 
        """
92
 
        Test that captureStats reads out of /proc/diskstats, if it is
93
 
        available.
94
 
        """
95
 
        stats = benchmark.captureStats()
96
 
        self.failUnless(isinstance(stats, dict), "Expected dictionary, got %r" % (stats,))
97
 
 
98
 
 
99
 
 
100
 
class ReporterTestCase(unittest.TestCase):
101
 
    def testFormatter(self):
102
 
        [msg] = juice.parseString(benchmark.formatResults(
103
 
            "frunk",
104
 
            4096,
105
 
            benchmark.ResourceSnapshot(
106
 
                3,
107
 
                benchmark.diskstat(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
108
 
                benchmark.partitionstat(1, 2, 3, 4),
109
 
                12),
110
 
            benchmark.ResourceSnapshot(
111
 
                7,
112
 
                benchmark.diskstat(11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21),
113
 
                benchmark.partitionstat(5, 7, 9, 11),
114
 
                56), False, False))
115
 
 
116
 
        self.assertEquals(msg['_command'], 'Result')
117
 
 
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')
123
 
 
124
 
        self.assertIn('sector_size', msg)
125
 
        self.assertIn('python_version', msg)
126
 
        self.assertIn('twisted_version', msg)
127
 
        self.assertIn('divmod_version', msg)
128
 
 
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')
137
 
 
138
 
 
139
 
    def testFormatterWithoutDiskStats(self):
140
 
        """
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.
144
 
        """
145
 
        [msg] = juice.parseString(benchmark.formatResults(
146
 
            "frunk",
147
 
            4096,
148
 
            benchmark.ResourceSnapshot(
149
 
                3,
150
 
                None,
151
 
                benchmark.partitionstat(1, 2, 3, 4),
152
 
                12),
153
 
            benchmark.ResourceSnapshot(
154
 
                7,
155
 
                None,
156
 
                benchmark.partitionstat(5, 7, 9, 11),
157
 
                56), False, False))
158
 
 
159
 
        self.assertEquals(msg['_command'], 'Result')
160
 
 
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')
166
 
 
167
 
        self.assertIn('sector_size', msg)
168
 
        self.assertIn('python_version', msg)
169
 
        self.assertIn('twisted_version', msg)
170
 
        self.assertIn('divmod_version', msg)
171
 
 
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')
178
 
 
179
 
        self.failIfIn('read_ms', msg)
180
 
        self.failIfIn('write_ms', msg)
181
 
 
182
 
 
183
 
    def testFormatterWithoutPartitionStats(self):
184
 
        """
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.
188
 
        """
189
 
        [msg] = juice.parseString(benchmark.formatResults(
190
 
            "frunk",
191
 
            4096,
192
 
            benchmark.ResourceSnapshot(
193
 
                3,
194
 
                benchmark.diskstat(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
195
 
                None,
196
 
                12),
197
 
            benchmark.ResourceSnapshot(
198
 
                7,
199
 
                benchmark.diskstat(11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21),
200
 
                None,
201
 
                56), False, False))
202
 
 
203
 
        self.assertEquals(msg['_command'], 'Result')
204
 
 
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')
210
 
 
211
 
        self.assertIn('sector_size', msg)
212
 
        self.assertIn('python_version', msg)
213
 
        self.assertIn('twisted_version', msg)
214
 
        self.assertIn('divmod_version', msg)
215
 
 
216
 
        self.assertEquals(msg['elapsed'], '4')
217
 
        self.assertEquals(msg['filesystem_growth'], '44')
218
 
 
219
 
        self.failIfIn('read_count', msg)
220
 
        self.failIfIn('read_sectors', msg)
221
 
        self.failIfIn('write_count', msg)
222
 
        self.failIfIn('write_sectors', msg)
223
 
 
224
 
        self.assertEquals(msg['read_ms'], '10')
225
 
        self.assertEquals(msg['write_ms'], '10')
226
 
 
227
 
 
228
 
    def testGetSize(self):
229
 
        path = self.mktemp()
230
 
        os.makedirs(path)
231
 
        fObj = file(os.path.join(path, 'foo'), 'wb')
232
 
        fObj.write('x' * 10)
233
 
        fObj.close()
234
 
        self.assertEquals(
235
 
            benchmark.getSize(filepath.FilePath(path)),
236
 
            os.path.getsize(path) + os.path.getsize(os.path.join(path, 'foo')))
237
 
 
238
 
 
239
 
    def test_getOneSizeBrokenSymlink(self):
240
 
        """
241
 
        Test that a broken symlink inside a directory passed to getOneSize doesn't
242
 
        cause it to freak out.
243
 
        """
244
 
        path = filepath.FilePath(self.mktemp())
245
 
        path.makedirs()
246
 
        link = path.child('foo')
247
 
        os.symlink('abcdefg', link.path)
248
 
        self.assertEquals(
249
 
            benchmark.getOneSize(link),
250
 
            len('abcdefg'))
251
 
 
252
 
 
253
 
 
254
 
class MockSpawnProcess(object):
255
 
    """
256
 
    A fake partial ITransport implementation for use in testing
257
 
    ProcessProtocols.
258
 
    """
259
 
 
260
 
    killed = False
261
 
 
262
 
    def __init__(self, proto, executable, args, path, env, childFDs):
263
 
        self.proto = proto
264
 
        self.executable = executable
265
 
        self.args = args
266
 
        self.path = path
267
 
        self.env = env
268
 
        self.childFDs = childFDs
269
 
        self.signals = []
270
 
 
271
 
 
272
 
    def signalProcess(self, signal):
273
 
        self.signals.append(signal)
274
 
        if signal == 'KILL':
275
 
            self.killed = True
276
 
            self.proto.processEnded(failure.Failure(error.ProcessTerminated()))
277
 
 
278
 
 
279
 
 
280
 
class SpawnMixin:
281
 
 
282
 
    def setUp(self):
283
 
        mock = []
284
 
        def spawnProcess(*a, **kw):
285
 
            mock.append(MockSpawnProcess(*a, **kw))
286
 
            return mock[0]
287
 
        self.workingDirectory = self.mktemp()
288
 
        os.makedirs(self.workingDirectory)
289
 
        self.spawnDeferred = self.processProtocol.spawn(
290
 
            'executable', ['args'], self.workingDirectory, {'env': 'stuff'},
291
 
            spawnProcess)
292
 
        self.mock = mock[0]
293
 
 
294
 
        self.sched = []
295
 
        self.currentTime = 0
296
 
 
297
 
        def seconds():
298
 
            return self.currentTime
299
 
 
300
 
        def canceller(c):
301
 
            self.sched.remove(c)
302
 
 
303
 
        def resetter(c):
304
 
            self.sched.sort(key=lambda d: d.getTime())
305
 
 
306
 
        def callLater(n, f, *a, **kw):
307
 
            c = base.DelayedCall(self.currentTime + n, f, a, kw, canceller, resetter, seconds)
308
 
            self.sched.append(c)
309
 
            return c
310
 
 
311
 
        self.mock.proto.callLater = callLater
312
 
        self.mock.proto.makeConnection(self.mock)
313
 
 
314
 
 
315
 
 
316
 
class BasicProcessTestCase(SpawnMixin, unittest.TestCase):
317
 
    processProtocol = benchmark.BasicProcess
318
 
 
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'})
324
 
 
325
 
 
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')
330
 
 
331
 
        def cbProcessFinished((proto, status, output)):
332
 
            self.assertIdentical(proto, self.mock.proto)
333
 
            self.assertEquals(status, 0)
334
 
            self.assertEquals(
335
 
                output,
336
 
                [(1, 'stdout bytes'),
337
 
                 (2, 'stderr 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
342
 
 
343
 
 
344
 
    def testTimeout(self):
345
 
        """
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.
348
 
        """
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)
352
 
 
353
 
        def cbTimedOut(ign):
354
 
            self.assertEquals(self.mock.signals, ['KILL'])
355
 
 
356
 
        d = self.assertFailure(self.spawnDeferred, error.TimeoutError)
357
 
        d.addCallback(cbTimedOut)
358
 
        return d
359
 
 
360
 
 
361
 
    def testTimeoutExtended(self):
362
 
        """
363
 
        Assert that input or connection-lost events reset the timeout.
364
 
        """
365
 
        self.currentTime = 1
366
 
        self.mock.proto.childDataReceived(1, 'bytes')
367
 
        self.assertEquals(len(self.sched), 1)
368
 
        self.assertEquals(self.sched[0].getTime(), 901.0)
369
 
 
370
 
        self.currentTime = 2
371
 
        self.mock.proto.childConnectionLost(1)
372
 
        self.assertEquals(len(self.sched), 1)
373
 
        self.assertEquals(self.sched[0].getTime(), 902.0)
374
 
 
375
 
 
376
 
    def testProcessKilled(self):
377
 
        """
378
 
        Assert that the spawn call's Deferred fails appropriately if someone
379
 
        else gets involved and kills the child process.
380
 
        """
381
 
        def cbKilled(exc):
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')])
386
 
 
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)
391
 
        return d
392
 
 
393
 
 
394
 
 
395
 
class SnapshotTestCase(unittest.TestCase):
396
 
    def testStart(self):
397
 
        c = benchmark.Change()
398
 
        c.start(filepath.FilePath('.'), 'hda', 'hda1')
399
 
        self.failUnless(isinstance(c.before, benchmark.ResourceSnapshot))
400
 
 
401
 
 
402
 
    def testStop(self):
403
 
        c = benchmark.Change()
404
 
        c.stop(filepath.FilePath('.'), 'hda', 'hda1')
405
 
        self.failUnless(isinstance(c.after, benchmark.ResourceSnapshot))
406
 
 
407
 
 
408
 
 
409
 
class BenchmarkProcessTestCase(SpawnMixin, unittest.TestCase):
410
 
 
411
 
    processProtocol = benchmark.BenchmarkProcess
412
 
 
413
 
    def testProcessStartTimingCommand(self):
414
 
        started = []
415
 
        p = self.mock.proto
416
 
        p.startTiming = lambda: started.append(None)
417
 
        self.mock.proto.childDataReceived(p.BACKCHANNEL_OUT, p.START)
418
 
        self.assertEquals(started, [None])
419
 
 
420
 
 
421
 
    def testProcessStopTimingCommand(self):
422
 
        stopped = []
423
 
        p = self.mock.proto
424
 
        p.stopTiming = lambda: stopped.append(None)
425
 
        self.mock.proto.childDataReceived(p.BACKCHANNEL_OUT, p.STOP)
426
 
        self.assertEquals(stopped, [None])