1
# Copyright 2008-2015 Canonical
3
# This program is free software: you can redistribute it and/or modify
4
# it under the terms of the GNU Affero General Public License as
5
# published by the Free Software Foundation, either version 3 of the
6
# License, or (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU Affero General Public License for more details.
13
# You should have received a copy of the GNU Affero General Public License
14
# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
# For further info, check http://launchpad.net/filesync-server
18
"""Test server shutdown."""
20
from twisted.trial.unittest import TestCase as TwistedTestCase
21
from twisted.internet import reactor, defer, error
23
from txstatsd.metrics.countermetric import CounterMetric
24
from txstatsd.metrics.metermetric import MeterMetric
27
from backends.filesync.data.services import make_storage_user
28
from backends.filesync.data.testing.testcase import StorageDALTestCase
29
from ubuntuone.storage.server.auth import DummyAuthProvider
30
from ubuntuone.storage.server.testing.testcase import StorageServerService
31
from ubuntuone.storageprotocol import request
32
from ubuntuone.storageprotocol.content_hash import content_hash_factory
33
from ubuntuone.storageprotocol.client import (
34
StorageClientFactory, StorageClient)
37
class TestClient(StorageClient):
38
"""A simple client for tests."""
40
def connectionMade(self):
41
"""Setup and call callback."""
42
StorageClient.connectionMade(self)
43
self.factory.connected(self)
46
class TestClientFactory(StorageClientFactory):
47
"""A test oriented protocol factory."""
51
class TestShutdown(TwistedTestCase, StorageDALTestCase):
52
"""Test the basic stuff."""
54
@defer.inlineCallbacks
56
"""Setup for testing."""
57
# make sure we start with clean state
58
yield super(TestShutdown, self).setUp()
59
self.s4_site = site = s4.server.Site(s4.Root())
60
self.s4_conn = reactor.listenTCP(0, site)
61
# since storageusers are not automatically created, we need to create
62
self.usr0 = make_storage_user(0, u"dummy", u"", 2 ** 20)
64
@defer.inlineCallbacks
66
"""Tear down after testing."""
67
yield self.s4_conn.stopListening()
68
yield super(TestShutdown, self).tearDown()
70
@defer.inlineCallbacks
71
def test_shutdown_upload(self):
72
"""Stop and restart the server."""
74
service = StorageServerService(
75
0, "localhost", self.s4_conn.getHost().port, False,
76
s4.AWS_DEFAULT_ACCESS_KEY_ID,
77
s4.AWS_DEFAULT_SECRET_ACCESS_KEY,
78
auth_provider_class=DummyAuthProvider,
80
yield service.startService()
82
# create a user, connect a client
83
usr0 = make_storage_user(0, u"dummy", u"", 2 ** 20)
85
f = TestClientFactory()
86
f.connected = d.callback
87
reactor.connectTCP("localhost", service.port, f)
90
# auth, get root, create a file
91
yield client.dummy_authenticate("open sesame")
92
root = yield client.get_root()
93
mkfile_req = yield client.make_file(request.ROOT, root, "hola")
95
# try to upload something that will fail when sending data
96
empty_hash = content_hash_factory().content_hash()
97
# lose the connection if something wrong
99
yield client.put_content(request.ROOT, mkfile_req.new_id,
100
empty_hash, "fake_hash", 1234, 1000, None)
102
client.transport.loseConnection()
104
# see that the server has not protocols alive
105
yield service.factory.wait_for_shutdown()
106
ujobs = usr0.get_uploadjobs(node_id=mkfile_req.new_id)
107
self.assertEqual(ujobs, [])
109
yield service.stopService()
111
@defer.inlineCallbacks
112
def test_shutdown_metrics(self):
113
"""Stop and restart the server."""
115
service = StorageServerService(
116
0, "localhost", self.s4_conn.getHost().port, False,
117
s4.AWS_DEFAULT_ACCESS_KEY_ID,
118
s4.AWS_DEFAULT_SECRET_ACCESS_KEY,
119
auth_provider_class=DummyAuthProvider,
120
heartbeat_interval=0)
122
yield service.startService()
124
# ensure we employ the correct metric name.
125
name = service.metrics.fully_qualify_name('server_start')
126
self.assertTrue(isinstance(service.metrics._metrics[name],
128
name = service.metrics.fully_qualify_name('services_active')
129
self.assertTrue(isinstance(service.metrics._metrics[name],
131
self.assertEquals(service.metrics._metrics[name].count(), 1)
133
yield service.stopService()
135
@defer.inlineCallbacks
136
def test_requests_leak(self):
137
"""Test that the server waits for pending requests."""
139
self.service = StorageServerService(
140
0, "localhost", self.s4_conn.getHost().port, False,
141
s4.AWS_DEFAULT_ACCESS_KEY_ID,
142
s4.AWS_DEFAULT_SECRET_ACCESS_KEY,
143
auth_provider_class=DummyAuthProvider,
144
heartbeat_interval=0)
146
yield self.service.startService()
148
make_storage_user(0, u"dummy", u"", 2 ** 20)
149
client_d = defer.Deferred()
150
f = TestClientFactory()
151
f.connected = client_d.callback
152
reactor.connectTCP("localhost", self.service.port, f)
153
client = yield client_d
154
# start with a client
155
yield client.dummy_authenticate("open sesame")
156
root_id = yield client.get_root()
157
# create a bunch of files
160
def handle_conn_done(f):
161
"""Ignore ConnectionDone errors."""
162
if f.check(error.ConnectionDone):
166
mk = client.make_file(request.ROOT, root_id, "hola_%s" % i)
167
mk.addErrback(handle_conn_done)
168
mk_deferreds.append(mk)
170
reactor.callLater(0.1, client.transport.loseConnection)
171
yield defer.DeferredList(mk_deferreds)
173
self.assertTrue(self.service.factory.protocols[0].requests)
174
# wait for protocol shutdown (this was hanging waiting for requests
176
yield self.service.factory.protocols[0].wait_for_shutdown()
177
# see that the server has not protocols alive
178
yield self.service.factory.wait_for_shutdown()
180
yield self.service.stopService()
182
test_requests_leak.skip = """
183
There seems to be a race condition on this test.
184
Skipped because of https://bugs.launchpad.net/bugs/989680