2016-05-03 21:49:31 +00:00
|
|
|
from mock import Mock, patch
|
2016-04-25 23:39:33 +00:00
|
|
|
from allmydata.util import base32
|
2014-11-23 05:46:33 +00:00
|
|
|
|
|
|
|
from twisted.trial import unittest
|
2016-04-26 17:44:58 +00:00
|
|
|
from twisted.internet.defer import succeed, inlineCallbacks
|
2016-04-25 23:39:33 +00:00
|
|
|
|
2014-11-23 05:46:33 +00:00
|
|
|
from allmydata.storage_client import NativeStorageServer
|
2016-07-22 00:23:22 +00:00
|
|
|
from allmydata.storage_client import StorageFarmBroker
|
2014-11-23 05:46:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
class NativeStorageServerWithVersion(NativeStorageServer):
|
2016-05-03 22:09:13 +00:00
|
|
|
def __init__(self, version):
|
|
|
|
# note: these instances won't work for anything other than
|
|
|
|
# get_available_space() because we don't upcall
|
|
|
|
self.version = version
|
2014-11-23 05:46:33 +00:00
|
|
|
def get_version(self):
|
|
|
|
return self.version
|
|
|
|
|
|
|
|
|
|
|
|
class TestNativeStorageServer(unittest.TestCase):
|
|
|
|
def test_get_available_space_new(self):
|
|
|
|
nss = NativeStorageServerWithVersion(
|
|
|
|
{ "http://allmydata.org/tahoe/protocols/storage/v1":
|
|
|
|
{ "maximum-immutable-share-size": 111,
|
|
|
|
"available-space": 222,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
self.failUnlessEqual(nss.get_available_space(), 222)
|
|
|
|
|
|
|
|
def test_get_available_space_old(self):
|
|
|
|
nss = NativeStorageServerWithVersion(
|
|
|
|
{ "http://allmydata.org/tahoe/protocols/storage/v1":
|
|
|
|
{ "maximum-immutable-share-size": 111,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
self.failUnlessEqual(nss.get_available_space(), 111)
|
|
|
|
|
2016-04-25 23:39:33 +00:00
|
|
|
|
|
|
|
class TestStorageFarmBroker(unittest.TestCase):
|
|
|
|
|
2016-08-24 21:11:58 +00:00
|
|
|
def test_static_announcement(self):
|
|
|
|
broker = StorageFarmBroker(True)
|
|
|
|
|
|
|
|
key_s = 'v0-1234-{}'.format(1)
|
|
|
|
ann = {
|
|
|
|
"service-name": "storage",
|
|
|
|
"anonymous-storage-FURL": "pb://{}@nowhere/fake".format(base32.b2a(str(1))),
|
|
|
|
"permutation-seed-base32": "aaaaaaaaaaaaaaaaaaaaaaaa",
|
|
|
|
}
|
2016-08-26 11:17:56 +00:00
|
|
|
broker.got_static_announcement(key_s, ann, None)
|
2016-08-24 21:11:58 +00:00
|
|
|
self.failUnlessEqual(len(broker.static_servers), 1)
|
make IServer.get_serverid() use pubkey, not tubid
This is a change I've wanted to make for many years, because when we get
to HTTP-based servers, we won't have tubids for them. What held me back
was that there's code all over the place that uses the serverid for
various purposes, so I wasn't sure it was safe. I did a big push a few
years ago to use IServer instances instead of serverids in most
places (in #1363), and to split out the values that actually depend upon
tubid into separate accessors (like get_lease_seed and
get_foolscap_write_enabler_seed), which I think took care of all the
important uses.
There are a number of places that use get_serverid() as dictionary key
to track shares (Checker results, mutable servermap). I believe these
are happy to use pubkeys instead of tubids: the only thing they do with
get_serverid() is to compare it to other values obtained from
get_serverid(). A few places in the WUI used serverid to compute display
values: these were fixed.
The main trouble was the Helper: it returns a HelperUploadResults (a
Copyable) with a share->server mapping that's keyed by whatever the
Helper's get_serverid() returns. If the uploader and the helper are on
different sides of this change, the Helper could return values that the
uploader won't recognize. This is cosmetic: that mapping is only used to
display the upload results on the "Recent and Active Operations" page.
I've added code to StorageFarmBroker.get_stub_server() to fall back to
tubids when looking up a server, so this should still work correctly
when the uploader is new and the Helper is old. If the Helper is new and
the uploader is old, the upload results will show unusual server ids.
refs ticket:1363
2016-08-26 19:16:17 +00:00
|
|
|
self.failUnlessEqual(broker.servers[key_s].announcement, ann)
|
2016-08-27 00:29:39 +00:00
|
|
|
self.failUnlessEqual(broker.servers[key_s].get_serverid(), key_s)
|
2016-08-24 21:11:58 +00:00
|
|
|
|
2016-04-26 06:32:21 +00:00
|
|
|
@inlineCallbacks
|
2016-04-25 23:39:33 +00:00
|
|
|
def test_threshold_reached(self):
|
|
|
|
introducer = Mock()
|
2016-05-02 15:23:07 +00:00
|
|
|
broker = StorageFarmBroker(True)
|
2016-07-22 00:23:22 +00:00
|
|
|
done = broker.when_connected_enough(5)
|
2016-04-25 23:39:33 +00:00
|
|
|
broker.use_introducer(introducer)
|
|
|
|
# subscribes to "storage" to learn of new storage nodes
|
|
|
|
subscribe = introducer.mock_calls[0]
|
|
|
|
self.assertEqual(subscribe[0], 'subscribe_to')
|
2016-05-03 21:03:17 +00:00
|
|
|
self.assertEqual(subscribe[1][0], 'storage')
|
|
|
|
got_announcement = subscribe[1][1]
|
2016-04-25 23:39:33 +00:00
|
|
|
|
|
|
|
data = {
|
|
|
|
"service-name": "storage",
|
|
|
|
"anonymous-storage-FURL": None,
|
|
|
|
"permutation-seed-base32": "aaaaaaaaaaaaaaaaaaaaaaaa",
|
|
|
|
}
|
|
|
|
|
|
|
|
def add_one_server(x):
|
|
|
|
data["anonymous-storage-FURL"] = "pb://{}@nowhere/fake".format(base32.b2a(str(x)))
|
2016-05-03 21:49:31 +00:00
|
|
|
tub = Mock()
|
|
|
|
with patch("allmydata.storage_client.Tub", side_effect=[tub]):
|
|
|
|
got_announcement('v0-1234-{}'.format(x), data)
|
|
|
|
self.assertEqual(tub.mock_calls[-1][0], 'connectTo')
|
|
|
|
got_connection = tub.mock_calls[-1][1][1]
|
2016-04-25 23:39:33 +00:00
|
|
|
rref = Mock()
|
|
|
|
rref.callRemote = Mock(return_value=succeed(1234))
|
|
|
|
got_connection(rref)
|
|
|
|
|
|
|
|
# first 4 shouldn't trigger connected_threashold
|
|
|
|
for x in range(4):
|
|
|
|
add_one_server(x)
|
|
|
|
self.assertFalse(done.called)
|
|
|
|
|
|
|
|
# ...but the 5th *should* trigger the threshold
|
|
|
|
add_one_server(42)
|
2016-04-26 06:32:21 +00:00
|
|
|
|
|
|
|
# so: the OneShotObserverList only notifies via
|
|
|
|
# foolscap.eventually() -- which forces the Deferred call
|
|
|
|
# through the reactor -- so it's no longer synchronous,
|
|
|
|
# meaning that we have to do "real reactor stuff" for the
|
|
|
|
# Deferred from when_connected_enough() to actually fire. (or
|
|
|
|
# @patch() out the reactor in foolscap.eventually to be a
|
|
|
|
# Clock() so we can advance time ourselves, but ... luckily
|
|
|
|
# eventually() uses 0 as the timeout currently)
|
|
|
|
|
|
|
|
yield done
|
2016-04-25 23:39:33 +00:00
|
|
|
self.assertTrue(done.called)
|