]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/test/common.py
deep-check: add webapi, add 'DEEP-CHECK' button to wui, add tests, rearrange checker...
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / test / common.py
1
2 import os
3 from zope.interface import implements
4 from twisted.internet import defer
5 from twisted.python import failure
6 from twisted.application import service
7 from allmydata import uri, dirnode
8 from allmydata.interfaces import IURI, IMutableFileNode, IFileNode, \
9      FileTooLargeError, ICheckable
10 from allmydata.immutable import checker
11 from allmydata.immutable.encode import NotEnoughSharesError
12 from allmydata.util import log
13
14 class FakeCHKFileNode:
15     """I provide IFileNode, but all of my data is stored in a class-level
16     dictionary."""
17     implements(IFileNode)
18     all_contents = {}
19
20     def __init__(self, u, client):
21         self.client = client
22         self.my_uri = u.to_string()
23
24     def get_uri(self):
25         return self.my_uri
26     def get_readonly_uri(self):
27         return self.my_uri
28     def get_verifier(self):
29         return IURI(self.my_uri).get_verifier()
30     def check(self, verify=False, repair=False):
31         r = checker.Results(None)
32         r.healthy = True
33         r.problems = []
34         return defer.succeed(r)
35     def is_mutable(self):
36         return False
37     def is_readonly(self):
38         return True
39
40     def download(self, target):
41         if self.my_uri not in self.all_contents:
42             f = failure.Failure(NotEnoughSharesError())
43             target.fail(f)
44             return defer.fail(f)
45         data = self.all_contents[self.my_uri]
46         target.open(len(data))
47         target.write(data)
48         target.close()
49         return defer.maybeDeferred(target.finish)
50     def download_to_data(self):
51         if self.my_uri not in self.all_contents:
52             return defer.fail(NotEnoughSharesError())
53         data = self.all_contents[self.my_uri]
54         return defer.succeed(data)
55     def get_size(self):
56         data = self.all_contents[self.my_uri]
57         return len(data)
58
59 def make_chk_file_uri(size):
60     return uri.CHKFileURI(key=os.urandom(16),
61                           uri_extension_hash=os.urandom(32),
62                           needed_shares=3,
63                           total_shares=10,
64                           size=size)
65
66 def create_chk_filenode(client, contents):
67     u = make_chk_file_uri(len(contents))
68     n = FakeCHKFileNode(u, client)
69     FakeCHKFileNode.all_contents[u.to_string()] = contents
70     return n
71
72
73 class FakeMutableFileNode:
74     """I provide IMutableFileNode, but all of my data is stored in a
75     class-level dictionary."""
76
77     implements(IMutableFileNode, ICheckable)
78     MUTABLE_SIZELIMIT = 10000
79     all_contents = {}
80
81     def __init__(self, client):
82         self.client = client
83         self.my_uri = make_mutable_file_uri()
84         self.storage_index = self.my_uri.storage_index
85     def create(self, initial_contents, key_generator=None):
86         if len(initial_contents) > self.MUTABLE_SIZELIMIT:
87             raise FileTooLargeError("SDMF is limited to one segment, and "
88                                     "%d > %d" % (len(initial_contents),
89                                                  self.MUTABLE_SIZELIMIT))
90         self.all_contents[self.storage_index] = initial_contents
91         return defer.succeed(self)
92     def init_from_uri(self, myuri):
93         self.my_uri = IURI(myuri)
94         self.storage_index = self.my_uri.storage_index
95         return self
96     def get_uri(self):
97         return self.my_uri.to_string()
98     def get_readonly(self):
99         return self.my_uri.get_readonly()
100     def get_readonly_uri(self):
101         return self.my_uri.get_readonly().to_string()
102     def is_readonly(self):
103         return self.my_uri.is_readonly()
104     def is_mutable(self):
105         return self.my_uri.is_mutable()
106     def get_writekey(self):
107         return "\x00"*16
108     def get_size(self):
109         return "?" # TODO: see mutable.MutableFileNode.get_size
110
111     def get_storage_index(self):
112         return self.storage_index
113
114     def check(self, verify=False, repair=False):
115         r = checker.Results(None)
116         r.healthy = True
117         r.problems = []
118         return defer.succeed(r)
119
120     def deep_check(self, verify=False, repair=False):
121         d = self.check(verify, repair)
122         def _done(r):
123             dr = DeepCheckResults(self.storage_index)
124             dr.add_check(r)
125             return dr
126         d.addCallback(_done)
127         return d
128
129     def download_best_version(self):
130         return defer.succeed(self.all_contents[self.storage_index])
131     def overwrite(self, new_contents):
132         if len(new_contents) > self.MUTABLE_SIZELIMIT:
133             raise FileTooLargeError("SDMF is limited to one segment, and "
134                                     "%d > %d" % (len(new_contents),
135                                                  self.MUTABLE_SIZELIMIT))
136         assert not self.is_readonly()
137         self.all_contents[self.storage_index] = new_contents
138         return defer.succeed(None)
139     def modify(self, modifier):
140         # this does not implement FileTooLargeError, but the real one does
141         return defer.maybeDeferred(self._modify, modifier)
142     def _modify(self, modifier):
143         assert not self.is_readonly()
144         old_contents = self.all_contents[self.storage_index]
145         self.all_contents[self.storage_index] = modifier(old_contents)
146         return None
147
148     def download(self, target):
149         if self.storage_index not in self.all_contents:
150             f = failure.Failure(NotEnoughSharesError())
151             target.fail(f)
152             return defer.fail(f)
153         data = self.all_contents[self.storage_index]
154         target.open(len(data))
155         target.write(data)
156         target.close()
157         return defer.maybeDeferred(target.finish)
158     def download_to_data(self):
159         if self.storage_index not in self.all_contents:
160             return defer.fail(NotEnoughSharesError())
161         data = self.all_contents[self.storage_index]
162         return defer.succeed(data)
163
164 def make_mutable_file_uri():
165     return uri.WriteableSSKFileURI(writekey=os.urandom(16),
166                                    fingerprint=os.urandom(32))
167 def make_verifier_uri():
168     return uri.SSKVerifierURI(storage_index=os.urandom(16),
169                               fingerprint=os.urandom(32))
170
171 class FakeDirectoryNode(dirnode.NewDirectoryNode):
172     """This offers IDirectoryNode, but uses a FakeMutableFileNode for the
173     backing store, so it doesn't go to the grid. The child data is still
174     encrypted and serialized, so this isn't useful for tests that want to
175     look inside the dirnodes and check their contents.
176     """
177     filenode_class = FakeMutableFileNode
178
179 class LoggingServiceParent(service.MultiService):
180     def log(self, *args, **kwargs):
181         return log.msg(*args, **kwargs)