]> arthur.barton.de Git - bup.git/blob - test/int/test_client.py
Fully (and explicitly) close PackIdxLists
[bup.git] / test / int / test_client.py
1
2 from __future__ import absolute_import
3 import os, time, random, subprocess, glob
4 import pytest
5
6 from bup import client, git, path
7 from bup.compat import bytes_from_uint, environ, range
8
9 def randbytes(sz):
10     s = b''
11     for i in range(sz):
12         s += bytes_from_uint(random.randrange(0,256))
13     return s
14
15
16 s1 = randbytes(10000)
17 s2 = randbytes(10000)
18 s3 = randbytes(10000)
19
20 IDX_PAT = b'/*.idx'
21
22
23 def test_server_split_with_indexes(tmpdir):
24     environ[b'BUP_DIR'] = bupdir = tmpdir
25     git.init_repo(bupdir)
26     with git.PackWriter() as lw:
27         lw.new_blob(s1)
28     with client.Client(bupdir, create=True) as c, \
29          c.new_packwriter() as rw:
30         rw.new_blob(s2)
31         rw.breakpoint()
32         rw.new_blob(s1)
33
34
35 def test_multiple_suggestions(tmpdir):
36     environ[b'BUP_DIR'] = bupdir = tmpdir
37     git.init_repo(bupdir)
38
39     with git.PackWriter() as lw:
40         lw.new_blob(s1)
41     with git.PackWriter() as lw:
42         lw.new_blob(s2)
43     assert len(glob.glob(git.repo(b'objects/pack'+IDX_PAT))) == 2
44
45     with client.Client(bupdir, create=True) as c, \
46          c.new_packwriter() as rw:
47
48         assert len(glob.glob(c.cachedir+IDX_PAT)) == 0
49         s1sha = rw.new_blob(s1)
50         assert rw.exists(s1sha)
51         s2sha = rw.new_blob(s2)
52
53         # This is a little hacky, but ensures that we test the
54         # code under test. First, flush to ensure that we've
55         # actually sent all the command ('receive-objects-v2')
56         # and their data to the server. This may be needed if
57         # the output buffer size is bigger than the data (both
58         # command and objects) we're writing. To see the need
59         # for this, change the object sizes at the beginning
60         # of this file to be very small (e.g. 10 instead of 10k)
61         c.conn.outp.flush()
62
63         # Then, check if we've already received the idx files.
64         # This may happen if we're preempted just after writing
65         # the data, then the server runs and suggests, and only
66         # then we continue in PackWriter_Remote::_raw_write()
67         # and check the has_input(), in that case we'll receive
68         # the idx still in the rw.new_blob() calls above.
69         #
70         # In most cases though, that doesn't happen, and we'll
71         # get past the has_input() check before the server has
72         # a chance to respond - it has to actually hash the new
73         # object here, so it takes some time. So also break out
74         # of the loop if the server has sent something on the
75         # connection.
76         #
77         # Finally, abort this after a little while (about one
78         # second) just in case something's actually broken.
79         n = 0
80         while (len(glob.glob(c.cachedir+IDX_PAT)) < 2 and
81                not c.conn.has_input() and n < 10):
82             time.sleep(0.1)
83             n += 1
84         assert len(glob.glob(c.cachedir+IDX_PAT)) == 2 or c.conn.has_input()
85         rw.new_blob(s2)
86         assert rw.objcache.exists(s1sha)
87         assert rw.objcache.exists(s2sha)
88         rw.new_blob(s3)
89         assert len(glob.glob(c.cachedir+IDX_PAT)) == 2
90     assert len(glob.glob(c.cachedir+IDX_PAT)) == 3
91
92
93 def test_dumb_client_server(tmpdir):
94     environ[b'BUP_DIR'] = bupdir = tmpdir
95     git.init_repo(bupdir)
96     open(git.repo(b'bup-dumb-server'), 'w').close()
97
98     with git.PackWriter() as lw:
99         lw.new_blob(s1)
100
101     with client.Client(bupdir, create=True) as c, \
102          c.new_packwriter() as rw:
103         assert len(glob.glob(c.cachedir+IDX_PAT)) == 1
104         rw.new_blob(s1)
105         assert len(glob.glob(c.cachedir+IDX_PAT)) == 1
106         rw.new_blob(s2)
107     assert len(glob.glob(c.cachedir+IDX_PAT)) == 2
108
109
110 def test_midx_refreshing(tmpdir):
111     environ[b'BUP_DIR'] = bupdir = tmpdir
112     git.init_repo(bupdir)
113     with client.Client(bupdir, create=True) as c, \
114          c.new_packwriter() as rw:
115         rw.new_blob(s1)
116         p1base = rw.breakpoint()
117         p1name = os.path.join(c.cachedir, p1base)
118         s1sha = rw.new_blob(s1)  # should not be written; it's already in p1
119         s2sha = rw.new_blob(s2)
120         p2base = rw.close()
121     p2name = os.path.join(c.cachedir, p2base)
122
123     with git.PackIdxList(bupdir + b'/objects/pack') as pi:
124         assert len(pi.packs) == 2
125         pi.refresh()
126         assert len(pi.packs) == 2
127         assert sorted([os.path.basename(i.name) for i in pi.packs]) \
128             == sorted([p1base, p2base])
129
130         with git.open_idx(p1name) as p1, \
131              git.open_idx(p2name) as p2:
132             assert p1.exists(s1sha)
133             assert not p2.exists(s1sha)
134             assert p2.exists(s2sha)
135
136         subprocess.call([path.exe(), b'midx', b'-f'])
137         pi.refresh()
138         assert len(pi.packs) == 1
139         pi.refresh(skip_midx=True)
140         assert len(pi.packs) == 2
141         pi.refresh(skip_midx=False)
142         assert len(pi.packs) == 1
143
144
145 def test_remote_parsing():
146     tests = (
147         (b':/bup', (b'file', None, None, b'/bup')),
148         (b'file:///bup', (b'file', None, None, b'/bup')),
149         (b'192.168.1.1:/bup', (b'ssh', b'192.168.1.1', None, b'/bup')),
150         (b'ssh://192.168.1.1:2222/bup', (b'ssh', b'192.168.1.1', b'2222', b'/bup')),
151         (b'ssh://[ff:fe::1]:2222/bup', (b'ssh', b'ff:fe::1', b'2222', b'/bup')),
152         (b'bup://foo.com:1950', (b'bup', b'foo.com', b'1950', None)),
153         (b'bup://foo.com:1950/bup', (b'bup', b'foo.com', b'1950', b'/bup')),
154         (b'bup://[ff:fe::1]/bup', (b'bup', b'ff:fe::1', None, b'/bup')),)
155     for remote, values in tests:
156         assert client.parse_remote(remote) == values
157
158     with pytest.raises(client.ClientError):
159         client.parse_remote(b'http://asdf.com/bup')