Merge lp:~vila/bzr/690563-better-env-isolation into lp:bzr

Proposed by Vincent Ladeuil
Status: Superseded
Proposed branch: lp:~vila/bzr/690563-better-env-isolation
Merge into: lp:bzr
Diff against target: 1544 lines (+302/-305)
39 files modified
bzrlib/plugins/launchpad/test_lp_directory.py (+1/-1)
bzrlib/plugins/launchpad/test_lp_service.py (+1/-1)
bzrlib/plugins/launchpad/test_register.py (+2/-2)
bzrlib/tests/__init__.py (+18/-9)
bzrlib/tests/blackbox/test_commit.py (+4/-4)
bzrlib/tests/blackbox/test_diff.py (+1/-2)
bzrlib/tests/blackbox/test_init.py (+3/-3)
bzrlib/tests/blackbox/test_non_ascii.py (+1/-1)
bzrlib/tests/blackbox/test_serve.py (+1/-1)
bzrlib/tests/blackbox/test_shared_repository.py (+2/-2)
bzrlib/tests/blackbox/test_too_much.py (+22/-31)
bzrlib/tests/blackbox/test_version.py (+3/-3)
bzrlib/tests/blackbox/test_whoami.py (+3/-3)
bzrlib/tests/per_controldir/test_controldir.py (+1/-1)
bzrlib/tests/per_repository/test_check.py (+1/-1)
bzrlib/tests/per_repository/test_commit_builder.py (+1/-1)
bzrlib/tests/per_transport.py (+1/-1)
bzrlib/tests/per_uifactory/__init__.py (+1/-1)
bzrlib/tests/test_config.py (+9/-9)
bzrlib/tests/test_crash.py (+1/-1)
bzrlib/tests/test_diff.py (+12/-21)
bzrlib/tests/test_http.py (+34/-67)
bzrlib/tests/test_https_ca_bundle.py (+5/-15)
bzrlib/tests/test_import_tariff.py (+11/-7)
bzrlib/tests/test_msgeditor.py (+25/-27)
bzrlib/tests/test_osutils.py (+17/-17)
bzrlib/tests/test_osutils_encodings.py (+3/-4)
bzrlib/tests/test_plugins.py (+11/-11)
bzrlib/tests/test_read_bundle.py (+1/-1)
bzrlib/tests/test_rules.py (+3/-3)
bzrlib/tests/test_selftest.py (+47/-3)
bzrlib/tests/test_sftp_transport.py (+11/-18)
bzrlib/tests/test_smart_transport.py (+12/-15)
bzrlib/tests/test_trace.py (+1/-3)
bzrlib/tests/test_transport.py (+1/-1)
bzrlib/tests/test_ui.py (+5/-12)
bzrlib/tests/test_win32utils.py (+2/-2)
doc/developers/testing.txt (+19/-0)
doc/en/release-notes/bzr-2.3.txt (+5/-0)
To merge this branch: bzr merge lp:~vila/bzr/690563-better-env-isolation
Reviewer Review Type Date Requested Status
Martin Packman (community) Approve
Martin Pool Approve
Review via email: mp+43871@code.launchpad.net

This proposal has been superseded by a proposal from 2010-12-16.

Description of the change

This just shows why _captureVar is not how we should override environment variables for tests.

I'd like feedback on the name before deploying it in the test code base.

I chose overrideEnv as it carries the same semantic that overrideAttr and alternatives didn't work for that (setenv, set_or_unset_env_var, etc).

To post a comment you must log in.
Revision history for this message
Vincent Ladeuil (vila) wrote :

I haven't fully investigated all usages but at least caught my eye:
  _captureVar('TERM', None)

Since TERM is one of the variables reset by TestCase, doing the above means that TERM is lost (as shown in the test in this mp).

Revision history for this message
Martin Pool (mbp) wrote :

spelled 'isolation'

I agree this name is better.

Rather than poking it into an instance attribute, perhaps we should register a cleanup? But I suppose that can't be done while there is other code depending on it.

It would be a bit more satisfying if this also cleaned up the existing callers but I'm fine with that being done separately.

review: Approve
Revision history for this message
Martin Packman (gz) wrote :

Agreed that _captureVar is dodgy and we want a public interface that does the right thing instead. Will need to fiddle with these environment things further to fix bug 321320, as doctests can't use TestCase methods to provide isolation.

+ if name in self._old_env:
+ # We already protect this variable so we should not record its
+ # initial value
+ osutils.set_or_unset_env(name, value)
+ else:
+ self._old_env[name] = osutils.set_or_unset_env(name, value)

I'd probably spell this in a positive way instead:

    old_value = osutils.set_or_unset_env(name, value)
    # Save the original value provided it's not already been recorded
    if name not in self._old_env:
        self._old_env[name] = old_value

review: Approve
Revision history for this message
Vincent Ladeuil (vila) wrote :

>>>>> Martin [gz] <email address hidden> writes:

    > Review: Approve
    > Agreed that _captureVar is dodgy and we want a public interface that does the right thing instead. Will need to fiddle with these environment things further to fix bug 321320, as doctests can't use TestCase methods to provide isolation.

    > + if name in self._old_env:
    > + # We already protect this variable so we should not record its
    > + # initial value
    > + osutils.set_or_unset_env(name, value)
    > + else:
    > + self._old_env[name] = osutils.set_or_unset_env(name, value)

    > I'd probably spell this in a positive way instead:

    > old_value = osutils.set_or_unset_env(name, value)
    > # Save the original value provided it's not already been recorded
    > if name not in self._old_env:
    > self._old_env[name] = old_value

Right, and even:

        old_value = osutils.set_or_unset_env(name, value)
        self.addCleanup(osutils.set_or_unset_env, name, old_value)

which is cleaner and clearer. Too bad os.environ is not a regular dict
or we could have used overrideAttr instead.

