Separate OSTF tests running

Closes-bp: https://blueprints.launchpad.net/fuel/+spec/ui-ostf-separate-test-run

Change-Id: I712abb487f990380c2f7c3a82b6403a894fc12ec
This commit is contained in:
astepanchuk 2013-12-10 12:00:38 +02:00 committed by jkirnosova
parent 8e50e545b2
commit fd42047aef
5 changed files with 194 additions and 49 deletions

View File

@ -4126,6 +4126,7 @@ input.input-append {
.healthcheck-table {margin: 0px 0px 30px 0px; } .healthcheck-table {margin: 0px 0px 30px 0px; }
.healthcheck-table th {font-weight: normal;} .healthcheck-table th {font-weight: normal;}
.healthcheck-table th label {margin: 0;} .healthcheck-table th label {margin: 0;}
.healthcheck-table th label.testset-name {font-weight: bold;}
.healthcheck-name {font-size: 15px; margin: 5px 0px 5px 0px;} .healthcheck-name {font-size: 15px; margin: 5px 0px 5px 0px;}
.healthcheck-duration {font-size: 15px; margin: 5px 0px 5px 0px; text-align: center; color: #777777} .healthcheck-duration {font-size: 15px; margin: 5px 0px 5px 0px; text-align: center; color: #777777}
.healthcheck-status {font-size: 20px; margin-top: 3px; text-align: center;} .healthcheck-status {font-size: 20px; margin-top: 3px; text-align: center;}
@ -4136,9 +4137,11 @@ input.input-append {
.healthcheck-status-stopped, .healthcheck-status-unknown, .healthcheck-status-wait_running {color: #999999;} .healthcheck-status-stopped, .healthcheck-status-unknown, .healthcheck-status-wait_running {color: #999999;}
.healthcheck-status-success {color: #2e8701;} .healthcheck-status-success {color: #2e8701;}
.healthcheck-status-failure, .healthcheck-status-error {color: #890000;} .healthcheck-status-failure, .healthcheck-status-error {color: #890000;}
.healthcheck-table .healthcheck-col-select {width: 24px;}
.healthcheck-table .healthcheck-col-status {width: 50px; text-align: center;} .healthcheck-table .healthcheck-col-status {width: 50px; text-align: center;}
.healthcheck-table .healthcheck-col-duration {width: 120px; text-align: center;} .healthcheck-table .healthcheck-col-duration {width: 120px; text-align: center;}
.healthcheck-table th.healthcheck-col-duration, .healthcheck-table th.healthcheck-col-status {padding: 12px 0 12px 0;} .healthcheck-table th {padding-top: 12px; padding-bottom: 12px;}
.healthcheck-table th.healthcheck-col-select {padding-top: 0; padding-bottom: 10px;}
/* Cluster toolbar */ /* Cluster toolbar */
.cluster-toolbar { .cluster-toolbar {

View File

@ -26,39 +26,31 @@ define(
function(utils, models, commonViews, dialogViews, healthcheckTabTemplate, healthcheckTestSetTemplate, healthcheckTestsTemplate) { function(utils, models, commonViews, dialogViews, healthcheckTabTemplate, healthcheckTestSetTemplate, healthcheckTestsTemplate) {
'use strict'; 'use strict';
var HealthCheckTab, TestSet; var HealthCheckTab, TestSet, Test;
HealthCheckTab = commonViews.Tab.extend({ HealthCheckTab = commonViews.Tab.extend({
template: _.template(healthcheckTabTemplate), template: _.template(healthcheckTabTemplate),
updateInterval: 3000, updateInterval: 3000,
events: { events: {
'change input.testset-select': 'testSetSelected',
'change input.select-all-tumbler': 'allTestSetsSelected',
'click .run-tests-btn:not(:disabled)': 'runTests', 'click .run-tests-btn:not(:disabled)': 'runTests',
'click .stop-tests-btn:not(:disabled)': 'stopTests' 'click .stop-tests-btn:not(:disabled)': 'stopTests'
}, },
getNumberOfCheckedTests: function() {
return this.tests.where({checked: true}).length;
},
isLocked: function() { isLocked: function() {
return this.model.get('status') == 'new' || this.hasRunningTests() || !!this.model.task('deploy', 'running') ; return this.model.get('status') == 'new' || this.hasRunningTests() || !!this.model.task('deploy', 'running') ;
}, },
disableControls: function(disable) { disableControls: function(disable) {
this.$('.btn, input').prop('disabled', disable || this.isLocked()); var disabledState = disable || this.isLocked();
this.runTestsButton.set({disabled: disabledState || !this.getNumberOfCheckedTests()});
this.stopTestsButton.set({disabled: !this.hasRunningTests()});
this.selectAllCheckbox.set({disabled: disabledState});
}, },
calculateTestControlButtonsState: function() { toggleTestsVisibility: function() {
var hasRunningTests = this.hasRunningTests(); var hasRunningTests = this.hasRunningTests();
this.$('.run-tests-btn').prop('disabled', !this.$('input.testset-select:checked').length || hasRunningTests).toggle(!hasRunningTests); this.runTestsButton.set({visible: !hasRunningTests});
this.$('.stop-tests-btn').prop('disabled', !hasRunningTests).toggle(hasRunningTests); this.stopTestsButton.set({visible: hasRunningTests});
},
calculateSelectAllTumblerState: function() {
this.$('.select-all-tumbler').prop('checked', this.$('input.testset-select:checked').length == this.$('input.testset-select').length);
},
allTestSetsSelected: function(e) {
var checked = $(e.currentTarget).is(':checked');
this.$('input.testset-select').prop('checked', checked);
this.calculateTestControlButtonsState();
},
testSetSelected: function() {
this.calculateSelectAllTumblerState();
this.calculateTestControlButtonsState();
}, },
getActiveTestRuns: function() { getActiveTestRuns: function() {
return this.testruns.where({status: 'running'}); return this.testruns.where({status: 'running'});
@ -70,36 +62,60 @@ function(utils, models, commonViews, dialogViews, healthcheckTabTemplate, health
if (this.hasRunningTests()) { if (this.hasRunningTests()) {
this.registerDeferred(this.timeout = $.timeout(this.updateInterval).done(_.bind(this.update, this))); this.registerDeferred(this.timeout = $.timeout(this.updateInterval).done(_.bind(this.update, this)));
} }
this.toggleTestsVisibility();
this.disableControls();
}, },
update: function() { update: function() {
this.registerDeferred( this.registerDeferred(
this.testruns.fetch() this.testruns.fetch()
.done(_.bind(function() { .done(_.bind(function() {
if (!this.hasRunningTests()) { if (!this.hasRunningTests()) {
this.$('input[type=checkbox]').prop('checked', false);
this.disableControls(false); this.disableControls(false);
} }
this.calculateTestControlButtonsState();
}, this)) }, this))
.always(_.bind(this.scheduleUpdate, this)) .always(_.bind(this.scheduleUpdate, this))
); );
}, },
runTests: function() { runTests: function() {
this.disableControls(true); this.disableControls(true);
var testruns = new models.TestRuns(); var testruns = new models.TestRuns(),
oldTestruns = new models.TestRuns();
_.each(this.subViews, function(subView) { _.each(this.subViews, function(subView) {
if (subView instanceof TestSet && subView.$('input.testset-select:checked').length) { var selectedTests = subView.tests.where({checked: true});
var testrun = new models.TestRun({ if (selectedTests.length) {
var selectedTestIds = _.pluck(selectedTests, 'id');
var currentTestrun = new models.TestRun({
testset: subView.testset.id, testset: subView.testset.id,
metadata: { metadata: {
config: {}, config: {},
cluster_id: this.model.id cluster_id: this.model.id
} },
tests: selectedTestIds
}); });
testruns.add(testrun); var currentTestForReRun = new models.TestRun({
id: subView.testrun.id,
tests: selectedTestIds,
status: 'restarted'
});
if (this.testruns.length != 0) {
if (this.testruns.where({testset: subView.testset.id}).length) {
oldTestruns.add(currentTestForReRun);
} else {
testruns.add(currentTestrun);
}
} else {
testruns.add(currentTestrun);
}
} }
}, this); }, this);
Backbone.sync('create', testruns).done(_.bind(this.update, this)); var requests = [];
if (testruns.models.length) {
requests.push(Backbone.sync('create', testruns));
}
if (oldTestruns.models.length) {
requests.push(Backbone.sync('update', oldTestruns));
}
$.when.apply($, requests).done(_.bind(this.update, this));
}, },
stopTests: function() { stopTests: function() {
var testruns = new models.TestRuns(this.getActiveTestRuns()); var testruns = new models.TestRuns(this.getActiveTestRuns());
@ -137,9 +153,27 @@ function(utils, models, commonViews, dialogViews, healthcheckTabTemplate, health
}, },
initialize: function(options) { initialize: function(options) {
_.defaults(this, options); _.defaults(this, options);
this.runTestsButton = new Backbone.Model({
visible: true,
disabled: true
});
this.stopTestsButton = new Backbone.Model({
visible: false,
disabled: true
});
this.selectAllCheckbox = new Backbone.Model({
checked: false,
disabled: false
});
this.model.on('change:status', this.render, this); this.model.on('change:status', this.render, this);
this.model.get('tasks').each(this.bindTaskEvents, this); this.model.get('tasks').each(this.bindTaskEvents, this);
this.model.get('tasks').on('add', this.onNewTask, this); this.model.get('tasks').on('add', this.onNewTask, this);
this.selectAllCheckbox.on('change:disabled', _.bind(function(model, value) {
_.each(this.subViews, function(testSetView) {
testSetView.selectAllCheckbox.set({disabled: value});
}, this);
this.tests.invoke('set', {disabled: value});
}, this));
if (!this.model.get('ostf')) { if (!this.model.get('ostf')) {
var ostf = {}; var ostf = {};
ostf.testsets = new models.TestSets(); ostf.testsets = new models.TestSets();
@ -154,7 +188,7 @@ function(utils, models, commonViews, dialogViews, healthcheckTabTemplate, health
this.tests.fetch(), this.tests.fetch(),
this.testruns.fetch() this.testruns.fetch()
).done(_.bind(function() { ).done(_.bind(function() {
this.model.set({'ostf': ostf}, {silent: true}); this.model.set({ostf: ostf}, {silent: true});
this.render(); this.render();
this.scheduleUpdate(); this.scheduleUpdate();
}, this) }, this)
@ -170,6 +204,40 @@ function(utils, models, commonViews, dialogViews, healthcheckTabTemplate, health
} }
this.testruns.on('sync', this.updateTestRuns, this); this.testruns.on('sync', this.updateTestRuns, this);
}, },
initStickitBindings: function() {
var visibleBindings = {
observe: 'visible',
visible: true
};
var disabledBindings = {
attributes: [
{
name: 'disabled',
observe: 'disabled'
}
]
};
this.stickit(this.runTestsButton, {'.run-tests-btn': _.extend({}, visibleBindings, disabledBindings)});
this.stickit(this.stopTestsButton, {'.stop-tests-btn': _.extend({}, visibleBindings, disabledBindings)});
var bindings = {
'.select-all-tumbler': {
observe: 'checked',
onSet: _.bind(function(value) {
_.each(this.subViews, function(testSetView) {
testSetView.selectAllCheckbox.set({checked: value});
});
this.tests.invoke('set', {checked: value});
}, this),
attributes: [
{
name: 'disabled',
observe: 'disabled'
}
]
}
};
this.stickit(this.selectAllCheckbox, bindings);
},
render: function() { render: function() {
this.tearDownRegisteredSubViews(); this.tearDownRegisteredSubViews();
this.$el.html(this.template({cluster: this.model})).i18n(); this.$el.html(this.template({cluster: this.model})).i18n();
@ -186,16 +254,15 @@ function(utils, models, commonViews, dialogViews, healthcheckTabTemplate, health
this.registerSubView(testsetView); this.registerSubView(testsetView);
this.$('.testsets').append(testsetView.render().el); this.$('.testsets').append(testsetView.render().el);
}, this); }, this);
this.disableControls();
} }
this.disableControls(false); this.initStickitBindings();
this.calculateTestControlButtonsState();
return this; return this;
} }
}); });
TestSet = Backbone.View.extend({ TestSet = Backbone.View.extend({
template: _.template(healthcheckTestSetTemplate), template: _.template(healthcheckTestSetTemplate),
testsTemplate: _.template(healthcheckTestsTemplate),
templateHelpers: _.extend(_.pick(utils, 'linebreaks'), {highlightStep: function(text, step) { templateHelpers: _.extend(_.pick(utils, 'linebreaks'), {highlightStep: function(text, step) {
var lines = text.split('\n'); var lines = text.split('\n');
var rx = new RegExp('^\\s*' + step + '\\.'); var rx = new RegExp('^\\s*' + step + '\\.');
@ -206,16 +273,85 @@ function(utils, models, commonViews, dialogViews, healthcheckTabTemplate, health
}); });
return lines.join('\n'); return lines.join('\n');
}}), }}),
calculateSelectAllCheckedState: function() {
this.selectAllCheckbox.set({checked: this.tests.where({checked: true}).length == this.tests.length});
this.tab.selectAllCheckbox.set({checked: this.tab.getNumberOfCheckedTests() == this.tab.tests.length});
},
initialize: function(options) { initialize: function(options) {
_.defaults(this, options); _.defaults(this, options);
this.selectAllCheckbox = new Backbone.Model({
checked: false,
disabled: false
});
this.testrun.on('change', this.renderTests, this); this.testrun.on('change', this.renderTests, this);
this.tests.invoke('set', {disabled: false});
this.tests.on('change:checked', _.bind(function() {
this.calculateSelectAllCheckedState();
this.tab.disableControls();
}, this));
}, },
renderTests: function() { renderTests: function() {
this.$('tbody').html(this.testsTemplate(_.extend({testrun: this.testrun, tests: this.tests}, this.templateHelpers))).i18n(); this.$('tbody').empty();
this.tests.each(function(test, index) {
var testView = new Test({
testset: this,
tab: this.tab,
testrun: this.testrun,
model: test,
testIndex: index
});
this.$('tbody').append(testView.render().el);
}, this);
},
initStickitBindings: function() {
var bindings = {
'.testset-select': {
observe: 'checked',
onSet: _.bind(function(value) {
this.tests.invoke('set', {checked: value});
}, this),
attributes: [{
name: 'disabled',
observe: 'disabled'
}]
}
};
this.stickit(this.selectAllCheckbox, bindings);
}, },
render: function() { render: function() {
this.$el.html(this.template({testset: this.testset})).i18n(); this.$el.html(this.template({testset: this.testset})).i18n();
this.renderTests(); this.renderTests();
this.initStickitBindings();
this.calculateSelectAllCheckedState();
return this;
}
});
Test = Backbone.View.extend({
template: _.template(healthcheckTestsTemplate),
tagName: 'tr',
initStickitBindings: function() {
var bindings = {
'.test-select': {
observe: 'checked',
attributes: [{
name: 'disabled',
observe: 'disabled'
}]
}
};
this.stickit(this.model, bindings);
},
initialize: function(options) {
_.defaults(this, options);
},
render: function() {
this.$el.html(this.template(_.extend({
testrun: this.testrun,
test: this.model,
testIndex: this.testIndex
}, this.testset.templateHelpers))).i18n();
this.initStickitBindings();
return this; return this;
} }
}); });

View File

@ -7,7 +7,7 @@
</label> </label>
</div> </div>
<div class="span2"> <div class="span2">
<button class="btn btn-success pull-right action-btn run-tests-btn" data-i18n="cluster_page.healthcheck_tab.run_tests_button" disabled> </button> <button class="btn btn-success pull-right action-btn run-tests-btn" data-i18n="cluster_page.healthcheck_tab.run_tests_button"></button>
<button class="btn btn-danger pull-right action-btn stop-tests-btn hide" data-i18n="cluster_page.healthcheck_tab.stop_tests_button"></button> <button class="btn btn-danger pull-right action-btn stop-tests-btn hide" data-i18n="cluster_page.healthcheck_tab.stop_tests_button"></button>
</div> </div>
</div> </div>

View File

@ -1,9 +1,17 @@
<% tests.each(function(test) { %>
<% var result = testrun && _.find(testrun.get('tests'), {id: test.id}) %> <% var result = testrun && _.find(testrun.get('tests'), {id: test.id}) %>
<% var status = result && result.status || 'unknown' %> <% var status = result && result.status || 'unknown' %>
<tr> <td class="healthcheck-col-select">
<div class="custom-tumbler">
<label>
<input type="checkbox" class="test-select" id="test-select-<%- test.get('testset') %>-<%= testIndex %>">
<!-- [if !IE |(gte IE 9)]> --><span>&nbsp;</span><!-- <![endif] -->
</label>
</div>
</td>
<td> <td>
<div class="healthcheck-name"><%- test.get('name') %></div> <div class="healthcheck-name">
<label for="test-select-<%- test.get('testset') %>-<%= testIndex %>"><%- test.get('name') %></label>
</div>
<% if (status == 'failure' || status == 'error' || status == 'skipped') { %> <% if (status == 'failure' || status == 'error' || status == 'skipped') { %>
<div class="healthcheck-msg healthcheck-status-failure"> <div class="healthcheck-msg healthcheck-status-failure">
<% if (result && result.message) { %> <% if (result && result.message) { %>
@ -44,5 +52,3 @@
<% } %> <% } %>
</div> </div>
</td> </td>
</tr>
<% }) %>

View File

@ -2,16 +2,16 @@
<table class="table table-bordered healthcheck-table enable-selection"> <table class="table table-bordered healthcheck-table enable-selection">
<thead> <thead>
<tr> <tr>
<th> <th class="healthcheck-col-select">
<label class="parameter-box clearfix">
<div class="parameter-control">
<div class="custom-tumbler"> <div class="custom-tumbler">
<input type="checkbox" class="testset-select" name="<%- testset.id %>" /> <label>
<input type="checkbox" class="testset-select" id="testset-select-<%- testset.id %>">
<!-- [if !IE |(gte IE 9)]> --><span>&nbsp;</span><!-- <![endif] --> <!-- [if !IE |(gte IE 9)]> --><span>&nbsp;</span><!-- <![endif] -->
</div>
</div>
<div class="parameter-name" style="cursor: pointer"><%- testset.get('name') %></div>
</label> </label>
</div>
</th>
<th>
<label class="testset-name" for="testset-select-<%- testset.id %>"><%- testset.get('name') %></label>
</th> </th>
<th class="healthcheck-col-duration" data-i18n="cluster_page.healthcheck_tab.expected_duration"></th> <th class="healthcheck-col-duration" data-i18n="cluster_page.healthcheck_tab.expected_duration"></th>
<th class="healthcheck-col-duration" data-i18n="cluster_page.healthcheck_tab.actual_duration"></th> <th class="healthcheck-col-duration" data-i18n="cluster_page.healthcheck_tab.actual_duration"></th>