Adds unit tests for network_ui

* Covers 100% of non-migration python lines of code
This commit is contained in:
Ben Thomasson
2018-04-04 12:56:58 -04:00
parent da5781bfc9
commit af4367b222
10 changed files with 812 additions and 28 deletions

View File

@@ -372,7 +372,8 @@ awx-link:
sed -i "s/placeholder/$(shell git describe --long | sed 's/\./\\./g')/" /awx_devel/awx.egg-info/PKG-INFO sed -i "s/placeholder/$(shell git describe --long | sed 's/\./\\./g')/" /awx_devel/awx.egg-info/PKG-INFO
cp /tmp/awx.egg-link /venv/awx/lib/python2.7/site-packages/awx.egg-link cp /tmp/awx.egg-link /venv/awx/lib/python2.7/site-packages/awx.egg-link
TEST_DIRS ?= awx/main/tests/unit awx/main/tests/functional awx/conf/tests awx/sso/tests TEST_DIRS ?= awx/main/tests/unit awx/main/tests/functional awx/conf/tests awx/sso/tests awx/network_ui/tests/unit
# Run all API unit tests. # Run all API unit tests.
test: test:
@if [ "$(VENV_BASE)" ]; then \ @if [ "$(VENV_BASE)" ]; then \
@@ -386,7 +387,7 @@ test_unit:
@if [ "$(VENV_BASE)" ]; then \ @if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \ . $(VENV_BASE)/awx/bin/activate; \
fi; \ fi; \
py.test awx/main/tests/unit awx/conf/tests/unit awx/sso/tests/unit py.test awx/main/tests/unit awx/conf/tests/unit awx/sso/tests/unit awx/network_ui/tests/unit
test_ansible: test_ansible:
@if [ "$(VENV_BASE)" ]; then \ @if [ "$(VENV_BASE)" ]; then \

View File

