Refactors network_ui_test out of network_ui

* Separates test messages from application messages
* Removes test runner and groups, processes, and streams from network_ui
* Adds network_ui_test
* Fixes routing for network_ui_test
* Removes coverage_report tool from network_ui
* Fixes network_ui_test test workflow
* Sets width and height of the page during tests
This commit is contained in:
Ben Thomasson 2018-03-15 13:09:23 -04:00
parent b29a605800
commit 766bee3753
No known key found for this signature in database
GPG Key ID: 5818EF4CC895D5F5
29 changed files with 920 additions and 929 deletions

View File

@ -1,4 +1,6 @@
from channels.routing import route
from awx.network_ui.routing import channel_routing as network_ui_routing
from awx.network_ui_test.routing import channel_routing as network_ui_test_routing
channel_routing = [
@ -7,6 +9,6 @@ channel_routing = [
route("websocket.receive", "awx.main.consumers.ws_receive", path=r'^/websocket/$'),
]
from awx.network_ui.routing import channel_routing as network_routing
channel_routing += network_routing
channel_routing += network_ui_routing
channel_routing += network_ui_test_routing

View File

@ -2,20 +2,12 @@
# In consumers.py
from channels import Group, Channel
from channels.sessions import channel_session
from awx.network_ui.models import Topology, Device, Link, Client, TopologyHistory, MessageType, Interface
from awx.network_ui.models import Group as DeviceGroup
from awx.network_ui.models import GroupDevice as GroupDeviceMap
from awx.network_ui.models import Process, Stream
from awx.network_ui.models import Toolbox, ToolboxItem
from awx.network_ui.models import FSMTrace, EventTrace, Coverage, TopologySnapshot
from awx.network_ui.models import Topology, Device, Link, Client, Interface
from awx.network_ui.models import TopologyInventory
from awx.network_ui.models import TestCase, TestResult, CodeUnderTest, Result
import urlparse
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q
from collections import defaultdict
import logging
from django.utils.dateparse import parse_datetime
from awx.network_ui.utils import transform_dict
@ -71,16 +63,6 @@ class _Persistence(object):
return
message_type = data[0]
message_value = data[1]
try:
message_type_id = MessageType.objects.get(name=message_type).pk
except ObjectDoesNotExist:
logger.warning("Unsupported message %s: no message type", message_type)
return
TopologyHistory(topology_id=topology_id,
client_id=client_id,
message_type_id=message_type_id,
message_id=data[1].get('message_id', 0),
message_data=message['text']).save()
handler = self.get_handler(message_type)
if handler is not None:
try:
@ -127,9 +109,6 @@ class _Persistence(object):
def onDeviceInventoryUpdate(self, device, topology_id, client_id):
Device.objects.filter(topology_id=topology_id, id=device['id']).update(host_id=device['host_id'])
def onGroupInventoryUpdate(self, group, topology_id, client_id):
DeviceGroup.objects.filter(topology_id=topology_id, id=group['id']).update(inventory_group_id=group['group_id'])
def onDeviceLabelEdit(self, device, topology_id, client_id):
Device.objects.filter(topology_id=topology_id, id=device['id']).update(name=device['name'])
@ -182,34 +161,6 @@ class _Persistence(object):
to_interface_id=Interface.objects.get(device_id=device_map[link['to_device_id']],
id=link['to_interface_id']).pk).delete()
def onProcessCreate(self, process, topology_id, client_id):
Process.objects.get_or_create(device_id=Device.objects.get(id=process['device_id'],
topology_id=topology_id).pk,
id=process['id'],
defaults=dict(name=process['name'], process_type=process['type']))
(Device.objects
.filter(id=process['device_id'],
topology_id=topology_id,
interface_id_seq__lt=process['id'])
.update(interface_id_seq=process['id']))
def onStreamCreate(self, stream, topology_id, client_id):
device_map = dict(Device.objects
.filter(topology_id=topology_id, id__in=[stream['from_id'], stream['to_id']])
.values_list('id', 'pk'))
logger.info("onStreamCreate %s", stream)
Stream.objects.get_or_create(id=stream['id'],
label='',
from_device_id=device_map[stream['from_id']],
to_device_id=device_map[stream['to_id']])
(Topology.objects
.filter(topology_id=topology_id, stream_id_seq__lt=stream['id'])
.update(stream_id_seq=stream['id']))
def onCopySite(self, site, topology_id, client_id):
site_toolbox, _ = Toolbox.objects.get_or_create(name="Site")
ToolboxItem(toolbox=site_toolbox, data=json.dumps(site['site'])).save()
def onDeviceSelected(self, message_value, topology_id, client_id):
'Ignore DeviceSelected messages'
pass
@ -234,121 +185,6 @@ class _Persistence(object):
else:
logger.warning("Unsupported message %s", message['msg_type'])
def onCoverageRequest(self, coverage, topology_id, client_id):
pass
def onTestResult(self, test_result, topology_id, client_id):
xyz, _, rest = test_result['code_under_test'].partition('-')
commits_since, _, commit_hash = rest.partition('-')
commit_hash = commit_hash.strip('g')
x, y, z = [int(i) for i in xyz.split('.')]
code_under_test, _ = CodeUnderTest.objects.get_or_create(version_x=x,
version_y=y,
version_z=z,
commits_since=int(commits_since),
commit_hash=commit_hash)
tr = TestResult(id=test_result['id'],
result_id=Result.objects.get(name=test_result['result']).pk,
test_case_id=TestCase.objects.get(name=test_result['name']).pk,
code_under_test_id=code_under_test.pk,
client_id=client_id,
time=parse_datetime(test_result['date']))
tr.save()
def onCoverage(self, coverage, topology_id, client_id):
Coverage(test_result_id=TestResult.objects.get(id=coverage['result_id'], client_id=client_id).pk,
coverage_data=json.dumps(coverage['coverage'])).save()
def onStartRecording(self, recording, topology_id, client_id):
pass
def onStopRecording(self, recording, topology_id, client_id):
pass
def write_event(self, event, topology_id, client_id):
if event.get('save', True):
EventTrace(trace_session_id=event['trace_id'],
event_data=json.dumps(event),
message_id=event['message_id'],
client_id=client_id).save()
onViewPort = write_event
onMouseEvent = write_event
onTouchEvent = write_event
onMouseWheelEvent = write_event
onKeyEvent = write_event
def onGroupCreate(self, group, topology_id, client_id):
logger.info("GroupCreate %s %s %s", group['id'], group['name'], group['type'])
group = transform_dict(dict(x1='x1',
y1='y1',
x2='x2',
y2='y2',
name='name',
id='id',
type='group_type',
group_id='inventory_group_id'), group)
d, _ = DeviceGroup.objects.get_or_create(topology_id=topology_id, id=group['id'], defaults=group)
d.x1 = group['x1']
d.y1 = group['y1']
d.x2 = group['x2']
d.y2 = group['y2']
d.group_type = group['group_type']
d.save()
(Topology.objects
.filter(topology_id=topology_id, group_id_seq__lt=group['id'])
.update(group_id_seq=group['id']))
def onGroupDestroy(self, group, topology_id, client_id):
DeviceGroup.objects.filter(topology_id=topology_id, id=group['id']).delete()
def onGroupLabelEdit(self, group, topology_id, client_id):
DeviceGroup.objects.filter(topology_id=topology_id, id=group['id']).update(name=group['name'])
def onGroupMove(self, group, topology_id, client_id):
DeviceGroup.objects.filter(topology_id=topology_id, id=group['id']).update(x1=group['x1'],
y1=group['y1'],
x2=group['x2'],
y2=group['y2'])
def onGroupMembership(self, group_membership, topology_id, client_id):
members = set(group_membership['members'])
group = DeviceGroup.objects.get(topology_id=topology_id, id=group_membership['id'])
existing = set(GroupDeviceMap.objects.filter(group=group).values_list('device__id', flat=True))
new = members - existing
removed = existing - members
GroupDeviceMap.objects.filter(group__group_id=group.group_id,
device__id__in=list(removed)).delete()
device_map = dict(Device.objects.filter(topology_id=topology_id, id__in=list(new)).values_list('id', 'device_id'))
new_entries = []
for i in new:
new_entries.append(GroupDeviceMap(group=group,
device_id=device_map[i]))
if new_entries:
GroupDeviceMap.objects.bulk_create(new_entries)
def onFSMTrace(self, message_value, diagram_id, client_id):
FSMTrace(trace_session_id=message_value['trace_id'],
fsm_name=message_value['fsm_name'],
from_state=message_value['from_state'],
to_state=message_value['to_state'],
order=message_value['order'],
client_id=client_id,
message_type=message_value['recv_message_type'] or "none").save()
def onSnapshot(self, snapshot, topology_id, client_id):
TopologySnapshot(trace_session_id=snapshot['trace_id'],
snapshot_data=json.dumps(snapshot),
order=snapshot['order'],
client_id=client_id,
topology_id=topology_id).save()
persistence = _Persistence()
@ -385,45 +221,23 @@ def ws_connect(message):
panY='panY',
scale='scale',
link_id_seq='link_id_seq',
device_id_seq='device_id_seq',
group_id_seq='group_id_seq'), topology.__dict__)
device_id_seq='device_id_seq'), topology.__dict__)
message.reply_channel.send({"text": json.dumps(["Topology", topology_data])})
send_snapshot(message.reply_channel, topology_id)
send_history(message.reply_channel, topology_id)
send_toolboxes(message.reply_channel)
send_tests(message.reply_channel)
def send_toolboxes(channel):
for toolbox_item in ToolboxItem.objects.filter(toolbox__name__in=['Process', 'Device', 'Rack', 'Site']).values('toolbox__name', 'data'):
item = dict(toolbox_name=toolbox_item['toolbox__name'],
data=toolbox_item['data'])
channel.send({"text": json.dumps(["ToolboxItem", item])})
def send_tests(channel):
for name, test_case_data in TestCase.objects.all().values_list('name', 'test_case_data'):
channel.send({"text": json.dumps(["TestCase", [name, json.loads(test_case_data)]])})
def send_snapshot(channel, topology_id):
interfaces = defaultdict(list)
processes = defaultdict(list)
for i in (Interface.objects
.filter(device__topology_id=topology_id)
.values()):
interfaces[i['device_id']].append(i)
for i in (Process.objects
.filter(device__topology_id=topology_id)
.values()):
processes[i['device_id']].append(i)
devices = list(Device.objects
.filter(topology_id=topology_id).values())
for device in devices:
device['interfaces'] = interfaces[device['device_id']]
device['processes'] = processes[device['device_id']]
links = [dict(id=x['id'],
name=x['name'],
@ -440,44 +254,12 @@ def send_snapshot(channel, topology_id):
'to_device__id',
'from_interface__id',
'to_interface__id'))]
groups = list(DeviceGroup.objects
.filter(topology_id=topology_id).values())
group_map = {g['id']: g for g in groups}
for group_id, device_id in GroupDeviceMap.objects.filter(group__topology_id=topology_id).values_list('group__id', 'device__id'):
if 'members' not in group_map[group_id]:
group_map[group_id]['members'] = [device_id]
else:
group_map[group_id]['members'].append(device_id)
streams = [dict(id=x['id'],
label=x['label'],
from_id=x['from_device__id'],
to_id=x['to_device__id'])
for x in list(Stream.objects
.filter(Q(from_device__topology_id=topology_id) |
Q(to_device__topology_id=topology_id)).values('id',
'label',
'from_device__id',
'to_device__id'))]
snapshot = dict(sender=0,
devices=devices,
links=links,
groups=groups,
streams=streams)
links=links)
channel.send({"text": json.dumps(["Snapshot", snapshot])})
def send_history(channel, topology_id):
history = list(TopologyHistory.objects
.filter(topology_id=topology_id)
.exclude(message_type__name__in=HISTORY_MESSAGE_IGNORE_TYPES)
.exclude(undone=True)
.order_by('pk')
.values_list('message_data', flat=True)[:1000])
channel.send({"text": json.dumps(["History", history])})
@channel_session
def ws_message(message):
# Send to all clients editing the topology

