mirror of
https://github.com/ansible/awx.git
synced 2026-05-09 10:27:37 -02:30
Adds network UI test framework
This adds a test framework to drive UI tests from the client instead of injecting events from the websocket. Tests consist of a pair of snapshots (before and after the test) and a list of UI events to process. Tests are run using a FSM in the client that controls the resetting of state to the snapshot, injecting the events into the UI, recording test coverage, and reporting tests to the server. * Adds design for event trace table * Adds design for a coverage tracking table * Adds models for EventTrace and Coverage * Adds trace_id to recording messages * Adds design for TopologySnapshot table * Adds order to TopologySnapshot table * Adds TopologySnapshot table * Adds Snapshot message when recordings are started and stoppped * Adds models for tracking test cases and test results * Adds designs for a test runner FSM * Updates test management commands with new schema * Adds download recording button * Adds models to track tests * Adds ui test runner * Adds id and client to TestResult design * Adds id and client to TestResult * Update message types * Stores test results and code coverage from the test runner * Adds tool to generate a test coverage report * Adds APIs for tests and code coverage * Adds per-test-case coverage reports * Breaks out coverage for loading the modules from the tests * Re-raises server-side errors * Captures errors during tests * Adds defaults for host name and host type * Disables test FSM trace storage * Adds support for sending server error message to the client * Resets the UI flags, history, and toolbox contents between tests * Adds istanbul instrumentation to network-ui
This commit is contained in:
@@ -36,6 +36,20 @@ from awx.network_ui.models import FSMTrace
|
|||||||
|
|
||||||
from awx.network_ui.models import TopologyInventory
|
from awx.network_ui.models import TopologyInventory
|
||||||
|
|
||||||
|
from awx.network_ui.models import EventTrace
|
||||||
|
|
||||||
|
from awx.network_ui.models import Coverage
|
||||||
|
|
||||||
|
from awx.network_ui.models import TopologySnapshot
|
||||||
|
|
||||||
|
from awx.network_ui.models import TestCase
|
||||||
|
|
||||||
|
from awx.network_ui.models import Result
|
||||||
|
|
||||||
|
from awx.network_ui.models import CodeUnderTest
|
||||||
|
|
||||||
|
from awx.network_ui.models import TestResult
|
||||||
|
|
||||||
|
|
||||||
class DeviceAdmin(admin.ModelAdmin):
|
class DeviceAdmin(admin.ModelAdmin):
|
||||||
fields = ('topology', 'name', 'x', 'y', 'id', 'type', 'interface_id_seq', 'process_id_seq', 'host_id',)
|
fields = ('topology', 'name', 'x', 'y', 'id', 'type', 'interface_id_seq', 'process_id_seq', 'host_id',)
|
||||||
@@ -179,3 +193,59 @@ class TopologyInventoryAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
|
|
||||||
admin.site.register(TopologyInventory, TopologyInventoryAdmin)
|
admin.site.register(TopologyInventory, TopologyInventoryAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
class EventTraceAdmin(admin.ModelAdmin):
|
||||||
|
fields = ('client', 'trace_session_id', 'event_data', 'message_id',)
|
||||||
|
raw_id_fields = ('client',)
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(EventTrace, EventTraceAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
class CoverageAdmin(admin.ModelAdmin):
|
||||||
|
fields = ('coverage_data', 'test_result',)
|
||||||
|
raw_id_fields = ('test_result',)
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(Coverage, CoverageAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
class TopologySnapshotAdmin(admin.ModelAdmin):
|
||||||
|
fields = ('client', 'topology_id', 'trace_session_id', 'snapshot_data', 'order',)
|
||||||
|
raw_id_fields = ('client', 'snapshot_data',)
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(TopologySnapshot, TopologySnapshotAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
class TestCaseAdmin(admin.ModelAdmin):
|
||||||
|
fields = ('name', 'test_case_data',)
|
||||||
|
raw_id_fields = ('name',)
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(TestCase, TestCaseAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
class ResultAdmin(admin.ModelAdmin):
|
||||||
|
fields = ('name',)
|
||||||
|
raw_id_fields = ()
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(Result, ResultAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
class CodeUnderTestAdmin(admin.ModelAdmin):
|
||||||
|
fields = ('version_x', 'version_y', 'version_z', 'commits_since', 'commit_hash',)
|
||||||
|
raw_id_fields = ('code_under_test_id',)
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(CodeUnderTest, CodeUnderTestAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
class TestResultAdmin(admin.ModelAdmin):
|
||||||
|
fields = ('test_case', 'result', 'code_under_test', 'time', 'id', 'client',)
|
||||||
|
raw_id_fields = ('test_case', 'result', 'code_under_test', 'client',)
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(TestResult, TestResultAdmin)
|
||||||
|
|||||||
@@ -8,8 +8,9 @@ from awx.network_ui.models import GroupDevice as GroupDeviceMap
|
|||||||
from awx.network_ui.models import DataSheet, DataBinding, DataType
|
from awx.network_ui.models import DataSheet, DataBinding, DataType
|
||||||
from awx.network_ui.models import Process, Stream
|
from awx.network_ui.models import Process, Stream
|
||||||
from awx.network_ui.models import Toolbox, ToolboxItem
|
from awx.network_ui.models import Toolbox, ToolboxItem
|
||||||
from awx.network_ui.models import FSMTrace
|
from awx.network_ui.models import FSMTrace, EventTrace, Coverage, TopologySnapshot
|
||||||
from awx.network_ui.models import TopologyInventory
|
from awx.network_ui.models import TopologyInventory
|
||||||
|
from awx.network_ui.models import TestCase, TestResult, CodeUnderTest, Result
|
||||||
from awx.network_ui.messages import MultipleMessage, InterfaceCreate, LinkCreate, to_dict
|
from awx.network_ui.messages import MultipleMessage, InterfaceCreate, LinkCreate, to_dict
|
||||||
import urlparse
|
import urlparse
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
@@ -18,14 +19,14 @@ from collections import defaultdict
|
|||||||
import math
|
import math
|
||||||
import random
|
import random
|
||||||
import logging
|
import logging
|
||||||
|
from django.utils.dateparse import parse_datetime
|
||||||
|
|
||||||
|
|
||||||
from awx.network_ui.utils import transform_dict
|
from awx.network_ui.utils import transform_dict
|
||||||
import dpath.util
|
import dpath.util
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
|
|
||||||
import os
|
|
||||||
import json
|
import json
|
||||||
import time
|
|
||||||
# Connected to websocket.connect
|
# Connected to websocket.connect
|
||||||
|
|
||||||
HISTORY_MESSAGE_IGNORE_TYPES = ['DeviceSelected',
|
HISTORY_MESSAGE_IGNORE_TYPES = ['DeviceSelected',
|
||||||
@@ -44,6 +45,10 @@ RACK_SPACING = 50
|
|||||||
|
|
||||||
logger = logging.getLogger("awx.network_ui.consumers")
|
logger = logging.getLogger("awx.network_ui.consumers")
|
||||||
|
|
||||||
|
class NetworkUIException(Exception):
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def circular_layout(topology_id):
|
def circular_layout(topology_id):
|
||||||
n = Device.objects.filter(topology_id=topology_id).count()
|
n = Device.objects.filter(topology_id=topology_id).count()
|
||||||
@@ -281,7 +286,7 @@ class _Persistence(object):
|
|||||||
try:
|
try:
|
||||||
message_type_id = MessageType.objects.get(name=message_type).pk
|
message_type_id = MessageType.objects.get(name=message_type).pk
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
logger.warning("Unsupported message %s", message_type)
|
logger.warning("Unsupported message %s: no message type", message_type)
|
||||||
return
|
return
|
||||||
TopologyHistory(topology_id=topology_id,
|
TopologyHistory(topology_id=topology_id,
|
||||||
client_id=client_id,
|
client_id=client_id,
|
||||||
@@ -290,9 +295,19 @@ class _Persistence(object):
|
|||||||
message_data=message['text']).save()
|
message_data=message['text']).save()
|
||||||
handler = self.get_handler(message_type)
|
handler = self.get_handler(message_type)
|
||||||
if handler is not None:
|
if handler is not None:
|
||||||
handler(message_value, topology_id, client_id)
|
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:
|
else:
|
||||||
logger.warning("Unsupported message %s", message_type)
|
logger.warning("Unsupported message %s: no handler", message_type)
|
||||||
|
|
||||||
def get_handler(self, message_type):
|
def get_handler(self, message_type):
|
||||||
return getattr(self, "on{0}".format(message_type), None)
|
return getattr(self, "on{0}".format(message_type), None)
|
||||||
@@ -454,12 +469,44 @@ class _Persistence(object):
|
|||||||
# grid_layout(topology_id)
|
# grid_layout(topology_id)
|
||||||
tier_layout(topology_id)
|
tier_layout(topology_id)
|
||||||
|
|
||||||
|
|
||||||
def onCoverageRequest(self, coverage, topology_id, client_id):
|
def onCoverageRequest(self, coverage, topology_id, client_id):
|
||||||
pass
|
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')
|
||||||
|
|
||||||
|
print (xyz)
|
||||||
|
print (commits_since)
|
||||||
|
print (commit_hash)
|
||||||
|
|
||||||
|
x, y, z = [int(i) for i in xyz.split('.')]
|
||||||
|
|
||||||
|
print (x, y, z)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
print (code_under_test)
|
||||||
|
|
||||||
|
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()
|
||||||
|
print (tr.pk)
|
||||||
|
|
||||||
|
|
||||||
def onCoverage(self, coverage, topology_id, client_id):
|
def onCoverage(self, coverage, topology_id, client_id):
|
||||||
with open(os.path.abspath("coverage/coverage{0}.json".format(int(time.time()))), "w") as f:
|
Coverage(test_result_id=TestResult.objects.get(id=coverage['result_id'], client_id=client_id).pk,
|
||||||
f.write(json.dumps(coverage['coverage']))
|
coverage_data=json.dumps(coverage['coverage'])).save()
|
||||||
|
|
||||||
def onStartRecording(self, recording, topology_id, client_id):
|
def onStartRecording(self, recording, topology_id, client_id):
|
||||||
pass
|
pass
|
||||||
@@ -469,9 +516,10 @@ class _Persistence(object):
|
|||||||
|
|
||||||
def write_event(self, event, topology_id, client_id):
|
def write_event(self, event, topology_id, client_id):
|
||||||
if event.get('save', True):
|
if event.get('save', True):
|
||||||
with open(os.path.abspath("recording/recording_{0}.log".format(topology_id)), "a") as f:
|
EventTrace(trace_session_id=event['trace_id'],
|
||||||
f.write(json.dumps(event))
|
event_data=json.dumps(event),
|
||||||
f.write("\n")
|
message_id=event['message_id'],
|
||||||
|
client_id=client_id).save()
|
||||||
|
|
||||||
onViewPort = write_event
|
onViewPort = write_event
|
||||||
onMouseEvent = write_event
|
onMouseEvent = write_event
|
||||||
@@ -538,6 +586,13 @@ class _Persistence(object):
|
|||||||
client_id=client_id,
|
client_id=client_id,
|
||||||
message_type=message_value['recv_message_type'] or "none").save()
|
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()
|
persistence = _Persistence()
|
||||||
|
|
||||||
@@ -554,7 +609,7 @@ class _UndoPersistence(object):
|
|||||||
if handler is not None:
|
if handler is not None:
|
||||||
handler(message_value, topology_id, client_id)
|
handler(message_value, topology_id, client_id)
|
||||||
else:
|
else:
|
||||||
logger.warnding("Unsupported undo message %s", message_type)
|
logger.warning("Unsupported undo message %s", message_type)
|
||||||
|
|
||||||
def onSnapshot(self, snapshot, topology_id, client_id):
|
def onSnapshot(self, snapshot, topology_id, client_id):
|
||||||
pass
|
pass
|
||||||
@@ -648,7 +703,7 @@ class _Discovery(object):
|
|||||||
if handler is not None:
|
if handler is not None:
|
||||||
handler(message_value, topology_id)
|
handler(message_value, topology_id)
|
||||||
else:
|
else:
|
||||||
logger.warning("Unsupported message %s", message_type)
|
logger.warning("Unsupported discovery message %s", message_type)
|
||||||
|
|
||||||
def get_handler(self, message_type):
|
def get_handler(self, message_type):
|
||||||
return getattr(self, "on{0}".format(message_type), None)
|
return getattr(self, "on{0}".format(message_type), None)
|
||||||
@@ -810,6 +865,7 @@ def ws_connect(message):
|
|||||||
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)
|
||||||
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(topology_id='topology_id',
|
topology_data = transform_dict(dict(topology_id='topology_id',
|
||||||
@@ -825,6 +881,7 @@ def ws_connect(message):
|
|||||||
send_snapshot(message.reply_channel, topology_id)
|
send_snapshot(message.reply_channel, topology_id)
|
||||||
send_history(message.reply_channel, topology_id)
|
send_history(message.reply_channel, topology_id)
|
||||||
send_toolboxes(message.reply_channel)
|
send_toolboxes(message.reply_channel)
|
||||||
|
send_tests(message.reply_channel)
|
||||||
|
|
||||||
|
|
||||||
def send_toolboxes(channel):
|
def send_toolboxes(channel):
|
||||||
@@ -834,6 +891,11 @@ def send_toolboxes(channel):
|
|||||||
channel.send({"text": json.dumps(["ToolboxItem", item])})
|
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):
|
def send_snapshot(channel, topology_id):
|
||||||
interfaces = defaultdict(list)
|
interfaces = defaultdict(list)
|
||||||
processes = defaultdict(list)
|
processes = defaultdict(list)
|
||||||
@@ -919,7 +981,8 @@ def ws_message(message):
|
|||||||
|
|
||||||
@channel_session
|
@channel_session
|
||||||
def ws_disconnect(message):
|
def ws_disconnect(message):
|
||||||
Group("topology-%s" % message.channel_session['topology_id']).discard(message.reply_channel)
|
if 'topology_id' in message.channel_session:
|
||||||
|
Group("topology-%s" % message.channel_session['topology_id']).discard(message.reply_channel)
|
||||||
|
|
||||||
|
|
||||||
def console_printer(message):
|
def console_printer(message):
|
||||||
|
|||||||
@@ -102,8 +102,8 @@ models:
|
|||||||
pk: true
|
pk: true
|
||||||
type: AutoField
|
type: AutoField
|
||||||
name: Client
|
name: Client
|
||||||
x: -510
|
x: -518
|
||||||
y: 141
|
y: 138
|
||||||
- fields:
|
- fields:
|
||||||
- name: topology_history_id
|
- name: topology_history_id
|
||||||
pk: true
|
pk: true
|
||||||
@@ -365,6 +365,130 @@ models:
|
|||||||
name: TopologyInventory
|
name: TopologyInventory
|
||||||
x: -226
|
x: -226
|
||||||
y: -19
|
y: -19
|
||||||
|
- fields:
|
||||||
|
- name: event_trace_id
|
||||||
|
pk: true
|
||||||
|
type: AutoField
|
||||||
|
- name: client
|
||||||
|
ref: Client
|
||||||
|
ref_field: client_id
|
||||||
|
type: ForeignKey
|
||||||
|
- default: 0
|
||||||
|
name: trace_session_id
|
||||||
|
type: IntegerField
|
||||||
|
- name: event_data
|
||||||
|
type: TextField
|
||||||
|
- name: message_id
|
||||||
|
type: IntegerField
|
||||||
|
name: EventTrace
|
||||||
|
x: -1087
|
||||||
|
y: 202
|
||||||
|
- fields:
|
||||||
|
- name: coverage_id
|
||||||
|
pk: true
|
||||||
|
type: AutoField
|
||||||
|
- name: coverage_data
|
||||||
|
type: TextField
|
||||||
|
- name: test_result
|
||||||
|
ref: TestResult
|
||||||
|
ref_field: test_result_id
|
||||||
|
type: ForeignKey
|
||||||
|
name: Coverage
|
||||||
|
x: -1068
|
||||||
|
y: -4
|
||||||
|
- fields:
|
||||||
|
- name: topology_snapshot_id
|
||||||
|
pk: true
|
||||||
|
type: AutoField
|
||||||
|
- name: client
|
||||||
|
ref: Client
|
||||||
|
ref_field: client_id
|
||||||
|
type: ForeignKey
|
||||||
|
- name: topology_id
|
||||||
|
type: IntegerField
|
||||||
|
- name: trace_session_id
|
||||||
|
type: IntegerField
|
||||||
|
- name: snapshot_data
|
||||||
|
ref: TopologySnapshot
|
||||||
|
ref_field: snapshot_data
|
||||||
|
type: TextField
|
||||||
|
- name: order
|
||||||
|
type: IntegerField
|
||||||
|
name: TopologySnapshot
|
||||||
|
x: -1123
|
||||||
|
y: -277
|
||||||
|
- fields:
|
||||||
|
- name: test_case_id
|
||||||
|
pk: true
|
||||||
|
type: AutoField
|
||||||
|
- len: 200
|
||||||
|
name: name
|
||||||
|
ref: TestCase
|
||||||
|
ref_field: name
|
||||||
|
type: CharField
|
||||||
|
- name: test_case_data
|
||||||
|
type: TextField
|
||||||
|
name: TestCase
|
||||||
|
x: -1642
|
||||||
|
y: -38
|
||||||
|
- fields:
|
||||||
|
- name: result_id
|
||||||
|
pk: true
|
||||||
|
type: AutoField
|
||||||
|
- len: 20
|
||||||
|
name: name
|
||||||
|
type: CharField
|
||||||
|
name: Result
|
||||||
|
x: -1610
|
||||||
|
y: 120
|
||||||
|
- fields:
|
||||||
|
- name: code_under_test_id
|
||||||
|
pk: true
|
||||||
|
ref: CodeUnderTest
|
||||||
|
ref_field: code_under_test_id
|
||||||
|
type: AutoField
|
||||||
|
- name: version_x
|
||||||
|
type: IntegerField
|
||||||
|
- name: version_y
|
||||||
|
type: IntegerField
|
||||||
|
- name: version_z
|
||||||
|
type: IntegerField
|
||||||
|
- name: commits_since
|
||||||
|
type: IntegerField
|
||||||
|
- len: 40
|
||||||
|
name: commit_hash
|
||||||
|
type: CharField
|
||||||
|
name: CodeUnderTest
|
||||||
|
x: -1612
|
||||||
|
y: 259
|
||||||
|
- fields:
|
||||||
|
- name: test_result_id
|
||||||
|
pk: true
|
||||||
|
type: AutoField
|
||||||
|
- name: test_case
|
||||||
|
ref: TestCase
|
||||||
|
ref_field: test_case_id
|
||||||
|
type: ForeignKey
|
||||||
|
- name: result
|
||||||
|
ref: Result
|
||||||
|
ref_field: result_id
|
||||||
|
type: ForeignKey
|
||||||
|
- name: code_under_test
|
||||||
|
ref: CodeUnderTest
|
||||||
|
ref_field: code_under_test_id
|
||||||
|
type: ForeignKey
|
||||||
|
- name: time
|
||||||
|
type: DateTimeField
|
||||||
|
- default: 0
|
||||||
|
name: id
|
||||||
|
type: IntegerField
|
||||||
|
- name: client
|
||||||
|
ref: Client
|
||||||
|
ref_field: client_id
|
||||||
|
type: ForeignKey
|
||||||
|
name: TestResult
|
||||||
|
x: -1336
|
||||||
|
y: -49
|
||||||
modules: []
|
modules: []
|
||||||
view:
|
view:
|
||||||
panX: 213.729555519212
|
panX: 213.729555519212
|
||||||
|
|||||||
@@ -3,26 +3,22 @@ from django.core.management.base import BaseCommand
|
|||||||
from awx.network_ui.models import Topology, Device, Link, Interface
|
from awx.network_ui.models import Topology, Device, Link, Interface
|
||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from .util import natural_numbers
|
||||||
|
|
||||||
def natural_numbers():
|
|
||||||
i = 1
|
|
||||||
while True:
|
|
||||||
yield i
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = '''Creates a 2 tier clos topology with n nodes in the 1st tier and m nodes
|
help = '''Adds a 2 tier clos topology with n nodes in the 1st tier and m nodes
|
||||||
in the 2nd tier and h hosts per pair of switches'''
|
in the 2nd tier and h hosts per pair of switches to the topology with id `id`'''
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument('id', type=int)
|
||||||
parser.add_argument('n', type=int)
|
parser.add_argument('n', type=int)
|
||||||
parser.add_argument('m', type=int)
|
parser.add_argument('m', type=int)
|
||||||
parser.add_argument('h', type=int)
|
parser.add_argument('h', type=int)
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
|
|
||||||
|
topology_id = options['id']
|
||||||
n = options['n']
|
n = options['n']
|
||||||
m = options['m']
|
m = options['m']
|
||||||
h = options['h']
|
h = options['h']
|
||||||
@@ -30,15 +26,15 @@ class Command(BaseCommand):
|
|||||||
print "n", n
|
print "n", n
|
||||||
print "m", m
|
print "m", m
|
||||||
|
|
||||||
topology = Topology(name="test_{0}".format(n), scale=1.0, panX=0, panY=0)
|
topology = Topology.objects.get(pk=topology_id)
|
||||||
topology.save()
|
|
||||||
|
|
||||||
devices = []
|
devices = []
|
||||||
hosts_per_leaf = []
|
hosts_per_leaf = []
|
||||||
leaves = []
|
leaves = []
|
||||||
spines = []
|
spines = []
|
||||||
|
|
||||||
id_seq = natural_numbers()
|
id_seq = natural_numbers(topology.device_id_seq)
|
||||||
|
link_id_seq = natural_numbers(topology.link_id_seq)
|
||||||
|
|
||||||
tier2 = 100
|
tier2 = 100
|
||||||
tier1 = 500
|
tier1 = 500
|
||||||
@@ -106,7 +102,8 @@ class Command(BaseCommand):
|
|||||||
link = Link(from_device=devices[leaf.id],
|
link = Link(from_device=devices[leaf.id],
|
||||||
to_device=devices[spine.id],
|
to_device=devices[spine.id],
|
||||||
from_interface=from_interface,
|
from_interface=from_interface,
|
||||||
to_interface=to_interface)
|
to_interface=to_interface,
|
||||||
|
id=next(link_id_seq))
|
||||||
links.append(link)
|
links.append(link)
|
||||||
for i, hosts in enumerate(hosts_per_leaf):
|
for i, hosts in enumerate(hosts_per_leaf):
|
||||||
leaf1 = leaves[2 * i]
|
leaf1 = leaves[2 * i]
|
||||||
@@ -125,7 +122,8 @@ class Command(BaseCommand):
|
|||||||
link = Link(from_device=devices[leaf1.id],
|
link = Link(from_device=devices[leaf1.id],
|
||||||
to_device=devices[host.id],
|
to_device=devices[host.id],
|
||||||
from_interface=from_interface,
|
from_interface=from_interface,
|
||||||
to_interface=to_interface)
|
to_interface=to_interface,
|
||||||
|
id=next(link_id_seq))
|
||||||
links.append(link)
|
links.append(link)
|
||||||
from_interface = Interface(device=devices[leaf2.id],
|
from_interface = Interface(device=devices[leaf2.id],
|
||||||
name="swp" + str(len(interfaces[leaf2.id]) + 1),
|
name="swp" + str(len(interfaces[leaf2.id]) + 1),
|
||||||
@@ -140,9 +138,14 @@ class Command(BaseCommand):
|
|||||||
link = Link(from_device=devices[leaf2.id],
|
link = Link(from_device=devices[leaf2.id],
|
||||||
to_device=devices[host.id],
|
to_device=devices[host.id],
|
||||||
from_interface=from_interface,
|
from_interface=from_interface,
|
||||||
to_interface=to_interface)
|
to_interface=to_interface,
|
||||||
|
id=next(link_id_seq))
|
||||||
links.append(link)
|
links.append(link)
|
||||||
|
|
||||||
Link.objects.bulk_create(links)
|
Link.objects.bulk_create(links)
|
||||||
|
|
||||||
|
topology.device_id_seq = next(id_seq)
|
||||||
|
topology.link_id_seq = next(link_id_seq)
|
||||||
|
topology.save()
|
||||||
|
|
||||||
print "Topology: ", topology.pk
|
print "Topology: ", topology.pk
|
||||||
|
|||||||
@@ -1,24 +1,29 @@
|
|||||||
# Copyright (c) 2017 Red Hat, Inc
|
# Copyright (c) 2017 Red Hat, Inc
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from awx.network_ui.models import Topology, Device, Link
|
from awx.network_ui.models import Topology, Device, Link, Interface
|
||||||
|
|
||||||
import math
|
import math
|
||||||
|
|
||||||
|
from collections import defaultdict
|
||||||
|
from .util import natural_numbers
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = 'Creates a fully connected topology with n nodes'
|
help = 'Adds a fully connected topology with n nodes to topology pk id'
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument('id', type=int)
|
||||||
parser.add_argument('n', type=int)
|
parser.add_argument('n', type=int)
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
|
|
||||||
|
topology_id = options['id']
|
||||||
n = options['n']
|
n = options['n']
|
||||||
|
|
||||||
topology = Topology(name="test_{0}".format(n), scale=1.0, panX=0, panY=0)
|
topology = Topology.objects.get(topology_id=topology_id)
|
||||||
topology.save()
|
|
||||||
|
|
||||||
|
link_id_seq = natural_numbers(topology.link_id_seq)
|
||||||
|
device_id_seq = natural_numbers(topology.device_id_seq)
|
||||||
devices = []
|
devices = []
|
||||||
|
|
||||||
r = 1000
|
r = 1000
|
||||||
@@ -30,25 +35,39 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
for i in xrange(n):
|
for i in xrange(n):
|
||||||
device = Device(name="R{0}".format(i),
|
device = Device(name="R{0}".format(i),
|
||||||
x=math.cos(arc_radians*i)*r,
|
x=math.cos(arc_radians * i) * r,
|
||||||
y=math.sin(arc_radians*i)*r,
|
y=math.sin(arc_radians * i) * r,
|
||||||
id=i,
|
id=next(device_id_seq),
|
||||||
type="router",
|
type="router",
|
||||||
topology_id=topology.pk)
|
topology_id=topology.pk)
|
||||||
devices.append(device)
|
devices.append(device)
|
||||||
|
|
||||||
Device.objects.bulk_create(devices)
|
Device.objects.bulk_create(devices)
|
||||||
|
|
||||||
devices = {x.id: x for x in Device.objects.filter(topology_id=topology.pk)}
|
devices = list(Device.objects.filter(topology_id=topology.pk))
|
||||||
|
|
||||||
links = []
|
links = []
|
||||||
|
interfaces = defaultdict(list)
|
||||||
|
|
||||||
for i in xrange(n):
|
for i in xrange(n):
|
||||||
for j in xrange(i):
|
for j in xrange(i):
|
||||||
if i == j:
|
if i == j:
|
||||||
continue
|
continue
|
||||||
|
from_interface = Interface(device=devices[i],
|
||||||
|
name="swp" + str(len(interfaces[i]) + 1),
|
||||||
|
id=(len(interfaces[i]) + 1))
|
||||||
|
from_interface.save()
|
||||||
|
interfaces[i].append(from_interface)
|
||||||
|
to_interface = Interface(device=devices[j],
|
||||||
|
name="swp" + str(len(interfaces[j]) + 1),
|
||||||
|
id=(len(interfaces[j]) + 1))
|
||||||
|
to_interface.save()
|
||||||
|
interfaces[j].append(to_interface)
|
||||||
link = Link(from_device=devices[i],
|
link = Link(from_device=devices[i],
|
||||||
to_device=devices[j])
|
to_device=devices[j],
|
||||||
|
from_interface=from_interface,
|
||||||
|
to_interface=to_interface,
|
||||||
|
id=next(link_id_seq))
|
||||||
links.append(link)
|
links.append(link)
|
||||||
Link.objects.bulk_create(links)
|
Link.objects.bulk_create(links)
|
||||||
|
|
||||||
|
|||||||
5
awx/network_ui/management/commands/util.py
Normal file
5
awx/network_ui/management/commands/util.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
def natural_numbers(i=1):
|
||||||
|
while True:
|
||||||
|
yield i
|
||||||
|
i += 1
|
||||||
24
awx/network_ui/migrations/0027_eventtrace.py
Normal file
24
awx/network_ui/migrations/0027_eventtrace.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('network_ui', '0026_auto_20180105_1403'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='EventTrace',
|
||||||
|
fields=[
|
||||||
|
('event_trace_id', models.AutoField(serialize=False, primary_key=True)),
|
||||||
|
('trace_session_id', models.IntegerField(default=0)),
|
||||||
|
('event_data', models.TextField()),
|
||||||
|
('message_id', models.IntegerField()),
|
||||||
|
('client', models.ForeignKey(to='network_ui.Client')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
23
awx/network_ui/migrations/0028_coverage.py
Normal file
23
awx/network_ui/migrations/0028_coverage.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('network_ui', '0027_eventtrace'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Coverage',
|
||||||
|
fields=[
|
||||||
|
('coverage_id', models.AutoField(serialize=False, primary_key=True)),
|
||||||
|
('trace_session_id', models.IntegerField()),
|
||||||
|
('coverage_data', models.TextField()),
|
||||||
|
('client', models.ForeignKey(to='network_ui.Client')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
27
awx/network_ui/migrations/0029_topologysnapshot.py
Normal file
27
awx/network_ui/migrations/0029_topologysnapshot.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.7 on 2018-01-09 17:12
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('network_ui', '0028_coverage'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
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')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
66
awx/network_ui/migrations/0030_auto_20180110_1751.py
Normal file
66
awx/network_ui/migrations/0030_auto_20180110_1751.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.7 on 2018-01-10 17:51
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('network_ui', '0029_topologysnapshot'),
|
||||||
|
]
|
||||||
|
|
||||||
|
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(max_length=40)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Result',
|
||||||
|
fields=[
|
||||||
|
('result_id', models.AutoField(primary_key=True, serialize=False)),
|
||||||
|
('name', models.CharField(max_length=20)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='TestCase',
|
||||||
|
fields=[
|
||||||
|
('test_case_id', models.AutoField(primary_key=True, serialize=False)),
|
||||||
|
('name', models.CharField(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()),
|
||||||
|
('code_under_test', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='network_ui.CodeUnderTest')),
|
||||||
|
('result', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='network_ui.Result')),
|
||||||
|
('test_case', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='network_ui.TestCase')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='coverage',
|
||||||
|
name='client',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='coverage',
|
||||||
|
name='trace_session_id',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='coverage',
|
||||||
|
name='test_result',
|
||||||
|
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='network_ui.TestResult'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
32
awx/network_ui/migrations/0031_auto_20180110_1752.py
Normal file
32
awx/network_ui/migrations/0031_auto_20180110_1752.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.7 on 2018-01-10 17:52
|
||||||
|
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', 'Result')
|
||||||
|
for result in results:
|
||||||
|
Result.objects.get_or_create(name=result)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('network_ui', '0030_auto_20180110_1751'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(
|
||||||
|
code=populate_result_types,
|
||||||
|
),
|
||||||
|
]
|
||||||
27
awx/network_ui/migrations/0032_auto_20180112_2135.py
Normal file
27
awx/network_ui/migrations/0032_auto_20180112_2135.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.7 on 2018-01-12 21:35
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('network_ui', '0031_auto_20180110_1752'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='testresult',
|
||||||
|
name='client',
|
||||||
|
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='network_ui.Client'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='testresult',
|
||||||
|
name='id',
|
||||||
|
field=models.IntegerField(default=0),
|
||||||
|
),
|
||||||
|
]
|
||||||
82
awx/network_ui/migrations/0033_auto_20180112_2202.py
Normal file
82
awx/network_ui/migrations/0033_auto_20180112_2202.py
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.7 on 2018-01-12 22:02
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
messages = yaml.load('''
|
||||||
|
messages:
|
||||||
|
- {msg_type: DeviceMove, fields: [msg_type, sender, id, x, y, previous_x, previous_y]}
|
||||||
|
- {msg_type: DeviceCreate, fields: [msg_type, sender, id, x, y, name, type, host_id]}
|
||||||
|
- {msg_type: DeviceDestroy, fields: [msg_type, sender, id, previous_x, previous_y, previous_name, previous_type, previous_host_id]}
|
||||||
|
- {msg_type: DeviceLabelEdit, fields: [msg_type, sender, id, name, previous_name]}
|
||||||
|
- {msg_type: DeviceSelected, fields: [msg_type, sender, id]}
|
||||||
|
- {msg_type: DeviceUnSelected, fields: [msg_type, sender, id]}
|
||||||
|
- {msg_type: InterfaceCreate, fields: [msg_type, sender, device_id, id, name]}
|
||||||
|
- {msg_type: InterfaceLabelEdit, fields: [msg_type, sender, id, device_id, name, previous_name]}
|
||||||
|
- {msg_type: LinkLabelEdit, fields: [msg_type, sender, id, name, previous_name]}
|
||||||
|
- {msg_type: LinkCreate, fields: [msg_type, id, sender, name, from_device_id, to_device_id, from_interface_id, to_interface_id]}
|
||||||
|
- {msg_type: LinkDestroy, fields: [msg_type, id, sender, name, from_device_id, to_device_id, from_interface_id, to_interface_id]}
|
||||||
|
- {msg_type: LinkSelected, fields: [msg_type, sender, id]}
|
||||||
|
- {msg_type: LinkUnSelected, fields: [msg_type, sender, id]}
|
||||||
|
- {msg_type: Undo, fields: [msg_type, sender, original_message]}
|
||||||
|
- {msg_type: Redo, fields: [msg_type, sender, original_message]}
|
||||||
|
- {msg_type: Deploy, fields: [msg_type, sender]}
|
||||||
|
- {msg_type: Destroy, fields: [msg_type, sender]}
|
||||||
|
- {msg_type: Discover, fields: [msg_type, sender]}
|
||||||
|
- {msg_type: Layout, fields: [msg_type, sender]}
|
||||||
|
- {msg_type: MultipleMessage, fields: [msg_type, sender, messages]}
|
||||||
|
- {msg_type: MouseEvent, fields: [msg_type, sender, x, y, type, trace_id]}
|
||||||
|
- {msg_type: MouseWheelEvent, fields: [msg_type, sender, delta, deltaX, deltaY, type, originalEvent, trace_id]}
|
||||||
|
- {msg_type: KeyEvent, fields: [msg_type, sender, key, keyCode, type, altKey, shiftKey, ctrlKey, metaKey, trace_id]}
|
||||||
|
- {msg_type: TouchEvent, fields: [msg_type, sender, type, touches]}
|
||||||
|
- {msg_type: StartRecording, fields: [msg_type, sender, trace_id]}
|
||||||
|
- {msg_type: StopRecording, fields: [msg_type, sender, trace_id]}
|
||||||
|
- {msg_type: ViewPort, fields: [msg_type, sender, scale, panX, panY, trace_id]}
|
||||||
|
- {msg_type: CopySite, fields: [msg_type, site]}
|
||||||
|
- {msg_type: GroupMove, fields: [msg_type, sender, id, x1, y1, x2, y2, previous_x1, previous_y1, previous_x2, previous_y2]}
|
||||||
|
- {msg_type: GroupCreate, fields: [msg_type, sender, id, x1, y1, x2, y2, name, type]}
|
||||||
|
- {msg_type: GroupDestroy, fields: [msg_type, sender, id, previous_x1, previous_y1, previous_x2, previous_y2, previous_name, previous_type]}
|
||||||
|
- {msg_type: GroupLabelEdit, fields: [msg_type, sender, id, name, previous_name]}
|
||||||
|
- {msg_type: GroupSelected, fields: [msg_type, sender, id]}
|
||||||
|
- {msg_type: GroupUnSelected, fields: [msg_type, sender, id]}
|
||||||
|
- {msg_type: GroupMembership, fields: [msg_type, sender, id, members]}
|
||||||
|
- {msg_type: TableCellEdit, fields: [msg_type, sender, sheet, col, row, old_value, new_value]}
|
||||||
|
- {msg_type: ProcessCreate, fields: [msg_type, id, name, type, device_id, x, y]}
|
||||||
|
- {msg_type: StreamCreate, fields: [msg_type, sender, id, from_id, to_id, label]}
|
||||||
|
- {msg_type: StreamDestroy, fields: [msg_type, sender, id, from_id, to_id, label]}
|
||||||
|
- {msg_type: StreamLabelEdit, fields: [msg_type, sender, id, label, previous_label]}
|
||||||
|
- {msg_type: StreamSelected, fields: [msg_type, sender, id]}
|
||||||
|
- {msg_type: StreamUnSelected, fields: [msg_type, sender, id]}
|
||||||
|
- {msg_type: FSMTrace, fields: [msg_type, order, sender, trace_id, fsm_name, from_state, to_state, recv_message_type]}
|
||||||
|
- {msg_type: ChannelTrace, fields: [msg_type, sender, trace_id, from_fsm, to_fsm, sent_message_type]}
|
||||||
|
- {msg_type: Snapshot, fields: [msg_type, sender, devices, links, groups, streams, order, trace_id]}
|
||||||
|
- {msg_type: EnableTest, fields: [msg_type]}
|
||||||
|
- {msg_type: DisableTest, fields: [msg_type]}
|
||||||
|
- {msg_type: StartTest, fields: [msg_type]}
|
||||||
|
- {msg_type: TestCompleted, fields: [msg_type]}
|
||||||
|
- {msg_type: TestResult, fields: [msg_type, sender, id, name, result, date, code_under_test]}
|
||||||
|
- {msg_type: Coverage, fields: [msg_type, sender, coverage, result_id]}
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
def populate_message_types(apps, schema_editor):
|
||||||
|
|
||||||
|
MessageType = apps.get_model('network_ui', 'MessageType')
|
||||||
|
for message in messages['messages']:
|
||||||
|
MessageType.objects.get_or_create(name=message['msg_type'])
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('network_ui', '0032_auto_20180112_2135'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(
|
||||||
|
code=populate_message_types,
|
||||||
|
),
|
||||||
|
]
|
||||||
24
awx/network_ui/migrations/0034_auto_20180113_1725.py
Normal file
24
awx/network_ui/migrations/0034_auto_20180113_1725.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.7 on 2018-01-13 17:25
|
||||||
|
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', 'TestCase')
|
||||||
|
TestCase.objects.get_or_create(name="Load", test_case_data=json.dumps(dict(runnable=False)))
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('network_ui', '0033_auto_20180112_2202'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(
|
||||||
|
code=add_load_test_case,
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -175,3 +175,63 @@ class TopologyInventory(models.Model):
|
|||||||
topology_inventory_id = models.AutoField(primary_key=True,)
|
topology_inventory_id = models.AutoField(primary_key=True,)
|
||||||
topology = models.ForeignKey('Topology',)
|
topology = models.ForeignKey('Topology',)
|
||||||
inventory_id = models.IntegerField()
|
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,)
|
||||||
|
test_case_data = models.TextField()
|
||||||
|
|
||||||
|
|
||||||
|
class Result(models.Model):
|
||||||
|
|
||||||
|
result_id = models.AutoField(primary_key=True,)
|
||||||
|
name = models.CharField(max_length=20,)
|
||||||
|
|
||||||
|
|
||||||
|
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,)
|
||||||
|
|
||||||
|
|
||||||
|
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',)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
messages:
|
messages:
|
||||||
- {msg_type: DeviceMove, fields: [msg_type, sender, id, x, y, previous_x, previous_y]}
|
- {msg_type: DeviceMove, fields: [msg_type, sender, id, x, y, previous_x, previous_y]}
|
||||||
- {msg_type: DeviceCreate, fields: [msg_type, sender, id, x, y, name, type]}
|
- {msg_type: DeviceCreate, fields: [msg_type, sender, id, x, y, name, type, host_id]}
|
||||||
- {msg_type: DeviceDestroy, fields: [msg_type, sender, id, previous_x, previous_y, previous_name, previous_type]}
|
- {msg_type: DeviceDestroy, fields: [msg_type, sender, id, previous_x, previous_y, previous_name, previous_type, previous_host_id]}
|
||||||
- {msg_type: DeviceLabelEdit, fields: [msg_type, sender, id, name, previous_name]}
|
- {msg_type: DeviceLabelEdit, fields: [msg_type, sender, id, name, previous_name]}
|
||||||
- {msg_type: DeviceSelected, fields: [msg_type, sender, id]}
|
- {msg_type: DeviceSelected, fields: [msg_type, sender, id]}
|
||||||
- {msg_type: DeviceUnSelected, fields: [msg_type, sender, id]}
|
- {msg_type: DeviceUnSelected, fields: [msg_type, sender, id]}
|
||||||
@@ -19,14 +19,13 @@ messages:
|
|||||||
- {msg_type: Discover, fields: [msg_type, sender]}
|
- {msg_type: Discover, fields: [msg_type, sender]}
|
||||||
- {msg_type: Layout, fields: [msg_type, sender]}
|
- {msg_type: Layout, fields: [msg_type, sender]}
|
||||||
- {msg_type: MultipleMessage, fields: [msg_type, sender, messages]}
|
- {msg_type: MultipleMessage, fields: [msg_type, sender, messages]}
|
||||||
- {msg_type: Coverage, fields: [msg_type, sender, coverage]}
|
- {msg_type: MouseEvent, fields: [msg_type, sender, x, y, type, trace_id]}
|
||||||
- {msg_type: MouseEvent, fields: [msg_type, sender, x, y, type]}
|
- {msg_type: MouseWheelEvent, fields: [msg_type, sender, delta, deltaX, deltaY, type, originalEvent, trace_id]}
|
||||||
- {msg_type: MouseWheelEvent, fields: [msg_type, sender, delta, deltaX, deltaY, type, originalEvent]}
|
- {msg_type: KeyEvent, fields: [msg_type, sender, key, keyCode, type, altKey, shiftKey, ctrlKey, metaKey, trace_id]}
|
||||||
- {msg_type: KeyEvent, fields: [msg_type, sender, key, keyCode, type, altKey, shiftKey, ctrlKey, metaKey]}
|
|
||||||
- {msg_type: TouchEvent, fields: [msg_type, sender, type, touches]}
|
- {msg_type: TouchEvent, fields: [msg_type, sender, type, touches]}
|
||||||
- {msg_type: StartRecording, fields: [msg_type, sender]}
|
- {msg_type: StartRecording, fields: [msg_type, sender, trace_id]}
|
||||||
- {msg_type: StopRecording, fields: [msg_type, sender]}
|
- {msg_type: StopRecording, fields: [msg_type, sender, trace_id]}
|
||||||
- {msg_type: ViewPort, fields: [msg_type, sender, scale, panX, panY]}
|
- {msg_type: ViewPort, fields: [msg_type, sender, scale, panX, panY, trace_id]}
|
||||||
- {msg_type: CopySite, fields: [msg_type, site]}
|
- {msg_type: CopySite, fields: [msg_type, site]}
|
||||||
- {msg_type: GroupMove, fields: [msg_type, sender, id, x1, y1, x2, y2, previous_x1, previous_y1, previous_x2, previous_y2]}
|
- {msg_type: GroupMove, fields: [msg_type, sender, id, x1, y1, x2, y2, previous_x1, previous_y1, previous_x2, previous_y2]}
|
||||||
- {msg_type: GroupCreate, fields: [msg_type, sender, id, x1, y1, x2, y2, name, type]}
|
- {msg_type: GroupCreate, fields: [msg_type, sender, id, x1, y1, x2, y2, name, type]}
|
||||||
@@ -44,4 +43,11 @@ messages:
|
|||||||
- {msg_type: StreamUnSelected, fields: [msg_type, sender, id]}
|
- {msg_type: StreamUnSelected, fields: [msg_type, sender, id]}
|
||||||
- {msg_type: FSMTrace, fields: [msg_type, order, sender, trace_id, fsm_name, from_state, to_state, recv_message_type]}
|
- {msg_type: FSMTrace, fields: [msg_type, order, sender, trace_id, fsm_name, from_state, to_state, recv_message_type]}
|
||||||
- {msg_type: ChannelTrace, fields: [msg_type, sender, trace_id, from_fsm, to_fsm, sent_message_type]}
|
- {msg_type: ChannelTrace, fields: [msg_type, sender, trace_id, from_fsm, to_fsm, sent_message_type]}
|
||||||
|
- {msg_type: Snapshot, fields: [msg_type, sender, devices, links, groups, streams, order, trace_id]}
|
||||||
|
- {msg_type: EnableTest, fields: [msg_type]}
|
||||||
|
- {msg_type: DisableTest, fields: [msg_type]}
|
||||||
|
- {msg_type: StartTest, fields: [msg_type]}
|
||||||
|
- {msg_type: TestCompleted, fields: [msg_type]}
|
||||||
|
- {msg_type: TestResult, fields: [msg_type, sender, id, name, result, date, code_under_test]}
|
||||||
|
- {msg_type: Coverage, fields: [msg_type, sender, coverage, result_id]}
|
||||||
|
|
||||||
|
|||||||
49
awx/network_ui/static/network_ui/designs/test.yml
Normal file
49
awx/network_ui/static/network_ui/designs/test.yml
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
diagram_id: 42
|
||||||
|
name: diagram
|
||||||
|
states:
|
||||||
|
- id: 6
|
||||||
|
label: Reporting
|
||||||
|
x: 926
|
||||||
|
y: 721
|
||||||
|
- id: 2
|
||||||
|
label: Disabled
|
||||||
|
x: 895
|
||||||
|
y: 344
|
||||||
|
- id: 5
|
||||||
|
label: Running
|
||||||
|
x: 720
|
||||||
|
y: 922
|
||||||
|
- id: 1
|
||||||
|
label: Ready
|
||||||
|
x: 722
|
||||||
|
y: 509
|
||||||
|
- id: 3
|
||||||
|
label: Start
|
||||||
|
x: 702
|
||||||
|
y: 186
|
||||||
|
- id: 4
|
||||||
|
label: Loading
|
||||||
|
x: 524
|
||||||
|
y: 710
|
||||||
|
transitions:
|
||||||
|
- from_state: Running
|
||||||
|
label: onTestCompleted
|
||||||
|
to_state: Reporting
|
||||||
|
- from_state: Ready
|
||||||
|
label: onDisable
|
||||||
|
to_state: Disabled
|
||||||
|
- from_state: Start
|
||||||
|
label: start
|
||||||
|
to_state: Disabled
|
||||||
|
- from_state: Loading
|
||||||
|
label: onTestLoaded
|
||||||
|
to_state: Running
|
||||||
|
- from_state: Disabled
|
||||||
|
label: onEnable
|
||||||
|
to_state: Ready
|
||||||
|
- from_state: Reporting
|
||||||
|
label: onTestReported
|
||||||
|
to_state: Ready
|
||||||
|
- from_state: Ready
|
||||||
|
label: onStartTest
|
||||||
|
to_state: Loading
|
||||||
112
awx/network_ui/static/network_ui/test.js
Normal file
112
awx/network_ui/static/network_ui/test.js
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
var inherits = require('inherits');
|
||||||
|
var fsm = require('./fsm.js');
|
||||||
|
|
||||||
|
function _State () {
|
||||||
|
}
|
||||||
|
inherits(_State, fsm._State);
|
||||||
|
|
||||||
|
|
||||||
|
function _Disabled () {
|
||||||
|
this.name = 'Disabled';
|
||||||
|
}
|
||||||
|
inherits(_Disabled, _State);
|
||||||
|
var Disabled = new _Disabled();
|
||||||
|
exports.Disabled = Disabled;
|
||||||
|
|
||||||
|
function _Start () {
|
||||||
|
this.name = 'Start';
|
||||||
|
}
|
||||||
|
inherits(_Start, _State);
|
||||||
|
var Start = new _Start();
|
||||||
|
exports.Start = Start;
|
||||||
|
|
||||||
|
function _Running () {
|
||||||
|
this.name = 'Running';
|
||||||
|
}
|
||||||
|
inherits(_Running, _State);
|
||||||
|
var Running = new _Running();
|
||||||
|
exports.Running = Running;
|
||||||
|
|
||||||
|
function _Loading () {
|
||||||
|
this.name = 'Loading';
|
||||||
|
}
|
||||||
|
inherits(_Loading, _State);
|
||||||
|
var Loading = new _Loading();
|
||||||
|
exports.Loading = Loading;
|
||||||
|
|
||||||
|
function _Ready () {
|
||||||
|
this.name = 'Ready';
|
||||||
|
}
|
||||||
|
inherits(_Ready, _State);
|
||||||
|
var Ready = new _Ready();
|
||||||
|
exports.Ready = Ready;
|
||||||
|
|
||||||
|
function _Reporting () {
|
||||||
|
this.name = 'Reporting';
|
||||||
|
}
|
||||||
|
inherits(_Reporting, _State);
|
||||||
|
var Reporting = new _Reporting();
|
||||||
|
exports.Reporting = Reporting;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Disabled.prototype.onEnable = function (controller) {
|
||||||
|
|
||||||
|
controller.changeState(Ready);
|
||||||
|
|
||||||
|
};
|
||||||
|
_Disabled.prototype.onEnable.transitions = ['Ready'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Start.prototype.start = function (controller) {
|
||||||
|
|
||||||
|
controller.changeState(Disabled);
|
||||||
|
|
||||||
|
};
|
||||||
|
_Start.prototype.start.transitions = ['Disabled'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Running.prototype.onTestCompleted = function (controller) {
|
||||||
|
|
||||||
|
controller.changeState(Reporting);
|
||||||
|
|
||||||
|
};
|
||||||
|
_Running.prototype.onTestCompleted.transitions = ['Reporting'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Loading.prototype.onTestLoaded = function (controller) {
|
||||||
|
|
||||||
|
controller.changeState(Running);
|
||||||
|
|
||||||
|
};
|
||||||
|
_Loading.prototype.onTestLoaded.transitions = ['Running'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Ready.prototype.onDisable = function (controller) {
|
||||||
|
|
||||||
|
controller.changeState(Disabled);
|
||||||
|
|
||||||
|
};
|
||||||
|
_Ready.prototype.onDisable.transitions = ['Disabled'];
|
||||||
|
|
||||||
|
_Ready.prototype.onStartTest = function (controller) {
|
||||||
|
|
||||||
|
controller.changeState(Loading);
|
||||||
|
|
||||||
|
};
|
||||||
|
_Ready.prototype.onStartTest.transitions = ['Loading'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Reporting.prototype.onTestReported = function (controller) {
|
||||||
|
|
||||||
|
controller.changeState(Ready);
|
||||||
|
|
||||||
|
};
|
||||||
|
_Reporting.prototype.onTestReported.transitions = ['Ready'];
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
<ul>
|
|
||||||
<li><a href="/#/topology/">New</a></li>
|
|
||||||
{%for o in topologies%}
|
|
||||||
<li>
|
|
||||||
<a href="/#/topology?topology_id={{o.pk}}">{{o.pk}} {{o}}</a>
|
|
||||||
{%for device in o.device_set.all%}
|
|
||||||
{{device}}
|
|
||||||
{%endfor%}
|
|
||||||
</li>
|
|
||||||
{%endfor%}
|
|
||||||
</ul>
|
|
||||||
5
awx/network_ui/templates/network_ui/upload_test.html
Normal file
5
awx/network_ui/templates/network_ui/upload_test.html
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<form action="/network_ui/upload_test" method="post" enctype="multipart/form-data">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{form}}
|
||||||
|
<button type="submit">Upload Test</button>
|
||||||
|
</form>
|
||||||
13
awx/network_ui/tools/Makefile
Normal file
13
awx/network_ui/tools/Makefile
Normal 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}
|
||||||
61
awx/network_ui/tools/coverage_report.py
Executable file
61
awx/network_ui/tools/coverage_report.py
Executable file
@@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Usage:
|
||||||
|
coverage_report [options] <server>
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help Show this page
|
||||||
|
--debug Show debug logging
|
||||||
|
--verbose Show verbose logging
|
||||||
|
"""
|
||||||
|
from docopt import docopt
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
logger = logging.getLogger('coverage_report')
|
||||||
|
|
||||||
|
TESTS_API = '/network_ui/tests'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main(args=None):
|
||||||
|
if args is None:
|
||||||
|
args = sys.argv[1:]
|
||||||
|
parsed_args = docopt(__doc__, args)
|
||||||
|
if parsed_args['--debug']:
|
||||||
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
elif parsed_args['--verbose']:
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
else:
|
||||||
|
logging.basicConfig(level=logging.WARNING)
|
||||||
|
|
||||||
|
|
||||||
|
print (parsed_args['<server>'])
|
||||||
|
server = parsed_args['<server>']
|
||||||
|
|
||||||
|
tests = requests.get(server + TESTS_API, verify=False).json()
|
||||||
|
|
||||||
|
for test in tests['tests']:
|
||||||
|
if not os.path.exists(test['name']):
|
||||||
|
os.mkdir(test['name'])
|
||||||
|
with open(test['name'] + "/coverage.json", 'w') as f:
|
||||||
|
f.write(requests.get(server + test['coverage'], verify=False).text)
|
||||||
|
|
||||||
|
|
||||||
|
for test in tests['tests']:
|
||||||
|
subprocess.Popen('istanbul report html', shell=True, cwd=test['name']).wait()
|
||||||
|
|
||||||
|
|
||||||
|
subprocess.Popen('istanbul report html', shell=True).wait()
|
||||||
|
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import sys
|
||||||
|
sys.exit(main(sys.argv[1:]))
|
||||||
|
|
||||||
2
awx/network_ui/tools/requirements.txt
Normal file
2
awx/network_ui/tools/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
requests
|
||||||
|
docopt
|
||||||
@@ -7,7 +7,11 @@ import awx.network_ui.routing
|
|||||||
|
|
||||||
app_name = 'network_ui'
|
app_name = 'network_ui'
|
||||||
urlpatterns = [
|
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_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.json$', views.json_topology_data, name='json_topology_data'),
|
||||||
url(r'^topology.yaml$', views.yaml_topology_data, name='json_topology_data'),
|
url(r'^topology.yaml$', views.yaml_topology_data, name='json_topology_data'),
|
||||||
url(r'^$', views.index, name='index'),
|
url(r'^$', views.index, name='index'),
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
# Copyright (c) 2017 Red Hat, Inc
|
# Copyright (c) 2017 Red Hat, Inc
|
||||||
from django.shortcuts import render
|
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, HttpResponseRedirect
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
from .models import Topology, FSMTrace
|
from .models import Topology, FSMTrace, EventTrace, TopologySnapshot
|
||||||
|
from .models import TestCase, TestResult, Coverage
|
||||||
from .serializers import topology_data
|
from .serializers import topology_data
|
||||||
|
|
||||||
|
|
||||||
@@ -56,3 +60,79 @@ def download_trace(request):
|
|||||||
return response
|
return response
|
||||||
else:
|
else:
|
||||||
return HttpResponse(form.errors)
|
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
|
||||||
|
|||||||
@@ -58,6 +58,17 @@ const base = {
|
|||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
use: {
|
||||||
|
loader: 'istanbul-instrumenter-loader',
|
||||||
|
options: { esModules: true }
|
||||||
|
},
|
||||||
|
enforce: 'pre',
|
||||||
|
include: [
|
||||||
|
/src\/network-ui\//
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.js$/,
|
test: /\.js$/,
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
|
|||||||
@@ -176,23 +176,18 @@ function MultipleMessage(sender, messages) {
|
|||||||
}
|
}
|
||||||
exports.MultipleMessage = MultipleMessage;
|
exports.MultipleMessage = MultipleMessage;
|
||||||
|
|
||||||
function Coverage(sender, coverage) {
|
|
||||||
this.msg_type = "Coverage";
|
|
||||||
this.sender = sender;
|
|
||||||
this.coverage = coverage;
|
|
||||||
}
|
|
||||||
exports.Coverage = Coverage;
|
|
||||||
|
|
||||||
function MouseEvent(sender, x, y, type) {
|
function MouseEvent(sender, x, y, type, trace_id) {
|
||||||
this.msg_type = "MouseEvent";
|
this.msg_type = "MouseEvent";
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.trace_id = trace_id;
|
||||||
}
|
}
|
||||||
exports.MouseEvent = MouseEvent;
|
exports.MouseEvent = MouseEvent;
|
||||||
|
|
||||||
function MouseWheelEvent(sender, delta, deltaX, deltaY, type, metaKey) {
|
function MouseWheelEvent(sender, delta, deltaX, deltaY, type, metaKey, trace_id) {
|
||||||
this.msg_type = "MouseWheelEvent";
|
this.msg_type = "MouseWheelEvent";
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
this.delta = delta;
|
this.delta = delta;
|
||||||
@@ -200,10 +195,11 @@ function MouseWheelEvent(sender, delta, deltaX, deltaY, type, metaKey) {
|
|||||||
this.deltaY = deltaY;
|
this.deltaY = deltaY;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.originalEvent = {metaKey: metaKey};
|
this.originalEvent = {metaKey: metaKey};
|
||||||
|
this.trace_id = trace_id;
|
||||||
}
|
}
|
||||||
exports.MouseWheelEvent = MouseWheelEvent;
|
exports.MouseWheelEvent = MouseWheelEvent;
|
||||||
|
|
||||||
function KeyEvent(sender, key, keyCode, type, altKey, shiftKey, ctrlKey, metaKey) {
|
function KeyEvent(sender, key, keyCode, type, altKey, shiftKey, ctrlKey, metaKey, trace_id) {
|
||||||
this.msg_type = "KeyEvent";
|
this.msg_type = "KeyEvent";
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
this.key = key;
|
this.key = key;
|
||||||
@@ -213,6 +209,7 @@ function KeyEvent(sender, key, keyCode, type, altKey, shiftKey, ctrlKey, metaKey
|
|||||||
this.shiftKey = shiftKey;
|
this.shiftKey = shiftKey;
|
||||||
this.ctrlKey = ctrlKey;
|
this.ctrlKey = ctrlKey;
|
||||||
this.metaKey = metaKey;
|
this.metaKey = metaKey;
|
||||||
|
this.trace_id = trace_id;
|
||||||
}
|
}
|
||||||
exports.KeyEvent = KeyEvent;
|
exports.KeyEvent = KeyEvent;
|
||||||
|
|
||||||
@@ -224,24 +221,27 @@ function TouchEvent(sender, type, touches) {
|
|||||||
}
|
}
|
||||||
exports.TouchEvent = TouchEvent;
|
exports.TouchEvent = TouchEvent;
|
||||||
|
|
||||||
function StartRecording(sender) {
|
function StartRecording(sender, trace_id) {
|
||||||
this.msg_type = "StartRecording";
|
this.msg_type = "StartRecording";
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
|
this.trace_id = trace_id;
|
||||||
}
|
}
|
||||||
exports.StartRecording = StartRecording;
|
exports.StartRecording = StartRecording;
|
||||||
|
|
||||||
function StopRecording(sender) {
|
function StopRecording(sender, trace_id) {
|
||||||
this.msg_type = "StopRecording";
|
this.msg_type = "StopRecording";
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
|
this.trace_id = trace_id;
|
||||||
}
|
}
|
||||||
exports.StopRecording = StopRecording;
|
exports.StopRecording = StopRecording;
|
||||||
|
|
||||||
function ViewPort(sender, scale, panX, panY) {
|
function ViewPort(sender, scale, panX, panY, trace_id) {
|
||||||
this.msg_type = "ViewPort";
|
this.msg_type = "ViewPort";
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
this.scale = scale;
|
this.scale = scale;
|
||||||
this.panX = panX;
|
this.panX = panX;
|
||||||
this.panY = panY;
|
this.panY = panY;
|
||||||
|
this.trace_id = trace_id;
|
||||||
}
|
}
|
||||||
exports.ViewPort = ViewPort;
|
exports.ViewPort = ViewPort;
|
||||||
|
|
||||||
@@ -446,3 +446,54 @@ function ChannelTrace(from_fsm, to_fsm, sent_message_type) {
|
|||||||
this.sent_message_type = sent_message_type;
|
this.sent_message_type = sent_message_type;
|
||||||
}
|
}
|
||||||
exports.ChannelTrace = ChannelTrace;
|
exports.ChannelTrace = ChannelTrace;
|
||||||
|
|
||||||
|
function Snapshot(sender, devices, links, groups, streams, order, trace_id) {
|
||||||
|
this.msg_type = 'Snapshot';
|
||||||
|
this.sender = 0;
|
||||||
|
this.devices = devices;
|
||||||
|
this.links = links;
|
||||||
|
this.groups = groups;
|
||||||
|
this.streams = streams;
|
||||||
|
this.order = order;
|
||||||
|
this.trace_id = trace_id;
|
||||||
|
}
|
||||||
|
exports.Snapshot = Snapshot;
|
||||||
|
|
||||||
|
function EnableTest() {
|
||||||
|
this.msg_type = "EnableTest";
|
||||||
|
}
|
||||||
|
exports.EnableTest = EnableTest;
|
||||||
|
|
||||||
|
function DisableTest() {
|
||||||
|
this.msg_type = "DisableTest";
|
||||||
|
}
|
||||||
|
exports.DisableTest = DisableTest;
|
||||||
|
|
||||||
|
function StartTest() {
|
||||||
|
this.msg_type = "StartTest";
|
||||||
|
}
|
||||||
|
exports.StartTest = StartTest;
|
||||||
|
|
||||||
|
function TestCompleted() {
|
||||||
|
this.msg_type = "TestCompleted";
|
||||||
|
}
|
||||||
|
exports.TestCompleted = TestCompleted;
|
||||||
|
|
||||||
|
function TestResult(sender, id, name, result, date, code_under_test) {
|
||||||
|
this.msg_type = "TestResult";
|
||||||
|
this.sender = sender;
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.result = result;
|
||||||
|
this.date = date;
|
||||||
|
this.code_under_test = code_under_test;
|
||||||
|
}
|
||||||
|
exports.TestResult = TestResult;
|
||||||
|
|
||||||
|
function Coverage(sender, coverage, result_id) {
|
||||||
|
this.msg_type = "Coverage";
|
||||||
|
this.sender = sender;
|
||||||
|
this.coverage = coverage;
|
||||||
|
this.result_id = result_id;
|
||||||
|
}
|
||||||
|
exports.Coverage = Coverage;
|
||||||
|
|||||||
@@ -36,8 +36,12 @@ Device.prototype.toJSON = function () {
|
|||||||
x: this.x,
|
x: this.x,
|
||||||
y: this.y,
|
y: this.y,
|
||||||
type: this.type,
|
type: this.type,
|
||||||
interfaces: this.interfaces,
|
interfaces: this.interfaces.map(function (x) {
|
||||||
processes: this.processes};
|
return x.toJSON();
|
||||||
|
}),
|
||||||
|
processes: this.processes.map(function (x) {
|
||||||
|
return x.toJSON();
|
||||||
|
})};
|
||||||
};
|
};
|
||||||
|
|
||||||
Device.prototype.is_selected = function (x, y) {
|
Device.prototype.is_selected = function (x, y) {
|
||||||
@@ -726,6 +730,11 @@ function Process(id, name, type, x, y) {
|
|||||||
}
|
}
|
||||||
exports.Process = Process;
|
exports.Process = Process;
|
||||||
|
|
||||||
|
Process.prototype.toJSON = function () {
|
||||||
|
return {id: this.id,
|
||||||
|
name: this.name};
|
||||||
|
};
|
||||||
|
|
||||||
function Stream(id, from_device, to_device, label) {
|
function Stream(id, from_device, to_device, label) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.from_device = from_device;
|
this.from_device = from_device;
|
||||||
@@ -919,3 +928,21 @@ Stream.prototype.start_arc_angle_rad = function () {
|
|||||||
Stream.prototype.start_arc_angle = function () {
|
Stream.prototype.start_arc_angle = function () {
|
||||||
return this.start_arc_angle_rad() * 180 / Math.PI;
|
return this.start_arc_angle_rad() * 180 / Math.PI;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function Test(name, event_trace, fsm_trace, pre_test_snapshot, post_test_snapshot) {
|
||||||
|
this.name = name;
|
||||||
|
this.event_trace = event_trace;
|
||||||
|
this.fsm_trace = fsm_trace;
|
||||||
|
this.pre_test_snapshot = pre_test_snapshot;
|
||||||
|
this.post_test_snapshot = post_test_snapshot;
|
||||||
|
}
|
||||||
|
exports.Test = Test;
|
||||||
|
|
||||||
|
function TestResult(id, name, result, date, code_under_test) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.result = result;
|
||||||
|
this.date = date;
|
||||||
|
this.code_under_test = code_under_test;
|
||||||
|
}
|
||||||
|
exports.TestResult = TestResult;
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ var inventoryToolboxClipPath = require('./inventory.toolbox.clip.path.directive.
|
|||||||
var statusLight = require('./status.light.directive.js');
|
var statusLight = require('./status.light.directive.js');
|
||||||
var taskStatus = require('./task.status.directive.js');
|
var taskStatus = require('./task.status.directive.js');
|
||||||
var debug = require('./debug.directive.js');
|
var debug = require('./debug.directive.js');
|
||||||
|
var test_results = require('./test_results.directive.js');
|
||||||
var awxNetworkUI = require('./network.ui.directive.js');
|
var awxNetworkUI = require('./network.ui.directive.js');
|
||||||
|
|
||||||
var networkUI = angular.module('networkUI', [
|
var networkUI = angular.module('networkUI', [
|
||||||
@@ -70,6 +71,7 @@ var networkUI = angular.module('networkUI', [
|
|||||||
.directive('awxNetInventoryToolboxClipPath', inventoryToolboxClipPath.inventoryToolboxClipPath)
|
.directive('awxNetInventoryToolboxClipPath', inventoryToolboxClipPath.inventoryToolboxClipPath)
|
||||||
.directive('awxNetStatusLight', statusLight.statusLight)
|
.directive('awxNetStatusLight', statusLight.statusLight)
|
||||||
.directive('awxNetTaskStatus', taskStatus.taskStatus)
|
.directive('awxNetTaskStatus', taskStatus.taskStatus)
|
||||||
|
.directive('awxNetTestResults', test_results.test_results)
|
||||||
.directive('awxNetworkUi', awxNetworkUI.awxNetworkUI);
|
.directive('awxNetworkUi', awxNetworkUI.awxNetworkUI);
|
||||||
|
|
||||||
exports.networkUI = networkUI;
|
exports.networkUI = networkUI;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ var stream_fsm = require('./stream.fsm.js');
|
|||||||
var group = require('./group.js');
|
var group = require('./group.js');
|
||||||
var buttons = require('./buttons.js');
|
var buttons = require('./buttons.js');
|
||||||
var time = require('./time.js');
|
var time = require('./time.js');
|
||||||
|
var test_fsm = require('./test.fsm.js');
|
||||||
var util = require('./util.js');
|
var util = require('./util.js');
|
||||||
var models = require('./models.js');
|
var models = require('./models.js');
|
||||||
var messages = require('./messages.js');
|
var messages = require('./messages.js');
|
||||||
@@ -22,7 +23,7 @@ var svg_crowbar = require('./svg-crowbar.js');
|
|||||||
var ReconnectingWebSocket = require('reconnectingwebsocket');
|
var ReconnectingWebSocket = require('reconnectingwebsocket');
|
||||||
|
|
||||||
var NetworkUIController = function($scope, $document, $location, $window, $http,
|
var NetworkUIController = function($scope, $document, $location, $window, $http,
|
||||||
$q, $state, ProcessErrors) {
|
$q, $state, ProcessErrors, ConfigService) {
|
||||||
|
|
||||||
window.scope = $scope;
|
window.scope = $scope;
|
||||||
var i = 0;
|
var i = 0;
|
||||||
@@ -96,6 +97,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
$scope.group_id_seq = util.natural_numbers(0);
|
$scope.group_id_seq = util.natural_numbers(0);
|
||||||
$scope.message_id_seq = util.natural_numbers(0);
|
$scope.message_id_seq = util.natural_numbers(0);
|
||||||
$scope.stream_id_seq = util.natural_numbers(0);
|
$scope.stream_id_seq = util.natural_numbers(0);
|
||||||
|
$scope.test_result_id_seq = util.natural_numbers(0);
|
||||||
$scope.overall_toolbox_collapsed = false;
|
$scope.overall_toolbox_collapsed = false;
|
||||||
$scope.time_pointer = -1;
|
$scope.time_pointer = -1;
|
||||||
$scope.frame = 0;
|
$scope.frame = 0;
|
||||||
@@ -108,6 +110,14 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
$scope.groups = [];
|
$scope.groups = [];
|
||||||
$scope.processes = [];
|
$scope.processes = [];
|
||||||
$scope.configurations = [];
|
$scope.configurations = [];
|
||||||
|
$scope.tests = [];
|
||||||
|
$scope.current_tests = [];
|
||||||
|
$scope.current_test = null;
|
||||||
|
$scope.testing = false;
|
||||||
|
$scope.version = null;
|
||||||
|
$scope.test_events = [];
|
||||||
|
$scope.test_results = [];
|
||||||
|
$scope.test_errors = [];
|
||||||
$scope.streams = [];
|
$scope.streams = [];
|
||||||
$scope.view_port = {'x': 0,
|
$scope.view_port = {'x': 0,
|
||||||
'y': 0,
|
'y': 0,
|
||||||
@@ -118,7 +128,9 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
$scope.trace_id = $scope.trace_id_seq();
|
$scope.trace_id = $scope.trace_id_seq();
|
||||||
|
|
||||||
$scope.send_trace_message = function (message) {
|
$scope.send_trace_message = function (message) {
|
||||||
console.log(message);
|
if (!$scope.recording) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
message.sender = $scope.client_id;
|
message.sender = $scope.client_id;
|
||||||
message.trace_id = $scope.trace_id;
|
message.trace_id = $scope.trace_id;
|
||||||
message.message_id = $scope.message_id_seq();
|
message.message_id = $scope.message_id_seq();
|
||||||
@@ -148,6 +160,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
$scope.site_controller = new fsm.FSMController($scope, "site_fsm", site_fsm.Disable, $scope);
|
$scope.site_controller = new fsm.FSMController($scope, "site_fsm", site_fsm.Disable, $scope);
|
||||||
$scope.buttons_controller = new fsm.FSMController($scope, "buttons_fsm", buttons.Start, $scope);
|
$scope.buttons_controller = new fsm.FSMController($scope, "buttons_fsm", buttons.Start, $scope);
|
||||||
$scope.time_controller = new fsm.FSMController($scope, "time_fsm", time.Start, $scope);
|
$scope.time_controller = new fsm.FSMController($scope, "time_fsm", time.Start, $scope);
|
||||||
|
$scope.test_controller = new fsm.FSMController($scope, "test_fsm", test_fsm.Start, $scope);
|
||||||
$scope.app_toolbox_controller = new fsm.FSMController($scope, "toolbox_fsm", toolbox_fsm.Start, $scope);
|
$scope.app_toolbox_controller = new fsm.FSMController($scope, "toolbox_fsm", toolbox_fsm.Start, $scope);
|
||||||
|
|
||||||
//App Toolbox Setup
|
//App Toolbox Setup
|
||||||
@@ -185,6 +198,12 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
let host = hosts[i];
|
let host = hosts[i];
|
||||||
console.log(host);
|
console.log(host);
|
||||||
host.data = jsyaml.safeLoad(host.variables);
|
host.data = jsyaml.safeLoad(host.variables);
|
||||||
|
if (host.data.type == undefined) {
|
||||||
|
host.data.type = 'unknown';
|
||||||
|
}
|
||||||
|
if (host.data.name == undefined) {
|
||||||
|
host.data.name = host.name;
|
||||||
|
}
|
||||||
var device = new models.Device(0, host.data.name, 0, 0, host.data.type, host.id, host.variables);
|
var device = new models.Device(0, host.data.name, 0, 0, host.data.type, host.id, host.variables);
|
||||||
device.icon = true;
|
device.icon = true;
|
||||||
$scope.inventory_toolbox.items.push(device);
|
$scope.inventory_toolbox.items.push(device);
|
||||||
@@ -288,9 +307,13 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
$scope.mode_controller.delegate_channel = new fsm.Channel($scope.mode_controller,
|
$scope.mode_controller.delegate_channel = new fsm.Channel($scope.mode_controller,
|
||||||
$scope.time_controller,
|
$scope.time_controller,
|
||||||
$scope);
|
$scope);
|
||||||
|
$scope.test_controller.delegate_channel = new fsm.Channel($scope.test_controller,
|
||||||
|
$scope.mode_controller,
|
||||||
|
$scope);
|
||||||
|
|
||||||
|
|
||||||
$scope.first_channel = new fsm.Channel(null,
|
$scope.first_channel = new fsm.Channel(null,
|
||||||
$scope.mode_controller,
|
$scope.test_controller,
|
||||||
$scope);
|
$scope);
|
||||||
|
|
||||||
var getMouseEventResult = function (mouseEvent) {
|
var getMouseEventResult = function (mouseEvent) {
|
||||||
@@ -464,7 +487,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
$scope.onMouseDown = function ($event) {
|
$scope.onMouseDown = function ($event) {
|
||||||
$scope.normalize_mouse_event($event);
|
$scope.normalize_mouse_event($event);
|
||||||
if ($scope.recording) {
|
if ($scope.recording) {
|
||||||
$scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.y, $event.type));
|
$scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.y, $event.type, $scope.trace_id));
|
||||||
}
|
}
|
||||||
$scope.last_event = $event;
|
$scope.last_event = $event;
|
||||||
$scope.first_channel.send('MouseDown', $event);
|
$scope.first_channel.send('MouseDown', $event);
|
||||||
@@ -475,7 +498,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
$scope.onMouseUp = function ($event) {
|
$scope.onMouseUp = function ($event) {
|
||||||
$scope.normalize_mouse_event($event);
|
$scope.normalize_mouse_event($event);
|
||||||
if ($scope.recording) {
|
if ($scope.recording) {
|
||||||
$scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.y, $event.type));
|
$scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.y, $event.type, $scope.trace_id));
|
||||||
}
|
}
|
||||||
$scope.last_event = $event;
|
$scope.last_event = $event;
|
||||||
$scope.first_channel.send('MouseUp', $event);
|
$scope.first_channel.send('MouseUp', $event);
|
||||||
@@ -486,7 +509,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
$scope.onMouseLeave = function ($event) {
|
$scope.onMouseLeave = function ($event) {
|
||||||
$scope.normalize_mouse_event($event);
|
$scope.normalize_mouse_event($event);
|
||||||
if ($scope.recording) {
|
if ($scope.recording) {
|
||||||
$scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.y, $event.type));
|
$scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.y, $event.type, $scope.trace_id));
|
||||||
}
|
}
|
||||||
$scope.onMouseLeaveResult = getMouseEventResult($event);
|
$scope.onMouseLeaveResult = getMouseEventResult($event);
|
||||||
$scope.cursor.hidden = true;
|
$scope.cursor.hidden = true;
|
||||||
@@ -496,7 +519,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
$scope.onMouseMove = function ($event) {
|
$scope.onMouseMove = function ($event) {
|
||||||
$scope.normalize_mouse_event($event);
|
$scope.normalize_mouse_event($event);
|
||||||
if ($scope.recording) {
|
if ($scope.recording) {
|
||||||
$scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.y, $event.type));
|
$scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.y, $event.type, $scope.trace_id));
|
||||||
}
|
}
|
||||||
//var coords = getCrossBrowserElementCoords($event);
|
//var coords = getCrossBrowserElementCoords($event);
|
||||||
$scope.cursor.hidden = false;
|
$scope.cursor.hidden = false;
|
||||||
@@ -513,7 +536,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
$scope.onMouseOver = function ($event) {
|
$scope.onMouseOver = function ($event) {
|
||||||
$scope.normalize_mouse_event($event);
|
$scope.normalize_mouse_event($event);
|
||||||
if ($scope.recording) {
|
if ($scope.recording) {
|
||||||
$scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.y, $event.type));
|
$scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.y, $event.type, $scope.trace_id));
|
||||||
}
|
}
|
||||||
$scope.onMouseOverResult = getMouseEventResult($event);
|
$scope.onMouseOverResult = getMouseEventResult($event);
|
||||||
$scope.cursor.hidden = false;
|
$scope.cursor.hidden = false;
|
||||||
@@ -529,11 +552,11 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
var deltaY = $event.deltaY;
|
var deltaY = $event.deltaY;
|
||||||
// console.log([$event, delta, deltaX, deltaY]);
|
// console.log([$event, delta, deltaX, deltaY]);
|
||||||
if ($scope.recording) {
|
if ($scope.recording) {
|
||||||
$scope.send_control_message(new messages.MouseWheelEvent($scope.client_id, delta, deltaX, deltaY, $event.type, $event.originalEvent.metaKey));
|
$scope.send_control_message(new messages.MouseWheelEvent($scope.client_id, delta, deltaX, deltaY, $event.type, $event.originalEvent.metaKey, $scope.trace_id));
|
||||||
}
|
}
|
||||||
$scope.last_event = $event;
|
$scope.last_event = $event;
|
||||||
$scope.first_channel.send('MouseWheel', [$event, delta, deltaX, deltaY]);
|
$scope.first_channel.send('MouseWheel', [$event, delta, deltaX, deltaY]);
|
||||||
event.preventDefault();
|
$event.preventDefault();
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.onKeyDown = function ($event) {
|
$scope.onKeyDown = function ($event) {
|
||||||
@@ -545,7 +568,8 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
$event.altKey,
|
$event.altKey,
|
||||||
$event.shiftKey,
|
$event.shiftKey,
|
||||||
$event.ctrlKey,
|
$event.ctrlKey,
|
||||||
$event.metaKey));
|
$event.metaKey,
|
||||||
|
$scope.trace_id));
|
||||||
}
|
}
|
||||||
$scope.last_event = $event;
|
$scope.last_event = $event;
|
||||||
$scope.last_key = $event.key;
|
$scope.last_key = $event.key;
|
||||||
@@ -653,6 +677,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.onRenameContextButton = function (button) {
|
$scope.onRenameContextButton = function (button) {
|
||||||
|
console.log(button.name);
|
||||||
$scope.context_menus[0].enabled = false;
|
$scope.context_menus[0].enabled = false;
|
||||||
$scope.first_channel.send("LabelEdit", {});
|
$scope.first_channel.send("LabelEdit", {});
|
||||||
};
|
};
|
||||||
@@ -690,14 +715,31 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
console.log(button.name);
|
console.log(button.name);
|
||||||
$scope.recording = ! $scope.recording;
|
$scope.recording = ! $scope.recording;
|
||||||
if ($scope.recording) {
|
if ($scope.recording) {
|
||||||
|
$scope.trace_id = $scope.trace_id_seq();
|
||||||
$scope.send_control_message(new messages.MultipleMessage($scope.client_id,
|
$scope.send_control_message(new messages.MultipleMessage($scope.client_id,
|
||||||
[new messages.StartRecording($scope.client_id),
|
[new messages.StartRecording($scope.client_id, $scope.trace_id),
|
||||||
new messages.ViewPort($scope.client_id,
|
new messages.ViewPort($scope.client_id,
|
||||||
$scope.current_scale,
|
$scope.current_scale,
|
||||||
$scope.panX,
|
$scope.panX,
|
||||||
$scope.panY)]));
|
$scope.panY,
|
||||||
|
$scope.trace_id),
|
||||||
|
new messages.Snapshot($scope.client_id,
|
||||||
|
$scope.devices,
|
||||||
|
$scope.links,
|
||||||
|
$scope.groups,
|
||||||
|
$scope.streams,
|
||||||
|
0,
|
||||||
|
$scope.trace_id)]));
|
||||||
} else {
|
} else {
|
||||||
$scope.send_control_message(new messages.StopRecording($scope.client_id));
|
$scope.send_control_message(new messages.MultipleMessage($scope.client_id,
|
||||||
|
[new messages.Snapshot($scope.client_id,
|
||||||
|
$scope.devices,
|
||||||
|
$scope.links,
|
||||||
|
$scope.groups,
|
||||||
|
$scope.streams,
|
||||||
|
1,
|
||||||
|
$scope.trace_id),
|
||||||
|
new messages.StopRecording($scope.client_id, $scope.trace_id)]));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -789,6 +831,25 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
console.log(button.label);
|
console.log(button.label);
|
||||||
window.open("/network_ui/download_trace?topology_id=" + $scope.topology_id + "&trace_id=" + $scope.trace_id + "&client_id=" + $scope.client_id);
|
window.open("/network_ui/download_trace?topology_id=" + $scope.topology_id + "&trace_id=" + $scope.trace_id + "&client_id=" + $scope.client_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.onDownloadRecordingButton = function (button) {
|
||||||
|
console.log(button.label);
|
||||||
|
window.open("/network_ui/download_recording?topology_id=" + $scope.topology_id + "&trace_id=" + $scope.trace_id + "&client_id=" + $scope.client_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.onUploadTestButton = function (button) {
|
||||||
|
console.log(button.name);
|
||||||
|
window.open("/network_ui/upload_test", "_top");
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.onRunTestsButton = function (button) {
|
||||||
|
console.log(button.name);
|
||||||
|
|
||||||
|
$scope.test_results = [];
|
||||||
|
$scope.current_tests = $scope.tests.slice();
|
||||||
|
$scope.first_channel.send("EnableTest", new messages.EnableTest());
|
||||||
|
};
|
||||||
|
|
||||||
// Buttons
|
// Buttons
|
||||||
var button_offset = 200;
|
var button_offset = 200;
|
||||||
|
|
||||||
@@ -802,6 +863,9 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
new models.Button("CONFIGURE", button_offset + 520, 48, 90, 30, $scope.onConfigureButton, $scope),
|
new models.Button("CONFIGURE", button_offset + 520, 48, 90, 30, $scope.onConfigureButton, $scope),
|
||||||
new models.Button("EXPORT YAML", button_offset + 620, 48, 120, 30, $scope.onExportYamlButton, $scope),
|
new models.Button("EXPORT YAML", button_offset + 620, 48, 120, 30, $scope.onExportYamlButton, $scope),
|
||||||
new models.Button("DOWNLOAD TRACE", button_offset + 750, 48, 150, 30, $scope.onDownloadTraceButton, $scope),
|
new models.Button("DOWNLOAD TRACE", button_offset + 750, 48, 150, 30, $scope.onDownloadTraceButton, $scope),
|
||||||
|
new models.Button("DOWNLOAD RECORDING", button_offset + 910, 48, 170, 30, $scope.onDownloadRecordingButton, $scope),
|
||||||
|
new models.Button("UPLOAD TEST", button_offset + 10, 88, 100, 30, $scope.onUploadTestButton, $scope),
|
||||||
|
new models.Button("RUN TESTS", button_offset + 120, 88, 100, 30, $scope.onRunTestsButton, $scope),
|
||||||
];
|
];
|
||||||
|
|
||||||
var LAYERS_X = 160;
|
var LAYERS_X = 160;
|
||||||
@@ -1429,6 +1493,8 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
//Erase the existing state
|
//Erase the existing state
|
||||||
$scope.devices = [];
|
$scope.devices = [];
|
||||||
$scope.links = [];
|
$scope.links = [];
|
||||||
|
$scope.groups = [];
|
||||||
|
$scope.streams = [];
|
||||||
|
|
||||||
var device_map = {};
|
var device_map = {};
|
||||||
var device_interface_map = {};
|
var device_interface_map = {};
|
||||||
@@ -1634,12 +1700,6 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.send_coverage = function () {
|
|
||||||
console.log("Sending coverage");
|
|
||||||
if (typeof(window.__coverage__) !== "undefined" && window.__coverage__ !== null) {
|
|
||||||
$scope.send_control_message(new messages.Coverage($scope.client_id, window.__coverage__));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
$scope.control_socket.onmessage = function(message) {
|
$scope.control_socket.onmessage = function(message) {
|
||||||
@@ -1743,6 +1803,112 @@ var NetworkUIController = function($scope, $document, $location, $window, $http,
|
|||||||
map.set(key, stream.offset + 1);
|
map.set(key, stream.offset + 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
setInterval( function () {
|
||||||
|
var test_event = null;
|
||||||
|
if ($scope.test_events.length > 0) {
|
||||||
|
test_event = $scope.test_events.shift();
|
||||||
|
console.log(test_event);
|
||||||
|
test_event.sender = 0;
|
||||||
|
try {
|
||||||
|
$scope.first_channel.send(test_event.msg_type, test_event);
|
||||||
|
} catch (err) {
|
||||||
|
$scope.test_errors.push(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$scope.$apply();
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
ConfigService
|
||||||
|
.getConfig()
|
||||||
|
.then(function(config){
|
||||||
|
$scope.version = config.version;
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.reset_coverage = function() {
|
||||||
|
var i = null;
|
||||||
|
var coverage = null;
|
||||||
|
var f = null;
|
||||||
|
if (typeof(window.__coverage__) !== "undefined" && window.__coverage__ !== null) {
|
||||||
|
for (f in window.__coverage__) {
|
||||||
|
coverage = window.__coverage__[f];
|
||||||
|
for (i in coverage.b) {
|
||||||
|
coverage.b[i] = [0, 0];
|
||||||
|
}
|
||||||
|
for (i in coverage.f) {
|
||||||
|
coverage.f[i] = 0;
|
||||||
|
}
|
||||||
|
for (i in coverage.s) {
|
||||||
|
coverage.s[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.reset_flags = function () {
|
||||||
|
$scope.debug = {'hidden': true};
|
||||||
|
$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.view_controller.state = view.Start;
|
||||||
|
$scope.view_controller.state.start($scope.view_controller);
|
||||||
|
$scope.device_detail_controller.state = device_detail_fsm.Start;
|
||||||
|
$scope.device_detail_controller.state.start($scope.device_detail_controller);
|
||||||
|
$scope.move_controller.state = move.Start;
|
||||||
|
$scope.move_controller.state.start($scope.move_controller);
|
||||||
|
$scope.link_controller.state = link.Start;
|
||||||
|
$scope.link_controller.state.start($scope.link_controller);
|
||||||
|
$scope.stream_controller.state = stream_fsm.Start;
|
||||||
|
$scope.stream_controller.state.start($scope.stream_controller);
|
||||||
|
$scope.group_controller.state = group.Start;
|
||||||
|
$scope.group_controller.state.start($scope.group_controller);
|
||||||
|
$scope.rack_controller.state = rack_fsm.Disable;
|
||||||
|
$scope.rack_controller.state.start($scope.rack_controller);
|
||||||
|
$scope.site_controller.state = site_fsm.Disable;
|
||||||
|
$scope.site_controller.state.start($scope.site_controller);
|
||||||
|
$scope.buttons_controller.state = buttons.Start;
|
||||||
|
$scope.buttons_controller.state.start($scope.buttons_controller);
|
||||||
|
$scope.time_controller.state = time.Start;
|
||||||
|
$scope.time_controller.state.start($scope.time_controller);
|
||||||
|
$scope.app_toolbox_controller.state = toolbox_fsm.Start;
|
||||||
|
$scope.app_toolbox_controller.state.start($scope.app_toolbox_controller);
|
||||||
|
$scope.inventory_toolbox_controller.state = toolbox_fsm.Start;
|
||||||
|
$scope.inventory_toolbox_controller.state.start($scope.inventory_toolbox_controller);
|
||||||
|
$scope.rack_toolbox_controller.state = toolbox_fsm.Start;
|
||||||
|
$scope.rack_toolbox_controller.state.start($scope.rack_toolbox_controller);
|
||||||
|
$scope.site_toolbox_controller.state = toolbox_fsm.Start;
|
||||||
|
$scope.site_toolbox_controller.state.start($scope.site_toolbox_controller);
|
||||||
|
$scope.mode_controller.state = mode_fsm.Start;
|
||||||
|
$scope.mode_controller.state.start($scope.mode_controller);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.reset_history = function () {
|
||||||
|
$scope.history = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.reset_toolboxes = function () {
|
||||||
|
$scope.app_toolbox.items = [];
|
||||||
|
$scope.app_toolbox.items.push(new models.Process(0, 'BGP', 'process', 0, 0));
|
||||||
|
$scope.app_toolbox.items.push(new models.Process(0, 'OSPF', 'process', 0, 0));
|
||||||
|
$scope.app_toolbox.items.push(new models.Process(0, 'STP', 'process', 0, 0));
|
||||||
|
$scope.app_toolbox.items.push(new models.Process(0, 'Zero Pipeline', 'process', 0, 0));
|
||||||
|
|
||||||
|
for(i = 0; i < $scope.app_toolbox.items.length; i++) {
|
||||||
|
$scope.app_toolbox.items[i].icon = true;
|
||||||
|
}
|
||||||
|
$scope.inventory_toolbox.items = [];
|
||||||
|
$scope.rack_toolbox.items = [];
|
||||||
|
$scope.site_toolbox.items = [];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.NetworkUIController = NetworkUIController;
|
exports.NetworkUIController = NetworkUIController;
|
||||||
|
|||||||
@@ -116,6 +116,7 @@
|
|||||||
ng-attr-transform="translate({{context_menus[0].x}}, {{context_menus[0].y}})">
|
ng-attr-transform="translate({{context_menus[0].x}}, {{context_menus[0].y}})">
|
||||||
</g>
|
</g>
|
||||||
<g awx-net-debug></g>
|
<g awx-net-debug></g>
|
||||||
|
<g awx-net-test-results></g>
|
||||||
<g awx-net-cursor></g>
|
<g awx-net-cursor></g>
|
||||||
<g ng-repeat="touch in touches">
|
<g ng-repeat="touch in touches">
|
||||||
<g awx-net-touch></g>
|
<g awx-net-touch></g>
|
||||||
|
|||||||
@@ -766,3 +766,8 @@
|
|||||||
.NetworkUI__contextMenuButton-pressed{
|
.NetworkUI__contextMenuButton-pressed{
|
||||||
fill:@button-body-hover;
|
fill:@button-body-hover;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.NetworkUI__test_results {
|
||||||
|
fill: @light-background;
|
||||||
|
stroke: @dark-widget-detail;
|
||||||
|
}
|
||||||
|
|||||||
160
awx/ui/client/src/network-ui/test.fsm.js
Normal file
160
awx/ui/client/src/network-ui/test.fsm.js
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
var inherits = require('inherits');
|
||||||
|
var fsm = require('./fsm.js');
|
||||||
|
var messages = require('./messages.js');
|
||||||
|
var models = require('./models.js');
|
||||||
|
|
||||||
|
function _State () {
|
||||||
|
}
|
||||||
|
inherits(_State, fsm._State);
|
||||||
|
|
||||||
|
|
||||||
|
function _Disabled () {
|
||||||
|
this.name = 'Disabled';
|
||||||
|
}
|
||||||
|
inherits(_Disabled, _State);
|
||||||
|
var Disabled = new _Disabled();
|
||||||
|
exports.Disabled = Disabled;
|
||||||
|
|
||||||
|
function _Start () {
|
||||||
|
this.name = 'Start';
|
||||||
|
}
|
||||||
|
inherits(_Start, _State);
|
||||||
|
var Start = new _Start();
|
||||||
|
exports.Start = Start;
|
||||||
|
|
||||||
|
function _Running () {
|
||||||
|
this.name = 'Running';
|
||||||
|
}
|
||||||
|
inherits(_Running, _State);
|
||||||
|
var Running = new _Running();
|
||||||
|
exports.Running = Running;
|
||||||
|
|
||||||
|
function _Loading () {
|
||||||
|
this.name = 'Loading';
|
||||||
|
}
|
||||||
|
inherits(_Loading, _State);
|
||||||
|
var Loading = new _Loading();
|
||||||
|
exports.Loading = Loading;
|
||||||
|
|
||||||
|
function _Ready () {
|
||||||
|
this.name = 'Ready';
|
||||||
|
}
|
||||||
|
inherits(_Ready, _State);
|
||||||
|
var Ready = new _Ready();
|
||||||
|
exports.Ready = Ready;
|
||||||
|
|
||||||
|
function _Reporting () {
|
||||||
|
this.name = 'Reporting';
|
||||||
|
}
|
||||||
|
inherits(_Reporting, _State);
|
||||||
|
var Reporting = new _Reporting();
|
||||||
|
exports.Reporting = Reporting;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Disabled.prototype.onEnableTest = function (controller) {
|
||||||
|
|
||||||
|
controller.changeState(Ready);
|
||||||
|
};
|
||||||
|
_Disabled.prototype.onEnableTest.transitions = ['Ready'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Start.prototype.start = function (controller) {
|
||||||
|
|
||||||
|
controller.changeState(Disabled);
|
||||||
|
|
||||||
|
};
|
||||||
|
_Start.prototype.start.transitions = ['Disabled'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Running.prototype.onTestCompleted = function (controller) {
|
||||||
|
|
||||||
|
controller.changeState(Reporting);
|
||||||
|
};
|
||||||
|
_Running.prototype.onTestCompleted.transitions = ['Reporting'];
|
||||||
|
|
||||||
|
_Reporting.prototype.start = function (controller) {
|
||||||
|
|
||||||
|
var test_result = null;
|
||||||
|
controller.scope.replay = false;
|
||||||
|
controller.scope.disconnected = false;
|
||||||
|
controller.scope.recording = false;
|
||||||
|
var result = "passed";
|
||||||
|
if (controller.scope.test_errors.length > 0) {
|
||||||
|
result = "errored";
|
||||||
|
}
|
||||||
|
test_result = new models.TestResult(controller.scope.test_result_id_seq(),
|
||||||
|
controller.scope.current_test.name,
|
||||||
|
result,
|
||||||
|
new Date().toISOString(),
|
||||||
|
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));
|
||||||
|
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.changeState(Loading);
|
||||||
|
};
|
||||||
|
_Reporting.prototype.start.transitions = ['Loading'];
|
||||||
|
|
||||||
|
|
||||||
|
_Loading.prototype.start = function (controller) {
|
||||||
|
|
||||||
|
if (controller.scope.current_tests.length === 0) {
|
||||||
|
controller.changeState(Disabled);
|
||||||
|
} else {
|
||||||
|
console.log("Starting test");
|
||||||
|
controller.scope.current_test = controller.scope.current_tests.shift();
|
||||||
|
controller.scope.onSnapshot(controller.scope.current_test.pre_test_snapshot);
|
||||||
|
controller.scope.replay = true;
|
||||||
|
controller.scope.disconnected = true;
|
||||||
|
controller.scope.test_errors = [];
|
||||||
|
controller.scope.test_events = controller.scope.current_test.event_trace.slice();
|
||||||
|
controller.scope.test_events.push(new messages.TestCompleted());
|
||||||
|
controller.scope.reset_coverage();
|
||||||
|
controller.scope.reset_flags();
|
||||||
|
controller.scope.reset_fsm_state();
|
||||||
|
controller.scope.reset_history();
|
||||||
|
controller.scope.reset_toolboxes();
|
||||||
|
controller.changeState(Running);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
_Loading.prototype.start.transitions = ['Running'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Ready.prototype.onDisableTest = function (controller) {
|
||||||
|
|
||||||
|
controller.changeState(Disabled);
|
||||||
|
};
|
||||||
|
_Ready.prototype.onDisableTest.transitions = ['Disabled'];
|
||||||
|
|
||||||
|
_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));
|
||||||
|
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.changeState(Loading);
|
||||||
|
};
|
||||||
|
_Ready.prototype.start.transitions = ['Loading'];
|
||||||
8
awx/ui/client/src/network-ui/test_results.directive.js
Normal file
8
awx/ui/client/src/network-ui/test_results.directive.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/* Copyright (c) 2018 Red Hat, Inc. */
|
||||||
|
|
||||||
|
const templateUrl = require('~network-ui/test_results.partial.svg');
|
||||||
|
|
||||||
|
function test_results () {
|
||||||
|
return { restrict: 'A', templateUrl};
|
||||||
|
}
|
||||||
|
exports.test_results = test_results;
|
||||||
14
awx/ui/client/src/network-ui/test_results.partial.svg
Normal file
14
awx/ui/client/src/network-ui/test_results.partial.svg
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<g ng-if="test_results.length > 0">
|
||||||
|
<g ng-attr-transform="translate({{graph.width - 300}}, {{graph.height-500}})">
|
||||||
|
<rect class="NetworkUI__test_results" width="280" height="480" x="0" y="0">
|
||||||
|
</rect>
|
||||||
|
<g transform="translate(20, 20)">
|
||||||
|
<text class="NetworkUI__text">Test Results {{version}}</text>
|
||||||
|
<g ng-repeat="result in test_results track by $index">
|
||||||
|
<g ng-attr-transform="translate(0, {{$index * 20 + 20}})">
|
||||||
|
<text class="NetworkUI__text">{{result.name}} - {{result.result}}</text>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
@@ -3,6 +3,7 @@ var inherits = require('inherits');
|
|||||||
var fsm = require('./fsm.js');
|
var fsm = require('./fsm.js');
|
||||||
var messages = require('./messages.js');
|
var messages = require('./messages.js');
|
||||||
var util = require('./util.js');
|
var util = require('./util.js');
|
||||||
|
var models = require('./models.js');
|
||||||
|
|
||||||
function _State () {
|
function _State () {
|
||||||
}
|
}
|
||||||
@@ -539,3 +540,23 @@ _Present.prototype.undo = function(controller) {
|
|||||||
controller.changeState(Past);
|
controller.changeState(Past);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
_Present.prototype.onTestCase = function(controller, msg_type, message) {
|
||||||
|
console.log([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.onError = function(controller, msg_type, message) {
|
||||||
|
console.log(["onError", msg_type, message]);
|
||||||
|
throw new Error("ServerError: " + message);
|
||||||
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
var angular = require('angular');
|
var angular = require('angular');
|
||||||
|
|
||||||
var tower = angular.module('tower', ['tablesUI', 'networkUI', 'ui.router']);
|
var tower = angular.module('tower', ['networkUI', 'ui.router']);
|
||||||
|
|
||||||
tower.config(function($stateProvider, $urlRouterProvider) {
|
tower.config(function($stateProvider, $urlRouterProvider) {
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,7 @@
|
|||||||
"html-loader": "^0.5.1",
|
"html-loader": "^0.5.1",
|
||||||
"html-webpack-harddisk-plugin": "^0.1.0",
|
"html-webpack-harddisk-plugin": "^0.1.0",
|
||||||
"html-webpack-plugin": "^2.30.1",
|
"html-webpack-plugin": "^2.30.1",
|
||||||
|
"istanbul-instrumenter-loader": "^3.0.0",
|
||||||
"jasmine-core": "^2.5.2",
|
"jasmine-core": "^2.5.2",
|
||||||
"jshint": "^2.9.4",
|
"jshint": "^2.9.4",
|
||||||
"jshint-stylish": "^2.2.0",
|
"jshint-stylish": "^2.2.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user