@@ -1,5 +1,5 @@
# Copyright (c) 2017 Red Hat, Inc # Copyright (c) 2017 Red Hat, Inc
from channels import Group import channels
from channels.auth import channel_session_user, channel_session_user_from_http from channels.auth import channel_session_user, channel_session_user_from_http
from awx.network_ui.models import Topology, Device, Link, Client, Interface from awx.network_ui.models import Topology, Device, Link, Client, Interface
from awx.network_ui.models import TopologyInventory from awx.network_ui.models import TopologyInventory
@@ -22,6 +22,10 @@ def parse_inventory_id(data):
inventory_id = int(inventory_id[0]) inventory_id = int(inventory_id[0])
except ValueError: except ValueError:
inventory_id = None inventory_id = None
except IndexError:
inventory_id = None
except TypeError:
inventory_id = None
if not inventory_id: if not inventory_id:
inventory_id = None inventory_id = None
return inventory_id return inventory_id
@@ -42,10 +46,10 @@ class NetworkingEvents(object):
message_type = data.pop(0) message_type = data.pop(0)
message_value = data.pop(0) message_value = data.pop(0)
if isinstance(message_value, list): if isinstance(message_value, list):
logger.error("Message has no sender") logger.warning("Message has no sender")
return None, None return None, None
if isinstance(message_value, dict) and client_id != message_value.get('sender'): if isinstance(message_value, dict) and client_id != message_value.get('sender'):
logger.error("client_id mismatch expected: %s actual %s", client_id, message_value.get('sender')) logger.warning("client_id mismatch expected: %s actual %s", client_id, message_value.get('sender'))
return None, None return None, None
return message_type, message_value return message_type, message_value
else: else:
@@ -58,11 +62,19 @@ class NetworkingEvents(object):
of name onX where X is the message type. of name onX where X is the message type.
''' '''
topology_id = message.get('topology') topology_id = message.get('topology')
assert topology_id is not None, "No topology_id" if topology_id is None:
logger.warning("Unsupported message %s: no topology", message)
return
client_id = message.get('client') client_id = message.get('client')
assert client_id is not None, "No client_id" if client_id is None:
logger.warning("Unsupported message %s: no client", message)
return
if 'text' not in message:
logger.warning("Unsupported message %s: no data", message)
return
message_type, message_value = self.parse_message_text(message['text'], client_id) message_type, message_value = self.parse_message_text(message['text'], client_id)
if message_type is None: if message_type is None:
logger.warning("Unsupported message %s: no message type", message)
return return
handler = self.get_handler(message_type) handler = self.get_handler(message_type)
if handler is not None: if handler is not None:
@@ -98,9 +110,6 @@ class NetworkingEvents(object):
def onDeviceMove(self, device, topology_id, client_id): def onDeviceMove(self, device, topology_id, client_id):
Device.objects.filter(topology_id=topology_id, cid=device['id']).update(x=device['x'], y=device['y']) Device.objects.filter(topology_id=topology_id, cid=device['id']).update(x=device['x'], y=device['y'])
def onDeviceInventoryUpdate(self, device, topology_id, client_id):
Device.objects.filter(topology_id=topology_id, cid=device['id']).update(host_id=device['host_id'])
def onDeviceLabelEdit(self, device, topology_id, client_id): def onDeviceLabelEdit(self, device, topology_id, client_id):
logger.debug("Device label edited %s", device) logger.debug("Device label edited %s", device)
Device.objects.filter(topology_id=topology_id, cid=device['id']).update(name=device['name']) Device.objects.filter(topology_id=topology_id, cid=device['id']).update(name=device['name'])
@@ -132,6 +141,12 @@ class NetworkingEvents(object):
device_map = dict(Device.objects device_map = dict(Device.objects
.filter(topology_id=topology_id, cid__in=[link['from_device_id'], link['to_device_id']]) .filter(topology_id=topology_id, cid__in=[link['from_device_id'], link['to_device_id']])
.values_list('cid', 'pk')) .values_list('cid', 'pk'))
if link['from_device_id'] not in device_map:
logger.warning('Device not found')
return
if link['to_device_id'] not in device_map:
logger.warning('Device not found')
return
Link.objects.get_or_create(cid=link['id'], Link.objects.get_or_create(cid=link['id'],
name=link['name'], name=link['name'],
from_device_id=device_map[link['from_device_id']], from_device_id=device_map[link['from_device_id']],
@@ -150,8 +165,10 @@ class NetworkingEvents(object):
.filter(topology_id=topology_id, cid__in=[link['from_device_id'], link['to_device_id']]) .filter(topology_id=topology_id, cid__in=[link['from_device_id'], link['to_device_id']])
.values_list('cid', 'pk')) .values_list('cid', 'pk'))
if link['from_device_id'] not in device_map: if link['from_device_id'] not in device_map:
logger.warning('Device not found')
return return
if link['to_device_id'] not in device_map: if link['to_device_id'] not in device_map:
logger.warning('Device not found')
return return
Link.objects.filter(cid=link['id'], Link.objects.filter(cid=link['id'],
from_device_id=device_map[link['from_device_id']], from_device_id=device_map[link['from_device_id']],
@@ -212,11 +229,11 @@ def ws_connect(message):
TopologyInventory(inventory_id=inventory_id, topology_id=topology.pk).save() TopologyInventory(inventory_id=inventory_id, topology_id=topology.pk).save()
topology_id = topology.pk topology_id = topology.pk
message.channel_session['topology_id'] = topology_id message.channel_session['topology_id'] = topology_id
Group("topology-%s" % topology_id).add(message.reply_channel) channels.Group("topology-%s" % topology_id).add(message.reply_channel)
client = Client() client = Client()
client.save() client.save()
message.channel_session['client_id'] = client.pk message.channel_session['client_id'] = client.pk
Group("client-%s" % client.pk).add(message.reply_channel) channels.Group("client-%s" % client.pk).add(message.reply_channel)
message.reply_channel.send({"text": json.dumps(["id", client.pk])}) message.reply_channel.send({"text": json.dumps(["id", client.pk])})
message.reply_channel.send({"text": json.dumps(["topology_id", topology_id])}) message.reply_channel.send({"text": json.dumps(["topology_id", topology_id])})
topology_data = transform_dict(dict(id='topology_id', topology_data = transform_dict(dict(id='topology_id',
@@ -278,7 +295,7 @@ def send_snapshot(channel, topology_id):
@channel_session_user @channel_session_user
def ws_message(message): def ws_message(message):
# Send to all clients editing the topology # Send to all clients editing the topology
Group("topology-%s" % message.channel_session['topology_id']).send({"text": message['text']}) channels.Group("topology-%s" % message.channel_session['topology_id']).send({"text": message['text']})
# Send to networking_events handler # Send to networking_events handler
networking_events_dispatcher.handle({"text": message['text'], networking_events_dispatcher.handle({"text": message['text'],
"topology": message.channel_session['topology_id'], "topology": message.channel_session['topology_id'],
@@ -288,5 +305,5 @@ def ws_message(message):
@channel_session_user @channel_session_user
def ws_disconnect(message): def ws_disconnect(message):
if 'topology_id' in message.channel_session: if 'topology_id' in message.channel_session:
Group("topology-%s" % message.channel_session['topology_id']).discard(message.reply_channel) channels.Group("topology-%s" % message.channel_session['topology_id']).discard(message.reply_channel)

View File

View File

View File

@@ -0,0 +1,240 @@
import mock
import logging
import json
import imp
from mock import patch
patch('channels.auth.channel_session_user', lambda x: x).start()
patch('channels.auth.channel_session_user_from_http', lambda x: x).start()
from awx.network_ui.consumers import parse_inventory_id, networking_events_dispatcher, send_snapshot # noqa
from awx.network_ui.models import Topology, Device, Link, Interface, TopologyInventory, Client # noqa
import awx # noqa
import awx.network_ui # noqa
import awx.network_ui.consumers # noqa
imp.reload(awx.network_ui.consumers)
def test_parse_inventory_id():
assert parse_inventory_id({}) is None
assert parse_inventory_id({'inventory_id': ['1']}) == 1
assert parse_inventory_id({'inventory_id': ['0']}) is None
assert parse_inventory_id({'inventory_id': ['X']}) is None
assert parse_inventory_id({'inventory_id': []}) is None
assert parse_inventory_id({'inventory_id': 'x'}) is None
assert parse_inventory_id({'inventory_id': '12345'}) == 1
assert parse_inventory_id({'inventory_id': 1}) is None
def test_network_events_handle_message_incomplete_message1():
logger = logging.getLogger('awx.network_ui.consumers')
with mock.patch.object(logger, 'warning') as log_mock:
networking_events_dispatcher.handle({})
log_mock.assert_called_once_with(
'Unsupported message %s: no topology', {})
def test_network_events_handle_message_incomplete_message2():
logger = logging.getLogger('awx.network_ui.consumers')
with mock.patch.object(logger, 'warning') as log_mock:
networking_events_dispatcher.handle({'topology': [0]})
log_mock.assert_called_once_with(
'Unsupported message %s: no client', {'topology': [0]})
def test_network_events_handle_message_incomplete_message3():
logger = logging.getLogger('awx.network_ui.consumers')
with mock.patch.object(logger, 'warning') as log_mock:
networking_events_dispatcher.handle({'topology': [1]})
log_mock.assert_called_once_with(
'Unsupported message %s: no client', {'topology': [1]})
def test_network_events_handle_message_incomplete_message4():
logger = logging.getLogger('awx.network_ui.consumers')
with mock.patch.object(logger, 'warning') as log_mock:
networking_events_dispatcher.handle({'topology': 1, 'client': 1})
log_mock.assert_called_once_with('Unsupported message %s: no data', {
'client': 1, 'topology': 1})
def test_network_events_handle_message_incomplete_message5():
logger = logging.getLogger('awx.network_ui.consumers')
with mock.patch.object(logger, 'warning') as log_mock:
message = ['DeviceCreate']
networking_events_dispatcher.handle(
{'topology': 1, 'client': 1, 'text': json.dumps(message)})
log_mock.assert_called_once_with('Unsupported message %s: no message type', {
'text': '["DeviceCreate"]', 'client': 1, 'topology': 1})
def test_network_events_handle_message_incomplete_message6():
logger = logging.getLogger('awx.network_ui.consumers')
with mock.patch.object(logger, 'warning') as log_mock:
message = ['DeviceCreate', []]
networking_events_dispatcher.handle(
{'topology': 1, 'client': 1, 'text': json.dumps(message)})
log_mock.assert_has_calls([
mock.call('Message has no sender'),
mock.call('Unsupported message %s: no message type', {'text': '["DeviceCreate", []]', 'client': 1, 'topology': 1})])
def test_network_events_handle_message_incomplete_message7():
logger = logging.getLogger('awx.network_ui.consumers')
with mock.patch.object(logger, 'warning') as log_mock:
message = ['DeviceCreate', {}]
networking_events_dispatcher.handle(
{'topology': 1, 'client': 1, 'text': json.dumps(message)})
log_mock.assert_has_calls([
mock.call('client_id mismatch expected: %s actual %s', 1, None),
mock.call('Unsupported message %s: no message type', {'text': '["DeviceCreate", {}]', 'client': 1, 'topology': 1})])
def test_network_events_handle_message_incomplete_message8():
logger = logging.getLogger('awx.network_ui.consumers')
with mock.patch.object(logger, 'warning') as log_mock:
message = ['Unsupported', {'sender': 1}]
networking_events_dispatcher.handle(
{'topology': 1, 'client': 1, 'text': json.dumps(message)})
log_mock.assert_called_once_with(
'Unsupported message %s: no handler', u'Unsupported')
def test_send_snapshot_empty():
channel = mock.MagicMock()
logger = logging.getLogger('awx.network_ui.consumers')
with mock.patch.object(logger, 'warning') as log_mock,\
mock.patch.object(Device, 'objects'),\
mock.patch.object(Link, 'objects'),\
mock.patch.object(Interface, 'objects'),\
mock.patch.object(Topology, 'objects'):
send_snapshot(channel, 1)
log_mock.assert_not_called()
channel.send.assert_called_once_with(
{'text': '["Snapshot", {"links": [], "devices": [], "sender": 0}]'})
def test_send_snapshot_single():
channel = mock.MagicMock()
logger = logging.getLogger('awx.network_ui.consumers')
with mock.patch.object(logger, 'warning') as log_mock,\
mock.patch.object(Device, 'objects') as device_objects_mock,\
mock.patch.object(Link, 'objects'),\
mock.patch.object(Interface, 'objects') as interface_objects_mock:
interface_objects_mock.filter.return_value.values.return_value = [
dict(cid=1, device_id=1, id=1, name="eth0")]
device_objects_mock.filter.return_value.values.return_value = [
dict(cid=1, id=1, device_type="host", name="host1", x=0, y=0,
interface_id_seq=1, host_id=1)]
send_snapshot(channel, 1)
device_objects_mock.filter.assert_called_once_with(topology_id=1)
device_objects_mock.filter.return_value.values.assert_called_once_with()
interface_objects_mock.filter.assert_called_once_with(
device__topology_id=1)
interface_objects_mock.filter.return_value.values.assert_called_once_with()
log_mock.assert_not_called()
channel.send.assert_called_once_with(
{'text': '''["Snapshot", {"links": [], "devices": [{"interface_id_seq": 1, \
"name": "host1", "interfaces": [{"id": 1, "device_id": 1, "name": "eth0", "interface_id": 1}], \
"device_type": "host", "host_id": 1, "y": 0, "x": 0, "id": 1, "device_id": 1}], "sender": 0}]'''})
def test_ws_disconnect():
message = mock.MagicMock()
message.channel_session = dict(topology_id=1)
message.reply_channel = 'foo'
with mock.patch('channels.Group') as group_mock:
awx.network_ui.consumers.ws_disconnect(message)
group_mock.assert_called_once_with('topology-1')
group_mock.return_value.discard.assert_called_once_with('foo')
def test_ws_disconnect_no_topology():
message = mock.MagicMock()
with mock.patch('channels.Group') as group_mock:
awx.network_ui.consumers.ws_disconnect(message)
group_mock.assert_not_called()
def test_ws_message():
message = mock.MagicMock()
message.channel_session = dict(topology_id=1, client_id=1)
message.__getitem__.return_value = json.dumps([])
print (message['text'])
with mock.patch('channels.Group') as group_mock:
awx.network_ui.consumers.ws_message(message)
group_mock.assert_called_once_with('topology-1')
group_mock.return_value.send.assert_called_once_with({'text': '[]'})
def test_ws_connect_unauthenticated():
message = mock.MagicMock()
message.user.is_authenticated.return_value = False
logger = logging.getLogger('awx.network_ui.consumers')
with mock.patch.object(logger, 'error') as log_mock:
awx.network_ui.consumers.ws_connect(message)
log_mock.assert_called_once_with('Request user is not authenticated to use websocket.')
def test_ws_connect_new_topology():
message = mock.MagicMock()
logger = logging.getLogger('awx.network_ui.consumers')
with mock.patch('awx.network_ui.consumers.Client') as client_mock,\
mock.patch('awx.network_ui.consumers.Topology') as topology_mock,\
mock.patch('channels.Group'),\
mock.patch('awx.network_ui.consumers.send_snapshot') as send_snapshot_mock,\
mock.patch.object(logger, 'warning'),\
mock.patch.object(TopologyInventory, 'objects'),\
mock.patch.object(TopologyInventory, 'save'),\
mock.patch.object(Topology, 'save'),\
mock.patch.object(Topology, 'objects'),\
mock.patch.object(Device, 'objects'),\
mock.patch.object(Link, 'objects'),\
mock.patch.object(Interface, 'objects'):
client_mock.return_value.pk = 777
topology_mock.return_value = Topology(
name="topology", scale=1.0, panX=0, panY=0, pk=999)
awx.network_ui.consumers.ws_connect(message)
message.reply_channel.send.assert_has_calls([
mock.call({'text': '["id", 777]'}),
mock.call({'text': '["topology_id", 999]'}),
mock.call(
{'text': '["Topology", {"scale": 1.0, "name": "topology", "device_id_seq": 0, "panY": 0, "panX": 0, "topology_id": 999, "link_id_seq": 0}]'}),
])
send_snapshot_mock.assert_called_once_with(message.reply_channel, 999)
def test_ws_connect_existing_topology():
message = mock.MagicMock()
logger = logging.getLogger('awx.network_ui.consumers')
with mock.patch('awx.network_ui.consumers.Client') as client_mock,\
mock.patch('awx.network_ui.consumers.send_snapshot') as send_snapshot_mock,\
mock.patch('channels.Group'),\
mock.patch.object(logger, 'warning'),\
mock.patch.object(TopologyInventory, 'objects') as topology_inventory_objects_mock,\
mock.patch.object(TopologyInventory, 'save'),\
mock.patch.object(Topology, 'save'),\
mock.patch.object(Topology, 'objects') as topology_objects_mock,\
mock.patch.object(Device, 'objects'),\
mock.patch.object(Link, 'objects'),\
mock.patch.object(Interface, 'objects'):
topology_inventory_objects_mock.filter.return_value.values_list.return_value = [
1]
client_mock.return_value.pk = 888
topology_objects_mock.get.return_value = Topology(pk=1001,
id=1,
name="topo",
panX=0,
panY=0,
scale=1.0,
link_id_seq=1,
device_id_seq=1)
awx.network_ui.consumers.ws_connect(message)
message.reply_channel.send.assert_has_calls([
mock.call({'text': '["id", 888]'}),
mock.call({'text': '["topology_id", 1001]'}),
mock.call(
{'text': '["Topology", {"scale": 1.0, "name": "topo", "device_id_seq": 1, "panY": 0, "panX": 0, "topology_id": 1001, "link_id_seq": 1}]'}),
])
send_snapshot_mock.assert_called_once_with(message.reply_channel, 1001)

View File

@@ -0,0 +1,15 @@
from awx.network_ui.models import Device, Topology, Interface
def test_device():
assert str(Device(name="foo")) == "foo"
def test_topology():
assert str(Topology(name="foo")) == "foo"
def test_interface():
assert str(Interface(name="foo")) == "foo"

View File

@@ -0,0 +1,451 @@
import mock
import json
import logging
from awx.network_ui.consumers import networking_events_dispatcher
from awx.network_ui.models import Topology, Device, Link, Interface
def message(message):
def wrapper(fn):
fn.tests_message = message
return fn
return wrapper
@message('DeviceMove')
def test_network_events_handle_message_DeviceMove():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['DeviceMove', dict(
msg_type='DeviceMove',
sender=1,
id=1,
x=100,
y=100,
previous_x=0,
previous_y=0
)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock,\
mock.patch.object(Device, 'objects') as device_objects_mock:
networking_events_dispatcher.handle(message)
device_objects_mock.filter.assert_called_once_with(
cid=1, topology_id=1)
device_objects_mock.filter.return_value.update.assert_called_once_with(
x=100, y=100)
log_mock.assert_not_called()
@message('DeviceCreate')
def test_network_events_handle_message_DeviceCreate():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['DeviceCreate', dict(msg_type='DeviceCreate',
sender=1,
id=1,
x=0,
y=0,
name="test_created",
type='host',
host_id=None)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock,\
mock.patch.object(Topology.objects, 'filter') as topology_objects_mock,\
mock.patch.object(Device.objects, 'get_or_create') as device_objects_mock:
device_mock = mock.MagicMock()
filter_mock = mock.MagicMock()
device_objects_mock.return_value = [device_mock, True]
topology_objects_mock.return_value = filter_mock
networking_events_dispatcher.handle(message)
device_objects_mock.assert_called_once_with(
cid=1,
defaults={'name': u'test_created', 'cid': 1, 'device_type': u'host',
'x': 0, 'y': 0, 'host_id': None},
topology_id=1)
device_mock.save.assert_called_once_with()
topology_objects_mock.assert_called_once_with(
device_id_seq__lt=1, pk=1)
filter_mock.update.assert_called_once_with(device_id_seq=1)
log_mock.assert_not_called()
@message('DeviceLabelEdit')
def test_network_events_handle_message_DeviceLabelEdit():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['DeviceLabelEdit', dict(
msg_type='DeviceLabelEdit',
sender=1,
id=1,
name='test_changed',
previous_name='test_created'
)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock,\
mock.patch.object(Device.objects, 'filter') as device_objects_filter_mock:
networking_events_dispatcher.handle(message)
device_objects_filter_mock.assert_called_once_with(
cid=1, topology_id=1)
log_mock.assert_not_called()
@message('DeviceSelected')
def test_network_events_handle_message_DeviceSelected():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['DeviceSelected', dict(
msg_type='DeviceSelected',
sender=1,
id=1
)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock:
networking_events_dispatcher.handle(message)
log_mock.assert_not_called()
@message('DeviceUnSelected')
def test_network_events_handle_message_DeviceUnSelected():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['DeviceUnSelected', dict(
msg_type='DeviceUnSelected',
sender=1,
id=1
)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock:
networking_events_dispatcher.handle(message)
log_mock.assert_not_called()
@message('DeviceDestroy')
def test_network_events_handle_message_DeviceDestory():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['DeviceDestroy', dict(
msg_type='DeviceDestroy',
sender=1,
id=1,
previous_x=0,
previous_y=0,
previous_name="",
previous_type="host",
previous_host_id="1")]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock,\
mock.patch.object(Device, 'objects') as device_objects_mock:
networking_events_dispatcher.handle(message)
device_objects_mock.filter.assert_called_once_with(
cid=1, topology_id=1)
device_objects_mock.filter.return_value.delete.assert_called_once_with()
log_mock.assert_not_called()
@message('InterfaceCreate')
def test_network_events_handle_message_InterfaceCreate():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['InterfaceCreate', dict(
msg_type='InterfaceCreate',
sender=1,
device_id=1,
id=1,
name='eth0'
)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock,\
mock.patch.object(Device, 'objects') as device_objects_mock,\
mock.patch.object(Interface, 'objects') as interface_objects_mock:
device_objects_mock.get.return_value.pk = 99
networking_events_dispatcher.handle(message)
device_objects_mock.get.assert_called_once_with(cid=1, topology_id=1)
device_objects_mock.filter.assert_called_once_with(
cid=1, interface_id_seq__lt=1, topology_id=1)
interface_objects_mock.get_or_create.assert_called_once_with(
cid=1, defaults={'name': u'eth0'}, device_id=99)
log_mock.assert_not_called()
@message('InterfaceLabelEdit')
def test_network_events_handle_message_InterfaceLabelEdit():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['InterfaceLabelEdit', dict(
msg_type='InterfaceLabelEdit',
sender=1,
id=1,
device_id=1,
name='new name',
previous_name='old name'
)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock,\
mock.patch.object(Interface, 'objects') as interface_objects_mock:
networking_events_dispatcher.handle(message)
interface_objects_mock.filter.assert_called_once_with(
cid=1, device__cid=1, device__topology_id=1)
interface_objects_mock.filter.return_value.update.assert_called_once_with(
name=u'new name')
log_mock.assert_not_called()
@message('LinkLabelEdit')
def test_network_events_handle_message_LinkLabelEdit():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['LinkLabelEdit', dict(
msg_type='LinkLabelEdit',
sender=1,
id=1,
name='new name',
previous_name='old name'
)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock,\
mock.patch.object(Link, 'objects') as link_objects_mock:
networking_events_dispatcher.handle(message)
link_objects_mock.filter.assert_called_once_with(
cid=1, from_device__topology_id=1)
link_objects_mock.filter.return_value.update.assert_called_once_with(
name=u'new name')
log_mock.assert_not_called()
@message('LinkCreate')
def test_network_events_handle_message_LinkCreate():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['LinkCreate', dict(
msg_type='LinkCreate',
id=1,
sender=1,
name="",
from_device_id=1,
to_device_id=2,
from_interface_id=1,
to_interface_id=1
)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock,\
mock.patch.object(Device, 'objects') as device_objects_mock,\
mock.patch.object(Link, 'objects') as link_objects_mock,\
mock.patch.object(Interface, 'objects') as interface_objects_mock,\
mock.patch.object(Topology, 'objects') as topology_objects_mock:
values_list_mock = mock.MagicMock()
values_list_mock.values_list.return_value = [(1,1), (2,2)]
interface_objects_mock.get.return_value = mock.MagicMock()
interface_objects_mock.get.return_value.pk = 7
device_objects_mock.filter.return_value = values_list_mock
topology_objects_mock.filter.return_value = mock.MagicMock()
networking_events_dispatcher.handle(message)
device_objects_mock.filter.assert_called_once_with(
cid__in=[1, 2], topology_id=1)
values_list_mock.values_list.assert_called_once_with('cid', 'pk')
link_objects_mock.get_or_create.assert_called_once_with(
cid=1, from_device_id=1, from_interface_id=7, name=u'',
to_device_id=2, to_interface_id=7)
topology_objects_mock.filter.assert_called_once_with(
link_id_seq__lt=1, pk=1)
topology_objects_mock.filter.return_value.update.assert_called_once_with(
link_id_seq=1)
log_mock.assert_not_called()
@message('LinkCreate')
def test_network_events_handle_message_LinkCreate_bad_device1():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['LinkCreate', dict(
msg_type='LinkCreate',
id=1,
sender=1,
name="",
from_device_id=1,
to_device_id=2,
from_interface_id=1,
to_interface_id=1
)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock,\
mock.patch.object(Device, 'objects') as device_objects_mock,\
mock.patch.object(Link, 'objects'),\
mock.patch.object(Interface, 'objects') as interface_objects_mock,\
mock.patch.object(Topology, 'objects') as topology_objects_mock:
values_list_mock = mock.MagicMock()
values_list_mock.values_list.return_value = [(9,1), (2,2)]
interface_objects_mock.get.return_value = mock.MagicMock()
interface_objects_mock.get.return_value.pk = 7
device_objects_mock.filter.return_value = values_list_mock
topology_objects_mock.filter.return_value = mock.MagicMock()
networking_events_dispatcher.handle(message)
device_objects_mock.filter.assert_called_once_with(
cid__in=[1, 2], topology_id=1)
values_list_mock.values_list.assert_called_once_with('cid', 'pk')
log_mock.assert_called_once_with('Device not found')
@message('LinkCreate')
def test_network_events_handle_message_LinkCreate_bad_device2():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['LinkCreate', dict(
msg_type='LinkCreate',
id=1,
sender=1,
name="",
from_device_id=1,
to_device_id=2,
from_interface_id=1,
to_interface_id=1
)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock,\
mock.patch.object(Device, 'objects') as device_objects_mock,\
mock.patch.object(Link, 'objects'),\
mock.patch.object(Interface, 'objects') as interface_objects_mock,\
mock.patch.object(Topology, 'objects') as topology_objects_mock:
values_list_mock = mock.MagicMock()
values_list_mock.values_list.return_value = [(1,1), (9,2)]
interface_objects_mock.get.return_value = mock.MagicMock()
interface_objects_mock.get.return_value.pk = 7
device_objects_mock.filter.return_value = values_list_mock
topology_objects_mock.filter.return_value = mock.MagicMock()
networking_events_dispatcher.handle(message)
device_objects_mock.filter.assert_called_once_with(
cid__in=[1, 2], topology_id=1)
values_list_mock.values_list.assert_called_once_with('cid', 'pk')
log_mock.assert_called_once_with('Device not found')
@message('LinkDestroy')
def test_network_events_handle_message_LinkDestroy():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['LinkDestroy', dict(
msg_type='LinkDestroy',
id=1,
sender=1,
name="",
from_device_id=1,
to_device_id=2,
from_interface_id=1,
to_interface_id=1
)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock,\
mock.patch.object(Device.objects, 'filter') as device_filter_mock,\
mock.patch.object(Link.objects, 'filter') as link_filter_mock,\
mock.patch.object(Interface.objects, 'get') as interface_get_mock:
values_mock = mock.MagicMock()
interface_get_mock.return_value = mock.MagicMock()
interface_get_mock.return_value.pk = 7
device_filter_mock.return_value = values_mock
values_mock.values_list.return_value = [(1,1), (2,2)]
networking_events_dispatcher.handle(message)
device_filter_mock.assert_called_once_with(
cid__in=[1, 2], topology_id=1)
values_mock.values_list.assert_called_once_with('cid', 'pk')
link_filter_mock.assert_called_once_with(
cid=1, from_device_id=1, from_interface_id=7, to_device_id=2, to_interface_id=7)
log_mock.assert_not_called()
@message('LinkDestroy')
def test_network_events_handle_message_LinkDestroy_bad_device_map1():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['LinkDestroy', dict(
msg_type='LinkDestroy',
id=1,
sender=1,
name="",
from_device_id=1,
to_device_id=2,
from_interface_id=1,
to_interface_id=1
)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock,\
mock.patch.object(Device.objects, 'filter') as device_filter_mock,\
mock.patch.object(Link.objects, 'filter'),\
mock.patch.object(Interface.objects, 'get') as interface_get_mock:
values_mock = mock.MagicMock()
interface_get_mock.return_value = mock.MagicMock()
interface_get_mock.return_value.pk = 7
device_filter_mock.return_value = values_mock
values_mock.values_list.return_value = [(9,1), (2,2)]
networking_events_dispatcher.handle(message)
log_mock.assert_called_once_with('Device not found')
@message('LinkDestroy')
def test_network_events_handle_message_LinkDestroy_bad_device_map2():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['LinkDestroy', dict(
msg_type='LinkDestroy',
id=1,
sender=1,
name="",
from_device_id=1,
to_device_id=2,
from_interface_id=1,
to_interface_id=1
)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock,\
mock.patch.object(Device.objects, 'filter') as device_filter_mock,\
mock.patch.object(Link.objects, 'filter'),\
mock.patch.object(Interface.objects, 'get') as interface_get_mock:
values_mock = mock.MagicMock()
interface_get_mock.return_value = mock.MagicMock()
interface_get_mock.return_value.pk = 7
device_filter_mock.return_value = values_mock
values_mock.values_list.return_value = [(1,1), (9,2)]
networking_events_dispatcher.handle(message)
log_mock.assert_called_once_with('Device not found')
@message('LinkSelected')
def test_network_events_handle_message_LinkSelected():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['LinkSelected', dict(
msg_type='LinkSelected',
sender=1,
id=1
)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock:
networking_events_dispatcher.handle(message)
log_mock.assert_not_called()
@message('LinkUnSelected')
def test_network_events_handle_message_LinkUnSelected():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['LinkUnSelected', dict(
msg_type='LinkUnSelected',
sender=1,
id=1
)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock:
networking_events_dispatcher.handle(message)
log_mock.assert_not_called()
@message('MultipleMessage')
def test_network_events_handle_message_MultipleMessage_unsupported_message():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['MultipleMessage', dict(
msg_type='MultipleMessage',
sender=1,
messages=[dict(msg_type="Unsupported")]
)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock:
networking_events_dispatcher.handle(message)
log_mock.assert_called_once_with(
'Unsupported message %s', u'Unsupported')
@message('MultipleMessage')
def test_network_events_handle_message_MultipleMessage():
logger = logging.getLogger('awx.network_ui.consumers')
message_data = ['MultipleMessage', dict(
msg_type='MultipleMessage',
sender=1,
messages=[dict(msg_type="DeviceSelected")]
)]
message = {'topology': 1, 'client': 1, 'text': json.dumps(message_data)}
with mock.patch.object(logger, 'warning') as log_mock:
networking_events_dispatcher.handle(message)
log_mock.assert_not_called()

View File

@@ -0,0 +1,9 @@
import awx.network_ui.routing
def test_routing():
'''
Tests that the number of routes in awx.network_ui.routing is 3.
'''
assert len(awx.network_ui.routing.channel_routing) == 3

View File

@@ -0,0 +1,65 @@
import mock
from awx.network_ui.views import topology_data, NetworkAnnotatedInterface, json_topology_data, yaml_topology_data
from awx.network_ui.models import Topology, Device, Link, Interface
def test_topology_data():
with mock.patch.object(Topology, 'objects'),\
mock.patch.object(Device, 'objects') as device_objects_mock,\
mock.patch.object(Link, 'objects') as link_objects_mock,\
mock.patch.object(Interface, 'objects'),\
mock.patch.object(NetworkAnnotatedInterface, 'filter'):
device_objects_mock.filter.return_value.order_by.return_value = [
Device(pk=1), Device(pk=2)]
link_objects_mock.filter.return_value = [Link(from_device=Device(name='from', cid=1),
to_device=Device(
name='to', cid=2),
from_interface=Interface(
name="eth0", cid=1),
to_interface=Interface(
name="eth0", cid=1),
name="",
pk=1
)]
data = topology_data(1)
assert len(data['devices']) == 2
assert len(data['links']) == 1
def test_json_topology_data():
request = mock.MagicMock()
request.GET = dict(topology_id=1)
with mock.patch('awx.network_ui.views.topology_data') as topology_data_mock:
topology_data_mock.return_value = dict()
json_topology_data(request)
topology_data_mock.assert_called_once_with(1)
def test_yaml_topology_data():
request = mock.MagicMock()
request.GET = dict(topology_id=1)
with mock.patch('awx.network_ui.views.topology_data') as topology_data_mock:
topology_data_mock.return_value = dict()
yaml_topology_data(request)
topology_data_mock.assert_called_once_with(1)
def test_json_topology_data_no_topology_id():
request = mock.MagicMock()
request.GET = dict()
with mock.patch('awx.network_ui.views.topology_data') as topology_data_mock:
topology_data_mock.return_value = dict()
json_topology_data(request)
topology_data_mock.assert_not_called()
def test_yaml_topology_data_no_topology_id():
request = mock.MagicMock()
request.GET = dict()
with mock.patch('awx.network_ui.views.topology_data') as topology_data_mock:
topology_data_mock.return_value = dict()
yaml_topology_data(request)
topology_data_mock.assert_not_called()

View File

@@ -1,11 +1,9 @@
# Copyright (c) 2017 Red Hat, Inc # Copyright (c) 2017 Red Hat, Inc
from django.shortcuts import render
from django import forms from django import forms
from django.http import JsonResponse, HttpResponseBadRequest, HttpResponse from django.http import JsonResponse, HttpResponseBadRequest, HttpResponse
from awx.network_ui.models import Topology, Device, Link, Interface from awx.network_ui.models import Topology, Device, Link, Interface
from django.db.models import Q from django.db.models import Q
import yaml import yaml
import json
NetworkAnnotatedInterface = Interface.objects.values('name', NetworkAnnotatedInterface = Interface.objects.values('name',
'cid', 'cid',
@@ -63,18 +61,6 @@ def topology_data(topology_id):
return data return data
def yaml_serialize_topology(topology_id):
return yaml.safe_dump(topology_data(topology_id), default_flow_style=False)
def json_serialize_topology(topology_id):
return json.dumps(topology_data(topology_id))
def index(request):
return render(request, "network_ui/index.html", dict(topologies=Topology.objects.all().order_by('-pk')))
class TopologyForm(forms.Form): class TopologyForm(forms.Form):
topology_id = forms.IntegerField() topology_id = forms.IntegerField()