View File

@ -0,0 +1,147 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.7 on 2018-03-06 18:37
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('network_ui', '0004_auto_20180304_2122'),
]
operations = [
migrations.RemoveField(
model_name='coverage',
name='test_result',
),
migrations.RemoveField(
model_name='eventtrace',
name='client',
),
migrations.RemoveField(
model_name='fsmtrace',
name='client',
),
migrations.RemoveField(
model_name='group',
name='topology',
),
migrations.RemoveField(
model_name='groupdevice',
name='device',
),
migrations.RemoveField(
model_name='groupdevice',
name='group',
),
migrations.RemoveField(
model_name='process',
name='device',
),
migrations.RemoveField(
model_name='stream',
name='from_device',
),
migrations.RemoveField(
model_name='stream',
name='to_device',
),
migrations.RemoveField(
model_name='testresult',
name='client',
),
migrations.RemoveField(
model_name='testresult',
name='code_under_test',
),
migrations.RemoveField(
model_name='testresult',
name='result',
),
migrations.RemoveField(
model_name='testresult',
name='test_case',
),
migrations.RemoveField(
model_name='toolboxitem',
name='toolbox',
),
migrations.RemoveField(
model_name='topologyhistory',
name='client',
),
migrations.RemoveField(
model_name='topologyhistory',
name='message_type',
),
migrations.RemoveField(
model_name='topologyhistory',
name='topology',
),
migrations.RemoveField(
model_name='topologysnapshot',
name='client',
),
migrations.RemoveField(
model_name='device',
name='process_id_seq',
),
migrations.RemoveField(
model_name='topology',
name='group_id_seq',
),
migrations.RemoveField(
model_name='topology',
name='stream_id_seq',
),
migrations.DeleteModel(
name='CodeUnderTest',
),
migrations.DeleteModel(
name='Coverage',
),
migrations.DeleteModel(
name='EventTrace',
),
migrations.DeleteModel(
name='FSMTrace',
),
migrations.DeleteModel(
name='Group',
),
migrations.DeleteModel(
name='GroupDevice',
),
migrations.DeleteModel(
name='MessageType',
),
migrations.DeleteModel(
name='Process',
),
migrations.DeleteModel(
name='Result',
),
migrations.DeleteModel(
name='Stream',
),
migrations.DeleteModel(
name='TestCase',
),
migrations.DeleteModel(
name='TestResult',
),
migrations.DeleteModel(
name='Toolbox',
),
migrations.DeleteModel(
name='ToolboxItem',
),
migrations.DeleteModel(
name='TopologyHistory',
),
migrations.DeleteModel(
name='TopologySnapshot',
),
]

View File

@ -11,7 +11,6 @@ class Device(models.Model):
id = models.IntegerField()
device_type = models.CharField(max_length=200, blank=True)
interface_id_seq = models.IntegerField(default=0,)
process_id_seq = models.IntegerField(default=0,)
host_id = models.IntegerField(default=0,)
def __unicode__(self):
@ -38,8 +37,6 @@ class Topology(models.Model):
panY = models.FloatField()
device_id_seq = models.IntegerField(default=0,)
link_id_seq = models.IntegerField(default=0,)
group_id_seq = models.IntegerField(default=0,)
stream_id_seq = models.IntegerField(default=0,)
def __unicode__(self):
return self.name
@ -50,26 +47,6 @@ class Client(models.Model):
client_id = models.AutoField(primary_key=True,)
class TopologyHistory(models.Model):
topology_history_id = models.AutoField(primary_key=True,)
topology = models.ForeignKey('Topology',)
client = models.ForeignKey('Client',)
message_type = models.ForeignKey('MessageType',)
message_id = models.IntegerField()
message_data = models.TextField()
undone = models.BooleanField(default=False,)
class MessageType(models.Model):
message_type_id = models.AutoField(primary_key=True,)
name = models.CharField(max_length=200, blank=True)
def __unicode__(self):
return self.name
class Interface(models.Model):
interface_id = models.AutoField(primary_key=True,)
@ -81,132 +58,8 @@ class Interface(models.Model):
return self.name
class Group(models.Model):
group_id = models.AutoField(primary_key=True,)
id = models.IntegerField()
name = models.CharField(max_length=200, blank=True)
x1 = models.IntegerField()
y1 = models.IntegerField()
x2 = models.IntegerField()
y2 = models.IntegerField()
topology = models.ForeignKey('Topology',)
group_type = models.CharField(max_length=200, blank=True)
inventory_group_id = models.IntegerField(default=0,)
class GroupDevice(models.Model):
group_device_id = models.AutoField(primary_key=True,)
group = models.ForeignKey('Group',)
device = models.ForeignKey('Device',)
class Stream(models.Model):
stream_id = models.AutoField('Stream', primary_key=True,)
from_device = models.ForeignKey('Device', related_name='from_stream',)
to_device = models.ForeignKey('Device', related_name='to_stream',)
label = models.CharField(max_length=200, blank=True)
id = models.IntegerField(default=0,)
class Process(models.Model):
process_id = models.AutoField(primary_key=True,)
device = models.ForeignKey('Device',)
name = models.CharField(max_length=200, blank=True)
process_type = models.CharField(max_length=200, blank=True)
id = models.IntegerField(default=0,)
class Toolbox(models.Model):
toolbox_id = models.AutoField(primary_key=True,)
name = models.CharField(max_length=200, blank=True)
class ToolboxItem(models.Model):
toolbox_item_id = models.AutoField(primary_key=True,)
toolbox = models.ForeignKey('Toolbox',)
data = models.TextField()
class FSMTrace(models.Model):
fsm_trace_id = models.AutoField(primary_key=True,)
fsm_name = models.CharField(max_length=200, blank=True)
from_state = models.CharField(max_length=200, blank=True)
to_state = models.CharField(max_length=200, blank=True)
message_type = models.CharField(max_length=200, blank=True)
client = models.ForeignKey('Client',)
trace_session_id = models.IntegerField(default=0,)
order = models.IntegerField(default=0,)
class TopologyInventory(models.Model):
topology_inventory_id = models.AutoField(primary_key=True,)
topology = models.ForeignKey('Topology',)
inventory_id = models.IntegerField()
class EventTrace(models.Model):
event_trace_id = models.AutoField(primary_key=True,)
client = models.ForeignKey('Client',)
trace_session_id = models.IntegerField(default=0,)
event_data = models.TextField()
message_id = models.IntegerField()
class Coverage(models.Model):
coverage_id = models.AutoField(primary_key=True,)
coverage_data = models.TextField()
test_result = models.ForeignKey('TestResult',)
class TopologySnapshot(models.Model):
topology_snapshot_id = models.AutoField(primary_key=True,)
client = models.ForeignKey('Client',)
topology_id = models.IntegerField()
trace_session_id = models.IntegerField()
snapshot_data = models.TextField('TopologySnapshot',)
order = models.IntegerField()
class TestCase(models.Model):
test_case_id = models.AutoField(primary_key=True,)
name = models.CharField('TestCase', max_length=200, blank=True)
test_case_data = models.TextField()
class Result(models.Model):
result_id = models.AutoField(primary_key=True,)
name = models.CharField(max_length=20, blank=True)
class CodeUnderTest(models.Model):
code_under_test_id = models.AutoField('CodeUnderTest', primary_key=True,)
version_x = models.IntegerField()
version_y = models.IntegerField()
version_z = models.IntegerField()
commits_since = models.IntegerField()
commit_hash = models.CharField(max_length=40, blank=True)
class TestResult(models.Model):
test_result_id = models.AutoField(primary_key=True,)
test_case = models.ForeignKey('TestCase',)
result = models.ForeignKey('Result',)
code_under_test = models.ForeignKey('CodeUnderTest',)
time = models.DateTimeField()
id = models.IntegerField(default=0,)
client = models.ForeignKey('Client',)

