gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / dulwich / tests / compat / test_client.py @ 959
History | View | Annotate | Download (19 KB)
1 |
# test_client.py -- Compatibilty tests for git client.
|
---|---|
2 |
# Copyright (C) 2010 Google, Inc.
|
3 |
#
|
4 |
# Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
|
5 |
# General Public License as public by the Free Software Foundation; version 2.0
|
6 |
# or (at your option) any later version. You can redistribute it and/or
|
7 |
# modify it under the terms of either of these two licenses.
|
8 |
#
|
9 |
# Unless required by applicable law or agreed to in writing, software
|
10 |
# distributed under the License is distributed on an "AS IS" BASIS,
|
11 |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12 |
# See the License for the specific language governing permissions and
|
13 |
# limitations under the License.
|
14 |
#
|
15 |
# You should have received a copy of the licenses; if not, see
|
16 |
# <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
|
17 |
# and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
|
18 |
# License, Version 2.0.
|
19 |
#
|
20 |
|
21 |
"""Compatibilty tests between the Dulwich client and the cgit server."""
|
22 |
|
23 |
import copy |
24 |
from io import BytesIO |
25 |
import os |
26 |
import select |
27 |
import signal |
28 |
import subprocess |
29 |
import sys |
30 |
import tarfile |
31 |
import tempfile |
32 |
import threading |
33 |
|
34 |
try:
|
35 |
from urlparse import unquote |
36 |
except ImportError: |
37 |
from urllib.parse import unquote |
38 |
|
39 |
|
40 |
try:
|
41 |
import BaseHTTPServer |
42 |
import SimpleHTTPServer |
43 |
except ImportError: |
44 |
import http.server |
45 |
BaseHTTPServer = http.server |
46 |
SimpleHTTPServer = http.server |
47 |
|
48 |
if sys.platform == 'win32': |
49 |
import ctypes |
50 |
|
51 |
from dulwich import ( |
52 |
client, |
53 |
errors, |
54 |
file,
|
55 |
index, |
56 |
protocol, |
57 |
objects, |
58 |
repo, |
59 |
) |
60 |
from dulwich.tests import ( |
61 |
SkipTest, |
62 |
expectedFailure, |
63 |
) |
64 |
from dulwich.tests.compat.utils import ( |
65 |
CompatTestCase, |
66 |
check_for_daemon, |
67 |
import_repo_to_dir, |
68 |
rmtree_ro, |
69 |
run_git_or_fail, |
70 |
_DEFAULT_GIT, |
71 |
) |
72 |
|
73 |
|
74 |
class DulwichClientTestBase(object): |
75 |
"""Tests for client/server compatibility."""
|
76 |
|
77 |
def setUp(self): |
78 |
self.gitroot = os.path.dirname(import_repo_to_dir('server_new.export').rstrip(os.sep)) |
79 |
self.dest = os.path.join(self.gitroot, 'dest') |
80 |
file.ensure_dir_exists(self.dest) |
81 |
run_git_or_fail(['init', '--quiet', '--bare'], cwd=self.dest) |
82 |
|
83 |
def tearDown(self): |
84 |
rmtree_ro(self.gitroot)
|
85 |
|
86 |
def assertDestEqualsSrc(self): |
87 |
repo_dir = os.path.join(self.gitroot, 'server_new.export') |
88 |
dest_repo_dir = os.path.join(self.gitroot, 'dest') |
89 |
with repo.Repo(repo_dir) as src: |
90 |
with repo.Repo(dest_repo_dir) as dest: |
91 |
self.assertReposEqual(src, dest)
|
92 |
|
93 |
def _client(self): |
94 |
raise NotImplementedError() |
95 |
|
96 |
def _build_path(self): |
97 |
raise NotImplementedError() |
98 |
|
99 |
def _do_send_pack(self): |
100 |
c = self._client()
|
101 |
srcpath = os.path.join(self.gitroot, 'server_new.export') |
102 |
with repo.Repo(srcpath) as src: |
103 |
sendrefs = dict(src.get_refs())
|
104 |
del sendrefs[b'HEAD'] |
105 |
c.send_pack(self._build_path(b'/dest'), lambda _: sendrefs, |
106 |
src.object_store.generate_pack_contents) |
107 |
|
108 |
def test_send_pack(self): |
109 |
self._do_send_pack()
|
110 |
self.assertDestEqualsSrc()
|
111 |
|
112 |
def test_send_pack_nothing_to_send(self): |
113 |
self._do_send_pack()
|
114 |
self.assertDestEqualsSrc()
|
115 |
# nothing to send, but shouldn't raise either.
|
116 |
self._do_send_pack()
|
117 |
|
118 |
def test_send_without_report_status(self): |
119 |
c = self._client()
|
120 |
c._send_capabilities.remove(b'report-status')
|
121 |
srcpath = os.path.join(self.gitroot, 'server_new.export') |
122 |
with repo.Repo(srcpath) as src: |
123 |
sendrefs = dict(src.get_refs())
|
124 |
del sendrefs[b'HEAD'] |
125 |
c.send_pack(self._build_path(b'/dest'), lambda _: sendrefs, |
126 |
src.object_store.generate_pack_contents) |
127 |
self.assertDestEqualsSrc()
|
128 |
|
129 |
def make_dummy_commit(self, dest): |
130 |
b = objects.Blob.from_string(b'hi')
|
131 |
dest.object_store.add_object(b) |
132 |
t = index.commit_tree(dest.object_store, [(b'hi', b.id, 0o100644)]) |
133 |
c = objects.Commit() |
134 |
c.author = c.committer = b'Foo Bar <foo@example.com>'
|
135 |
c.author_time = c.commit_time = 0
|
136 |
c.author_timezone = c.commit_timezone = 0
|
137 |
c.message = b'hi'
|
138 |
c.tree = t |
139 |
dest.object_store.add_object(c) |
140 |
return c.id
|
141 |
|
142 |
def disable_ff_and_make_dummy_commit(self): |
143 |
# disable non-fast-forward pushes to the server
|
144 |
dest = repo.Repo(os.path.join(self.gitroot, 'dest')) |
145 |
run_git_or_fail(['config', 'receive.denyNonFastForwards', 'true'], |
146 |
cwd=dest.path) |
147 |
commit_id = self.make_dummy_commit(dest)
|
148 |
return dest, commit_id
|
149 |
|
150 |
def compute_send(self, src): |
151 |
sendrefs = dict(src.get_refs())
|
152 |
del sendrefs[b'HEAD'] |
153 |
return sendrefs, src.object_store.generate_pack_contents
|
154 |
|
155 |
def test_send_pack_one_error(self): |
156 |
dest, dummy_commit = self.disable_ff_and_make_dummy_commit()
|
157 |
dest.refs[b'refs/heads/master'] = dummy_commit
|
158 |
repo_dir = os.path.join(self.gitroot, 'server_new.export') |
159 |
with repo.Repo(repo_dir) as src: |
160 |
sendrefs, gen_pack = self.compute_send(src)
|
161 |
c = self._client()
|
162 |
try:
|
163 |
c.send_pack(self._build_path(b'/dest'), lambda _: sendrefs, gen_pack) |
164 |
except errors.UpdateRefsError as e: |
165 |
self.assertEqual('refs/heads/master failed to update', |
166 |
e.args[0])
|
167 |
self.assertEqual({b'refs/heads/branch': b'ok', |
168 |
b'refs/heads/master': b'non-fast-forward'}, |
169 |
e.ref_status) |
170 |
|
171 |
def test_send_pack_multiple_errors(self): |
172 |
dest, dummy = self.disable_ff_and_make_dummy_commit()
|
173 |
# set up for two non-ff errors
|
174 |
branch, master = b'refs/heads/branch', b'refs/heads/master' |
175 |
dest.refs[branch] = dest.refs[master] = dummy |
176 |
repo_dir = os.path.join(self.gitroot, 'server_new.export') |
177 |
with repo.Repo(repo_dir) as src: |
178 |
sendrefs, gen_pack = self.compute_send(src)
|
179 |
c = self._client()
|
180 |
try:
|
181 |
c.send_pack(self._build_path(b'/dest'), lambda _: sendrefs, gen_pack) |
182 |
except errors.UpdateRefsError as e: |
183 |
self.assertIn(str(e), |
184 |
['{0}, {1} failed to update'.format(
|
185 |
branch.decode('ascii'), master.decode('ascii')), |
186 |
'{1}, {0} failed to update'.format(
|
187 |
branch.decode('ascii'), master.decode('ascii'))]) |
188 |
self.assertEqual({branch: b'non-fast-forward', |
189 |
master: b'non-fast-forward'},
|
190 |
e.ref_status) |
191 |
|
192 |
def test_archive(self): |
193 |
c = self._client()
|
194 |
f = BytesIO() |
195 |
c.archive(self._build_path(b'/server_new.export'), b'HEAD', f.write) |
196 |
f.seek(0)
|
197 |
tf = tarfile.open(fileobj=f) |
198 |
self.assertEqual(['baz', 'foo'], tf.getnames()) |
199 |
|
200 |
def test_fetch_pack(self): |
201 |
c = self._client()
|
202 |
with repo.Repo(os.path.join(self.gitroot, 'dest')) as dest: |
203 |
refs = c.fetch(self._build_path(b'/server_new.export'), dest) |
204 |
for r in refs.items(): |
205 |
dest.refs.set_if_equals(r[0], None, r[1]) |
206 |
self.assertDestEqualsSrc()
|
207 |
|
208 |
def test_incremental_fetch_pack(self): |
209 |
self.test_fetch_pack()
|
210 |
dest, dummy = self.disable_ff_and_make_dummy_commit()
|
211 |
dest.refs[b'refs/heads/master'] = dummy
|
212 |
c = self._client()
|
213 |
repo_dir = os.path.join(self.gitroot, 'server_new.export') |
214 |
with repo.Repo(repo_dir) as dest: |
215 |
refs = c.fetch(self._build_path(b'/dest'), dest) |
216 |
for r in refs.items(): |
217 |
dest.refs.set_if_equals(r[0], None, r[1]) |
218 |
self.assertDestEqualsSrc()
|
219 |
|
220 |
def test_fetch_pack_no_side_band_64k(self): |
221 |
c = self._client()
|
222 |
c._fetch_capabilities.remove(b'side-band-64k')
|
223 |
with repo.Repo(os.path.join(self.gitroot, 'dest')) as dest: |
224 |
refs = c.fetch(self._build_path(b'/server_new.export'), dest) |
225 |
for r in refs.items(): |
226 |
dest.refs.set_if_equals(r[0], None, r[1]) |
227 |
self.assertDestEqualsSrc()
|
228 |
|
229 |
def test_fetch_pack_zero_sha(self): |
230 |
# zero sha1s are already present on the client, and should
|
231 |
# be ignored
|
232 |
c = self._client()
|
233 |
with repo.Repo(os.path.join(self.gitroot, 'dest')) as dest: |
234 |
refs = c.fetch(self._build_path(b'/server_new.export'), dest, |
235 |
lambda refs: [protocol.ZERO_SHA])
|
236 |
for r in refs.items(): |
237 |
dest.refs.set_if_equals(r[0], None, r[1]) |
238 |
|
239 |
def test_send_remove_branch(self): |
240 |
with repo.Repo(os.path.join(self.gitroot, 'dest')) as dest: |
241 |
dummy_commit = self.make_dummy_commit(dest)
|
242 |
dest.refs[b'refs/heads/master'] = dummy_commit
|
243 |
dest.refs[b'refs/heads/abranch'] = dummy_commit
|
244 |
sendrefs = dict(dest.refs)
|
245 |
sendrefs[b'refs/heads/abranch'] = b"00" * 20 |
246 |
del sendrefs[b'HEAD'] |
247 |
gen_pack = lambda have, want: []
|
248 |
c = self._client()
|
249 |
self.assertEqual(dest.refs[b"refs/heads/abranch"], dummy_commit) |
250 |
c.send_pack(self._build_path(b'/dest'), lambda _: sendrefs, gen_pack) |
251 |
self.assertFalse(b"refs/heads/abranch" in dest.refs) |
252 |
|
253 |
def test_get_refs(self): |
254 |
c = self._client()
|
255 |
refs = c.get_refs(self._build_path(b'/server_new.export')) |
256 |
|
257 |
repo_dir = os.path.join(self.gitroot, 'server_new.export') |
258 |
with repo.Repo(repo_dir) as dest: |
259 |
self.assertDictEqual(dest.refs.as_dict(), refs)
|
260 |
|
261 |
|
262 |
class DulwichTCPClientTest(CompatTestCase, DulwichClientTestBase): |
263 |
|
264 |
def setUp(self): |
265 |
CompatTestCase.setUp(self)
|
266 |
DulwichClientTestBase.setUp(self)
|
267 |
if check_for_daemon(limit=1): |
268 |
raise SkipTest('git-daemon was already running on port %s' % |
269 |
protocol.TCP_GIT_PORT) |
270 |
fd, self.pidfile = tempfile.mkstemp(prefix='dulwich-test-git-client', |
271 |
suffix=".pid")
|
272 |
os.fdopen(fd).close() |
273 |
args = [_DEFAULT_GIT, 'daemon', '--verbose', '--export-all', |
274 |
'--pid-file=%s' % self.pidfile, |
275 |
'--base-path=%s' % self.gitroot, |
276 |
'--enable=receive-pack', '--enable=upload-archive', |
277 |
'--listen=localhost', '--reuseaddr', |
278 |
self.gitroot]
|
279 |
self.process = subprocess.Popen(
|
280 |
args, cwd=self.gitroot,
|
281 |
stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
282 |
if not check_for_daemon(): |
283 |
raise SkipTest('git-daemon failed to start') |
284 |
|
285 |
def tearDown(self): |
286 |
with open(self.pidfile) as f: |
287 |
pid = int(f.read().strip())
|
288 |
if sys.platform == 'win32': |
289 |
PROCESS_TERMINATE = 1
|
290 |
handle = ctypes.windll.kernel32.OpenProcess( |
291 |
PROCESS_TERMINATE, False, pid)
|
292 |
ctypes.windll.kernel32.TerminateProcess(handle, -1)
|
293 |
ctypes.windll.kernel32.CloseHandle(handle) |
294 |
else:
|
295 |
try:
|
296 |
os.kill(pid, signal.SIGKILL) |
297 |
os.unlink(self.pidfile)
|
298 |
except (OSError, IOError): |
299 |
pass
|
300 |
self.process.wait()
|
301 |
self.process.stdout.close()
|
302 |
self.process.stderr.close()
|
303 |
DulwichClientTestBase.tearDown(self)
|
304 |
CompatTestCase.tearDown(self)
|
305 |
|
306 |
def _client(self): |
307 |
return client.TCPGitClient('localhost') |
308 |
|
309 |
def _build_path(self, path): |
310 |
return path
|
311 |
|
312 |
if sys.platform == 'win32': |
313 |
@expectedFailure
|
314 |
def test_fetch_pack_no_side_band_64k(self): |
315 |
DulwichClientTestBase.test_fetch_pack_no_side_band_64k(self)
|
316 |
|
317 |
|
318 |
class TestSSHVendor(object): |
319 |
|
320 |
@staticmethod
|
321 |
def run_command(host, command, username=None, port=None): |
322 |
cmd, path = command.split(b' ')
|
323 |
cmd = cmd.split(b'-', 1) |
324 |
path = path.replace(b"'", b"") |
325 |
p = subprocess.Popen(cmd + [path], bufsize=0, stdin=subprocess.PIPE,
|
326 |
stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
327 |
return client.SubprocessWrapper(p)
|
328 |
|
329 |
|
330 |
class DulwichMockSSHClientTest(CompatTestCase, DulwichClientTestBase): |
331 |
|
332 |
def setUp(self): |
333 |
CompatTestCase.setUp(self)
|
334 |
DulwichClientTestBase.setUp(self)
|
335 |
self.real_vendor = client.get_ssh_vendor
|
336 |
client.get_ssh_vendor = TestSSHVendor |
337 |
|
338 |
def tearDown(self): |
339 |
DulwichClientTestBase.tearDown(self)
|
340 |
CompatTestCase.tearDown(self)
|
341 |
client.get_ssh_vendor = self.real_vendor
|
342 |
|
343 |
def _client(self): |
344 |
return client.SSHGitClient('localhost') |
345 |
|
346 |
def _build_path(self, path): |
347 |
return self.gitroot.encode(sys.getfilesystemencoding()) + path |
348 |
|
349 |
|
350 |
class DulwichSubprocessClientTest(CompatTestCase, DulwichClientTestBase): |
351 |
|
352 |
def setUp(self): |
353 |
CompatTestCase.setUp(self)
|
354 |
DulwichClientTestBase.setUp(self)
|
355 |
|
356 |
def tearDown(self): |
357 |
DulwichClientTestBase.tearDown(self)
|
358 |
CompatTestCase.tearDown(self)
|
359 |
|
360 |
def _client(self): |
361 |
return client.SubprocessGitClient(stderr=subprocess.PIPE)
|
362 |
|
363 |
def _build_path(self, path): |
364 |
return self.gitroot.encode(sys.getfilesystemencoding()) + path |
365 |
|
366 |
|
367 |
class GitHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): |
368 |
"""HTTP Request handler that calls out to 'git http-backend'."""
|
369 |
|
370 |
# Make rfile unbuffered -- we need to read one line and then pass
|
371 |
# the rest to a subprocess, so we can't use buffered input.
|
372 |
rbufsize = 0
|
373 |
|
374 |
def do_POST(self): |
375 |
self.run_backend()
|
376 |
|
377 |
def do_GET(self): |
378 |
self.run_backend()
|
379 |
|
380 |
def send_head(self): |
381 |
return self.run_backend() |
382 |
|
383 |
def log_request(self, code='-', size='-'): |
384 |
# Let's be quiet, the test suite is noisy enough already
|
385 |
pass
|
386 |
|
387 |
def run_backend(self): |
388 |
"""Call out to git http-backend."""
|
389 |
# Based on CGIHTTPServer.CGIHTTPRequestHandler.run_cgi:
|
390 |
# Copyright (c) 2001-2010 Python Software Foundation; All Rights Reserved
|
391 |
# Licensed under the Python Software Foundation License.
|
392 |
rest = self.path
|
393 |
# find an explicit query string, if present.
|
394 |
i = rest.rfind('?')
|
395 |
if i >= 0: |
396 |
rest, query = rest[:i], rest[i+1:]
|
397 |
else:
|
398 |
query = ''
|
399 |
|
400 |
env = copy.deepcopy(os.environ) |
401 |
env['SERVER_SOFTWARE'] = self.version_string() |
402 |
env['SERVER_NAME'] = self.server.server_name |
403 |
env['GATEWAY_INTERFACE'] = 'CGI/1.1' |
404 |
env['SERVER_PROTOCOL'] = self.protocol_version |
405 |
env['SERVER_PORT'] = str(self.server.server_port) |
406 |
env['GIT_PROJECT_ROOT'] = self.server.root_path |
407 |
env["GIT_HTTP_EXPORT_ALL"] = "1" |
408 |
env['REQUEST_METHOD'] = self.command |
409 |
uqrest = unquote(rest) |
410 |
env['PATH_INFO'] = uqrest
|
411 |
env['SCRIPT_NAME'] = "/" |
412 |
if query:
|
413 |
env['QUERY_STRING'] = query
|
414 |
host = self.address_string()
|
415 |
if host != self.client_address[0]: |
416 |
env['REMOTE_HOST'] = host
|
417 |
env['REMOTE_ADDR'] = self.client_address[0] |
418 |
authorization = self.headers.get("authorization") |
419 |
if authorization:
|
420 |
authorization = authorization.split() |
421 |
if len(authorization) == 2: |
422 |
import base64, binascii |
423 |
env['AUTH_TYPE'] = authorization[0] |
424 |
if authorization[0].lower() == "basic": |
425 |
try:
|
426 |
authorization = base64.decodestring(authorization[1])
|
427 |
except binascii.Error:
|
428 |
pass
|
429 |
else:
|
430 |
authorization = authorization.split(':')
|
431 |
if len(authorization) == 2: |
432 |
env['REMOTE_USER'] = authorization[0] |
433 |
# XXX REMOTE_IDENT
|
434 |
env['CONTENT_TYPE'] = self.headers.get('content-type') |
435 |
length = self.headers.get('content-length') |
436 |
if length:
|
437 |
env['CONTENT_LENGTH'] = length
|
438 |
referer = self.headers.get('referer') |
439 |
if referer:
|
440 |
env['HTTP_REFERER'] = referer
|
441 |
accept = [] |
442 |
for line in self.headers.getallmatchingheaders('accept'): |
443 |
if line[:1] in "\t\n\r ": |
444 |
accept.append(line.strip()) |
445 |
else:
|
446 |
accept = accept + line[7:].split(',') |
447 |
env['HTTP_ACCEPT'] = ','.join(accept) |
448 |
ua = self.headers.get('user-agent') |
449 |
if ua:
|
450 |
env['HTTP_USER_AGENT'] = ua
|
451 |
co = self.headers.get('cookie') |
452 |
if co:
|
453 |
env['HTTP_COOKIE'] = co
|
454 |
# XXX Other HTTP_* headers
|
455 |
# Since we're setting the env in the parent, provide empty
|
456 |
# values to override previously set values
|
457 |
for k in ('QUERY_STRING', 'REMOTE_HOST', 'CONTENT_LENGTH', |
458 |
'HTTP_USER_AGENT', 'HTTP_COOKIE', 'HTTP_REFERER'): |
459 |
env.setdefault(k, "")
|
460 |
|
461 |
self.wfile.write(b"HTTP/1.1 200 Script output follows\r\n") |
462 |
self.wfile.write(
|
463 |
("Server: %s\r\n" % self.server.server_name).encode('ascii')) |
464 |
self.wfile.write(
|
465 |
("Date: %s\r\n" % self.date_time_string()).encode('ascii')) |
466 |
|
467 |
decoded_query = query.replace('+', ' ') |
468 |
|
469 |
try:
|
470 |
nbytes = int(length)
|
471 |
except (TypeError, ValueError): |
472 |
nbytes = 0
|
473 |
if self.command.lower() == "post" and nbytes > 0: |
474 |
data = self.rfile.read(nbytes)
|
475 |
else:
|
476 |
data = None
|
477 |
# throw away additional data [see bug #427345]
|
478 |
while select.select([self.rfile._sock], [], [], 0)[0]: |
479 |
if not self.rfile._sock.recv(1): |
480 |
break
|
481 |
args = ['http-backend']
|
482 |
if '=' not in decoded_query: |
483 |
args.append(decoded_query) |
484 |
stdout = run_git_or_fail(args, input=data, env=env, stderr=subprocess.PIPE) |
485 |
self.wfile.write(stdout)
|
486 |
|
487 |
|
488 |
class HTTPGitServer(BaseHTTPServer.HTTPServer): |
489 |
|
490 |
allow_reuse_address = True
|
491 |
|
492 |
def __init__(self, server_address, root_path): |
493 |
BaseHTTPServer.HTTPServer.__init__(self, server_address, GitHTTPRequestHandler)
|
494 |
self.root_path = root_path
|
495 |
self.server_name = "localhost" |
496 |
|
497 |
def get_url(self): |
498 |
return 'http://%s:%s/' % (self.server_name, self.server_port) |
499 |
|
500 |
|
501 |
class DulwichHttpClientTest(CompatTestCase, DulwichClientTestBase): |
502 |
|
503 |
min_git_version = (1, 7, 0, 2) |
504 |
|
505 |
def setUp(self): |
506 |
CompatTestCase.setUp(self)
|
507 |
DulwichClientTestBase.setUp(self)
|
508 |
self._httpd = HTTPGitServer(("localhost", 0), self.gitroot) |
509 |
self.addCleanup(self._httpd.shutdown) |
510 |
threading.Thread(target=self._httpd.serve_forever).start()
|
511 |
run_git_or_fail(['config', 'http.uploadpack', 'true'], |
512 |
cwd=self.dest)
|
513 |
run_git_or_fail(['config', 'http.receivepack', 'true'], |
514 |
cwd=self.dest)
|
515 |
|
516 |
def tearDown(self): |
517 |
DulwichClientTestBase.tearDown(self)
|
518 |
CompatTestCase.tearDown(self)
|
519 |
self._httpd.shutdown()
|
520 |
self._httpd.socket.close()
|
521 |
|
522 |
def _client(self): |
523 |
return client.HttpGitClient(self._httpd.get_url()) |
524 |
|
525 |
def _build_path(self, path): |
526 |
if sys.version_info[0] == 3: |
527 |
return path.decode('ascii') |
528 |
else:
|
529 |
return path
|
530 |
|
531 |
def test_archive(self): |
532 |
raise SkipTest("exporting archives not supported over http") |