1 | Sat Feb 20 13:07:13 PST 2010 Kevan Carstensen <kevan@isnotajoke.com> |
---|
2 | * Change OphandleTable to use a deterministic clock, so we can test it |
---|
3 | |
---|
4 | To test the changes for #577, we need a deterministic way to simulate |
---|
5 | the passage of long periods of time. twisted.internet.task.Clock seems, |
---|
6 | from my Googling, to be the way to go for this functionality. I changed |
---|
7 | a few things so that OphandleTable would use twisted.internet.task.Clock |
---|
8 | when testing: |
---|
9 | |
---|
10 | * WebishServer.__init___ now takes an optional 'clock' parameter, |
---|
11 | * which it passes to the root.Root instance it creates. |
---|
12 | * root.Root.__init__ now takes an optional 'clock' parameter, which it |
---|
13 | passes to the OphandleTable.__init__ method. |
---|
14 | * OphandleTable.__init__ now takes an optional 'clock' parameter. If |
---|
15 | it is provided, and it isn't None, its callLater method will be used |
---|
16 | to schedule ophandle expirations (as opposed to using |
---|
17 | reactor.callLater, which is what OphandleTable does normally). |
---|
18 | * The WebMixin object in test_web.py now sets a self.clock parameter, |
---|
19 | which is a twisted.internet.task.Clock that it feeds to the |
---|
20 | WebishServer it creates. |
---|
21 | |
---|
22 | Tests using the WebMixin can control the passage of time in |
---|
23 | OphandleTable by accessing self.clock. |
---|
24 | |
---|
25 | New patches: |
---|
26 | |
---|
27 | [Change OphandleTable to use a deterministic clock, so we can test it |
---|
28 | Kevan Carstensen <kevan@isnotajoke.com>**20100220210713 |
---|
29 | Ignore-this: a7437f4eda359bdfa243bd534f23bf52 |
---|
30 | |
---|
31 | To test the changes for #577, we need a deterministic way to simulate |
---|
32 | the passage of long periods of time. twisted.internet.task.Clock seems, |
---|
33 | from my Googling, to be the way to go for this functionality. I changed |
---|
34 | a few things so that OphandleTable would use twisted.internet.task.Clock |
---|
35 | when testing: |
---|
36 | |
---|
37 | * WebishServer.__init___ now takes an optional 'clock' parameter, |
---|
38 | * which it passes to the root.Root instance it creates. |
---|
39 | * root.Root.__init__ now takes an optional 'clock' parameter, which it |
---|
40 | passes to the OphandleTable.__init__ method. |
---|
41 | * OphandleTable.__init__ now takes an optional 'clock' parameter. If |
---|
42 | it is provided, and it isn't None, its callLater method will be used |
---|
43 | to schedule ophandle expirations (as opposed to using |
---|
44 | reactor.callLater, which is what OphandleTable does normally). |
---|
45 | * The WebMixin object in test_web.py now sets a self.clock parameter, |
---|
46 | which is a twisted.internet.task.Clock that it feeds to the |
---|
47 | WebishServer it creates. |
---|
48 | |
---|
49 | Tests using the WebMixin can control the passage of time in |
---|
50 | OphandleTable by accessing self.clock. |
---|
51 | ] { |
---|
52 | hunk ./src/allmydata/test/test_web.py 7 |
---|
53 | from twisted.application import service |
---|
54 | from twisted.trial import unittest |
---|
55 | from twisted.internet import defer, reactor |
---|
56 | +from twisted.internet.task import Clock |
---|
57 | from twisted.web import client, error, http |
---|
58 | from twisted.python import failure, log |
---|
59 | from nevow import rend |
---|
60 | hunk ./src/allmydata/test/test_web.py 123 |
---|
61 | self.s = FakeClient() |
---|
62 | self.s.startService() |
---|
63 | self.staticdir = self.mktemp() |
---|
64 | - self.ws = webish.WebishServer(self.s, "0", staticdir=self.staticdir) |
---|
65 | + self.clock = Clock() |
---|
66 | + self.ws = webish.WebishServer(self.s, "0", staticdir=self.staticdir, |
---|
67 | + clock=self.clock) |
---|
68 | self.ws.setServiceParent(self.s) |
---|
69 | self.webish_port = port = self.ws.listener._port.getHost().port |
---|
70 | self.webish_url = "http://localhost:%d" % port |
---|
71 | hunk ./src/allmydata/test/test_web.py 2871 |
---|
72 | self.failUnless("finished" in data, res) |
---|
73 | d.addCallback(_check1) |
---|
74 | # the retain-for=0 will cause the handle to be expired very soon |
---|
75 | - d.addCallback(self.stall, 2.0) |
---|
76 | + d.addCallback(lambda ign: |
---|
77 | + self.clock.advance(2.0)) |
---|
78 | d.addCallback(lambda ignored: |
---|
79 | self.shouldHTTPError("test_ophandle_retainfor", |
---|
80 | 404, "404 Not Found", |
---|
81 | hunk ./src/allmydata/web/operations.py 26 |
---|
82 | UNCOLLECTED_HANDLE_LIFETIME = 1*HOUR |
---|
83 | COLLECTED_HANDLE_LIFETIME = 10*MINUTE |
---|
84 | |
---|
85 | - def __init__(self): |
---|
86 | + def __init__(self, clock=None): |
---|
87 | # both of these are indexed by ophandle |
---|
88 | self.handles = {} # tuple of (monitor, renderer, when_added) |
---|
89 | self.timers = {} |
---|
90 | hunk ./src/allmydata/web/operations.py 30 |
---|
91 | + # The tests will provide a deterministic clock |
---|
92 | + # (twisted.internet.task.Clock) that they can control so that |
---|
93 | + # they can test ophandle expiration. If this is provided, I'll |
---|
94 | + # use it schedule the expiration of ophandles. |
---|
95 | + self.clock = clock |
---|
96 | |
---|
97 | def stopService(self): |
---|
98 | for t in self.timers.values(): |
---|
99 | hunk ./src/allmydata/web/operations.py 110 |
---|
100 | def _set_timer(self, ophandle, when): |
---|
101 | if ophandle in self.timers and self.timers[ophandle].active(): |
---|
102 | self.timers[ophandle].cancel() |
---|
103 | - t = reactor.callLater(when, self._release_ophandle, ophandle) |
---|
104 | + if self.clock: |
---|
105 | + t = self.clock.callLater(when, self._release_ophandle, ophandle) |
---|
106 | + else: |
---|
107 | + t = reactor.callLater(when, self._release_ophandle, ophandle) |
---|
108 | self.timers[ophandle] = t |
---|
109 | |
---|
110 | def _release_ophandle(self, ophandle): |
---|
111 | hunk ./src/allmydata/web/root.py 148 |
---|
112 | addSlash = True |
---|
113 | docFactory = getxmlfile("welcome.xhtml") |
---|
114 | |
---|
115 | - def __init__(self, client): |
---|
116 | + def __init__(self, client, clock=None): |
---|
117 | rend.Page.__init__(self, client) |
---|
118 | self.client = client |
---|
119 | hunk ./src/allmydata/web/root.py 151 |
---|
120 | - self.child_operations = operations.OphandleTable() |
---|
121 | + # If set, clock is a twisted.internet.task.Clock that the tests |
---|
122 | + # use to test ophandle expiration. |
---|
123 | + self.child_operations = operations.OphandleTable(clock) |
---|
124 | try: |
---|
125 | s = client.getServiceNamed("storage") |
---|
126 | except KeyError: |
---|
127 | hunk ./src/allmydata/webish.py 124 |
---|
128 | class WebishServer(service.MultiService): |
---|
129 | name = "webish" |
---|
130 | |
---|
131 | - def __init__(self, client, webport, nodeurl_path=None, staticdir=None): |
---|
132 | + def __init__(self, client, webport, nodeurl_path=None, staticdir=None, |
---|
133 | + clock=None): |
---|
134 | service.MultiService.__init__(self) |
---|
135 | # the 'data' argument to all render() methods default to the Client |
---|
136 | hunk ./src/allmydata/webish.py 128 |
---|
137 | - self.root = root.Root(client) |
---|
138 | + # the 'clock' argument to root.Root is, if set, a |
---|
139 | + # twisted.internet.task.Clock that is provided by the unit tests |
---|
140 | + # so that they can test features that involve the passage of |
---|
141 | + # time in a deterministic manner. |
---|
142 | + self.root = root.Root(client, clock) |
---|
143 | self.buildServer(webport, nodeurl_path, staticdir) |
---|
144 | if self.root.child_operations: |
---|
145 | self.site.remember(self.root.child_operations, IOpHandleTable) |
---|
146 | } |
---|
147 | |
---|
148 | Context: |
---|
149 | |
---|
150 | [setup: comment-out the dependency on pycrypto, see #953 |
---|
151 | zooko@zooko.com**20100215050844 |
---|
152 | Ignore-this: 2751120921ff35b8189d8fcd896da149 |
---|
153 | ] |
---|
154 | [web/storage.py: display total-seen on the last-complete-cycle line. For #940. |
---|
155 | Brian Warner <warner@lothar.com>**20100208002010 |
---|
156 | Ignore-this: c0ed860f3e9628d3171d2b055d96c5aa |
---|
157 | ] |
---|
158 | [Add tests for #939 |
---|
159 | Kevan Carstensen <kevan@isnotajoke.com>**20100212062137 |
---|
160 | Ignore-this: 5459e8c64ba76cca70aa720e68549637 |
---|
161 | ] |
---|
162 | [Alter CLI utilities to handle nonexistent aliases better |
---|
163 | Kevan Carstensen <kevan@isnotajoke.com>**20100211024318 |
---|
164 | Ignore-this: e698ea4a57f5fe27c24336581ca0cf65 |
---|
165 | ] |
---|
166 | [adding pycrypto to the auto dependencies |
---|
167 | secorp@allmydata.com**20100206054314 |
---|
168 | Ignore-this: b873fc00a6a5b001d30d479e6053cf2f |
---|
169 | ] |
---|
170 | [docs running.html - "tahoe run ." does not work with the current installation, replaced with "tahoe start ." |
---|
171 | secorp@allmydata.com**20100206165320 |
---|
172 | Ignore-this: fdb2dcb0e417d303cd43b1951a4f8c03 |
---|
173 | ] |
---|
174 | [code coverage: replace figleaf with coverage.py, should work on py2.6 now. |
---|
175 | Brian Warner <warner@lothar.com>**20100203165421 |
---|
176 | Ignore-this: 46ab590360be6a385cb4fc4e68b6b42c |
---|
177 | |
---|
178 | It still lacks the right HTML report (the builtin report is very pretty, but |
---|
179 | lacks the "lines uncovered" numbers that I want), and the half-finished |
---|
180 | delta-from-last-run measurements. |
---|
181 | ] |
---|
182 | [More comprehensive changes and ticket references for NEWS |
---|
183 | david-sarah@jacaranda.org**20100202061256 |
---|
184 | Ignore-this: 696cf0106e8a7fd388afc5b55fba8a1b |
---|
185 | ] |
---|
186 | [docs: install.html: link into Python 2.5.5 download page |
---|
187 | zooko@zooko.com**20100202065852 |
---|
188 | Ignore-this: 1a9471b8175b7de5741d8445a7ede29d |
---|
189 | ] |
---|
190 | [TAG allmydata-tahoe-1.6.0 |
---|
191 | zooko@zooko.com**20100202061125 |
---|
192 | Ignore-this: dee6ade7ac1452cf5d1d9c69a8146d84 |
---|
193 | ] |
---|
194 | Patch bundle hash: |
---|
195 | 4c2db026660c5f16ae93d624f6757e7bcbc5c9ee |
---|