View File

@ -1,10 +1,9 @@
# Copyright (c) 2017 Red Hat, Inc
from awx.network_ui.models import Topology, Device, Link, Interface, Group, GroupDevice, Process, Stream
from awx.network_ui.models import Topology, Device, Link, Interface
from django.db.models import Q
import yaml
import json
from collections import defaultdict
NetworkAnnotatedInterface = Interface.objects.values('name',
'id',
@ -19,36 +18,18 @@ NetworkAnnotatedInterface = Interface.objects.values('name',
def topology_data(topology_id):
data = dict(devices=[],
links=[],
groups=[],
streams=[])
links=[])
topology = Topology.objects.get(pk=topology_id)
data['name'] = topology.name
data['topology_id'] = topology_id
groups = list(Group.objects.filter(topology_id=topology_id).values())
group_devices = GroupDevice.objects.filter(group__topology_id=topology_id).values('group_id', 'device_id', 'device__name', 'group__name')
group_device_map = defaultdict(list)
for group_device in group_devices:
group_device_map[group_device['group_id']].append(group_device)
device_group_map = defaultdict(list)
for group_device in group_devices:
device_group_map[group_device['device_id']].append(group_device)
for group in groups:
group['members'] = [x['device__name'] for x in group_device_map[group['group_id']]]
data['groups'] = groups
links = list(Link.objects
.filter(Q(from_device__topology_id=topology_id) |
Q(to_device__topology_id=topology_id)))
interfaces = Interface.objects.filter(device__topology_id=topology_id)
processes = Process.objects.filter(device__topology_id=topology_id)
for device in Device.objects.filter(topology_id=topology_id).order_by('name'):
interfaces = list(NetworkAnnotatedInterface.filter(device_id=device.pk).order_by('name'))
@ -58,15 +39,12 @@ def topology_data(topology_id):
remote_interface_name=x['from_link__to_interface__name'] or x['to_link__from_interface__name'],
id=x['id'],
) for x in interfaces]
processes = list(Process.objects.filter(device_id=device.pk).values())
data['devices'].append(dict(name=device.name,
type=device.device_type,
x=device.x,
y=device.y,
id=device.id,
interfaces=interfaces,
processes=processes,
groups=[x['group__name'] for x in device_group_map[device.device_id]]))
interfaces=interfaces))
for link in links:
data['links'].append(dict(from_device=link.from_device.name,
@ -80,18 +58,6 @@ def topology_data(topology_id):
name=link.name,
network=link.pk))
streams = list(Stream.objects
.filter(Q(from_device__topology_id=topology_id) |
Q(to_device__topology_id=topology_id)))
for stream in streams:
data['streams'].append(dict(from_id=stream.from_device.id,
to_id=stream.to_device.id,
from_device=stream.from_device.name,
to_device=stream.to_device.name,
label=stream.label,
id=stream.id))
return data

View File

@ -5,11 +5,6 @@ from awx.network_ui import views
app_name = 'network_ui'
urlpatterns = [
url(r'^tests$', views.tests, name='tests'),
url(r'^upload_test$', views.upload_test, name='upload_test'),
url(r'^download_coverage/(?P<pk>[0-9]+)$', views.download_coverage, name='download_coverage'),
url(r'^download_trace$', views.download_trace, name='download_trace'),
url(r'^download_recording$', views.download_recording, name='download_recording'),
url(r'^topology.json$', views.json_topology_data, name='json_topology_data'),
url(r'^topology.yaml$', views.yaml_topology_data, name='json_topology_data'),
]

View File

@ -1,16 +1,12 @@
# Copyright (c) 2017 Red Hat, Inc
from django.shortcuts import render
from django import forms
from django.http import JsonResponse, HttpResponseBadRequest, HttpResponse, HttpResponseRedirect
from django.core.exceptions import ObjectDoesNotExist
from django.http import JsonResponse, HttpResponseBadRequest, HttpResponse
from awx.network_ui.models import Topology
import yaml
import json
# Create your views here.
from .models import Topology, FSMTrace, EventTrace, TopologySnapshot
from .models import TestCase, TestResult, Coverage
from .serializers import topology_data
@ -39,100 +35,3 @@ def yaml_topology_data(request):
else:
return HttpResponseBadRequest(form.errors)
class FSMTraceForm(forms.Form):
topology_id = forms.IntegerField()
trace_id = forms.IntegerField()
client_id = forms.IntegerField()
def download_trace(request):
form = FSMTraceForm(request.GET)
if form.is_valid():
topology_id = form.cleaned_data['topology_id']
trace_id = form.cleaned_data['trace_id']
client_id = form.cleaned_data['client_id']
data = list(FSMTrace.objects.filter(trace_session_id=trace_id,
client_id=client_id).order_by('order').values())
response = HttpResponse(yaml.safe_dump(data, default_flow_style=False),
content_type="application/force-download")
response['Content-Disposition'] = 'attachment; filename="trace_{0}_{1}_{2}.yml"'.format(topology_id, client_id, trace_id)
return response
else:
return HttpResponse(form.errors)
class RecordingForm(forms.Form):
topology_id = forms.IntegerField()
trace_id = forms.IntegerField()
client_id = forms.IntegerField()
def download_recording(request):
form = RecordingForm(request.GET)
if form.is_valid():
topology_id = form.cleaned_data['topology_id']
trace_id = form.cleaned_data['trace_id']
client_id = form.cleaned_data['client_id']
data = dict()
data['event_trace'] = [json.loads(x) for x in EventTrace
.objects.filter(trace_session_id=trace_id, client_id=client_id)
.order_by('message_id')
.values_list('event_data', flat=True)]
data['fsm_trace'] = list(FSMTrace
.objects
.filter(trace_session_id=trace_id, client_id=client_id)
.order_by('order')
.values())
data['snapshots'] = [json.loads(x) for x in TopologySnapshot
.objects.filter(trace_session_id=trace_id, client_id=client_id)
.order_by('order')
.values_list('snapshot_data', flat=True)]
response = HttpResponse(json.dumps(data, sort_keys=True, indent=4),
content_type="application/force-download")
response['Content-Disposition'] = 'attachment; filename="trace_{0}_{1}_{2}.yml"'.format(topology_id, client_id, trace_id)
return response
else:
return HttpResponse(form.errors)
def tests(request):
tests = list(TestCase.objects.all().values('test_case_id', 'name'))
for x in tests:
x['coverage'] = "/network_ui/download_coverage/{0}".format(x['test_case_id'])
return JsonResponse(dict(tests=tests))
def create_test(name, data):
try:
test_case = TestCase.objects.get(name=name)
test_case.test_case_data=json.dumps(data)
test_case.save()
except ObjectDoesNotExist:
TestCase(name=name, test_case_data=json.dumps(data)).save()
class UploadTestForm(forms.Form):
name = forms.CharField()
file = forms.FileField()
def upload_test(request):
if request.method == 'POST':
form = UploadTestForm(request.POST, request.FILES)
if form.is_valid():
name = form.cleaned_data['name']
data = json.loads(request.FILES['file'].read())
create_test(name, data)
return HttpResponseRedirect('/network_ui/tests')
else:
form = UploadTestForm()
return render(request, 'network_ui/upload_test.html', {'form': form})
def download_coverage(request, pk):
latest_tr = TestResult.objects.filter(test_case_id=pk).order_by('-time')[0]
coverage = Coverage.objects.get(test_result_id=latest_tr.pk)
response = HttpResponse(coverage.coverage_data,
content_type="application/json")
return response

View File

@ -0,0 +1 @@
# Copyright (c) 2017 Red Hat, Inc

View File

