1
# Copyright 2013-2014 Canonical Ltd. This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
4
"""Test maasserver networks views."""
6
from __future__ import (
19
from urllib import urlencode
21
from django.core.urlresolvers import reverse
22
from lxml.html import fromstring
23
from maasserver.models import Network
24
from maasserver.testing import (
29
from maasserver.testing.factory import factory
30
from maasserver.testing.testcase import MAASServerTestCase
31
from maasserver.views.networks import NetworkAdd
32
from testtools.matchers import (
41
class NetworkListingViewTest(MAASServerTestCase):
43
def test_network_list_link_present_on_homepage(self):
45
response = self.client.get(reverse('index'))
46
network_list_link = reverse('network-list')
49
get_content_links(response, element='#main-nav'))
51
def test_network_list_displays_network_details(self):
52
# Network listing displays the network name, description,
53
# network information and VLAN tag.
55
[factory.make_network() for i in range(3)]
56
networks = Network.objects.all()
57
response = self.client.get(reverse('network-list'))
61
network.description[:20],
62
'%s' % network.get_network(),
63
'%s' % network.vlan_tag if network.vlan_tag else '',
65
for network in networks]
66
details = list(itertools.chain(*details_list))
67
self.assertThat(response.content, ContainsAll(details))
69
def test_network_list_displays_sorted_list_of_networks(self):
70
# Networks are alphabetically sorted on the network list page.
72
[factory.make_network() for i in range(3)]
73
networks = Network.objects.all()
74
sorted_networks = sorted(networks, key=lambda x: x.name.lower())
75
response = self.client.get(reverse('network-list'))
77
reverse('network-view', args=[network.name])
78
for network in sorted_networks]
81
[link for link in get_content_links(response)
82
if link.startswith('/networks/')])
84
def test_network_list_displays_links_to_network_node(self):
86
[factory.make_network() for i in range(3)]
87
networks = Network.objects.all()
88
sorted_networks = sorted(networks, key=lambda x: x.name.lower())
89
response = self.client.get(reverse('network-list'))
90
network_node_links = [
91
reverse('node-list') + "?" +
92
urlencode({'query': 'networks=%s' % network.name})
93
for network in sorted_networks]
96
[link for link in get_content_links(response)
97
if link.startswith('/nodes/')])
100
class NetworkListingViewTestNonAdmin(MAASServerTestCase):
102
def test_network_list_does_not_contain_edit_and_delete_links(self):
104
networks = [factory.make_network() for i in range(3)]
105
response = self.client.get(reverse('network-list'))
106
network_edit_links = [
107
reverse('network-edit', args=[network.name])
108
for network in networks
110
network_delete_links = [
111
reverse('network-del', args=[network.name])
112
for network in networks
114
all_links = get_content_links(response)
117
MatchesAll(*[Not(Equals(link)) for link in network_edit_links]))
120
MatchesAll(*[Not(Equals(link)) for link in network_delete_links]))
122
def test_network_list_does_not_contain_add_link(self):
124
response = self.client.get(reverse('network-list'))
125
add_link = reverse('network-add')
126
self.assertNotIn(add_link, get_content_links(response))
129
class NetworkListingViewTestAdmin(MAASServerTestCase):
131
def test_network_list_contains_edit_links(self):
132
self.client_log_in(as_admin=True)
133
networks = [factory.make_network() for i in range(3)]
134
network_edit_links = [
135
reverse('network-edit', args=[network.name])
136
for network in networks
138
network_delete_links = [
139
reverse('network-del', args=[network.name])
140
for network in networks
143
response = self.client.get(reverse('network-list'))
144
all_links = get_content_links(response)
146
self.assertThat(all_links, ContainsAll(
147
network_edit_links + network_delete_links))
149
def test_network_list_contains_add_link(self):
150
self.client_log_in(as_admin=True)
151
response = self.client.get(reverse('network-list'))
152
add_link = reverse('network-add')
153
self.assertIn(add_link, get_content_links(response))
156
class NetworkAddTestNonAdmin(MAASServerTestCase):
158
def test_cannot_add_network(self):
160
name = factory.make_name('network')
161
response = self.client.post(reverse('network-add'), {'name': name})
162
# This returns an inappropriate response (302 FOUND, redirect to the
163
# login page; should be 403 FORBIDDEN) but does not actually create the
164
# network, and that's the main thing.
165
self.assertEqual(reverse('login'), extract_redirect(response))
166
self.assertEqual([], list(Network.objects.filter(name=name)))
169
class NetworkAddTestAdmin(MAASServerTestCase):
171
def test_adds_network(self):
172
self.client_log_in(as_admin=True)
173
network = factory.getRandomNetwork()
175
'name': factory.make_name('network'),
176
'description': factory.getRandomString(),
177
'ip': "%s" % network.cidr.ip,
178
'netmask': "%s" % network.netmask,
179
'vlan_tag': factory.make_vlan_tag(),
181
response = self.client.post(reverse('network-add'), definition)
182
self.assertEqual(httplib.FOUND, response.status_code)
183
network = Network.objects.get(name=definition['name'])
185
[definition[key] for key in sorted(definition)],
186
[getattr(network, key) for key in sorted(definition)])
187
self.assertEqual(reverse('network-list'), extract_redirect(response))
189
def test_get_success_url_returns_valid_url(self):
190
self.client_log_in(as_admin=True)
191
url = NetworkAdd().get_success_url()
192
self.assertIn("/networks", url)
195
class NetworkDetailViewTest(MAASServerTestCase):
197
def test_network_detail_displays_network_detail(self):
198
# The Network detail view displays the network name and the network
201
network = factory.make_network()
202
response = self.client.get(
203
reverse('network-view', args=[network.name]))
209
reverse('node-list') + "?" + urlencode(
210
{'query': 'networks=%s' % network.name}),
214
def test_network_detail_displays_node_count(self):
216
network = factory.make_network()
217
[factory.make_node(networks=[network]) for i in range(12)]
218
response = self.client.get(
219
reverse('network-view', args=[network.name]))
220
document = fromstring(response.content)
221
count_text = document.get_element_by_id("nodecount").text_content()
222
self.assertThat(count_text, Contains('12'))
225
class NetworkDetailViewNonAdmin(MAASServerTestCase):
227
def test_network_detail_does_not_contain_edit_link(self):
229
network = factory.make_network()
230
response = self.client.get(
231
reverse('network-view', args=[network.name]))
232
network_edit_link = reverse('network-edit', args=[network.name])
233
self.assertNotIn(network_edit_link, get_content_links(response))
235
def test_network_detail_does_not_contain_delete_link(self):
237
network = factory.make_network()
238
response = self.client.get(
239
reverse('network-view', args=[network.name]))
240
network_delete_link = reverse('network-del', args=[network.name])
241
self.assertNotIn(network_delete_link, get_content_links(response))
244
class NetworkDetailViewAdmin(MAASServerTestCase):
246
def test_network_detail_contains_edit_link(self):
247
self.client_log_in(as_admin=True)
248
network = factory.make_network()
249
response = self.client.get(
250
reverse('network-view', args=[network.name]))
251
network_edit_link = reverse('network-edit', args=[network.name])
252
self.assertIn(network_edit_link, get_content_links(response))
254
def test_network_detail_contains_delete_link(self):
255
self.client_log_in(as_admin=True)
256
network = factory.make_network()
257
response = self.client.get(
258
reverse('network-view', args=[network.name]))
259
network_delete_link = reverse('network-del', args=[network.name])
260
self.assertIn(network_delete_link, get_content_links(response))
263
class NetworkEditNonAdminTest(MAASServerTestCase):
265
def test_cannot_access_network_edit(self):
267
network = factory.make_network()
268
response = self.client.post(
269
reverse('network-edit', args=[network.name]))
270
self.assertEqual(reverse('login'), extract_redirect(response))
273
class NetworkEditAdminTest(MAASServerTestCase):
275
def test_network_edit(self):
276
self.client_log_in(as_admin=True)
277
network = factory.make_network()
278
new_name = factory.make_name('name')
279
new_description = factory.make_name('description')
280
response = self.client.post(
281
reverse('network-edit', args=[network.name]),
284
'description': new_description,
287
reverse('network-list'), extract_redirect(response),
289
network = reload_object(network)
291
(new_name, new_description),
292
(network.name, network.description),
296
class NetworkDeleteNonAdminTest(MAASServerTestCase):
298
def test_cannot_delete(self):
300
network = factory.make_network()
301
response = self.client.post(
302
reverse('network-del', args=[network.name]))
303
self.assertEqual(reverse('login'), extract_redirect(response))
304
self.assertIsNotNone(reload_object(network))
307
class NetworkDeleteAdminTest(MAASServerTestCase):
309
def test_deletes_network(self):
310
self.client_log_in(as_admin=True)
311
network = factory.make_network()
312
response = self.client.post(
313
reverse('network-del', args=[network.name]),
315
self.assertEqual(httplib.FOUND, response.status_code)
316
self.assertIsNone(reload_object(network))
318
def test_redirects_to_listing(self):
319
self.client_log_in(as_admin=True)
320
network = factory.make_network()
321
response = self.client.post(
322
reverse('network-del', args=[network.name]),
324
self.assertEqual(reverse('network-list'), extract_redirect(response))