--367D41813B0.1292493572/axe--

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bzrlib/plugins/launchpad/test_lp_directory.py'
2--- bzrlib/plugins/launchpad/test_lp_directory.py 2010-12-03 11:16:25 +0000
3+++ bzrlib/plugins/launchpad/test_lp_directory.py 2010-12-16 17:48:29 +0000
4@@ -298,7 +298,7 @@
5 self.server = self.server_class()
6 self.server.start_server()
7 # Ensure we don't clobber env
8- self._captureVar('BZR_LP_XMLRPC_URL', None)
9+ self.overrideEnv('BZR_LP_XMLRPC_URL', None)
10
11 def tearDown(self):
12 self.server.stop_server()
13
14=== modified file 'bzrlib/plugins/launchpad/test_lp_service.py'
15--- bzrlib/plugins/launchpad/test_lp_service.py 2010-11-26 17:33:55 +0000
16+++ bzrlib/plugins/launchpad/test_lp_service.py 2010-12-16 17:48:29 +0000
17@@ -32,7 +32,7 @@
18 def setUp(self):
19 super(LaunchpadServiceTests, self).setUp()
20 # make sure we have a reproducible standard environment
21- self._captureVar('BZR_LP_XMLRPC_URL', None)
22+ self.overrideEnv('BZR_LP_XMLRPC_URL', None)
23
24 def test_default_service(self):
25 service = LaunchpadService()
26
27=== modified file 'bzrlib/plugins/launchpad/test_register.py'
28--- bzrlib/plugins/launchpad/test_register.py 2010-12-07 09:06:39 +0000
29+++ bzrlib/plugins/launchpad/test_register.py 2010-12-16 17:48:29 +0000
30@@ -137,7 +137,7 @@
31 def setUp(self):
32 super(TestBranchRegistration, self).setUp()
33 # make sure we have a reproducible standard environment
34- self._captureVar('BZR_LP_XMLRPC_URL', None)
35+ self.overrideEnv('BZR_LP_XMLRPC_URL', None)
36
37 def test_register_help(self):
38 """register-branch accepts --help"""
39@@ -296,7 +296,7 @@
40 def setUp(self):
41 super(TestGatherUserCredentials, self).setUp()
42 # make sure we have a reproducible standard environment
43- self._captureVar('BZR_LP_XMLRPC_URL', None)
44+ self.overrideEnv('BZR_LP_XMLRPC_URL', None)
45
46 def test_gather_user_credentials_has_password(self):
47 service = LaunchpadService()
48
49=== modified file 'bzrlib/tests/__init__.py'
50--- bzrlib/tests/__init__.py 2010-12-16 14:39:57 +0000
51+++ bzrlib/tests/__init__.py 2010-12-16 17:48:29 +0000
52@@ -851,6 +851,7 @@
53 self.addDetail("log", content.Content(content.ContentType("text",
54 "plain", {"charset": "utf8"}),
55 lambda:[self._get_log(keep_log_file=True)]))
56+ self._old_env = {}
57 self._cleanEnvironment()
58 self._silenceUI()
59 self._startLogFile()
60@@ -1539,6 +1540,20 @@
61 setattr(obj, attr_name, new)
62 return value
63
64+ def overrideEnv(self, name, new):
65+ """Set an environment variable, and reset it fater the test.
66+
67+ :param name: The environment variable name.
68+
69+ :param new: The value to set the variable to. If None, the
70+ variable is deleted from the environment.
71+
72+ :returns: The actual variable value.
73+ """
74+ value = osutils.set_or_unset_env(name, new)
75+ self.addCleanup(osutils.set_or_unset_env, name, value)
76+ return value
77+
78 def _cleanEnvironment(self):
79 new_env = {
80 'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
81@@ -1588,19 +1603,13 @@
82 # use an env var so it propagates to subprocesses.
83 'APPORT_DISABLE': '1',
84 }
85- self._old_env = {}
86- self.addCleanup(self._restoreEnvironment)
87 for name, value in new_env.iteritems():
88- self._captureVar(name, value)
89+ self.overrideEnv(name, value)
90
91 def _captureVar(self, name, newvalue):
92 """Set an environment variable, and reset it when finished."""
93 self._old_env[name] = osutils.set_or_unset_env(name, newvalue)
94
95- def _restoreEnvironment(self):
96- for name, value in self._old_env.iteritems():
97- osutils.set_or_unset_env(name, value)
98-
99 def _restoreHooks(self):
100 for klass, (name, hooks) in self._preserved_hooks.items():
101 setattr(klass, name, hooks)
102@@ -2442,8 +2451,8 @@
103 test_home_dir = self.test_home_dir
104 if isinstance(test_home_dir, unicode):
105 test_home_dir = test_home_dir.encode(sys.getfilesystemencoding())
106- os.environ['HOME'] = test_home_dir
107- os.environ['BZR_HOME'] = test_home_dir
108+ self.overrideEnv('HOME', test_home_dir)
109+ self.overrideEnv('BZR_HOME', test_home_dir)
110
111 def setUp(self):
112 super(TestCaseWithMemoryTransport, self).setUp()
113
114=== modified file 'bzrlib/tests/blackbox/test_commit.py'
115--- bzrlib/tests/blackbox/test_commit.py 2010-12-02 09:23:10 +0000
116+++ bzrlib/tests/blackbox/test_commit.py 2010-12-16 17:48:29 +0000
117@@ -719,13 +719,13 @@
118 f = file('fed.bat', 'w')
119 f.write('@rem dummy fed')
120 f.close()
121- osutils.set_or_unset_env('BZR_EDITOR', "fed.bat")
122+ self.overrideEnv('BZR_EDITOR', "fed.bat")
123 else:
124 f = file('fed.sh', 'wb')
125 f.write('#!/bin/sh\n')
126 f.close()
127 os.chmod('fed.sh', 0755)
128- osutils.set_or_unset_env('BZR_EDITOR', "./fed.sh")
129+ self.overrideEnv('BZR_EDITOR', "./fed.sh")
130
131 def setup_commit_with_template(self):
132 self.setup_editor()
133@@ -756,8 +756,8 @@
134 os.chdir('foo')
135 open('foo.txt', 'w').write('hello')
136 self.run_bzr(['add'])
137- osutils.set_or_unset_env('EMAIL', None)
138- osutils.set_or_unset_env('BZR_EMAIL', None)
139+ self.overrideEnv('EMAIL', None)
140+ self.overrideEnv('BZR_EMAIL', None)
141 out, err = self.run_bzr(['commit', '-m', 'initial'], 3)
142 self.assertContainsRe(err, 'Unable to determine your name')
143
144
145=== modified file 'bzrlib/tests/blackbox/test_diff.py'
146--- bzrlib/tests/blackbox/test_diff.py 2010-07-22 13:19:48 +0000
147+++ bzrlib/tests/blackbox/test_diff.py 2010-12-16 17:48:29 +0000
148@@ -386,8 +386,7 @@
149 # subprocess.py that we had to workaround).
150 # However, if 'diff' may not be available
151 self.make_example_branch()
152- # this will be automatically restored by the base bzr test class
153- os.environ['BZR_PROGRESS_BAR'] = 'none'
154+ self.overrideEnv('BZR_PROGRESS_BAR', 'none')
155 out, err = self.run_bzr_subprocess('diff -r 1 --diff-options -ub',
156 universal_newlines=True,
157 retcode=None)
158
159=== modified file 'bzrlib/tests/blackbox/test_init.py'
160--- bzrlib/tests/blackbox/test_init.py 2010-10-12 09:46:37 +0000
161+++ bzrlib/tests/blackbox/test_init.py 2010-12-16 17:48:29 +0000
162@@ -226,9 +226,9 @@
163 # and uses whoami only in a lock file. Without whoami the login name
164 # is used. This test is to ensure that init passes even when whoami
165 # is not available.
166- osutils.set_or_unset_env('EMAIL', None)
167- osutils.set_or_unset_env('BZR_EMAIL', None)
168+ self.overrideEnv('EMAIL', None)
169+ self.overrideEnv('BZR_EMAIL', None)
170 out, err = self.run_bzr(['init', 'foo'])
171 self.assertEqual(err, '')
172 self.assertTrue(os.path.exists('foo'))
173-
174+
175
176=== modified file 'bzrlib/tests/blackbox/test_non_ascii.py'
177--- bzrlib/tests/blackbox/test_non_ascii.py 2010-12-09 04:26:53 +0000
178+++ bzrlib/tests/blackbox/test_non_ascii.py 2010-12-16 17:48:29 +0000
179@@ -42,7 +42,7 @@
180
181 self.overrideAttr(osutils, '_cached_user_encoding', self.encoding)
182 email = self.info['committer'] + ' <joe@foo.com>'
183- os.environ['BZR_EMAIL'] = email.encode(osutils.get_user_encoding())
184+ self.overrideEnv('BZR_EMAIL', email.encode(osutils.get_user_encoding()))
185 self.create_base()
186
187 def run_bzr_decode(self, args, encoding=None, fail=False, retcode=None,
188
189=== modified file 'bzrlib/tests/blackbox/test_serve.py'
190--- bzrlib/tests/blackbox/test_serve.py 2010-06-20 11:18:38 +0000
191+++ bzrlib/tests/blackbox/test_serve.py 2010-12-16 17:48:29 +0000
192@@ -225,7 +225,7 @@
193 # -Dhpss, and does drop some hpss logging to the file.
194 self.make_branch('.')
195 log_fname = os.getcwd() + '/server.log'
196- self._captureVar('BZR_LOG', log_fname)
197+ self.overrideEnv('BZR_LOG', log_fname)
198 process, transport = self.start_server_inet(['-Dhpss'])
199 branch = BzrDir.open_from_transport(transport).open_branch()
200 self.make_read_requests(branch)
201
202=== modified file 'bzrlib/tests/blackbox/test_shared_repository.py'
203--- bzrlib/tests/blackbox/test_shared_repository.py 2010-05-05 14:02:53 +0000
204+++ bzrlib/tests/blackbox/test_shared_repository.py 2010-12-16 17:48:29 +0000
205@@ -155,8 +155,8 @@
206 # and uses whoami only in a lock file. Without whoami the login name
207 # is used. This test is to ensure that init-repo passes even when whoami
208 # is not available.
209- osutils.set_or_unset_env('EMAIL', None)
210- osutils.set_or_unset_env('BZR_EMAIL', None)
211+ self.overrideEnv('EMAIL', None)
212+ self.overrideEnv('BZR_EMAIL', None)
213 out, err = self.run_bzr(['init-repo', 'foo'])
214 self.assertEqual(err, '')
215 self.assertTrue(os.path.exists('foo'))
216
217=== modified file 'bzrlib/tests/blackbox/test_too_much.py'
218--- bzrlib/tests/blackbox/test_too_much.py 2010-06-11 07:32:12 +0000
219+++ bzrlib/tests/blackbox/test_too_much.py 2010-12-16 17:48:29 +0000
220@@ -315,37 +315,28 @@
221 cmd_name = 'test-command'
222 if sys.platform == 'win32':
223 cmd_name += '.bat'
224- oldpath = os.environ.get('BZRPATH', None)
225- try:
226- if 'BZRPATH' in os.environ:
227- del os.environ['BZRPATH']
228-
229- f = file(cmd_name, 'wb')
230- if sys.platform == 'win32':
231- f.write('@echo off\n')
232- else:
233- f.write('#!/bin/sh\n')
234- # f.write('echo Hello from test-command')
235- f.close()
236- os.chmod(cmd_name, 0755)
237-
238- # It should not find the command in the local
239- # directory by default, since it is not in my path
240- self.run_bzr(cmd_name, retcode=3)
241-
242- # Now put it into my path
243- os.environ['BZRPATH'] = '.'
244-
245- self.run_bzr(cmd_name)
246-
247- # Make sure empty path elements are ignored
248- os.environ['BZRPATH'] = os.pathsep
249-
250- self.run_bzr(cmd_name, retcode=3)
251-
252- finally:
253- if oldpath:
254- os.environ['BZRPATH'] = oldpath
255+ self.overrideEnv('BZRPATH', None)
256+
257+ f = file(cmd_name, 'wb')
258+ if sys.platform == 'win32':
259+ f.write('@echo off\n')
260+ else:
261+ f.write('#!/bin/sh\n')
262+ # f.write('echo Hello from test-command')
263+ f.close()
264+ os.chmod(cmd_name, 0755)
265+
266+ # It should not find the command in the local
267+ # directory by default, since it is not in my path
268+ self.run_bzr(cmd_name, retcode=3)
269+
270+ # Now put it into my path
271+ self.overrideEnv('BZRPATH', '.')
272+ self.run_bzr(cmd_name)
273+
274+ # Make sure empty path elements are ignored
275+ self.overrideEnv('BZRPATH', os.pathsep)
276+ self.run_bzr(cmd_name, retcode=3)
277
278
279 def listdir_sorted(dir):
280
281=== modified file 'bzrlib/tests/blackbox/test_version.py'
282--- bzrlib/tests/blackbox/test_version.py 2009-12-02 16:43:09 +0000
283+++ bzrlib/tests/blackbox/test_version.py 2010-12-16 17:48:29 +0000
284@@ -95,7 +95,7 @@
285 raise TestSkipped('Cannot find a unicode character that works in'
286 ' encoding %s' % (osutils.get_user_encoding(),))
287
288- osutils.set_or_unset_env('BZR_HOME', str_val)
289+ self.overrideEnv('BZR_HOME', str_val)
290 self.permit_source_tree_branch_repo()
291 out = self.run_bzr("version")[0]
292 self.assertTrue(len(out) > 0)
293@@ -106,7 +106,7 @@
294
295 def test_simple(self):
296 bzr_log = 'my.bzr.log'
297- osutils.set_or_unset_env('BZR_LOG', bzr_log)
298+ self.overrideEnv('BZR_LOG', bzr_log)
299 default_log = os.path.join(os.environ['BZR_HOME'], '.bzr.log')
300 self.failIfExists([default_log, bzr_log])
301 out = self.run_bzr_subprocess('version')[0]
302@@ -122,7 +122,7 @@
303 bzr_log = 'NUL'
304 else:
305 bzr_log = '/dev/null'
306- osutils.set_or_unset_env('BZR_LOG', bzr_log)
307+ self.overrideEnv('BZR_LOG', bzr_log)
308 default_log = os.path.join(os.environ['BZR_HOME'], '.bzr.log')
309 self.failIfExists(default_log)
310 out = self.run_bzr_subprocess('version')[0]
311
312=== modified file 'bzrlib/tests/blackbox/test_whoami.py'
313--- bzrlib/tests/blackbox/test_whoami.py 2010-06-23 08:19:28 +0000
314+++ bzrlib/tests/blackbox/test_whoami.py 2010-12-16 17:48:29 +0000
315@@ -52,7 +52,7 @@
316
317 # Verify that the environment variable overrides the value
318 # in the file
319- os.environ['BZR_EMAIL'] = 'Different ID <other@environ.ment>'
320+ self.overrideEnv('BZR_EMAIL', 'Different ID <other@environ.ment>')
321 whoami = self.run_bzr("whoami")[0]
322 self.assertEquals('Different ID <other@environ.ment>\n', whoami)
323 whoami_email = self.run_bzr("whoami --email")[0]
324@@ -94,8 +94,8 @@
325 def test_whoami_not_set(self):
326 """Ensure whoami error if username is not set.
327 """
328- osutils.set_or_unset_env('EMAIL', None)
329- osutils.set_or_unset_env('BZR_EMAIL', None)
330+ self.overrideEnv('EMAIL', None)
331+ self.overrideEnv('BZR_EMAIL', None)
332 out, err = self.run_bzr(['whoami'], 3)
333 self.assertContainsRe(err, 'Unable to determine your name')
334
335
336=== modified file 'bzrlib/tests/per_controldir/test_controldir.py'
337--- bzrlib/tests/per_controldir/test_controldir.py 2010-11-26 17:59:08 +0000
338+++ bzrlib/tests/per_controldir/test_controldir.py 2010-12-16 17:48:29 +0000
339@@ -257,7 +257,7 @@
340
341 def test_clone_bzrdir_branch_and_repo_fixed_user_id(self):
342 # Bug #430868 is about an email containing '.sig'
343- os.environ['BZR_EMAIL'] = 'murphy@host.sighup.org'
344+ self.overrideEnv('BZR_EMAIL', 'murphy@host.sighup.org')
345 tree = self.make_branch_and_tree('commit_tree')
346 self.build_tree(['commit_tree/foo'])
347 tree.add('foo')
348
349=== modified file 'bzrlib/tests/per_repository/test_check.py'
350--- bzrlib/tests/per_repository/test_check.py 2010-02-17 17:11:16 +0000
351+++ bzrlib/tests/per_repository/test_check.py 2010-12-16 17:48:29 +0000
352@@ -135,7 +135,7 @@
353 repo.lock_write()
354 self.addCleanup(repo.unlock)
355 config = _mod_config.Config()
356- os.environ['BZR_EMAIL'] = 'foo@sample.com'
357+ self.overrideEnv('BZR_EMAIL', 'foo@sample.com')
358 builder = repo.get_commit_builder(None, [], config)
359 list(builder.record_iter_changes(None, _mod_revision.NULL_REVISION, [
360 ('TREE_ROOT', (None, ''), True, (False, True), (None, None),
361
362=== modified file 'bzrlib/tests/per_repository/test_commit_builder.py'
363--- bzrlib/tests/per_repository/test_commit_builder.py 2010-10-15 16:43:03 +0000
364+++ bzrlib/tests/per_repository/test_commit_builder.py 2010-12-16 17:48:29 +0000
365@@ -1317,7 +1317,7 @@
366 def test_committer_no_username(self):
367 # Ensure that when no username is available but a committer is
368 # supplied, commit works.
369- del os.environ['EMAIL']
370+ self.overrideEnv('EMAIL', None)
371 tree = self.make_branch_and_tree(".")
372 tree.lock_write()
373 try:
374
375=== modified file 'bzrlib/tests/per_transport.py'
376--- bzrlib/tests/per_transport.py 2010-09-21 03:20:09 +0000
377+++ bzrlib/tests/per_transport.py 2010-12-16 17:48:29 +0000
378@@ -98,7 +98,7 @@
379
380 def setUp(self):
381 super(TransportTests, self).setUp()
382- self._captureVar('BZR_NO_SMART_VFS', None)
383+ self.overrideEnv('BZR_NO_SMART_VFS', None)
384
385 def check_transport_contents(self, content, transport, relpath):
386 """Check that transport.get(relpath).read() == content."""
387
388=== modified file 'bzrlib/tests/per_uifactory/__init__.py'
389--- bzrlib/tests/per_uifactory/__init__.py 2010-09-09 07:49:00 +0000
390+++ bzrlib/tests/per_uifactory/__init__.py 2010-12-16 17:48:29 +0000
391@@ -190,7 +190,7 @@
392
393 # Remove 'TERM' == 'dumb' which causes us to *not* treat output as a
394 # real terminal, even though isatty returns True
395- self._captureVar('TERM', None)
396+ self.overrideEnv('TERM', None)
397 self.stderr = TTYStringIO()
398 self.stdout = TTYStringIO()
399 self.factory = ui.text.TextUIFactory(self.stdin, self.stdout,
400
401=== modified file 'bzrlib/tests/test_config.py'
402--- bzrlib/tests/test_config.py 2010-11-29 01:23:53 +0000
403+++ bzrlib/tests/test_config.py 2010-12-16 17:48:29 +0000
404@@ -402,11 +402,11 @@
405
406 def setUp(self):
407 super(TestConfigPath, self).setUp()
408- os.environ['HOME'] = '/home/bogus'
409- os.environ['XDG_CACHE_DIR'] = ''
410+ self.overrideEnv('HOME', '/home/bogus')
411+ self.overrideEnv('XDG_CACHE_DIR', '')
412 if sys.platform == 'win32':
413- os.environ['BZR_HOME'] = \
414- r'C:\Documents and Settings\bogus\Application Data'
415+ self.overrideEnv(
416+ 'BZR_HOME', r'C:\Documents and Settings\bogus\Application Data')
417 self.bzr_home = \
418 'C:/Documents and Settings/bogus/Application Data/bazaar/2.0'
419 else:
420@@ -441,9 +441,9 @@
421 raise tests.TestNotApplicable(
422 'XDG config dir not used on this platform')
423 super(TestXDGConfigDir, self).setUp()
424- os.environ['HOME'] = self.test_home_dir
425+ self.overrideEnv('HOME', self.test_home_dir)
426 # BZR_HOME overrides everything we want to test so unset it.
427- del os.environ['BZR_HOME']
428+ self.overrideEnv('BZR_HOME', None)
429
430 def test_xdg_config_dir_exists(self):
431 """When ~/.config/bazaar exists, use it as the config dir."""
432@@ -454,7 +454,7 @@
433 def test_xdg_config_home(self):
434 """When XDG_CONFIG_HOME is set, use it."""
435 xdgconfigdir = osutils.pathjoin(self.test_home_dir, 'xdgconfig')
436- os.environ['XDG_CONFIG_HOME'] = xdgconfigdir
437+ self.overrideEnv('XDG_CONFIG_HOME', xdgconfigdir)
438 newdir = osutils.pathjoin(xdgconfigdir, 'bazaar')
439 os.makedirs(newdir)
440 self.assertEqual(config.config_dir(), newdir)
441@@ -1308,7 +1308,7 @@
442 self.assertEqual('bzr', my_config.get_bzr_remote_path())
443 my_config.set_user_option('bzr_remote_path', '/path-bzr')
444 self.assertEqual('/path-bzr', my_config.get_bzr_remote_path())
445- os.environ['BZR_REMOTE_PATH'] = '/environ-bzr'
446+ self.overrideEnv('BZR_REMOTE_PATH', '/environ-bzr')
447 self.assertEqual('/environ-bzr', my_config.get_bzr_remote_path())
448
449
450@@ -1360,7 +1360,7 @@
451 self.assertEqual("John", my_config._get_user_id())
452
453 def test_BZR_EMAIL_OVERRIDES(self):
454- os.environ['BZR_EMAIL'] = "Robert Collins <robertc@example.org>"
455+ self.overrideEnv('BZR_EMAIL', "Robert Collins <robertc@example.org>")
456 branch = FakeBranch()
457 my_config = config.BranchConfig(branch)
458 self.assertEqual("Robert Collins <robertc@example.org>",
459
460=== modified file 'bzrlib/tests/test_crash.py'
461--- bzrlib/tests/test_crash.py 2010-04-08 04:34:03 +0000
462+++ bzrlib/tests/test_crash.py 2010-12-16 17:48:29 +0000
463@@ -40,7 +40,7 @@
464 def test_apport_report(self):
465 crash_dir = osutils.joinpath((self.test_base_dir, 'crash'))
466 os.mkdir(crash_dir)
467- os.environ['APPORT_CRASH_DIR'] = crash_dir
468+ self.overrideEnv('APPORT_CRASH_DIR', crash_dir)
469 self.assertEquals(crash_dir, config.crash_dir())
470
471 stderr = StringIO()
472
473=== modified file 'bzrlib/tests/test_diff.py'
474--- bzrlib/tests/test_diff.py 2010-05-26 15:58:08 +0000
475+++ bzrlib/tests/test_diff.py 2010-12-16 17:48:29 +0000
476@@ -144,31 +144,22 @@
477 self.check_patch(lines)
478
479 def test_external_diff_binary_lang_c(self):
480- old_env = {}
481 for lang in ('LANG', 'LC_ALL', 'LANGUAGE'):
482- old_env[lang] = osutils.set_or_unset_env(lang, 'C')
483- try:
484- lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
485- # Older versions of diffutils say "Binary files", newer
486- # versions just say "Files".
487- self.assertContainsRe(lines[0],
488- '(Binary f|F)iles old and new differ\n')
489- self.assertEquals(lines[1:], ['\n'])
490- finally:
491- for lang, old_val in old_env.iteritems():
492- osutils.set_or_unset_env(lang, old_val)
493+ self.overrideEnv(lang, 'C')
494+ lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
495+ # Older versions of diffutils say "Binary files", newer
496+ # versions just say "Files".
497+ self.assertContainsRe(lines[0], '(Binary f|F)iles old and new differ\n')
498+ self.assertEquals(lines[1:], ['\n'])
499
500 def test_no_external_diff(self):
501 """Check that NoDiff is raised when diff is not available"""
502- # Use os.environ['PATH'] to make sure no 'diff' command is available
503- orig_path = os.environ['PATH']
504- try:
505- os.environ['PATH'] = ''
506- self.assertRaises(errors.NoDiff, diff.external_diff,
507- 'old', ['boo\n'], 'new', ['goo\n'],
508- StringIO(), diff_opts=['-u'])
509- finally:
510- os.environ['PATH'] = orig_path
511+ # Make sure no 'diff' command is available
512+ # XXX: Weird, using None instead of '' breaks the test -- vila 20101216
513+ self.overrideEnv('PATH', '')
514+ self.assertRaises(errors.NoDiff, diff.external_diff,
515+ 'old', ['boo\n'], 'new', ['goo\n'],
516+ StringIO(), diff_opts=['-u'])
517
518 def test_internal_diff_default(self):
519 # Default internal diff encoding is utf8
520
521=== modified file 'bzrlib/tests/test_http.py'
522--- bzrlib/tests/test_http.py 2010-12-15 16:39:25 +0000
523+++ bzrlib/tests/test_http.py 2010-12-16 17:48:29 +0000
524@@ -1073,19 +1073,6 @@
525 Only the urllib implementation is tested here.
526 """
527
528- def setUp(self):
529- tests.TestCase.setUp(self)
530- self._http_saved_env = {}
531- self.addCleanup(self._restore_env)
532-
533- def _install_env(self, env):
534- for name, value in env.iteritems():
535- self._http_saved_env[name] = osutils.set_or_unset_env(name, value)
536-
537- def _restore_env(self):
538- for name, value in self._http_saved_env.iteritems():
539- osutils.set_or_unset_env(name, value)
540-
541 def _proxied_request(self):
542 handler = _urllib2_wrappers.ProxyHandler()
543 request = _urllib2_wrappers.Request('GET','http://baz/buzzle')
544@@ -1093,13 +1080,13 @@
545 return request
546
547 def test_empty_user(self):
548- self._install_env({'http_proxy': 'http://bar.com'})
549+ self.overrideEnv('http_proxy', 'http://bar.com')
550 request = self._proxied_request()
551 self.assertFalse(request.headers.has_key('Proxy-authorization'))
552
553 def test_invalid_proxy(self):
554 """A proxy env variable without scheme"""
555- self._install_env({'http_proxy': 'host:1234'})
556+ self.overrideEnv('http_proxy', 'host:1234')
557 self.assertRaises(errors.InvalidURL, self._proxied_request)
558
559
560@@ -1136,39 +1123,23 @@
561 self.no_proxy_host = self.server_host_port
562 # The secondary server is the proxy
563 self.proxy_url = self.get_secondary_url()
564- self._http_saved_env = {}
565
566 def _testing_pycurl(self):
567 # TODO: This is duplicated for lots of the classes in this file
568 return (features.pycurl.available()
569 and self._transport == PyCurlTransport)
570
571- def _install_env(self, env):
572- for name, value in env.iteritems():
573- self._http_saved_env[name] = osutils.set_or_unset_env(name, value)
574-
575- def _restore_env(self):
576- for name, value in self._http_saved_env.iteritems():
577- osutils.set_or_unset_env(name, value)
578-
579- def proxied_in_env(self, env):
580- self._install_env(env)
581- t = self.get_readonly_transport()
582- try:
583- self.assertEqual('proxied contents of foo\n', t.get('foo').read())
584- finally:
585- self._restore_env()
586-
587- def not_proxied_in_env(self, env):
588- self._install_env(env)
589- t = self.get_readonly_transport()
590- try:
591- self.assertEqual('contents of foo\n', t.get('foo').read())
592- finally:
593- self._restore_env()
594+ def assertProxied(self):
595+ t = self.get_readonly_transport()
596+ self.assertEqual('proxied contents of foo\n', t.get('foo').read())
597+
598+ def assertNotProxied(self):
599+ t = self.get_readonly_transport()
600+ self.assertEqual('contents of foo\n', t.get('foo').read())
601
602 def test_http_proxy(self):
603- self.proxied_in_env({'http_proxy': self.proxy_url})
604+ self.overrideEnv('http_proxy', self.proxy_url)
605+ self.assertProxied()
606
607 def test_HTTP_PROXY(self):
608 if self._testing_pycurl():
609@@ -1177,43 +1148,49 @@
610 # about. Should we ?)
611 raise tests.TestNotApplicable(
612 'pycurl does not check HTTP_PROXY for security reasons')
613- self.proxied_in_env({'HTTP_PROXY': self.proxy_url})
614+ self.overrideEnv('HTTP_PROXY', self.proxy_url)
615+ self.assertProxied()
616
617 def test_all_proxy(self):
618- self.proxied_in_env({'all_proxy': self.proxy_url})
619+ self.overrideEnv('all_proxy', self.proxy_url)
620+ self.assertProxied()
621
622 def test_ALL_PROXY(self):
623- self.proxied_in_env({'ALL_PROXY': self.proxy_url})
624+ self.overrideEnv('ALL_PROXY', self.proxy_url)
625+ self.assertProxied()
626
627 def test_http_proxy_with_no_proxy(self):
628- self.not_proxied_in_env({'http_proxy': self.proxy_url,
629- 'no_proxy': self.no_proxy_host})
630+ self.overrideEnv('no_proxy', self.no_proxy_host)
631+ self.overrideEnv('http_proxy', self.proxy_url)
632+ self.assertNotProxied()
633
634 def test_HTTP_PROXY_with_NO_PROXY(self):
635 if self._testing_pycurl():
636 raise tests.TestNotApplicable(
637 'pycurl does not check HTTP_PROXY for security reasons')
638- self.not_proxied_in_env({'HTTP_PROXY': self.proxy_url,
639- 'NO_PROXY': self.no_proxy_host})
640+ self.overrideEnv('NO_PROXY', self.no_proxy_host)
641+ self.overrideEnv('HTTP_PROXY', self.proxy_url)
642+ self.assertNotProxied()
643
644 def test_all_proxy_with_no_proxy(self):
645- self.not_proxied_in_env({'all_proxy': self.proxy_url,
646- 'no_proxy': self.no_proxy_host})
647+ self.overrideEnv('no_proxy', self.no_proxy_host)
648+ self.overrideEnv('all_proxy', self.proxy_url)
649+ self.assertNotProxied()
650
651 def test_ALL_PROXY_with_NO_PROXY(self):
652- self.not_proxied_in_env({'ALL_PROXY': self.proxy_url,
653- 'NO_PROXY': self.no_proxy_host})
654+ self.overrideEnv('NO_PROXY', self.no_proxy_host)
655+ self.overrideEnv('ALL_PROXY', self.proxy_url)
656+ self.assertNotProxied()
657
658 def test_http_proxy_without_scheme(self):
659+ self.overrideEnv('http_proxy', self.server_host_port)
660 if self._testing_pycurl():
661 # pycurl *ignores* invalid proxy env variables. If that ever change
662 # in the future, this test will fail indicating that pycurl do not
663 # ignore anymore such variables.
664- self.not_proxied_in_env({'http_proxy': self.server_host_port})
665+ self.assertNotProxied()
666 else:
667- self.assertRaises(errors.InvalidURL,
668- self.proxied_in_env,
669- {'http_proxy': self.server_host_port})
670+ self.assertRaises(errors.InvalidURL, self.assertProxied)
671
672
673 class TestRanges(http_utils.TestCaseWithWebserver):
674@@ -1707,8 +1684,6 @@
675
676 def setUp(self):
677 super(TestProxyAuth, self).setUp()
678- self._http_saved_env = {}
679- self.addCleanup(self._restore_env)
680 # Override the contents to avoid false positives
681 self.build_tree_contents([('a', 'not proxied contents of a\n'),
682 ('b', 'not proxied contents of b\n'),
683@@ -1717,17 +1692,9 @@
684 ])
685
686 def get_user_transport(self, user, password):
687- self._install_env({'all_proxy': self.get_user_url(user, password)})
688+ self.overrideEnv('all_proxy', self.get_user_url(user, password))
689 return TestAuth.get_user_transport(self, user, password)
690
691- def _install_env(self, env):
692- for name, value in env.iteritems():
693- self._http_saved_env[name] = osutils.set_or_unset_env(name, value)
694-
695- def _restore_env(self):
696- for name, value in self._http_saved_env.iteritems():
697- osutils.set_or_unset_env(name, value)
698-
699 def test_empty_pass(self):
700 if self._testing_pycurl():
701 import pycurl
702@@ -1770,7 +1737,7 @@
703 def setUp(self):
704 super(SmartHTTPTunnellingTest, self).setUp()
705 # We use the VFS layer as part of HTTP tunnelling tests.
706- self._captureVar('BZR_NO_SMART_VFS', None)
707+ self.overrideEnv('BZR_NO_SMART_VFS', None)
708 self.transport_readonly_server = http_utils.HTTPServerWithSmarts
709 self.http_server = self.get_readonly_server()
710
711
712=== modified file 'bzrlib/tests/test_https_ca_bundle.py'
713--- bzrlib/tests/test_https_ca_bundle.py 2010-12-15 16:39:25 +0000
714+++ bzrlib/tests/test_https_ca_bundle.py 2010-12-16 17:48:29 +0000
715@@ -31,19 +31,9 @@
716 class TestGetCAPath(TestCaseInTempDir):
717
718 def setUp(self):
719- TestCaseInTempDir.setUp(self)
720- new_env = {
721- 'CURL_CA_BUNDLE': None,
722- 'PATH': None,
723- }
724- self._http_saved_env = {}
725- self.addCleanup(self._restore)
726- for name, value in new_env.iteritems():
727- self._http_saved_env[name] = osutils.set_or_unset_env(name, None)
728-
729- def _restore(self):
730- for name, value in self._http_saved_env.iteritems():
731- osutils.set_or_unset_env(name, value)
732+ super(TestGetCAPath, self).setUp()
733+ self.overrideEnv('CURL_CA_BUNDLE', None)
734+ self.overrideEnv('PATH', None)
735
736 def _make_file(self, in_dir='.'):
737 fname = os.path.join(in_dir, 'curl-ca-bundle.crt')
738@@ -55,7 +45,7 @@
739 self.assertEqual('', ca_bundle.get_ca_path(use_cache=False))
740
741 def test_env_var(self):
742- osutils.set_or_unset_env('CURL_CA_BUNDLE', 'foo.bar')
743+ self.overrideEnv('CURL_CA_BUNDLE', 'foo.bar')
744 self._make_file()
745 self.assertEqual('foo.bar', ca_bundle.get_ca_path(use_cache=False))
746
747@@ -65,6 +55,6 @@
748 os.mkdir('foo')
749 in_dir = os.path.join(os.getcwd(), 'foo')
750 self._make_file(in_dir=in_dir)
751- osutils.set_or_unset_env('PATH', in_dir)
752+ self.overrideEnv('PATH', in_dir)
753 shouldbe = os.path.join(in_dir, 'curl-ca-bundle.crt')
754 self.assertEqual(shouldbe, ca_bundle.get_ca_path(use_cache=False))
755
756=== modified file 'bzrlib/tests/test_import_tariff.py'
757--- bzrlib/tests/test_import_tariff.py 2010-10-20 11:16:16 +0000
758+++ bzrlib/tests/test_import_tariff.py 2010-12-16 17:48:29 +0000
759@@ -17,6 +17,7 @@
760
761 """Tests for how many modules are loaded in executing various commands."""
762
763+import os
764 from testtools import content
765
766 from bzrlib.plugin import (
767@@ -29,12 +30,19 @@
768
769
770 class TestImportTariffs(TestCaseWithTransport):
771-
772 """Check how many modules are loaded for some representative scenarios.
773
774 See the Testing Guide in the developer documentation for more explanation.
775 """
776
777+ def setUp(self):
778+ # Preserve some env vars as we want to escape the isolation for them
779+ self.preserved_env_vars = {}
780+ for name in ('BZR_HOME', 'BZR_PLUGIN_PATH', 'BZR_DISABLE_PLUGINS',
781+ 'BZR_PLUGINS_AT', 'HOME'):
782+ self.preserved_env_vars[name] = os.environ.get(name)
783+ super(TestImportTariffs, self).setUp()
784+
785 def run_command_check_imports(self, args, forbidden_imports):
786 """Run bzr ARGS in a subprocess and check its imports.
787
788@@ -50,15 +58,11 @@
789 # more likely to always show everything. And we use the environment
790 # variable rather than 'python -v' in the hope it will work even if
791 # bzr is frozen and python is not explicitly specified. -- mbp 20100208
792- #
793+
794 # Normally we want test isolation from the real $HOME but here we
795 # explicitly do want to test against things installed there, therefore
796 # we pass it through.
797- env_changes = dict(PYTHONVERBOSE='1')
798- for name in ['BZR_HOME', 'BZR_PLUGIN_PATH',
799- 'BZR_DISABLE_PLUGINS', 'BZR_PLUGINS_AT',
800- 'HOME',]:
801- env_changes[name] = self._old_env.get(name)
802+ env_changes = dict(PYTHONVERBOSE='1', **self.preserved_env_vars)
803 out, err = self.run_bzr_subprocess(args,
804 allow_plugins=(not are_plugins_disabled()),
805 env_changes=env_changes)
806
807=== modified file 'bzrlib/tests/test_msgeditor.py'
808--- bzrlib/tests/test_msgeditor.py 2010-11-11 13:45:02 +0000
809+++ bzrlib/tests/test_msgeditor.py 2010-12-16 17:48:29 +0000
810@@ -157,7 +157,7 @@
811 return './fed.sh'
812
813 def test_run_editor(self):
814- os.environ['BZR_EDITOR'] = self.make_do_nothing_editor()
815+ self.overrideEnv('BZR_EDITOR', self.make_do_nothing_editor())
816 self.assertEqual(True, msgeditor._run_editor(''),
817 'Unable to run dummy fake editor')
818
819@@ -191,11 +191,11 @@
820 "%s" fed.py %%1
821 """ % sys.executable)
822 f.close()
823- os.environ['BZR_EDITOR'] = 'fed.bat'
824+ self.overrideEnv('BZR_EDITOR', 'fed.bat')
825 else:
826 # [non-win32] make python script executable and set BZR_EDITOR
827 os.chmod('fed.py', 0755)
828- os.environ['BZR_EDITOR'] = './fed.py'
829+ self.overrideEnv('BZR_EDITOR', './fed.py')
830
831 def test_edit_commit_message(self):
832 working_tree = self.make_uncommitted_tree()
833@@ -230,16 +230,17 @@
834 working_tree = self.make_uncommitted_tree()
835
836 if sys.platform == 'win32':
837- os.environ['BZR_EDITOR'] = 'cmd.exe /c del'
838+ editor = 'cmd.exe /c del'
839 else:
840- os.environ['BZR_EDITOR'] = 'rm'
841+ editor = 'rm'
842+ self.overrideEnv('BZR_EDITOR', editor)
843
844 self.assertRaises((IOError, OSError), msgeditor.edit_commit_message, '')
845
846 def test__get_editor(self):
847- os.environ['BZR_EDITOR'] = 'bzr_editor'
848- os.environ['VISUAL'] = 'visual'
849- os.environ['EDITOR'] = 'editor'
850+ self.overrideEnv('BZR_EDITOR', 'bzr_editor')
851+ self.overrideEnv('VISUAL', 'visual')
852+ self.overrideEnv('EDITOR', 'editor')
853
854 conf = config.GlobalConfig.from_string('editor = config_editor\n',
855 save=True)
856@@ -259,7 +260,7 @@
857
858 def test__run_editor_EACCES(self):
859 """If running a configured editor raises EACESS, the user is warned."""
860- os.environ['BZR_EDITOR'] = 'eacces.py'
861+ self.overrideEnv('BZR_EDITOR', 'eacces.py')
862 f = file('eacces.py', 'wb')
863 f.write('# Not a real editor')
864 f.close()
865@@ -267,7 +268,7 @@
866 os.chmod('eacces.py', 0)
867 # Set $EDITOR so that _run_editor will terminate before trying real
868 # editors.
869- os.environ['EDITOR'] = self.make_do_nothing_editor()
870+ self.overrideEnv('EDITOR', self.make_do_nothing_editor())
871 # Call _run_editor, capturing mutter.warning calls.
872 warnings = []
873 def warning(*args):
874@@ -319,23 +320,20 @@
875 self.assertFileEqual('', msgfilename)
876
877 def test_unsupported_encoding_commit_message(self):
878- old_env = osutils.set_or_unset_env('LANG', 'C')
879- try:
880- # LANG env variable has no effect on Windows
881- # but some characters anyway cannot be represented
882- # in default user encoding
883- char = probe_bad_non_ascii(osutils.get_user_encoding())
884- if char is None:
885- raise TestSkipped('Cannot find suitable non-ascii character '
886- 'for user_encoding (%s)' % osutils.get_user_encoding())
887-
888- self.make_fake_editor(message=char)
889-
890- working_tree = self.make_uncommitted_tree()
891- self.assertRaises(errors.BadCommitMessageEncoding,
892- msgeditor.edit_commit_message, '')
893- finally:
894- osutils.set_or_unset_env('LANG', old_env)
895+ self.overrideEnv('LANG', 'C')
896+ # LANG env variable has no effect on Windows
897+ # but some characters anyway cannot be represented
898+ # in default user encoding
899+ char = probe_bad_non_ascii(osutils.get_user_encoding())
900+ if char is None:
901+ raise TestSkipped('Cannot find suitable non-ascii character '
902+ 'for user_encoding (%s)' % osutils.get_user_encoding())
903+
904+ self.make_fake_editor(message=char)
905+
906+ working_tree = self.make_uncommitted_tree()
907+ self.assertRaises(errors.BadCommitMessageEncoding,
908+ msgeditor.edit_commit_message, '')
909
910 def test_generate_commit_message_template_no_hooks(self):
911 commit_obj = commit.Commit()
912
913=== modified file 'bzrlib/tests/test_osutils.py'
914--- bzrlib/tests/test_osutils.py 2010-12-10 00:12:42 +0000
915+++ bzrlib/tests/test_osutils.py 2010-12-16 17:48:29 +0000
916@@ -1899,17 +1899,17 @@
917 self.assertIsInstance(concurrency, int)
918
919 def test_local_concurrency_environment_variable(self):
920- os.environ['BZR_CONCURRENCY'] = '2'
921+ self.overrideEnv('BZR_CONCURRENCY', '2')
922 self.assertEqual(2, osutils.local_concurrency(use_cache=False))
923- os.environ['BZR_CONCURRENCY'] = '3'
924+ self.overrideEnv('BZR_CONCURRENCY', '3')
925 self.assertEqual(3, osutils.local_concurrency(use_cache=False))
926- os.environ['BZR_CONCURRENCY'] = 'foo'
927+ self.overrideEnv('BZR_CONCURRENCY', 'foo')
928 self.assertEqual(1, osutils.local_concurrency(use_cache=False))
929
930 def test_option_concurrency(self):
931- os.environ['BZR_CONCURRENCY'] = '1'
932+ self.overrideEnv('BZR_CONCURRENCY', '1')
933 self.run_bzr('rocks --concurrency 42')
934- # Command line overrides envrionment variable
935+ # Command line overrides environment variable
936 self.assertEquals('42', os.environ['BZR_CONCURRENCY'])
937 self.assertEquals(42, osutils.local_concurrency(use_cache=False))
938
939@@ -1985,19 +1985,19 @@
940 def test_defaults_to_BZR_COLUMNS(self):
941 # BZR_COLUMNS is set by the test framework
942 self.assertNotEqual('12', os.environ['BZR_COLUMNS'])
943- os.environ['BZR_COLUMNS'] = '12'
944+ self.overrideEnv('BZR_COLUMNS', '12')
945 self.assertEqual(12, osutils.terminal_width())
946
947 def test_falls_back_to_COLUMNS(self):
948- del os.environ['BZR_COLUMNS']
949+ self.overrideEnv('BZR_COLUMNS', None)
950 self.assertNotEqual('42', os.environ['COLUMNS'])
951 self.set_fake_tty()
952- os.environ['COLUMNS'] = '42'
953+ self.overrideEnv('COLUMNS', '42')
954 self.assertEqual(42, osutils.terminal_width())
955
956 def test_tty_default_without_columns(self):
957- del os.environ['BZR_COLUMNS']
958- del os.environ['COLUMNS']
959+ self.overrideEnv('BZR_COLUMNS', None)
960+ self.overrideEnv('COLUMNS', None)
961
962 def terminal_size(w, h):
963 return 42, 42
964@@ -2010,8 +2010,8 @@
965 self.assertEqual(42, osutils.terminal_width())
966
967 def test_non_tty_default_without_columns(self):
968- del os.environ['BZR_COLUMNS']
969- del os.environ['COLUMNS']
970+ self.overrideEnv('BZR_COLUMNS', None)
971+ self.overrideEnv('COLUMNS', None)
972 self.replace_stdout(None)
973 self.assertEqual(None, osutils.terminal_width())
974
975@@ -2027,8 +2027,8 @@
976 else:
977 self.overrideAttr(termios, 'TIOCGWINSZ')
978 del termios.TIOCGWINSZ
979- del os.environ['BZR_COLUMNS']
980- del os.environ['COLUMNS']
981+ self.overrideEnv('BZR_COLUMNS', None)
982+ self.overrideEnv('COLUMNS', None)
983 # Whatever the result is, if we don't raise an exception, it's ok.
984 osutils.terminal_width()
985
986@@ -2070,7 +2070,7 @@
987 class TestGetuserUnicode(tests.TestCase):
988
989 def test_ascii_user(self):
990- osutils.set_or_unset_env('LOGNAME', 'jrandom')
991+ self.overrideEnv('LOGNAME', 'jrandom')
992 self.assertEqual(u'jrandom', osutils.getuser_unicode())
993
994 def test_unicode_user(self):
995@@ -2082,9 +2082,9 @@
996 % (osutils.get_user_encoding(),))
997 uni_username = u'jrandom' + uni_val
998 encoded_username = uni_username.encode(ue)
999- osutils.set_or_unset_env('LOGNAME', encoded_username)
1000+ self.overrideEnv('LOGNAME', encoded_username)
1001 self.assertEqual(uni_username, osutils.getuser_unicode())
1002- osutils.set_or_unset_env('LOGNAME', u'jrandom\xb6'.encode(ue))
1003+ self.overrideEnv('LOGNAME', u'jrandom\xb6'.encode(ue))
1004 self.assertEqual(u'jrandom\xb6', osutils.getuser_unicode())
1005
1006 class TestBackupNames(tests.TestCase):
1007
1008=== modified file 'bzrlib/tests/test_osutils_encodings.py'
1009--- bzrlib/tests/test_osutils_encodings.py 2010-06-29 16:21:13 +0000
1010+++ bzrlib/tests/test_osutils_encodings.py 2010-12-16 17:48:29 +0000
1011@@ -171,8 +171,6 @@
1012 def setUp(self):
1013 TestCase.setUp(self)
1014 self.overrideAttr(locale, 'getpreferredencoding')
1015- self.addCleanup(osutils.set_or_unset_env,
1016- 'LANG', os.environ.get('LANG'))
1017 self.overrideAttr(sys, 'stderr', StringIOWrapper())
1018
1019 def test_get_user_encoding(self):
1020@@ -181,7 +179,8 @@
1021
1022 locale.getpreferredencoding = f
1023 fake_codec.add('user_encoding')
1024- self.assertEquals('user_encoding', osutils.get_user_encoding(use_cache=False))
1025+ self.assertEquals('user_encoding',
1026+ osutils.get_user_encoding(use_cache=False))
1027 self.assertEquals('', sys.stderr.getvalue())
1028
1029 def test_user_cp0(self):
1030@@ -216,7 +215,7 @@
1031 raise locale.Error, 'unsupported locale'
1032
1033 locale.getpreferredencoding = f
1034- os.environ['LANG'] = 'BOGUS'
1035+ self.overrideEnv('LANG', 'BOGUS')
1036 self.assertEquals('ascii', osutils.get_user_encoding(use_cache=False))
1037 self.assertEquals('bzr: warning: unsupported locale\n'
1038 ' Could not determine what text encoding to use.\n'
1039
1040=== modified file 'bzrlib/tests/test_plugins.py'
1041--- bzrlib/tests/test_plugins.py 2010-06-11 08:02:42 +0000
1042+++ bzrlib/tests/test_plugins.py 2010-12-16 17:48:29 +0000
1043@@ -656,7 +656,7 @@
1044 self.fail('No path to global plugins')
1045
1046 def test_get_standard_plugins_path_env(self):
1047- os.environ['BZR_PLUGIN_PATH'] = 'foo/'
1048+ self.overrideEnv('BZR_PLUGIN_PATH', 'foo/')
1049 path = plugin.get_standard_plugins_path()
1050 for directory in path:
1051 self.assertNotContainsRe(directory, r'\\/$')
1052@@ -692,7 +692,7 @@
1053
1054 def _set_path(self, *args):
1055 path = os.pathsep.join(self._list2paths(*args))
1056- osutils.set_or_unset_env('BZR_PLUGIN_PATH', path)
1057+ self.overrideEnv('BZR_PLUGIN_PATH', path)
1058
1059 def check_path(self, expected_dirs, setting_dirs):
1060 if setting_dirs:
1061@@ -779,7 +779,7 @@
1062 self.addCleanup(self._unregister_plugin, 'test_foo')
1063
1064 def test_cannot_import(self):
1065- osutils.set_or_unset_env('BZR_DISABLE_PLUGINS', 'test_foo')
1066+ self.overrideEnv('BZR_DISABLE_PLUGINS', 'test_foo')
1067 plugin.set_plugins_path(['.'])
1068 try:
1069 import bzrlib.plugins.test_foo
1070@@ -801,7 +801,7 @@
1071 self.overrideAttr(trace, 'warning', captured_warning)
1072 # Reset the flag that protect against double loading
1073 self.overrideAttr(plugin, '_loaded', False)
1074- osutils.set_or_unset_env('BZR_DISABLE_PLUGINS', 'test_foo')
1075+ self.overrideEnv('BZR_DISABLE_PLUGINS', 'test_foo')
1076 plugin.load_plugins(['.'])
1077 self.assertPluginUnknown('test_foo')
1078 # Make sure we don't warn about the plugin ImportError since this has
1079@@ -859,7 +859,7 @@
1080 self.assertTestFooLoadedFrom('standard/test_foo')
1081
1082 def test_import(self):
1083- osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
1084+ self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
1085 plugin.set_plugins_path(['standard'])
1086 try:
1087 import bzrlib.plugins.test_foo
1088@@ -868,12 +868,12 @@
1089 self.assertTestFooLoadedFrom('non-standard-dir')
1090
1091 def test_loading(self):
1092- osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
1093+ self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
1094 plugin.load_plugins(['standard'])
1095 self.assertTestFooLoadedFrom('non-standard-dir')
1096
1097 def test_compiled_loaded(self):
1098- osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
1099+ self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
1100 plugin.load_plugins(['standard'])
1101 self.assertTestFooLoadedFrom('non-standard-dir')
1102 self.assertIsSameRealPath('non-standard-dir/__init__.py',
1103@@ -896,7 +896,7 @@
1104 self.create_plugin_package('test_bar', dir='non-standard-dir/test_bar')
1105 self.addCleanup(self._unregister_plugin_submodule,
1106 'test_foo', 'test_bar')
1107- osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
1108+ self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
1109 plugin.set_plugins_path(['standard'])
1110 import bzrlib.plugins.test_foo
1111 self.assertEqual('bzrlib.plugins.test_foo',
1112@@ -913,7 +913,7 @@
1113 self.create_plugin_package('test_bar', dir='another-dir/test_bar')
1114 self.addCleanup(self._unregister_plugin_submodule,
1115 'test_foo', 'test_bar')
1116- osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@another-dir')
1117+ self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@another-dir')
1118 plugin.set_plugins_path(['standard'])
1119 import bzrlib.plugins.test_foo
1120 self.assertEqual('bzrlib.plugins.test_foo',
1121@@ -928,7 +928,7 @@
1122 random = 'non-standard-dir/setup.py'
1123 os.rename(init, random)
1124 self.addCleanup(os.rename, random, init)
1125- osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
1126+ self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
1127 plugin.load_plugins(['standard'])
1128 self.assertPluginUnknown('test_foo')
1129
1130@@ -942,6 +942,6 @@
1131 ''' % ('test_foo', plugin_path)
1132 self.create_plugin('test_foo', source=source,
1133 dir=plugin_dir, file_name=plugin_file_name)
1134- osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@%s' % plugin_path)
1135+ self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@%s' % plugin_path)
1136 plugin.load_plugins(['standard'])
1137 self.assertTestFooLoadedFrom(plugin_path)
1138
1139=== modified file 'bzrlib/tests/test_read_bundle.py'
1140--- bzrlib/tests/test_read_bundle.py 2010-12-09 04:26:53 +0000
1141+++ bzrlib/tests/test_read_bundle.py 2010-12-16 17:48:29 +0000
1142@@ -69,7 +69,7 @@
1143 # from the one we want to test, so we must inject a correct transport
1144 # into possible_transports first).
1145 self.possible_transports = [self.get_transport(self.bundle_name)]
1146- self._captureVar('BZR_NO_SMART_VFS', None)
1147+ self.overrideEnv('BZR_NO_SMART_VFS', None)
1148 wt = self.create_test_bundle()
1149
1150 def read_mergeable_from_url(self, url):
1151
1152=== modified file 'bzrlib/tests/test_rules.py'
1153--- bzrlib/tests/test_rules.py 2010-01-14 15:24:04 +0000
1154+++ bzrlib/tests/test_rules.py 2010-12-16 17:48:29 +0000
1155@@ -118,10 +118,10 @@
1156
1157 def setUp(self):
1158 super(TestRulesPath, self).setUp()
1159- os.environ['HOME'] = '/home/bogus'
1160+ self.overrideEnv('HOME', '/home/bogus')
1161 if sys.platform == 'win32':
1162- os.environ['BZR_HOME'] = \
1163- r'C:\Documents and Settings\bogus\Application Data'
1164+ self.overrideEnv(
1165+ 'BZR_HOME', r'C:\Documents and Settings\bogus\Application Data')
1166 self.bzr_home = \
1167 'C:/Documents and Settings/bogus/Application Data/bazaar/2.0'
1168 else:
1169
1170=== modified file 'bzrlib/tests/test_selftest.py'
1171--- bzrlib/tests/test_selftest.py 2010-11-19 23:03:19 +0000
1172+++ bzrlib/tests/test_selftest.py 2010-12-16 17:48:29 +0000
1173@@ -3387,10 +3387,9 @@
1174 result = tests.ExtendedTestResult(StringIO(), 0, 1)
1175 post_mortem_calls = []
1176 self.overrideAttr(pdb, "post_mortem", post_mortem_calls.append)
1177- self.addCleanup(osutils.set_or_unset_env, "BZR_TEST_PDB",
1178- osutils.set_or_unset_env("BZR_TEST_PDB", None))
1179+ self.overrideEnv('BZR_TEST_PDB', None)
1180 result._post_mortem(1)
1181- os.environ["BZR_TEST_PDB"] = "on"
1182+ self.overrideEnv('BZR_TEST_PDB', 'on')
1183 result._post_mortem(2)
1184 self.assertEqual([2], post_mortem_calls)
1185
1186@@ -3411,3 +3410,48 @@
1187 self.verbosity)
1188 tests.run_suite(suite, runner_class=MyRunner, stream=StringIO())
1189 self.assertLength(1, calls)
1190+
1191+
1192+class TestEnvironHandling(tests.TestCase):
1193+
1194+ def test__captureVar_None_called_twice_leaks(self):
1195+ self.failIf('MYVAR' in os.environ)
1196+ self._captureVar('MYVAR', '42')
1197+ # We need an embedded test to observe the bug
1198+ class Test(tests.TestCase):
1199+ def test_me(self):
1200+ # The first call save the 42 value
1201+ self._captureVar('MYVAR', None)
1202+ self.assertEquals(None, os.environ.get('MYVAR'))
1203+ self.assertEquals('42', self._old_env.get('MYVAR'))
1204+ # But the second one erases it !
1205+ self._captureVar('MYVAR', None)
1206+ self.assertEquals(None, self._old_env.get('MYVAR'))
1207+ output = StringIO()
1208+ result = tests.TextTestResult(output, 0, 1)
1209+ Test('test_me').run(result)
1210+ if not result.wasStrictlySuccessful():
1211+ self.fail(output.getvalue())
1212+ # And we have lost all trace of the original value
1213+ self.assertEquals(None, os.environ.get('MYVAR'))
1214+ self.assertEquals(None, self._old_env.get('MYVAR'))
1215+
1216+ def test_overrideEnv_None_called_twice_doesnt_leak(self):
1217+ self.failIf('MYVAR' in os.environ)
1218+ self.overrideEnv('MYVAR', '42')
1219+ # We use an embedded test to make sure we fix the _captureVar bug
1220+ class Test(tests.TestCase):
1221+ def test_me(self):
1222+ # The first call save the 42 value
1223+ self.overrideEnv('MYVAR', None)
1224+ self.assertEquals(None, os.environ.get('MYVAR'))
1225+ # Make sure we can call it twice
1226+ self.overrideEnv('MYVAR', None)
1227+ self.assertEquals(None, os.environ.get('MYVAR'))
1228+ output = StringIO()
1229+ result = tests.TextTestResult(output, 0, 1)
1230+ Test('test_me').run(result)
1231+ if not result.wasStrictlySuccessful():
1232+ self.fail(output.getvalue())
1233+ # We get our value back
1234+ self.assertEquals('42', os.environ.get('MYVAR'))
1235
1236=== modified file 'bzrlib/tests/test_sftp_transport.py'
1237--- bzrlib/tests/test_sftp_transport.py 2010-06-23 08:17:20 +0000
1238+++ bzrlib/tests/test_sftp_transport.py 2010-12-16 17:48:29 +0000
1239@@ -32,7 +32,6 @@
1240 from bzrlib.osutils import (
1241 pathjoin,
1242 lexists,
1243- set_or_unset_env,
1244 )
1245 from bzrlib.tests import (
1246 features,
1247@@ -174,27 +173,21 @@
1248 """Test that if no 'ssh' is available we get builtin paramiko"""
1249 from bzrlib.transport import ssh
1250 # set '.' as the only location in the path, forcing no 'ssh' to exist
1251- orig_vendor = ssh._ssh_vendor_manager._cached_ssh_vendor
1252- orig_path = set_or_unset_env('PATH', '.')
1253- try:
1254- # No vendor defined yet, query for one
1255- ssh._ssh_vendor_manager.clear_cache()
1256- vendor = ssh._get_ssh_vendor()
1257- self.assertIsInstance(vendor, ssh.ParamikoVendor)
1258- finally:
1259- set_or_unset_env('PATH', orig_path)
1260- ssh._ssh_vendor_manager._cached_ssh_vendor = orig_vendor
1261+ self.overrideAttr(ssh, '_ssh_vendor_manager')
1262+ self.overrideEnv('PATH', '.')
1263+ ssh._ssh_vendor_manager.clear_cache()
1264+ vendor = ssh._get_ssh_vendor()
1265+ self.assertIsInstance(vendor, ssh.ParamikoVendor)
1266
1267 def test_abspath_root_sibling_server(self):
1268 server = stub_sftp.SFTPSiblingAbsoluteServer()
1269 server.start_server()
1270- try:
1271- transport = _mod_transport.get_transport(server.get_url())
1272- self.assertFalse(transport.abspath('/').endswith('/~/'))
1273- self.assertTrue(transport.abspath('/').endswith('/'))
1274- del transport
1275- finally:
1276- server.stop_server()
1277+ self.addCleanup(server.stop_server)
1278+
1279+ transport = _mod_transport.get_transport(server.get_url())
1280+ self.assertFalse(transport.abspath('/').endswith('/~/'))
1281+ self.assertTrue(transport.abspath('/').endswith('/'))
1282+ del transport
1283
1284
1285 class SFTPBranchTest(TestCaseWithSFTPServer):
1286
1287=== modified file 'bzrlib/tests/test_smart_transport.py'
1288--- bzrlib/tests/test_smart_transport.py 2010-07-01 15:25:41 +0000
1289+++ bzrlib/tests/test_smart_transport.py 2010-12-16 17:48:29 +0000
1290@@ -615,7 +615,7 @@
1291
1292 def setUp(self):
1293 super(TestSmartServerStreamMedium, self).setUp()
1294- self._captureVar('BZR_NO_SMART_VFS', None)
1295+ self.overrideEnv('BZR_NO_SMART_VFS', None)
1296
1297 def portable_socket_pair(self):
1298 """Return a pair of TCP sockets connected to each other.
1299@@ -970,7 +970,7 @@
1300
1301 def test_get_error_unexpected(self):
1302 """Error reported by server with no specific representation"""
1303- self._captureVar('BZR_NO_SMART_VFS', None)
1304+ self.overrideEnv('BZR_NO_SMART_VFS', None)
1305 class FlakyTransport(object):
1306 base = 'a_url'
1307 def external_url(self):
1308@@ -1077,14 +1077,14 @@
1309
1310 def test_smart_transport_has(self):
1311 """Checking for file existence over smart."""
1312- self._captureVar('BZR_NO_SMART_VFS', None)
1313+ self.overrideEnv('BZR_NO_SMART_VFS', None)
1314 self.backing_transport.put_bytes("foo", "contents of foo\n")
1315 self.assertTrue(self.transport.has("foo"))
1316 self.assertFalse(self.transport.has("non-foo"))
1317
1318 def test_smart_transport_get(self):
1319 """Read back a file over smart."""
1320- self._captureVar('BZR_NO_SMART_VFS', None)
1321+ self.overrideEnv('BZR_NO_SMART_VFS', None)
1322 self.backing_transport.put_bytes("foo", "contents\nof\nfoo\n")
1323 fp = self.transport.get("foo")
1324 self.assertEqual('contents\nof\nfoo\n', fp.read())
1325@@ -1094,7 +1094,7 @@
1326 # The path in a raised NoSuchFile exception should be the precise path
1327 # asked for by the client. This gives meaningful and unsurprising errors
1328 # for users.
1329- self._captureVar('BZR_NO_SMART_VFS', None)
1330+ self.overrideEnv('BZR_NO_SMART_VFS', None)
1331 err = self.assertRaises(
1332 errors.NoSuchFile, self.transport.get, 'not%20a%20file')
1333 self.assertSubset([err.path], ['not%20a%20file', './not%20a%20file'])
1334@@ -1119,7 +1119,7 @@
1335
1336 def test_open_dir(self):
1337 """Test changing directory"""
1338- self._captureVar('BZR_NO_SMART_VFS', None)
1339+ self.overrideEnv('BZR_NO_SMART_VFS', None)
1340 transport = self.transport
1341 self.backing_transport.mkdir('toffee')
1342 self.backing_transport.mkdir('toffee/apple')
1343@@ -1147,7 +1147,7 @@
1344
1345 def test_mkdir_error_readonly(self):
1346 """TransportNotPossible should be preserved from the backing transport."""
1347- self._captureVar('BZR_NO_SMART_VFS', None)
1348+ self.overrideEnv('BZR_NO_SMART_VFS', None)
1349 self.start_server(readonly=True)
1350 self.assertRaises(errors.TransportNotPossible, self.transport.mkdir,
1351 'foo')
1352@@ -1261,7 +1261,7 @@
1353
1354 def setUp(self):
1355 super(SmartServerRequestHandlerTests, self).setUp()
1356- self._captureVar('BZR_NO_SMART_VFS', None)
1357+ self.overrideEnv('BZR_NO_SMART_VFS', None)
1358
1359 def build_handler(self, transport):
1360 """Returns a handler for the commands in protocol version one."""
1361@@ -1286,10 +1286,7 @@
1362 handler = vfs.HasRequest(None, '/')
1363 # set environment variable after construction to make sure it's
1364 # examined.
1365- # Note that we can safely clobber BZR_NO_SMART_VFS here, because setUp
1366- # has called _captureVar, so it will be restored to the right state
1367- # afterwards.
1368- os.environ['BZR_NO_SMART_VFS'] = ''
1369+ self.overrideEnv('BZR_NO_SMART_VFS', '')
1370 self.assertRaises(errors.DisabledMethod, handler.execute)
1371
1372 def test_readonly_exception_becomes_transport_not_possible(self):
1373@@ -1602,7 +1599,7 @@
1374 self.assertTrue(self.end_received)
1375
1376 def test_accept_request_and_body_all_at_once(self):
1377- self._captureVar('BZR_NO_SMART_VFS', None)
1378+ self.overrideEnv('BZR_NO_SMART_VFS', None)
1379 mem_transport = memory.MemoryTransport()
1380 mem_transport.put_bytes('foo', 'abcdefghij')
1381 out_stream = StringIO()
1382@@ -1868,7 +1865,7 @@
1383 self.assertTrue(self.end_received)
1384
1385 def test_accept_request_and_body_all_at_once(self):
1386- self._captureVar('BZR_NO_SMART_VFS', None)
1387+ self.overrideEnv('BZR_NO_SMART_VFS', None)
1388 mem_transport = memory.MemoryTransport()
1389 mem_transport.put_bytes('foo', 'abcdefghij')
1390 out_stream = StringIO()
1391@@ -3517,7 +3514,7 @@
1392 def setUp(self):
1393 super(HTTPTunnellingSmokeTest, self).setUp()
1394 # We use the VFS layer as part of HTTP tunnelling tests.
1395- self._captureVar('BZR_NO_SMART_VFS', None)
1396+ self.overrideEnv('BZR_NO_SMART_VFS', None)
1397
1398 def test_smart_http_medium_request_accept_bytes(self):
1399 medium = FakeHTTPMedium()
1400
1401=== modified file 'bzrlib/tests/test_trace.py'
1402--- bzrlib/tests/test_trace.py 2010-10-11 09:53:16 +0000
1403+++ bzrlib/tests/test_trace.py 2010-12-16 17:48:29 +0000
1404@@ -301,9 +301,7 @@
1405 # set up.
1406 self.overrideAttr(sys, 'stderr', StringIO())
1407 # Set the log file to something that cannot exist
1408- # FIXME: A bit dangerous: we are not in an isolated dir here -- vilajam
1409- # 20100125
1410- os.environ['BZR_LOG'] = os.getcwd() + '/no-dir/bzr.log'
1411+ self.overrideEnv('BZR_LOG', os.getcwd() + '/no-dir/bzr.log')
1412 self.overrideAttr(trace, '_bzr_log_filename')
1413 logf = trace._open_bzr_log()
1414 self.assertIs(None, logf)
1415
1416=== modified file 'bzrlib/tests/test_transport.py'
1417--- bzrlib/tests/test_transport.py 2010-10-08 07:17:16 +0000
1418+++ bzrlib/tests/test_transport.py 2010-12-16 17:48:29 +0000
1419@@ -967,7 +967,7 @@
1420 bzr_remote_path = sys.executable + ' ' + self.get_bzr_path()
1421 else:
1422 bzr_remote_path = self.get_bzr_path()
1423- os.environ['BZR_REMOTE_PATH'] = bzr_remote_path
1424+ self.overrideEnv('BZR_REMOTE_PATH', bzr_remote_path)
1425
1426 # Access the branch via a bzr+ssh URL. The BZR_REMOTE_PATH environment
1427 # variable is used to tell bzr what command to run on the remote end.
1428
1429=== modified file 'bzrlib/tests/test_ui.py'
1430--- bzrlib/tests/test_ui.py 2010-12-02 10:41:05 +0000
1431+++ bzrlib/tests/test_ui.py 2010-12-16 17:48:29 +0000
1432@@ -158,7 +158,7 @@
1433 def test_text_factory_prompts_and_clears(self):
1434 # a get_boolean call should clear the pb before prompting
1435 out = test_progress._TTYStringIO()
1436- os.environ['TERM'] = 'xterm'
1437+ self.overrideEnv('TERM', 'xterm')
1438 factory = _mod_ui_text.TextUIFactory(
1439 stdin=tests.StringIOWrapper("yada\ny\n"),
1440 stdout=out, stderr=out)
1441@@ -226,7 +226,7 @@
1442 pb.finished()
1443
1444 def test_quietness(self):
1445- os.environ['BZR_PROGRESS_BAR'] = 'text'
1446+ self.overrideEnv('BZR_PROGRESS_BAR', 'text')
1447 ui_factory = _mod_ui_text.TextUIFactory(None,
1448 test_progress._TTYStringIO(),
1449 test_progress._TTYStringIO())
1450@@ -313,12 +313,8 @@
1451 # however, it can still be forced on
1452 (FileStringIO, 'dumb', 'text', _mod_ui_text.TextProgressView),
1453 ):
1454- os.environ['TERM'] = term
1455- if pb is None:
1456- if 'BZR_PROGRESS_BAR' in os.environ:
1457- del os.environ['BZR_PROGRESS_BAR']
1458- else:
1459- os.environ['BZR_PROGRESS_BAR'] = pb
1460+ self.overrideEnv('TERM', term)
1461+ self.overrideEnv('BZR_PROGRESS_BAR', pb)
1462 stdin = file_class('')
1463 stderr = file_class()
1464 stdout = file_class()
1465@@ -335,10 +331,7 @@
1466 stderr = test_progress._NonTTYStringIO()
1467 stdout = test_progress._NonTTYStringIO()
1468 for term_type in ['dumb', None, 'xterm']:
1469- if term_type is None:
1470- del os.environ['TERM']
1471- else:
1472- os.environ['TERM'] = term_type
1473+ self.overrideEnv('TERM', term_type)
1474 uif = _mod_ui.make_ui_for_terminal(stdin, stdout, stderr)
1475 self.assertIsInstance(uif, _mod_ui_text.TextUIFactory,
1476 'TERM=%r' % (term_type,))
1477
1478=== modified file 'bzrlib/tests/test_win32utils.py'
1479--- bzrlib/tests/test_win32utils.py 2010-12-07 17:28:31 +0000
1480+++ bzrlib/tests/test_win32utils.py 2010-12-16 17:48:29 +0000
1481@@ -217,7 +217,7 @@
1482 def test_appdata_not_using_environment(self):
1483 # Test that we aren't falling back to the environment
1484 first = win32utils.get_appdata_location()
1485- self._captureVar("APPDATA", None)
1486+ self.overrideEnv("APPDATA", None)
1487 self.assertPathsEqual(first, win32utils.get_appdata_location())
1488
1489 def test_appdata_matches_environment(self):
1490@@ -234,7 +234,7 @@
1491 def test_local_appdata_not_using_environment(self):
1492 # Test that we aren't falling back to the environment
1493 first = win32utils.get_local_appdata_location()
1494- self._captureVar("LOCALAPPDATA", None)
1495+ self.overrideEnv("LOCALAPPDATA", None)
1496 self.assertPathsEqual(first, win32utils.get_local_appdata_location())
1497
1498 def test_local_appdata_matches_environment(self):
1499
1500=== modified file 'doc/developers/testing.txt'
1501--- doc/developers/testing.txt 2010-12-09 00:18:26 +0000
1502+++ doc/developers/testing.txt 2010-12-16 17:48:29 +0000
1503@@ -977,6 +977,25 @@
1504
1505 self.overrideAttr(osutils, '_cached_user_encoding', 'latin-1')
1506
1507+Temporarily changing environment variables
1508+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1509+
1510+If yout test needs to temporarily change some environment variable value
1511+(which generally means you want it restored at the end), you can use::
1512+
1513+ self.overrideEnv('BZR_ENV_VAR', 'new_value')
1514+
1515+If you want to remove a variable from the environment, you should use the
1516+special ``None`` value::
1517+
1518+ self.overrideEnv('PATH', None)
1519+
1520+If you add a new feature which depends on a new environment variable, make
1521+sure it behaves properly when this variable is not defined (if applicable) and
1522+if you need to enforce a specific default value, check the
1523+``TestCase._cleanEnvironment`` in ``bzrlib.tests.__init__.py`` which defines a
1524+proper set of values for all tests.
1525+
1526 Cleaning up
1527 ~~~~~~~~~~~
1528
1529
1530=== modified file 'doc/en/release-notes/bzr-2.3.txt'
1531--- doc/en/release-notes/bzr-2.3.txt 2010-12-16 15:15:17 +0000
1532+++ doc/en/release-notes/bzr-2.3.txt 2010-12-16 17:48:29 +0000
1533@@ -189,6 +189,11 @@
1534 to 0.9.5 which will allow tests that need the fixed unicode handling to be
1535 written. (Martin [gz])
1536
1537+* Introduce an ``overrideEnv()`` helper for tests that needs to change the
1538+ environment variables while respecting the isolation rules. Get rid of
1539+ TestCase._restoreEnvironment which is now useless.
1540+ (Vincent Ladeuil, #690563)
1541+
1542 * Printing selftest results to a non-UTF-8 console will now escape characters
1543 that can't be encoded rather than aborting the test run with an exception.
1544 (Martin [gz], #633216)