@ -0,0 +1,205 @@
# Copyright (c) 2018 Red Hat, Inc
# In consumers.py
from channels import Group, Channel
from channels.sessions import channel_session
from awx.network_ui.models import Topology, Client
from awx.network_ui.models import TopologyInventory
from awx.network_ui_test.models import FSMTrace, EventTrace, Coverage, TopologySnapshot
from awx.network_ui_test.models import TestCase, TestResult, CodeUnderTest, Result
import urlparse
import logging
from django.utils.dateparse import parse_datetime
from pprint import pformat
import json
# Connected to websocket.connect
HISTORY_MESSAGE_IGNORE_TYPES = ['DeviceSelected',
'DeviceUnSelected',
'LinkSelected',
'LinkUnSelected',
'MouseEvent',
'MouseWheelEvent',
'KeyEvent']
logger = logging.getLogger("awx.network_ui_test.consumers")
class NetworkUIException(Exception):
pass
def parse_inventory_id(data):
inventory_id = data.get('inventory_id', ['null'])
try:
inventory_id = int(inventory_id[0])
except ValueError:
inventory_id = None
if not inventory_id:
inventory_id = None
return inventory_id
# TestPersistence
class _TestPersistence(object):
def handle(self, message):
topology_id = message.get('topology')
assert topology_id is not None, "No topology_id"
client_id = message.get('client')
assert client_id is not None, "No client_id"
data = json.loads(message['text'])
if isinstance(data[1], list):
logger.error("Message has no sender")
return
if isinstance(data[1], dict) and client_id != data[1].get('sender'):
logger.error("client_id mismatch expected: %s actual %s", client_id, data[1].get('sender'))
logger.error(pformat(data))
return
message_type = data[0]
message_value = data[1]
handler = self.get_handler(message_type)
if handler is not None:
try:
handler(message_value, topology_id, client_id)
except NetworkUIException, e:
Group("client-%s" % client_id).send({"text": json.dumps(["Error", str(e)])})
raise
except Exception, e:
Group("client-%s" % client_id).send({"text": json.dumps(["Error", "Server Error"])})
raise
except BaseException, e:
Group("client-%s" % client_id).send({"text": json.dumps(["Error", "Server Error"])})
raise
else:
logger.warning("Unsupported message %s: no handler", message_type)
def get_handler(self, message_type):
return getattr(self, "on{0}".format(message_type), None)
def onMultipleMessage(self, message_value, topology_id, client_id):
for message in message_value['messages']:
handler = self.get_handler(message['msg_type'])
if handler is not None:
handler(message, topology_id, client_id)
else:
logger.warning("Unsupported message %s", message['msg_type'])
def onCoverageRequest(self, coverage, topology_id, client_id):
pass
def onTestResult(self, test_result, topology_id, client_id):
xyz, _, rest = test_result['code_under_test'].partition('-')
commits_since, _, commit_hash = rest.partition('-')
commit_hash = commit_hash.strip('g')
x, y, z = [int(i) for i in xyz.split('.')]
code_under_test, _ = CodeUnderTest.objects.get_or_create(version_x=x,
version_y=y,
version_z=z,
commits_since=int(commits_since),
commit_hash=commit_hash)
logger.error("TR: %s", test_result)
tr = TestResult(id=test_result['id'],
result_id=Result.objects.get(name=test_result['result']).pk,
test_case_id=TestCase.objects.get(name=test_result['name']).pk,
code_under_test_id=code_under_test.pk,
client_id=client_id,
time=parse_datetime(test_result['date']))
tr.save()
def onCoverage(self, coverage, topology_id, client_id):
Coverage(test_result_id=TestResult.objects.get(id=coverage['result_id'], client_id=client_id).pk,
coverage_data=json.dumps(coverage['coverage'])).save()
def onStartRecording(self, recording, topology_id, client_id):
pass
def onStopRecording(self, recording, topology_id, client_id):
pass
def write_event(self, event, topology_id, client_id):
if event.get('save', True):
EventTrace(trace_session_id=event['trace_id'],
event_data=json.dumps(event),
message_id=event['message_id'],
client_id=client_id).save()
onViewPort = write_event
onMouseEvent = write_event
onTouchEvent = write_event
onMouseWheelEvent = write_event
onKeyEvent = write_event
def onFSMTrace(self, message_value, diagram_id, client_id):
FSMTrace(trace_session_id=message_value['trace_id'],
fsm_name=message_value['fsm_name'],
from_state=message_value['from_state'],
to_state=message_value['to_state'],
order=message_value['order'],
client_id=client_id,
message_type=message_value['recv_message_type'] or "none").save()
def onSnapshot(self, snapshot, topology_id, client_id):
TopologySnapshot(trace_session_id=snapshot['trace_id'],
snapshot_data=json.dumps(snapshot),
order=snapshot['order'],
client_id=client_id,
topology_id=topology_id).save()
test_persistence = _TestPersistence()
# UI Channel Events
@channel_session
def ws_connect(message):
# Accept connection
data = urlparse.parse_qs(message.content['query_string'])
inventory_id = parse_inventory_id(data)
topology_ids = list(TopologyInventory.objects.filter(inventory_id=inventory_id).values_list('topology_id', flat=True))
topology_id = 0
if len(topology_ids) > 0:
topology_id = topology_ids[0]
if topology_id:
topology = Topology.objects.get(topology_id=topology_id)
else:
topology = Topology(name="topology", scale=1.0, panX=0, panY=0)
topology.save()
TopologyInventory(inventory_id=inventory_id, topology_id=topology.topology_id).save()
topology_id = topology.topology_id
message.channel_session['topology_id'] = topology_id
client = Client()
client.save()
message.channel_session['client_id'] = client.pk
Group("client-%s" % client.pk).add(message.reply_channel)
message.reply_channel.send({"text": json.dumps(["id", client.pk])})
send_tests(message.reply_channel)
def send_tests(channel):
for name, test_case_data in TestCase.objects.all().values_list('name', 'test_case_data'):
channel.send({"text": json.dumps(["TestCase", [name, json.loads(test_case_data)]])})
@channel_session
def ws_message(message):
Channel('test_persistence').send({"text": message['text'],
"topology": message.channel_session['topology_id'],
"client": message.channel_session['client_id']})
@channel_session
def ws_disconnect(message):
pass

View File

@ -0,0 +1,102 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.7 on 2018-03-06 18:40
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('network_ui', '0005_auto_20180306_1837'),
]
operations = [
migrations.CreateModel(
name='CodeUnderTest',
fields=[
('code_under_test_id', models.AutoField(primary_key=True, serialize=False, verbose_name=b'CodeUnderTest')),
('version_x', models.IntegerField()),
('version_y', models.IntegerField()),
('version_z', models.IntegerField()),
('commits_since', models.IntegerField()),
('commit_hash', models.CharField(blank=True, max_length=40)),
],
),
migrations.CreateModel(
name='Coverage',
fields=[
('coverage_id', models.AutoField(primary_key=True, serialize=False)),
('coverage_data', models.TextField()),
],
),
migrations.CreateModel(
name='EventTrace',
fields=[
('event_trace_id', models.AutoField(primary_key=True, serialize=False)),
('trace_session_id', models.IntegerField(default=0)),
('event_data', models.TextField()),
('message_id', models.IntegerField()),
('client', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='network_ui.Client')),
],
),
migrations.CreateModel(
name='FSMTrace',
fields=[
('fsm_trace_id', models.AutoField(primary_key=True, serialize=False)),
('fsm_name', models.CharField(blank=True, max_length=200)),
('from_state', models.CharField(blank=True, max_length=200)),
('to_state', models.CharField(blank=True, max_length=200)),
('message_type', models.CharField(blank=True, max_length=200)),
('trace_session_id', models.IntegerField(default=0)),
('order', models.IntegerField(default=0)),
('client', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='network_ui.Client')),
],
),
migrations.CreateModel(
name='Result',
fields=[
('result_id', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(blank=True, max_length=20)),
],
),
migrations.CreateModel(
name='TestCase',
fields=[
('test_case_id', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(blank=True, max_length=200, verbose_name=b'TestCase')),
('test_case_data', models.TextField()),
],
),
migrations.CreateModel(
name='TestResult',
fields=[
('test_result_id', models.AutoField(primary_key=True, serialize=False)),
('time', models.DateTimeField()),
('id', models.IntegerField(default=0)),
('client', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='network_ui.Client')),
('code_under_test', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='network_ui_test.CodeUnderTest')),
('result', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='network_ui_test.Result')),
('test_case', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='network_ui_test.TestCase')),
],
),
migrations.CreateModel(
name='TopologySnapshot',
fields=[
('topology_snapshot_id', models.AutoField(primary_key=True, serialize=False)),
('topology_id', models.IntegerField()),
('trace_session_id', models.IntegerField()),
('snapshot_data', models.TextField(verbose_name=b'TopologySnapshot')),
('order', models.IntegerField()),
('client', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='network_ui.Client')),
],
),
migrations.AddField(
model_name='coverage',
name='test_result',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='network_ui_test.TestResult'),
),
]

View File

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.7 on 2018-03-06 22:43
from __future__ import unicode_literals
from django.db import migrations
results = ['passed',
'failed',
'errored',
'skipped',
'aborted',
'not run',
'blocked']
def populate_result_types(apps, schema_editor):
Result = apps.get_model('network_ui_test', 'Result')
for result in results:
Result.objects.get_or_create(name=result)
class Migration(migrations.Migration):
dependencies = [
('network_ui_test', '0001_initial'),
]
operations = [
migrations.RunPython(
code=populate_result_types,
),
]

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.7 on 2018-03-06 23:06
from __future__ import unicode_literals
from django.db import migrations
import json
def add_load_test_case(apps, schema_editor):
TestCase = apps.get_model('network_ui_test', 'TestCase')
TestCase.objects.get_or_create(name="Load", test_case_data=json.dumps(dict(runnable=False)))
class Migration(migrations.Migration):
dependencies = [
('network_ui_test', '0002_auto_20180306_2243'),
]
operations = [
migrations.RunPython(
code=add_load_test_case,
),
]

