Merge pull request #918 from tahoe-lafs/3521.test_storage_client-no-mock

Remove Mock usage from test_storage_client

Fixes: ticket:3521
This commit is contained in:
Jean-Paul Calderone 2020-12-08 15:36:28 -05:00 committed by GitHub
commit 8f3acb7eb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 117 additions and 24 deletions

0
newsfragments/3521.minor Normal file
View File

View File

@ -521,7 +521,6 @@ class IStorageBroker(Interface):
oldest_supported: the peer's oldest supported version, same oldest_supported: the peer's oldest supported version, same
rref: the RemoteReference, if connected, otherwise None rref: the RemoteReference, if connected, otherwise None
remote_host: the IAddress, if connected, otherwise None
This method is intended for monitoring interfaces, such as a web page This method is intended for monitoring interfaces, such as a web page
that describes connecting and connected peers. that describes connecting and connected peers.

View File

@ -154,6 +154,9 @@ class StorageFarmBroker(service.MultiService):
I'm also responsible for subscribing to the IntroducerClient to find out I'm also responsible for subscribing to the IntroducerClient to find out
about new servers as they are announced by the Introducer. about new servers as they are announced by the Introducer.
:ivar _tub_maker: A one-argument callable which accepts a dictionary of
"handler overrides" and returns a ``foolscap.api.Tub``.
:ivar StorageClientConfig storage_client_config: Values from the node :ivar StorageClientConfig storage_client_config: Values from the node
configuration file relating to storage behavior. configuration file relating to storage behavior.
""" """
@ -690,7 +693,6 @@ class NativeStorageServer(service.MultiService):
@ivar nickname: the server's self-reported nickname (unicode), same @ivar nickname: the server's self-reported nickname (unicode), same
@ivar rref: the RemoteReference, if connected, otherwise None @ivar rref: the RemoteReference, if connected, otherwise None
@ivar remote_host: the IAddress, if connected, otherwise None
""" """
VERSION_DEFAULTS = UnicodeKeyDict({ VERSION_DEFAULTS = UnicodeKeyDict({
@ -716,7 +718,6 @@ class NativeStorageServer(service.MultiService):
self.last_connect_time = None self.last_connect_time = None
self.last_loss_time = None self.last_loss_time = None
self.remote_host = None
self._rref = None self._rref = None
self._is_connected = False self._is_connected = False
self._reconnector = None self._reconnector = None
@ -825,8 +826,6 @@ class NativeStorageServer(service.MultiService):
return None return None
def get_announcement(self): def get_announcement(self):
return self.announcement return self.announcement
def get_remote_host(self):
return self.remote_host
def get_connection_status(self): def get_connection_status(self):
last_received = None last_received = None
@ -874,7 +873,6 @@ class NativeStorageServer(service.MultiService):
level=log.NOISY, parent=lp) level=log.NOISY, parent=lp)
self.last_connect_time = time.time() self.last_connect_time = time.time()
self.remote_host = rref.getLocationHints()
self._rref = rref self._rref = rref
self._is_connected = True self._is_connected = True
rref.notifyOnDisconnect(self._lost) rref.notifyOnDisconnect(self._lost)
@ -900,7 +898,6 @@ class NativeStorageServer(service.MultiService):
# get_connected_servers() or get_servers_for_psi()) can continue to # get_connected_servers() or get_servers_for_psi()) can continue to
# use s.get_rref().callRemote() and not worry about it being None. # use s.get_rref().callRemote() and not worry about it being None.
self._is_connected = False self._is_connected = False
self.remote_host = None
def stop_connecting(self): def stop_connecting(self):
# used when this descriptor has been superceded by another # used when this descriptor has been superceded by another

View File

@ -744,8 +744,6 @@ class SystemTest(SystemTestMixin, AsyncTestCase):
class FakeRemoteReference(object): class FakeRemoteReference(object):
def notifyOnDisconnect(self, *args, **kwargs): pass def notifyOnDisconnect(self, *args, **kwargs): pass
def getRemoteTubID(self): return "62ubehyunnyhzs7r6vdonnm2hpi52w6y" def getRemoteTubID(self): return "62ubehyunnyhzs7r6vdonnm2hpi52w6y"
def getLocationHints(self): return ["tcp:here.example.com:1234",
"tcp:there.example.com2345"]
def getPeer(self): return address.IPv4Address("TCP", "remote.example.com", def getPeer(self): return address.IPv4Address("TCP", "remote.example.com",
3456) 3456)

View File

@ -17,7 +17,6 @@ from json import (
) )
import hashlib import hashlib
from mock import Mock
from fixtures import ( from fixtures import (
TempDir, TempDir,
) )
@ -44,12 +43,20 @@ from hyperlink import (
URL, URL,
) )
import attr
from twisted.internet.interfaces import (
IStreamClientEndpoint,
)
from twisted.application.service import ( from twisted.application.service import (
Service, Service,
) )
from twisted.trial import unittest from twisted.trial import unittest
from twisted.internet.defer import succeed, inlineCallbacks from twisted.internet.defer import (
Deferred,
inlineCallbacks,
)
from twisted.python.filepath import ( from twisted.python.filepath import (
FilePath, FilePath,
) )
@ -57,7 +64,11 @@ from twisted.python.filepath import (
from foolscap.api import ( from foolscap.api import (
Tub, Tub,
) )
from foolscap.ipb import (
IConnectionHintHandler,
)
from .no_network import LocalWrapper
from .common import ( from .common import (
EMPTY_CLIENT_CONFIG, EMPTY_CLIENT_CONFIG,
SyncTestCase, SyncTestCase,
@ -65,6 +76,7 @@ from .common import (
UseTestPlugins, UseTestPlugins,
UseNode, UseNode,
SameProcessStreamEndpointAssigner, SameProcessStreamEndpointAssigner,
MemoryIntroducerClient,
) )
from .common_web import ( from .common_web import (
do_http, do_http,
@ -83,6 +95,9 @@ from allmydata.storage_client import (
_FoolscapStorage, _FoolscapStorage,
_NullStorage, _NullStorage,
) )
from ..storage.server import (
StorageServer,
)
from allmydata.interfaces import ( from allmydata.interfaces import (
IConnectionStatus, IConnectionStatus,
IStorageServer, IStorageServer,
@ -505,14 +520,68 @@ class StoragePluginWebPresence(AsyncTestCase):
) )
def make_broker(tub_maker=lambda h: Mock()): _aCertPEM = Tub().myCertificate.dumpPEM()
def new_tub():
"""
Make a new ``Tub`` with a hard-coded private key.
"""
# Use a private key / certificate generated by Tub how it wants. But just
# re-use the same one every time so we don't waste a lot of time
# generating them over and over in the tests.
return Tub(certData=_aCertPEM)
def make_broker(tub_maker=None):
""" """
Create a ``StorageFarmBroker`` with the given tub maker and an empty Create a ``StorageFarmBroker`` with the given tub maker and an empty
client configuration. client configuration.
""" """
if tub_maker is None:
tub_maker = lambda handler_overrides: new_tub()
return StorageFarmBroker(True, tub_maker, EMPTY_CLIENT_CONFIG) return StorageFarmBroker(True, tub_maker, EMPTY_CLIENT_CONFIG)
@implementer(IStreamClientEndpoint)
@attr.s
class SpyEndpoint(object):
"""
Observe and record connection attempts.
:ivar list _append: A callable that accepts two-tuples. For each
attempted connection, it will be called with ``Deferred`` that was
returned and the ``Factory`` that was passed in.
"""
_append = attr.ib()
def connect(self, factory):
"""
Record the connection attempt.
:return: A ``Deferred`` that ``SpyEndpoint`` will not fire.
"""
d = Deferred()
self._append((d, factory))
return d
@implementer(IConnectionHintHandler)
@attr.s
class SpyHandler(object):
"""
A Foolscap connection hint handler for the "spy" hint type. Connections
are handled by just observing and recording them.
:ivar list _connects: A list containing one element for each connection
attempted with this handler. Each element is a two-tuple of the
``Deferred`` that was returned from ``connect`` and the factory that
was passed to ``connect``.
"""
_connects = attr.ib(default=attr.Factory(list))
def hint_to_endpoint(self, hint, reactor, update_status):
return (SpyEndpoint(self._connects.append), hint)
class TestStorageFarmBroker(unittest.TestCase): class TestStorageFarmBroker(unittest.TestCase):
def test_static_servers(self): def test_static_servers(self):
@ -585,18 +654,38 @@ storage:
@inlineCallbacks @inlineCallbacks
def test_threshold_reached(self): def test_threshold_reached(self):
introducer = Mock() """
``StorageFarmBroker.when_connected_enough`` returns a ``Deferred`` which
only fires after the ``StorageFarmBroker`` has established at least as
many connections as requested.
"""
introducer = MemoryIntroducerClient(
new_tub(),
SOME_FURL,
b"",
None,
None,
None,
None,
)
new_tubs = [] new_tubs = []
def make_tub(*args, **kwargs): def make_tub(*args, **kwargs):
return new_tubs.pop() return new_tubs.pop()
broker = make_broker(make_tub) broker = make_broker(make_tub)
# Start the broker so that it will start Tubs attached to it so they
# will attempt to make connections as necessary so that we can observe
# those connections.
broker.startService()
self.addCleanup(broker.stopService)
done = broker.when_connected_enough(5) done = broker.when_connected_enough(5)
broker.use_introducer(introducer) broker.use_introducer(introducer)
# subscribes to "storage" to learn of new storage nodes # subscribes to "storage" to learn of new storage nodes
subscribe = introducer.mock_calls[0] [subscribe] = introducer.subscribed_to
self.assertEqual(subscribe[0], 'subscribe_to') self.assertEqual(
self.assertEqual(subscribe[1][0], 'storage') subscribe.service_name,
got_announcement = subscribe[1][1] "storage",
)
got_announcement = subscribe.cb
data = { data = {
"service-name": "storage", "service-name": "storage",
@ -605,15 +694,25 @@ storage:
} }
def add_one_server(x): def add_one_server(x):
data["anonymous-storage-FURL"] = b"pb://%s@nowhere/fake" % (base32.b2a(b"%d" % x),) data["anonymous-storage-FURL"] = b"pb://%s@spy:nowhere/fake" % (base32.b2a(b"%d" % x),)
tub = Mock() tub = new_tub()
connects = []
spy = SpyHandler(connects)
tub.addConnectionHintHandler("spy", spy)
new_tubs.append(tub) new_tubs.append(tub)
got_announcement(b'v0-1234-%d' % x, data) got_announcement(b'v0-1234-%d' % x, data)
self.assertEqual(tub.mock_calls[-1][0], 'connectTo')
got_connection = tub.mock_calls[-1][1][1] self.assertEqual(
rref = Mock() 1, len(connects),
rref.callRemote = Mock(return_value=succeed(1234)) "Expected one connection attempt, got {!r} instead".format(connects),
got_connection(rref) )
# Skip over all the Foolscap negotiation. It's complex with lots
# of pieces and I don't want to figure out how to fake
# it. -exarkun
native = broker.servers[b"v0-1234-%d" % (x,)]
rref = LocalWrapper(StorageServer(self.mktemp(), b"x" * 20))
native._got_connection(rref)
# first 4 shouldn't trigger connected_threashold # first 4 shouldn't trigger connected_threashold
for x in range(4): for x in range(4):