1 | """ |
---|
2 | A storage server plugin the test suite can use to validate the |
---|
3 | functionality. |
---|
4 | |
---|
5 | Ported to Python 3. |
---|
6 | """ |
---|
7 | |
---|
8 | from six import ensure_str |
---|
9 | |
---|
10 | import attr |
---|
11 | |
---|
12 | from zope.interface import ( |
---|
13 | implementer, |
---|
14 | ) |
---|
15 | |
---|
16 | from twisted.internet.defer import ( |
---|
17 | succeed, |
---|
18 | ) |
---|
19 | from twisted.web.resource import ( |
---|
20 | Resource, |
---|
21 | ) |
---|
22 | from twisted.web.static import ( |
---|
23 | Data, |
---|
24 | ) |
---|
25 | from foolscap.api import ( |
---|
26 | RemoteInterface, |
---|
27 | ) |
---|
28 | |
---|
29 | from allmydata.interfaces import ( |
---|
30 | IFoolscapStoragePlugin, |
---|
31 | IStorageServer, |
---|
32 | ) |
---|
33 | from allmydata.client import ( |
---|
34 | AnnounceableStorageServer, |
---|
35 | ) |
---|
36 | from allmydata.util.jsonbytes import ( |
---|
37 | dumps, |
---|
38 | ) |
---|
39 | |
---|
40 | |
---|
41 | class RIDummy(RemoteInterface): |
---|
42 | __remote_name__ = "RIDummy.tahoe.allmydata.com" |
---|
43 | |
---|
44 | def just_some_method(): |
---|
45 | """ |
---|
46 | Just some method so there is something callable on this object. We won't |
---|
47 | pretend to actually offer any storage capabilities. |
---|
48 | """ |
---|
49 | |
---|
50 | |
---|
51 | # type ignored due to missing stubs for Twisted |
---|
52 | # https://twistedmatrix.com/trac/ticket/9717 |
---|
53 | @implementer(IFoolscapStoragePlugin) # type: ignore |
---|
54 | @attr.s |
---|
55 | class DummyStorage(object): |
---|
56 | name = attr.ib() |
---|
57 | |
---|
58 | @property |
---|
59 | def _client_section_name(self): |
---|
60 | return u"storageclient.plugins.{}".format(self.name) |
---|
61 | |
---|
62 | def get_storage_server(self, configuration, get_anonymous_storage_server): |
---|
63 | if u"invalid" in configuration: |
---|
64 | raise Exception("The plugin is unhappy.") |
---|
65 | |
---|
66 | announcement = {u"value": configuration.get(u"some", u"default-value")} |
---|
67 | storage_server = DummyStorageServer(get_anonymous_storage_server) |
---|
68 | return succeed( |
---|
69 | AnnounceableStorageServer( |
---|
70 | announcement, |
---|
71 | storage_server, |
---|
72 | ), |
---|
73 | ) |
---|
74 | |
---|
75 | def get_storage_client(self, configuration, announcement, get_rref): |
---|
76 | return DummyStorageClient( |
---|
77 | get_rref, |
---|
78 | dict(configuration.items(self._client_section_name, [])), |
---|
79 | announcement, |
---|
80 | ) |
---|
81 | |
---|
82 | def get_client_resource(self, configuration): |
---|
83 | """ |
---|
84 | :return: A static data resource that produces the given configuration when |
---|
85 | rendered, as an aid to testing. |
---|
86 | """ |
---|
87 | items = configuration.items(self._client_section_name, []) |
---|
88 | resource = Data( |
---|
89 | dumps(dict(items)).encode("utf-8"), |
---|
90 | ensure_str("text/json"), |
---|
91 | ) |
---|
92 | # Give it some dynamic stuff too. |
---|
93 | resource.putChild(b"counter", GetCounter()) |
---|
94 | return resource |
---|
95 | |
---|
96 | |
---|
97 | class GetCounter(Resource, object): |
---|
98 | """ |
---|
99 | ``GetCounter`` is a resource that returns a count of the number of times |
---|
100 | it has rendered a response to a GET request. |
---|
101 | |
---|
102 | :ivar int value: The number of ``GET`` requests rendered so far. |
---|
103 | """ |
---|
104 | value = 0 |
---|
105 | def render_GET(self, request): |
---|
106 | self.value += 1 |
---|
107 | return dumps({"value": self.value}).encode("utf-8") |
---|
108 | |
---|
109 | |
---|
110 | @implementer(RIDummy) |
---|
111 | @attr.s(frozen=True) |
---|
112 | class DummyStorageServer(object): # type: ignore # warner/foolscap#78 |
---|
113 | get_anonymous_storage_server = attr.ib() |
---|
114 | |
---|
115 | def remote_just_some_method(self): |
---|
116 | pass |
---|
117 | |
---|
118 | |
---|
119 | @implementer(IStorageServer) |
---|
120 | @attr.s |
---|
121 | class DummyStorageClient(object): # type: ignore # incomplete implementation |
---|
122 | get_rref = attr.ib() |
---|
123 | configuration = attr.ib() |
---|
124 | announcement = attr.ib() |
---|