View File

@ -0,0 +1,73 @@
from django.db import models
class FSMTrace(models.Model):
fsm_trace_id = models.AutoField(primary_key=True,)
fsm_name = models.CharField(max_length=200, blank=True)
from_state = models.CharField(max_length=200, blank=True)
to_state = models.CharField(max_length=200, blank=True)
message_type = models.CharField(max_length=200, blank=True)
client = models.ForeignKey('network_ui.Client',)
trace_session_id = models.IntegerField(default=0,)
order = models.IntegerField(default=0,)
class EventTrace(models.Model):
event_trace_id = models.AutoField(primary_key=True,)
client = models.ForeignKey('network_ui.Client',)
trace_session_id = models.IntegerField(default=0,)
event_data = models.TextField()
message_id = models.IntegerField()
class Coverage(models.Model):
coverage_id = models.AutoField(primary_key=True,)
coverage_data = models.TextField()
test_result = models.ForeignKey('TestResult',)
class TopologySnapshot(models.Model):
topology_snapshot_id = models.AutoField(primary_key=True,)
client = models.ForeignKey('network_ui.Client',)
topology_id = models.IntegerField()
trace_session_id = models.IntegerField()
snapshot_data = models.TextField('TopologySnapshot',)
order = models.IntegerField()
class TestCase(models.Model):
test_case_id = models.AutoField(primary_key=True,)
name = models.CharField('TestCase', max_length=200, blank=True)
test_case_data = models.TextField()
class Result(models.Model):
result_id = models.AutoField(primary_key=True,)
name = models.CharField(max_length=20, blank=True)
class CodeUnderTest(models.Model):
code_under_test_id = models.AutoField('CodeUnderTest', primary_key=True,)
version_x = models.IntegerField()
version_y = models.IntegerField()
version_z = models.IntegerField()
commits_since = models.IntegerField()
commit_hash = models.CharField(max_length=40, blank=True)
class TestResult(models.Model):
test_result_id = models.AutoField(primary_key=True,)
test_case = models.ForeignKey('TestCase',)
result = models.ForeignKey('Result',)
code_under_test = models.ForeignKey('CodeUnderTest',)
time = models.DateTimeField()
id = models.IntegerField(default=0,)
client = models.ForeignKey('network_ui.Client',)

View File

@ -0,0 +1,12 @@
# Copyright (c) 2017 Red Hat, Inc
from channels.routing import route
from awx.network_ui_test.consumers import ws_connect, ws_message, ws_disconnect, test_persistence
channel_routing = [
route("websocket.connect", ws_connect, path=r"^/network_ui/test"),
route("websocket.receive", ws_message, path=r"^/network_ui/test"),
route("websocket.disconnect", ws_disconnect, path=r"^/network_ui/test"),
route("test_persistence", test_persistence.handle),
]

View File

@ -1,4 +1,4 @@
<form action="/network_ui/upload_test" method="post" enctype="multipart/form-data">
<form action="/network_ui_test/upload_test" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{form}}
<button type="submit">Upload Test</button>

View File

@ -0,0 +1,13 @@
SERVER = "https://meganuke:8043"
PORT = "9000"
.PHONY: clean coverage
clean:
git clean -fdX .
git clean -fd .
coverage:
./coverage_report.py ${SERVER}
python -m SimpleHTTPServer ${PORT}

View File

@ -18,7 +18,7 @@ import subprocess
logger = logging.getLogger('coverage_report')
TESTS_API = '/network_ui/tests'
TESTS_API = '/network_ui_test/tests'

View File

@ -0,0 +1,2 @@
requests
docopt

View File

@ -0,0 +1,14 @@
# Copyright (c) 2017 Red Hat, Inc
from django.conf.urls import url
from awx.network_ui_test import views
app_name = 'network_ui_test'
urlpatterns = [
url(r'^tests$', views.tests, name='tests'),
url(r'^upload_test$', views.upload_test, name='upload_test'),
url(r'^download_coverage/(?P<pk>[0-9]+)$', views.download_coverage, name='download_coverage'),
url(r'^download_trace$', views.download_trace, name='download_trace'),
url(r'^download_recording$', views.download_recording, name='download_recording'),
]

View File

@ -0,0 +1,112 @@
# Copyright (c) 2017 Red Hat, Inc
from django.shortcuts import render
from django import forms
from django.http import JsonResponse, HttpResponse, HttpResponseRedirect
from django.core.exceptions import ObjectDoesNotExist
import yaml
import json
# Create your views here.
from .models import FSMTrace, EventTrace, TopologySnapshot
from .models import TestCase, TestResult, Coverage
class FSMTraceForm(forms.Form):
topology_id = forms.IntegerField()
trace_id = forms.IntegerField()
client_id = forms.IntegerField()
def download_trace(request):
form = FSMTraceForm(request.GET)
if form.is_valid():
topology_id = form.cleaned_data['topology_id']
trace_id = form.cleaned_data['trace_id']
client_id = form.cleaned_data['client_id']
data = list(FSMTrace.objects.filter(trace_session_id=trace_id,
client_id=client_id).order_by('order').values())
response = HttpResponse(yaml.safe_dump(data, default_flow_style=False),
content_type="application/force-download")
response['Content-Disposition'] = 'attachment; filename="trace_{0}_{1}_{2}.yml"'.format(topology_id, client_id, trace_id)
return response
else:
return HttpResponse(form.errors)
class RecordingForm(forms.Form):
topology_id = forms.IntegerField()
trace_id = forms.IntegerField()
client_id = forms.IntegerField()
def download_recording(request):
form = RecordingForm(request.GET)
if form.is_valid():
topology_id = form.cleaned_data['topology_id']
trace_id = form.cleaned_data['trace_id']
client_id = form.cleaned_data['client_id']
data = dict()
data['event_trace'] = [json.loads(x) for x in EventTrace
.objects.filter(trace_session_id=trace_id, client_id=client_id)
.order_by('message_id')
.values_list('event_data', flat=True)]
data['fsm_trace'] = list(FSMTrace
.objects
.filter(trace_session_id=trace_id, client_id=client_id)
.order_by('order')
.values())
data['snapshots'] = [json.loads(x) for x in TopologySnapshot
.objects.filter(trace_session_id=trace_id, client_id=client_id)
.order_by('order')
.values_list('snapshot_data', flat=True)]
response = HttpResponse(json.dumps(data, sort_keys=True, indent=4),
content_type="application/force-download")
response['Content-Disposition'] = 'attachment; filename="trace_{0}_{1}_{2}.yml"'.format(topology_id, client_id, trace_id)
return response
else:
return HttpResponse(form.errors)
def tests(request):
tests = list(TestCase.objects.all().values('test_case_id', 'name'))
for x in tests:
x['coverage'] = "/network_ui_test/download_coverage/{0}".format(x['test_case_id'])
return JsonResponse(dict(tests=tests))
def create_test(name, data):
try:
test_case = TestCase.objects.get(name=name)
test_case.test_case_data=json.dumps(data)
test_case.save()
except ObjectDoesNotExist:
TestCase(name=name, test_case_data=json.dumps(data)).save()
class UploadTestForm(forms.Form):
name = forms.CharField()
file = forms.FileField()
def upload_test(request):
if request.method == 'POST':
form = UploadTestForm(request.POST, request.FILES)
if form.is_valid():
name = form.cleaned_data['name']
data = json.loads(request.FILES['file'].read())
create_test(name, data)
return HttpResponseRedirect('/network_ui_test/tests')
else:
form = UploadTestForm()
return render(request, 'network_ui_test/upload_test.html', {'form': form})
def download_coverage(request, pk):
latest_tr = TestResult.objects.filter(test_case_id=pk).order_by('-time')[0]
coverage = Coverage.objects.get(test_result_id=latest_tr.pk)
response = HttpResponse(coverage.coverage_data,
content_type="application/json")
return response

View File

@ -280,6 +280,7 @@ INSTALLED_APPS = (
'awx.sso',
'solo',
'awx.network_ui',
'awx.network_ui_test',
)
INTERNAL_IPS = ('127.0.0.1',)

View File

