mirror of
https://github.com/ansible/awx.git
synced 2026-07-10 07:48:05 -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:
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,
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user