@ -196,12 +196,14 @@ function StopRecording(sender, trace_id) {
}
exports.StopRecording = StopRecording;
function ViewPort(sender, scale, panX, panY, trace_id) {
function ViewPort(sender, scale, panX, panY, graph_width, graph_height, trace_id) {
this.msg_type = "ViewPort";
this.sender = sender;
this.scale = scale;
this.panX = panX;
this.panY = panY;
this.graph_width = graph_width;
this.graph_height = graph_height;
this.trace_id = trace_id;
}
exports.ViewPort = ViewPort;

View File

@ -378,7 +378,6 @@ _Move.prototype.onMouseMove = function (controller) {
var i = 0;
var j = 0;
var previous_x, previous_y;
var membership_old_new;
for (i = 0; i < devices.length; i++) {
previous_x = devices[i].x;
previous_y = devices[i].y;

View File

@ -1,7 +1,6 @@
/* Copyright (c) 2017 Red Hat, Inc. */
var angular = require('angular');
var fsm = require('./fsm.js');
var null_fsm = require('./null.fsm.js');
var mode_fsm = require('./mode.fsm.js');
var hotkeys = require('./hotkeys.fsm.js');
var toolbox_fsm = require('./toolbox.fsm.js');
@ -57,6 +56,9 @@ var NetworkUIController = function($scope,
$scope.control_socket = new ReconnectingWebSocket(protocol + "://" + window.location.host + "/network_ui/topology?inventory_id=" + $scope.inventory_id,
null,
{debug: false, reconnectInterval: 300});
$scope.test_socket = new ReconnectingWebSocket(protocol + "://" + window.location.host + "/network_ui/test?inventory_id=" + $scope.inventory_id,
null,
{debug: false, reconnectInterval: 300});
} else {
$scope.control_socket = {
on_message: util.noop
@ -65,6 +67,7 @@ var NetworkUIController = function($scope,
$scope.my_location = $location.protocol() + "://" + $location.host() + ':' + $location.port();
$scope.history = [];
$scope.client_id = 0;
$scope.test_client_id = 0;
$scope.onMouseDownResult = "";
$scope.onMouseUpResult = "";
$scope.onMouseEnterResult = "";
@ -91,7 +94,6 @@ var NetworkUIController = function($scope,
$scope.selected_items = [];
$scope.new_link = null;
$scope.new_stream = null;
$scope.new_group_type = null;
$scope.last_key = "";
$scope.last_key_code = null;
$scope.last_event = null;
@ -108,9 +110,7 @@ var NetworkUIController = function($scope,
$scope.MIN_ZOOM = 0.1;
$scope.device_id_seq = util.natural_numbers(0);
$scope.link_id_seq = util.natural_numbers(0);
$scope.group_id_seq = util.natural_numbers(0);
$scope.message_id_seq = util.natural_numbers(0);
$scope.stream_id_seq = util.natural_numbers(0);
$scope.test_result_id_seq = util.natural_numbers(0);
$scope.animation_id_seq = util.natural_numbers(0);
$scope.overall_toolbox_collapsed = false;
@ -180,13 +180,13 @@ var NetworkUIController = function($scope,
if (!$scope.recording) {
return;
}
message.sender = $scope.client_id;
message.sender = $scope.test_client_id;
message.trace_id = $scope.trace_id;
message.message_id = $scope.message_id_seq();
var data = messages.serialize(message);
if (!$scope.disconnected) {
try {
$scope.control_socket.send(data);
$scope.test_socket.send(data);
}
catch(err) {
$scope.initial_messages.push(message);
@ -196,15 +196,15 @@ var NetworkUIController = function($scope,
$scope.onKeyDown = function ($event) {
if ($scope.recording) {
$scope.send_control_message(new messages.KeyEvent($scope.client_id,
$event.key,
$event.keyCode,
$event.type,
$event.altKey,
$event.shiftKey,
$event.ctrlKey,
$event.metaKey,
$scope.trace_id));
$scope.send_test_message(new messages.KeyEvent($scope.test_client_id,
$event.key,
$event.keyCode,
$event.type,
$event.altKey,
$event.shiftKey,
$event.ctrlKey,
$event.metaKey,
$scope.trace_id));
}
$scope.last_event = $event;
$scope.last_key = $event.key;
@ -215,7 +215,6 @@ var NetworkUIController = function($scope,
};
//Define the FSMs
$scope.null_controller = new fsm.FSMController($scope, "null_fsm", null_fsm.Start, $scope);
$scope.hotkeys_controller = new fsm.FSMController($scope, "hotkeys_fsm", hotkeys.Start, $scope);
$scope.keybindings_controller = new fsm.FSMController($scope, "keybindings_fsm", keybindings.Start, $scope);
$scope.view_controller = new fsm.FSMController($scope, "view_fsm", view.Start, $scope);
@ -325,9 +324,13 @@ var NetworkUIController = function($scope,
$scope.first_channel = new fsm.Channel(null,
$scope.test_controller,
$scope.mode_controller,
$scope);
$scope.test_channel = new fsm.Channel(null,
$scope.test_controller,
$scope);
var getMouseEventResult = function (mouseEvent) {
return "(" + mouseEvent.x + ", " + mouseEvent.y + ")";
};
@ -508,7 +511,7 @@ var NetworkUIController = function($scope,
$scope.onMouseDown = function ($event) {
$scope.normalize_mouse_event($event);
if ($scope.recording) {
$scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.y, $event.type, $scope.trace_id));
$scope.send_test_message(new messages.MouseEvent($scope.test_client_id, $event.x, $event.y, $event.type, $scope.trace_id));
}
$scope.last_event = $event;
$scope.first_channel.send('MouseDown', $event);
@ -519,7 +522,7 @@ var NetworkUIController = function($scope,
$scope.onMouseUp = function ($event) {
$scope.normalize_mouse_event($event);
if ($scope.recording) {
$scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.y, $event.type, $scope.trace_id));
$scope.send_test_message(new messages.MouseEvent($scope.test_client_id, $event.x, $event.y, $event.type, $scope.trace_id));
}
$scope.last_event = $event;
$scope.first_channel.send('MouseUp', $event);
@ -530,7 +533,7 @@ var NetworkUIController = function($scope,
$scope.onMouseLeave = function ($event) {
$scope.normalize_mouse_event($event);
if ($scope.recording) {
$scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.y, $event.type, $scope.trace_id));
$scope.send_test_message(new messages.MouseEvent($scope.test_client_id, $event.x, $event.y, $event.type, $scope.trace_id));
}
$scope.onMouseLeaveResult = getMouseEventResult($event);
$scope.cursor.hidden = true;
@ -540,7 +543,7 @@ var NetworkUIController = function($scope,
$scope.onMouseMove = function ($event) {
$scope.normalize_mouse_event($event);
if ($scope.recording) {
$scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.y, $event.type, $scope.trace_id));
$scope.send_test_message(new messages.MouseEvent($scope.test_client_id, $event.x, $event.y, $event.type, $scope.trace_id));
}
//var coords = getCrossBrowserElementCoords($event);
$scope.cursor.hidden = false;
@ -557,7 +560,7 @@ var NetworkUIController = function($scope,
$scope.onMouseOver = function ($event) {
$scope.normalize_mouse_event($event);
if ($scope.recording) {
$scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.y, $event.type, $scope.trace_id));
$scope.send_test_message(new messages.MouseEvent($scope.test_client_id, $event.x, $event.y, $event.type, $scope.trace_id));
}
$scope.onMouseOverResult = getMouseEventResult($event);
$scope.cursor.hidden = false;
@ -572,7 +575,7 @@ var NetworkUIController = function($scope,
var deltaX = $event.deltaX;
var deltaY = $event.deltaY;
if ($scope.recording) {
$scope.send_control_message(new messages.MouseWheelEvent($scope.client_id, delta, deltaX, deltaY, $event.type, $event.originalEvent.metaKey, $scope.trace_id));
$scope.send_test_message(new messages.MouseWheelEvent($scope.test_client_id, delta, deltaX, deltaY, $event.type, $event.originalEvent.metaKey, $scope.trace_id));
}
$scope.last_event = $event;
$scope.first_channel.send('MouseWheel', [$event, delta, deltaX, deltaY]);
@ -679,12 +682,12 @@ var NetworkUIController = function($scope,
links[i].remote_selected = false;
$scope.links.splice(index, 1);
$scope.send_control_message(new messages.LinkDestroy($scope.client_id,
links[i].id,
links[i].from_device.id,
links[i].to_device.id,
links[i].from_interface.id,
links[i].to_interface.id,
links[i].name));
links[i].id,
links[i].from_device.id,
links[i].to_device.id,
links[i].from_interface.id,
links[i].to_interface.id,
links[i].name));
}
}
for (i = 0; i < devices.length; i++) {
@ -693,12 +696,12 @@ var NetworkUIController = function($scope,
$scope.devices.splice(index, 1);
$scope.$emit('removeSearchOption', devices[i]);
$scope.send_control_message(new messages.DeviceDestroy($scope.client_id,
devices[i].id,
devices[i].x,
devices[i].y,
devices[i].name,
devices[i].type,
devices[i].host_id));
devices[i].id,
devices[i].x,
devices[i].y,
devices[i].name,
devices[i].type,
devices[i].host_id));
}
for (j = 0; j < all_links.length; j++) {
if (all_links[j].to_device === devices[i] ||
@ -823,38 +826,30 @@ var NetworkUIController = function($scope,
$scope.jump_to_animation(v_center.x, v_center.y, scale, false);
});
$scope.onDeployButton = function () {
$scope.send_control_message(new messages.Deploy($scope.client_id));
};
$scope.onDestroyButton = function () {
$scope.send_control_message(new messages.Destroy($scope.client_id));
};
$scope.onRecordButton = function () {
$scope.recording = ! $scope.recording;
if ($scope.recording) {
$scope.trace_id = $scope.trace_id_seq();
$scope.send_control_message(new messages.MultipleMessage($scope.client_id,
[new messages.StartRecording($scope.client_id, $scope.trace_id),
new messages.ViewPort($scope.client_id,
$scope.current_scale,
$scope.panX,
$scope.panY,
$scope.trace_id),
new messages.Snapshot($scope.client_id,
$scope.devices,
$scope.links,
0,
$scope.trace_id)]));
$scope.send_test_message(new messages.MultipleMessage($scope.test_client_id,
[new messages.StartRecording($scope.test_client_id, $scope.trace_id),
new messages.ViewPort($scope.test_client_id,
$scope.current_scale,
$scope.panX,
$scope.panY,
$scope.trace_id),
new messages.Snapshot($scope.test_client_id,
$scope.devices,
$scope.links,
0,
$scope.trace_id)]));
} else {
$scope.send_control_message(new messages.MultipleMessage($scope.client_id,
[new messages.Snapshot($scope.client_id,
$scope.devices,
$scope.links,
1,
$scope.trace_id),
new messages.StopRecording($scope.client_id, $scope.trace_id)]));
$scope.send_test_message(new messages.MultipleMessage($scope.test_client_id,
[new messages.Snapshot($scope.test_client_id,
$scope.devices,
$scope.links,
1,
$scope.trace_id),
new messages.StopRecording($scope.test_client_id, $scope.trace_id)]));
}
};
@ -909,7 +904,7 @@ var NetworkUIController = function($scope,
$scope.test_results = [];
$scope.current_tests = $scope.tests.slice();
$scope.first_channel.send("EnableTest", new messages.EnableTest());
$scope.test_channel.send("EnableTest", new messages.EnableTest());
};
$scope.all_buttons = [];
@ -961,35 +956,6 @@ var NetworkUIController = function($scope,
$scope.devices.push(device);
};
$scope.onGroupCreate = function(data) {
$scope.create_group(data);
};
$scope.create_group = function(data) {
var group = new models.Group(data.id,
data.name,
data.type,
data.x1,
data.y1,
data.x2,
data.y2,
false);
$scope.group_id_seq = util.natural_numbers(data.id);
$scope.groups.push(group);
};
$scope.breadcrumbGroups = function(){
let breadcrumbGroups = [];
for(var i = 0; i < $scope.groups.length; i++){
let group = $scope.groups[i];
if(group.is_in_breadcrumb($scope.view_port)){
group.distance = util.distance(group.x1, group.y1, group.x2, group.y2);
breadcrumbGroups.push(group);
}
}
return breadcrumbGroups;
};
$scope.forDevice = function(device_id, data, fn) {
var i = 0;
for (i = 0; i < $scope.devices.length; i++) {
@ -1025,16 +991,6 @@ var NetworkUIController = function($scope,
}
};
$scope.forGroup = function(group_id, data, fn) {
var i = 0;
for (i = 0; i < $scope.groups.length; i++) {
if ($scope.groups[i].id === group_id) {
fn($scope.groups[i], data);
break;
}
}
};
$scope.onDeviceLabelEdit = function(data) {
$scope.edit_device_label(data);
};
@ -1201,88 +1157,6 @@ var NetworkUIController = function($scope,
}
};
$scope.onGroupLabelEdit = function(data) {
$scope.edit_group_label(data);
};
$scope.edit_group_label = function(data) {
$scope.forGroup(data.id, data, function(group, data) {
group.name = data.name;
});
};
$scope.redo = function(type_data) {
var type = type_data[0];
var data = type_data[1];
if (type === "DeviceMove") {
$scope.move_device(data);
}
if (type === "DeviceCreate") {
$scope.create_device(data);
}
if (type === "DeviceDestroy") {
$scope.destroy_device(data);
}
if (type === "DeviceLabelEdit") {
$scope.edit_device_label(data);
}
if (type === "LinkCreate") {
$scope.create_link(data);
}
if (type === "LinkDestroy") {
$scope.destroy_link(data);
}
};
$scope.undo = function(type_data) {
var type = type_data[0];
var data = type_data[1];
var inverted_data;
if (type === "DeviceMove") {
inverted_data = angular.copy(data);
inverted_data.x = data.previous_x;
inverted_data.y = data.previous_y;
$scope.move_device(inverted_data);
}
if (type === "DeviceCreate") {
$scope.destroy_device(data);
}
if (type === "DeviceDestroy") {
inverted_data = new messages.DeviceCreate(data.sender,
data.id,
data.previous_x,
data.previous_y,
data.previous_name,
data.previous_type,
data.previous_host_id);
$scope.create_device(inverted_data);
}
if (type === "DeviceLabelEdit") {
inverted_data = angular.copy(data);
inverted_data.name = data.previous_name;
$scope.edit_device_label(inverted_data);
}
if (type === "LinkCreate") {
$scope.destroy_link(data);
}
if (type === "LinkDestroy") {
$scope.create_link(data);
}
};
$scope.onClientId = function(data) {
$scope.client_id = data;
$scope.send_initial_messages();
@ -1295,7 +1169,6 @@ var NetworkUIController = function($scope,
$scope.current_scale = data.scale;
$scope.$emit('awxNet-UpdateZoomWidget', $scope.current_scale, true);
$scope.link_id_seq = util.natural_numbers(data.link_id_seq);
$scope.group_id_seq = util.natural_numbers(data.group_id_seq);
$scope.device_id_seq = util.natural_numbers(data.device_id_seq);
};
@ -1326,99 +1199,11 @@ var NetworkUIController = function($scope,
}
};
$scope.onToolboxItem = function (data) {
if (data.toolbox_name === "Site") {
var site = util.parse_variables(data.data);
var i = 0;
var j = 0;
var site_copy = new models.Group(site.id,
site.name,
site.type,
site.x1,
site.y1,
site.x2,
site.y2,
false);
var device, device_copy;
var process, process_copy;
var intf, intf_copy;
var device_map = {};
for (i = 0; i < site.devices.length; i++) {
device = site.devices[i];
device_copy = new models.Device(device.id,
device.name,
device.x,
device.y,
device.type);
device_map[device.id] = device_copy;
device_copy.interface_map = {};
site_copy.devices.push(device_copy);
for(j=0; j < device.interfaces.length; j++) {
intf = device.interfaces[j];
intf_copy = new models.Interface(intf.id, intf.name);
intf_copy.device = device_copy;
device_copy.interfaces.push(intf_copy);
device_copy.interface_map[intf.id] = intf_copy;
}
for(j=0; j < device.processes.length; j++) {
process = device.processes[j];
process_copy = new models.Process(process.id,
process.name,
process.type,
process.x,
process.y);
process_copy.device = device;
device_copy.processes.push(process_copy);
}
}
var group, group_copy;
for (i = 0; i < site.groups.length; i++) {
group = site.groups[i];
group_copy = new models.Group(group.id,
group.name,
group.type,
group.x1,
group.y1,
group.x2,
group.y2,
false);
site_copy.groups.push(group_copy);
}
var link, link_copy;
for (i = 0; i < site.links.length; i++) {
link = site.links[i];
link_copy = new models.Link(link.id,
device_map[link.from_device_id],
device_map[link.to_device_id],
device_map[link.from_device_id].interface_map[link.from_interface_id],
device_map[link.to_device_id].interface_map[link.to_interface_id]);
link_copy.name = link.name;
device_map[link.from_device_id].interface_map[link.from_interface_id].link = link_copy;
device_map[link.to_device_id].interface_map[link.to_interface_id].link = link_copy;
site_copy.links.push(link_copy);
}
var stream, stream_copy;
for(i = 0; i < site.streams.length;i++) {
stream = site.streams[i];
stream_copy = new models.Stream(stream.id,
device_map[stream.from_device],
device_map[stream.to_device],
stream.label);
site_copy.streams.push(stream_copy);
}
$scope.site_toolbox.items.push(site_copy);
}
};
$scope.onSnapshot = function (data) {
//Erase the existing state
$scope.devices = [];
$scope.links = [];
$scope.groups = [];
$scope.streams = [];
var device_map = {};
var device_interface_map = {};
@ -1430,17 +1215,11 @@ var NetworkUIController = function($scope,
var new_intf = null;
var max_device_id = null;
var max_link_id = null;
var max_group_id = null;
var max_stream_id = null;
var min_x = null;
var min_y = null;
var max_x = null;
var max_y = null;
var new_link = null;
var new_group = null;
var process = null;
var new_process = null;
var new_stream = null;
//Build the devices
for (i = 0; i < data.devices.length; i++) {
@ -1478,16 +1257,6 @@ var NetworkUIController = function($scope,
$scope.devices.push(new_device);
device_map[device.id] = new_device;
device_interface_map[device.id] = {};
for (j = 0; j < device.processes.length; j++) {
process = device.processes[j];
new_process = (new models.Process(process.id,
process.name,
process.process_type,
0,
0));
new_process.device = new_device;
new_device.processes.push(new_process);
}
for (j = 0; j < device.interfaces.length; j++) {
intf = device.interfaces[j];
new_intf = (new models.Interface(intf.id,
@ -1516,50 +1285,6 @@ var NetworkUIController = function($scope,
device_interface_map[link.to_device_id][link.to_interface_id].link = new_link;
}
//Build the streams
var stream = null;
for (i = 0; i < data.streams.length; i++) {
stream = data.streams[i];
if (max_stream_id === null || stream.id > max_stream_id) {
max_stream_id = stream.id;
}
new_stream = new models.Stream(stream.id,
device_map[stream.from_id],
device_map[stream.to_id],
stream.label);
$scope.streams.push(new_stream);
}
//Build the groups
var group = null;
for (i = 0; i < data.groups.length; i++) {
group = data.groups[i];
if (max_group_id === null || group.id > max_group_id) {
max_group_id = group.id;
}
new_group = new models.Group(group.id,
group.name,
group.group_type,
group.x1,
group.y1,
group.x2,
group.y2,
false);
new_group.group_id = group.inventory_group_id;
if (group.members !== undefined) {
for (j=0; j < group.members.length; j++) {
new_group.devices.push(device_map[group.members[j]]);
}
}
$scope.groups.push(new_group);
}
//Update group membership
for (i = 0; i < $scope.groups.length; i++) {
$scope.groups[i].update_membership($scope.devices, $scope.groups);
}
var diff_x;
var diff_y;
@ -1592,18 +1317,9 @@ var NetworkUIController = function($scope,
if (max_link_id !== null) {
$scope.link_id_seq = util.natural_numbers(max_link_id);
}
//Update the stream_id_seq to be greater than all stream ids to prevent duplicate ids.
if (max_stream_id !== null) {
$scope.stream_id_seq = util.natural_numbers(max_stream_id);
}
//Update the group_id_seq to be greater than all group ids to prevent duplicate ids.
if (max_group_id !== null) {
$scope.group_id_seq = util.natural_numbers(max_group_id);
}
$scope.updateInterfaceDots();
$scope.$emit('instatiateSelect', $scope.devices);
$scope.$emit('awxNet-breadcrumbGroups', $scope.breadcrumbGroups());
$scope.update_device_variables();
};
@ -1656,6 +1372,15 @@ var NetworkUIController = function($scope,
//ignore
};
$scope.test_socket.onmessage = function(message) {
$scope.test_channel.send('Message', message);
$scope.$apply();
};
$scope.test_socket.onopen = function() {
//ignore
};
$scope.send_initial_messages = function() {
var i = 0;
var messages_to_send = $scope.initial_messages;
@ -1664,9 +1389,9 @@ var NetworkUIController = function($scope,
$scope.initial_messages = [];
for(i = 0; i < messages_to_send.length; i++) {
message = messages_to_send[i];
message.sender = $scope.client_id;
message.sender = $scope.test_client_id;
data = messages.serialize(message);
$scope.control_socket.send(data);
$scope.test_socket.send(data);
}
};
@ -1674,6 +1399,25 @@ var NetworkUIController = function($scope,
if ($scope.control_socket.readyState === WebSocket.OPEN) {
$scope.control_socket.onopen();
}
// Call onopen directly if $scope.test_socket is already open
if ($scope.test_socket.readyState === WebSocket.OPEN) {
$scope.test_socket.onopen();
}
$scope.send_test_message = function (message) {
var i = 0;
message.sender = $scope.test_client_id;
message.message_id = $scope.message_id_seq();
if (message.constructor.name === "MultipleMessage") {
for (i=0; i < message.messages.length; i++) {
message.messages[i].message_id = $scope.message_id_seq();
}
}
var data = messages.serialize(message);
if (!$scope.disconnected) {
$scope.test_socket.send(data);
}
};
$scope.send_control_message = function (message) {
var i = 0;
@ -1811,13 +1555,10 @@ var NetworkUIController = function($scope,
$scope.hide_buttons = false;
$scope.hide_links = false;
$scope.hide_interfaces = false;
$scope.hide_groups = false;
};
$scope.reset_fsm_state = function () {
$scope.null_controller.state = null_fsm.Start;
$scope.null_controller.state.start($scope.null_controller);
$scope.hotkeys_controller.state = hotkeys.Start;
$scope.hotkeys_controller.state.start($scope.hotkeys_controller);
$scope.keybindings_controller.state = keybindings.Start;

View File

@ -1,36 +0,0 @@
/* Copyright (c) 2017 Red Hat, Inc. */
var inherits = require('inherits');
var fsm = require('./fsm.js');
function _State () {
}
inherits(_State, fsm._State);
function _Start () {
this.name = 'Start';
}
inherits(_Start, _State);
var Start = new _Start();
exports.Start = Start;
function _Ready () {
this.name = 'Ready';
}
inherits(_Ready, _State);
var Ready = new _Ready();
exports.Ready = Ready;
_Start.prototype.start = function (controller) {
controller.changeState(Ready);
};
_Start.prototype.start.transitions = ['Ready'];

View File

@ -51,7 +51,31 @@ var Reporting = new _Reporting();
exports.Reporting = Reporting;
_State.prototype.onMessage = function(controller, msg_type, message) {
var type_data = JSON.parse(message.data);
var type = type_data[0];
var data = type_data[1];
controller.handle_message(type, data);
};
_State.prototype.onid = function(controller, msg_type, message) {
controller.scope.test_client_id = message;
};
_State.prototype.onTestCase = function(controller, msg_type, message) {
if ('runnable' in message[1]) {
if (!message[1].runnable) {
return;
}
}
controller.scope.tests.push(new models.Test(message[0],
message[1].event_trace,
[],
message[1].snapshots[0],
message[1].snapshots[1]));
};
_Disabled.prototype.onEnableTest = function (controller) {
@ -93,15 +117,15 @@ _Reporting.prototype.start = function (controller) {
controller.scope.version);
controller.scope.test_results.push(test_result);
console.log(["Reporting test", test_result.name, test_result.id]);
controller.scope.send_control_message(new messages.TestResult(controller.scope.client_id,
test_result.id,
test_result.name,
test_result.result,
test_result.date,
test_result.code_under_test));
controller.scope.send_test_message(new messages.TestResult(controller.scope.client_id,
test_result.id,
test_result.name,
test_result.result,
test_result.date,
test_result.code_under_test));
if (typeof(window.__coverage__) !== "undefined" && window.__coverage__ !== null) {
console.log(["Reporting coverage", test_result.name, test_result.id]);
controller.scope.send_control_message(new messages.Coverage(controller.scope.client_id, window.__coverage__, test_result.id));
controller.scope.send_test_message(new messages.Coverage(controller.scope.client_id, window.__coverage__, test_result.id));
}
controller.changeState(Loading);
};
@ -144,15 +168,15 @@ _Ready.prototype.start = function (controller) {
var load_id = controller.scope.test_result_id_seq();
console.log(["Reporting Load", load_id]);
controller.scope.send_control_message(new messages.TestResult(controller.scope.client_id,
load_id,
"Load",
"passed",
new Date().toISOString(),
controller.scope.version));
controller.scope.send_test_message(new messages.TestResult(controller.scope.client_id,
load_id,
"Load",
"passed",
new Date().toISOString(),
controller.scope.version));
if (typeof(window.__coverage__) !== "undefined" && window.__coverage__ !== null) {
console.log(["Reporting Load Coverage", load_id]);
controller.scope.send_control_message(new messages.Coverage(controller.scope.client_id, window.__coverage__, load_id));
controller.scope.send_test_message(new messages.Coverage(controller.scope.client_id, window.__coverage__, load_id));
}
controller.changeState(Loading);

View File

@ -2,7 +2,6 @@
var inherits = require('inherits');
var fsm = require('./fsm.js');
var util = require('./util.js');
var models = require('./models.js');
function _State () {
}
@ -176,6 +175,13 @@ _Present.prototype.onViewPort = function(controller, msg_type, message) {
controller.scope.current_scale = message.scale;
controller.scope.panX = message.panX;
controller.scope.panY = message.panY;
if (message.graph_width !== undefined) {
controller.scope.graph.width = message.graph_width;
}
if (message.graph_height !== undefined) {
controller.scope.graph.height = message.graph_height;
}
controller.scope.update_toolbox_heights();
controller.scope.updateScaledXY();
controller.scope.updatePanAndScale();
};
@ -224,19 +230,36 @@ _Present.prototype.onMouseWheelEvent = function(controller, msg_type, message) {
}
};
_Present.prototype.onTestCase = function(controller, msg_type, message) {
if ('runnable' in message[1]) {
if (!message[1].runnable) {
return;
}
}
controller.scope.tests.push(new models.Test(message[0],
message[1].event_trace,
[],
message[1].snapshots[0],
message[1].snapshots[1]));
_Present.prototype.onRecordButton = function(controller) {
controller.scope.onRecordButton();
};
_Present.prototype.onExportButton = function(controller) {
controller.scope.onExportButton();
};
_Present.prototype.onExportYamlButton = function(controller) {
controller.scope.onExportYamlButton();
};
_Present.prototype.onDownloadTraceButton = function(controller) {
controller.scope.onDownloadTraceButton();
};
_Present.prototype.onDownloadRecordingButton = function(controller) {
controller.scope.onDownloadRecordingButton();
};
_Present.prototype.onNoop = function(controller, msg_type, message) {
};
_Present.prototype.onTestCompleted = function(controller, msg_type, message) {
controller.scope.test_channel.send(msg_type, message);
}
_Present.prototype.onError = function(controller, msg_type, message) {
throw new Error("ServerError: " + message);
};

View File

@ -85,7 +85,6 @@ _Scale.prototype.onMouseWheel = function (controller, msg_type, message) {
var item = controller.scope.context_menus[0];
item.enabled = false;
controller.scope.$emit('awxNet-UpdateZoomWidget', controller.scope.current_scale, true);
controller.scope.$emit('awxNet-breadcrumbGroups', controller.scope.breadcrumbGroups());
controller.scope.updatePanAndScale();
controller.changeState(Ready);
};