Repository: tez Updated Branches: refs/heads/master 44c660a34 -> c9c7d8099
TEZ-3170. Tez UI 2: Swimlane - Display computed events, event bars & dependencies (sree) Project: http://git-wip-us.apache.org/repos/asf/tez/repo Commit: http://git-wip-us.apache.org/repos/asf/tez/commit/c9c7d809 Tree: http://git-wip-us.apache.org/repos/asf/tez/tree/c9c7d809 Diff: http://git-wip-us.apache.org/repos/asf/tez/diff/c9c7d809 Branch: refs/heads/master Commit: c9c7d80997373f424abba9a0ec6a99b8db983d2b Parents: 44c660a Author: Sreenath Somarajapuram <[email protected]> Authored: Fri Mar 18 15:34:33 2016 +0530 Committer: Sreenath Somarajapuram <[email protected]> Committed: Fri Mar 18 15:34:33 2016 +0530 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../components/em-swimlane-blocking-event.js | 50 +++++++ .../app/components/em-swimlane-event-bar.js | 67 +++++++++ .../webapp/app/components/em-swimlane-event.js | 23 ++- .../components/em-swimlane-process-visual.js | 11 +- .../main/webapp/app/components/em-swimlane.js | 79 ++++++++++ .../main/webapp/app/controllers/dag/swimlane.js | 35 +++++ .../src/main/webapp/app/styles/em-swimlane.less | 58 +++++--- .../components/em-swimlane-blocking-event.hbs | 19 +++ .../components/em-swimlane-event-bar.hbs | 19 +++ .../templates/components/em-swimlane-event.hbs | 4 +- .../components/em-swimlane-process-visual.hbs | 21 ++- .../app/templates/components/em-swimlane.hbs | 5 +- .../webapp/app/templates/dag/index/index.hbs | 1 + .../main/webapp/app/templates/dag/swimlane.hbs | 3 +- tez-ui2/src/main/webapp/app/utils/process.js | 101 +++++++++++++ .../src/main/webapp/app/utils/vertex-process.js | 109 ++++++++++++++ .../em-swimlane-blocking-event-test.js | 78 ++++++++++ .../components/em-swimlane-event-bar-test.js | 43 ++++++ .../components/em-swimlane-event-test.js | 13 +- .../em-swimlane-process-visual-test.js | 15 +- .../integration/components/em-swimlane-test.js | 42 +++++- .../tests/unit/controllers/dag/swimlane-test.js | 45 ++++++ .../webapp/tests/unit/utils/process-test.js | 147 +++++++++++++++++++ .../tests/unit/utils/vertex-process-test.js | 98 +++++++++++++ 25 files changed, 1034 insertions(+), 53 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index f14a2fa..30e4fc6 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1885,6 +1885,7 @@ ALL CHANGES TEZ-642. Fix poms for release. (hitesh) TEZ-643. Change getProgress APIs to return some form of progress and 1.0f once the map or reduce phase complete. (sseth) TEZ-3160. Tez UI 2: Swimlane - Create swimlane page & component (sree) + TEZ-3170. Tez UI 2: Swimlane - Display computed events, event bars & dependencies (sree) Release 0.2.0-incubating: 2013-11-30 http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/app/components/em-swimlane-blocking-event.js ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/app/components/em-swimlane-blocking-event.js b/tez-ui2/src/main/webapp/app/components/em-swimlane-blocking-event.js new file mode 100644 index 0000000..a58ded8 --- /dev/null +++ b/tez-ui2/src/main/webapp/app/components/em-swimlane-blocking-event.js @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Ember from 'ember'; + +export default Ember.Component.extend({ + + process: null, + blocking: null, + events: null, + + classNames: ["em-swimlane-blocking-event"], + + blockingEvent: Ember.computed("events.length", "process.blockingEventName", function () { + var events = this.get("events"), + blockingEventName = this.get("process.blockingEventName"); + + return events.find(function (event) { + return event.name === blockingEventName; + }); + }), + + didInsertElement: Ember.observer("blockingEvent", function () { + var blockerEventHeight = (this.get("blocking.index") - this.get("process.index")) * 30; + + this.$().css({ + "left": this.get("blockingEvent.pos") + "%" + }); + this.$(".event-line").css({ + "height": `${blockerEventHeight}px`, + "border-color": this.get("process").getColor() + }); + }), + +}); http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/app/components/em-swimlane-event-bar.js ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/app/components/em-swimlane-event-bar.js b/tez-ui2/src/main/webapp/app/components/em-swimlane-event-bar.js new file mode 100644 index 0000000..e0e835e --- /dev/null +++ b/tez-ui2/src/main/webapp/app/components/em-swimlane-event-bar.js @@ -0,0 +1,67 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Ember from 'ember'; + +export default Ember.Component.extend({ + + process: null, + events: [], + + bars: [], + bar: null, + barIndex: 0, + + classNames: ["em-swimlane-event-bar"], + + fromEvent: Ember.computed("events.length", "bar.fromEvent", function () { + var events = this.get("events"), + fromEventName = this.get("bar.fromEvent"); + return events.find(function (event) { + return event.name === fromEventName; + }); + }), + toEvent: Ember.computed("events.length", "bar.toEvent", function () { + var events = this.get("events"), + toEventName = this.get("bar.toEvent"); + return events.find(function (event) { + return event.name === toEventName; + }); + }), + + didInsertElement: Ember.observer("fromEvent.pos", "toEvent.pos", "barIndex", function () { + var fromEventPos = this.get("fromEvent.pos"), + toEventPos = this.get("toEvent.pos"), + color = this.get("bar.color") || + this.get("process").getColor(1 - (this.get("barIndex") / this.get("bars.length"))); + + if(fromEventPos && toEventPos) { + this.$().show(); + this.$(".event-bar").css({ + left: fromEventPos + "%", + right: (100 - toEventPos) + "%", + "background-color": color, + "border-color": this.get("process").getColor() + }); + } + else { + this.$().hide(); + } + }) + +}); http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/app/components/em-swimlane-event.js ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/app/components/em-swimlane-event.js b/tez-ui2/src/main/webapp/app/components/em-swimlane-event.js index a292085..5eb6f0a 100644 --- a/tez-ui2/src/main/webapp/app/components/em-swimlane-event.js +++ b/tez-ui2/src/main/webapp/app/components/em-swimlane-event.js @@ -20,14 +20,25 @@ import Ember from 'ember'; export default Ember.Component.extend({ - title: null, - position: 0, - time: 0, + process: null, + event: null, classNames: ["em-swimlane-event"], - didInsertElement: Ember.observer("position", function () { - this.$().css("left", this.get("position") + "%"); - }) + didInsertElement: Ember.observer("event.pos", function () { + var color = this.get("process").getColor(); + + this.$().css({ + "left": this.get("event.pos") + "%" + }); + this.$(".event-line").css("border-color", color); + this.$(".event-bubble").css("border-color", color); + }), + + actions: { + showTooltip: function () { + console.log(this.get("event.name")); + } + } }); http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/app/components/em-swimlane-process-visual.js ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/app/components/em-swimlane-process-visual.js b/tez-ui2/src/main/webapp/app/components/em-swimlane-process-visual.js index b21eadb..5942cf1 100644 --- a/tez-ui2/src/main/webapp/app/components/em-swimlane-process-visual.js +++ b/tez-ui2/src/main/webapp/app/components/em-swimlane-process-visual.js @@ -26,17 +26,18 @@ export default Ember.Component.extend({ endTime: 0, timeWindow: 0, - events: [], + normalizedEvents: [], startEvent: null, endEvent: null, + eventBars: [], classNames: ["em-swimlane-process-visual"], didInsertElement: function () { Ember.run.later(this, "normalizeEvents"); }, - normalizeEvents: Ember.observer("[email protected]", "startTime", "timeWindow", function () { + normalizeEvents: Ember.observer("[email protected]", "startTime", "timeWindow", function () { var events = Ember.get(this.get("process"), "events") || [], startEvent, endEvent, @@ -45,8 +46,7 @@ export default Ember.Component.extend({ timeWindow = this.get("timeWindow"); events = events.map(function (event) { - var position = ((event.timestamp - startTime) / timeWindow) * 100; - + var position = ((event.time - startTime) / timeWindow) * 100; event = { name: event.name, text: event.text || event.name, @@ -65,7 +65,7 @@ export default Ember.Component.extend({ }); this.setProperties({ - events: events, + normalizedEvents: events, startEvent: startEvent, endEvent: endEvent }); @@ -75,6 +75,7 @@ export default Ember.Component.extend({ this.$(".event-window-line").css({ left: this.get("startEvent.pos") + "%", right: (100 - this.get("endEvent.pos")) + "%", + "background-color": this.get("process").getColor() }); }) http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/app/components/em-swimlane.js ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/app/components/em-swimlane.js b/tez-ui2/src/main/webapp/app/components/em-swimlane.js index 93a2cff..3f22c50 100644 --- a/tez-ui2/src/main/webapp/app/components/em-swimlane.js +++ b/tez-ui2/src/main/webapp/app/components/em-swimlane.js @@ -19,6 +19,18 @@ import Ember from 'ember'; import ProcessDefinition from '../utils/process-definition'; +import Process from '../utils/process'; + +function getVibrantHSL(colorNum, totalColors) { + if (totalColors < 1){ + totalColors = 1; + } + return { + h: colorNum * (360 / totalColors) % 360, + s: 100 - (colorNum % 2) * 30, + l: 40 + }; +} export default Ember.Component.extend({ @@ -30,8 +42,75 @@ export default Ember.Component.extend({ startTime: null, endTime: null, + eventBars: [], + timeWindow: Ember.computed("startTime", "endTime", function () { return Math.max(0, this.get("endTime") - this.get("startTime")); + }), + + normalizedProcesses: Ember.computed("[email protected]", function () { + var processes = this.get("processes"), + processCount = processes.length, + normalizedProcesses, + idHash = {}, + containsBlockers = false; + + // Validate and reset blocking + processes.forEach(function (process) { + if(!(process instanceof Process)) { + Ember.Logger.error("em-swimlane : Unknown type, must be of type Process"); + } + + if(process.get("blockers.length")) { + containsBlockers = true; + } + process.set("blocking", Ember.A()); + }); + + if(containsBlockers) { + normalizedProcesses = []; + + // Recreate blocking list + processes.forEach(function (process) { + var blockers = process.get("blockers"); + if(blockers) { + blockers.forEach(function (blocker) { + blocker.get("blocking").push(process); + }); + } + }); + + // Give an array of the processes in blocking order + processes.forEach(function (process) { + if(process.get("blocking.length") === 0) { // The root processes + normalizedProcesses.push(process); + normalizedProcesses.push.apply(normalizedProcesses, process.getAllBlockers()); + } + }); + normalizedProcesses.reverse(); + normalizedProcesses = normalizedProcesses.filter(function (process, index) { + // Filters out the recurring processes in the list (after graph traversal), we just + // need the top processes + var id = process.get("_id"); + if(idHash[id] === undefined) { + idHash[id] = index; + } + return idHash[id] === index; + }); + } + else { + normalizedProcesses = processes; + } + + // Set process colors & index + normalizedProcesses.forEach(function (process, index) { + process.setProperties({ + color: getVibrantHSL(index, processCount), + index: index + }); + }); + + return Ember.A(normalizedProcesses); }) }); http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/app/controllers/dag/swimlane.js ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/app/controllers/dag/swimlane.js b/tez-ui2/src/main/webapp/app/controllers/dag/swimlane.js index 1028a2c..1699708 100644 --- a/tez-ui2/src/main/webapp/app/controllers/dag/swimlane.js +++ b/tez-ui2/src/main/webapp/app/controllers/dag/swimlane.js @@ -20,6 +20,7 @@ import Ember from 'ember'; import MultiTableController from '../multi-table'; import ColumnDefinition from 'em-table/utils/column-definition'; +import VertexProcess from '../../utils/vertex-process'; import fullscreen from 'em-tgraph/utils/fullscreen'; @@ -40,4 +41,38 @@ export default MultiTableController.extend({ } }, + processes: Ember.computed("model", function () { + var processes = [], + processHash = {}, + + dagPlanEdges = this.get("model.firstObject.dag.edges"); + + // Create process instances for each vertices + this.get("model").forEach(function (vertex) { + var process = VertexProcess.create({ + vertex: vertex, + blockers: Ember.A() + }); + processHash[vertex.get("name")] = process; + processes.push(process); + }); + + // Add process(vertex) dependencies based on dagPlan + dagPlanEdges.forEach(function (edge) { + var process = processHash[edge.outputVertexName]; + if(process) { + process.blockers.push(processHash[edge.inputVertexName]); + } + }); + + return Ember.A(processes); + }), + + eventBars: [{ + fromEvent: "VERTEX_TASK_START", + toEvent: "VERTEX_TASK_FINISH", + }, { + fromEvent: "BLOCKING_VERTICES_COMPLETE", + toEvent: "VERTEX_TASK_FINISH", + }] }); http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/app/styles/em-swimlane.less ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/app/styles/em-swimlane.less b/tez-ui2/src/main/webapp/app/styles/em-swimlane.less index 5087e8f..a982712 100644 --- a/tez-ui2/src/main/webapp/app/styles/em-swimlane.less +++ b/tez-ui2/src/main/webapp/app/styles/em-swimlane.less @@ -25,14 +25,13 @@ .process-names { width: 100px; + border-right: 1px solid @border-color; } .process-visuals { position: absolute; left: 100px; right: 0px; top: 0px; - - border-left: 1px solid @border-color; } } @@ -52,20 +51,32 @@ position: relative; height: 30px; + margin-left: 10px; + cursor: pointer; .base-line { position: relative; height: 1px; + margin-left: -10px; top: unit(unit(@process-height) * 0.5, get-unit(@process-height)); border-top: 1px dotted @border-color; } .event-window-line { position: absolute; - top: unit(unit(@process-height) * 0.5, get-unit(@process-height)); - border-top: 1px solid; - height: 1px; + top: unit(unit(@process-height) * 0.5 - 1, get-unit(@process-height)); + height: 3px; + } + + .event-bar { + position: absolute; + top: unit((unit(@process-height) * 0.5) - 10, get-unit(@process-height)); + height: 20px; + background-color: @border-lite; + border-radius: 2px; + border: 1px solid; + margin-right: -1px; } } @@ -73,10 +84,10 @@ position: absolute; top: unit(unit(@process-height) * 0.5, get-unit(@process-height)); - .event-bar { + .event-line { position: absolute; - top: -10px; - height: 20px; + top: -9px; + height: 18px; border-left: 1px solid; } @@ -87,23 +98,36 @@ bottom: 0; left: 0; - -webkit-transition: top .2s, right .2s, bottom .2s, left .2s; /* Safari */ - transition: top .2s, right .2s, bottom .2s, left .2s; - transition-timing-function: cubic-bezier(.87,-.41,.19,1.44); + -webkit-transition: top .2s, right .2s, bottom .2s, left .2s, border-width .2s; /* Safari */ + transition: top .2s, right .2s, bottom .2s, left .2s, border-width .2s; + transition-timing-function: cubic-bezier(1.44); - border-radius: 5px; + border-radius: 7px; + border: 0px solid; + background-color: white; + } +} + +.em-swimlane-blocking-event { + position: absolute; + top: unit(unit(@process-height) * 0.5, get-unit(@process-height)); - background-color: black; + .event-line { + position: absolute; + top: 0px; + border-left: 1px solid; } } .em-swimlane-process-visual { &:hover { .event-bubble { - top: -5px; - right: -6px; - bottom: -6px; - left: -5px; + top: -7px; + right: -8px; + bottom: -8px; + left: -7px; + + border: 2px solid; } } } http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-blocking-event.hbs ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-blocking-event.hbs b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-blocking-event.hbs new file mode 100644 index 0000000..0fabd16 --- /dev/null +++ b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-blocking-event.hbs @@ -0,0 +1,19 @@ +{{! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +}} + +<div class="event-line"></div> http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-event-bar.hbs ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-event-bar.hbs b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-event-bar.hbs new file mode 100644 index 0000000..b2cc9bd --- /dev/null +++ b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-event-bar.hbs @@ -0,0 +1,19 @@ +{{! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +}} + +<div class="event-bar"></div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-event.hbs ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-event.hbs b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-event.hbs index 0211466..9b6330f 100644 --- a/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-event.hbs +++ b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-event.hbs @@ -16,5 +16,5 @@ * limitations under the License. }} -<div class="event-bar"></div> -<div class="event-bubble"></div> \ No newline at end of file +<div class="event-line"></div> +<div class="event-bubble" {{action "showTooltip" on="mouseEnter"}}></div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-process-visual.hbs ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-process-visual.hbs b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-process-visual.hbs index 6a3a7b9..6e4603d 100644 --- a/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-process-visual.hbs +++ b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-process-visual.hbs @@ -17,11 +17,18 @@ }} <div class="base-line"></div> -{{#each events as |event|}} - {{em-swimlane-event - title=event.text - position=event.pos - time=event.time - }} +<div class="event-window-line"></div> +{{#each process.blocking as |blocking|}} + {{em-swimlane-blocking-event process=process blocking=blocking events=normalizedEvents}} +{{/each}} +{{#each eventBars as |bar index|}} + {{em-swimlane-event-bar + events=normalizedEvents + bar=bar + barIndex=index + bars=eventBars + process=process}} +{{/each}} +{{#each normalizedEvents as |event|}} + {{em-swimlane-event process=process event=event}} {{/each}} -<div class="event-window-line"></div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/app/templates/components/em-swimlane.hbs ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/app/templates/components/em-swimlane.hbs b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane.hbs index a9ab876..a4777f0 100644 --- a/tez-ui2/src/main/webapp/app/templates/components/em-swimlane.hbs +++ b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane.hbs @@ -17,14 +17,15 @@ }} <div class="process-names"> - {{#each processes as |process|}} + {{#each normalizedProcesses as |process|}} {{em-swimlane-process-name process=process definition=processDefinition}} {{/each}} </div><div class="process-visuals"> - {{#each processes as |process|}} + {{#each normalizedProcesses as |process|}} {{em-swimlane-process-visual process=process definition=processDefinition + eventBars=eventBars startTime=startTime endTime=endTime timeWindow=timeWindow http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/app/templates/dag/index/index.hbs ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/app/templates/dag/index/index.hbs b/tez-ui2/src/main/webapp/app/templates/dag/index/index.hbs index 02c88da..c6864fb 100644 --- a/tez-ui2/src/main/webapp/app/templates/dag/index/index.hbs +++ b/tez-ui2/src/main/webapp/app/templates/dag/index/index.hbs @@ -68,6 +68,7 @@ enableSearch=false enablePagination=false + rowCount=model.length searchAction="searchChanged" sortAction="sortChanged" rowAction="rowCountChanged" http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/app/templates/dag/swimlane.hbs ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/app/templates/dag/swimlane.hbs b/tez-ui2/src/main/webapp/app/templates/dag/swimlane.hbs index adb8586..a2b2cbe 100644 --- a/tez-ui2/src/main/webapp/app/templates/dag/swimlane.hbs +++ b/tez-ui2/src/main/webapp/app/templates/dag/swimlane.hbs @@ -25,7 +25,8 @@ {{em-swimlane columns=visibleColumns - processes=model + processes=processes + eventBars=eventBars startTime=model.firstObject.dag.startTime endTime=model.firstObject.dag.endTime }} http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/app/utils/process.js ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/app/utils/process.js b/tez-ui2/src/main/webapp/app/utils/process.js new file mode 100644 index 0000000..eba3e72 --- /dev/null +++ b/tez-ui2/src/main/webapp/app/utils/process.js @@ -0,0 +1,101 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +import Ember from 'ember'; + +var processIndex = 1; + +export default Ember.Object.extend({ + _id: null, + + name: null, + events: null, + + index: 0, + color: null, + + blockers: null, // Array of processes that's blocking the current process + blocking: null, // Array of processes blocked by the current process + + init: function () { + this.set("_id", `process-id-${processIndex}`); + processIndex++; + }, + + getColor: function (lightnessFactor) { + var color = this.get("color"), + l; + + if(!color) { + return "#0"; + } + l = color.l; + if(lightnessFactor !== undefined) { + l += 5 + 25 * lightnessFactor; + } + return `hsl( ${color.h}, ${color.s}%, ${l}% )`; + }, + + startEvent: Ember.computed("[email protected]", function () { + var events = this.get("events"), + startEvent; + if(events) { + startEvent = events[0]; + events.forEach(function (event) { + if(startEvent.time > event.time) { + startEvent = event; + } + }); + } + return startEvent; + }), + + endEvent: Ember.computed("[email protected]", function () { + var events = this.get("events"), + endEvent; + if(events) { + endEvent = events[events.length - 1]; + events.forEach(function (event) { + if(endEvent.time < event.time) { + endEvent = event; + } + }); + } + return endEvent; + }), + + getAllBlockers: function (parentHash) { + var blockers = [], + currentId = this.get("_id"); + + parentHash = parentHash || {}; // To keep a check on cyclic blockers + + parentHash[currentId] = true; + if(this.get("blockers.length")) { + this.get("blockers").forEach(function (blocker) { + if(!parentHash[blocker.get("_id")]) { + blockers.push(blocker); + blockers.push.apply(blockers, blocker.getAllBlockers(parentHash)); + } + }); + } + parentHash[currentId] = false; + + return blockers; + } + +}); http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/app/utils/vertex-process.js ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/app/utils/vertex-process.js b/tez-ui2/src/main/webapp/app/utils/vertex-process.js new file mode 100644 index 0000000..e48532d --- /dev/null +++ b/tez-ui2/src/main/webapp/app/utils/vertex-process.js @@ -0,0 +1,109 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +import Ember from 'ember'; + +import Process from './process'; + +const EVENT_TEXTS = { + VERTEX_INITIALIZED: "Initialized", + VERTEX_STARTED: "Started", + VERTEX_FINISHED: "Finished", + VERTEX_TASK_START: "First Task Start", + VERTEX_TASK_FINISH: "All Tasks Complete", + BLOCKING_VERTICES_COMPLETE: "All Blocking Vertices Complete" +}; + +export default Process.extend({ + vertex: null, + + name: Ember.computed.oneWay("vertex.name"), + completeTime: Ember.computed.oneWay("vertex.endTime"), + + blockingEventName: "VERTEX_FINISHED", + + events: Ember.computed( + "[email protected]", + "vertex.firstTaskStartTime", + "vertex.lastTaskFinishTime", + "unblockTime", + function () { + var events = this.get("vertex.events").map(function (event) { + return { + name: event.eventtype, + test: EVENT_TEXTS[event.eventtype], + time: event.timestamp + }; + }), + firstTaskStartTime = this.get("vertex.firstTaskStartTime"), + lastTaskFinishTime = this.get("vertex.lastTaskFinishTime"), + unblockTime = this.get("unblockTime"); + + if(firstTaskStartTime) { + let type = "VERTEX_TASK_START"; + events.push({ + name: type, + test: EVENT_TEXTS[type], + time: firstTaskStartTime + }); + } + + if(lastTaskFinishTime) { + let type = "VERTEX_TASK_FINISH"; + events.push({ + name: type, + test: EVENT_TEXTS[type], + time: lastTaskFinishTime + }); + } + + if(unblockTime && unblockTime >= firstTaskStartTime) { + let type = "BLOCKING_VERTICES_COMPLETE"; + events.push({ + name: type, + test: EVENT_TEXTS[type], + time: unblockTime + }); + } + + return events; + } + ), + + unblockTime: Ember.computed("[email protected]", function () { + var blockers = this.get("blockers"), + time; + + if(blockers) { + time = 0; + for(var i = 0, length = blockers.length; i < length; i++) { + let blockerComplete = blockers[i].get("completeTime"); + + if(!blockerComplete) { + time = undefined; + break; + } + else if(blockerComplete > time) { + time = blockerComplete; + } + } + } + + return time; + }), + +}); http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-blocking-event-test.js ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-blocking-event-test.js b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-blocking-event-test.js new file mode 100644 index 0000000..3ffab01 --- /dev/null +++ b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-blocking-event-test.js @@ -0,0 +1,78 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; + +import Process from 'tez-ui/utils/process'; + +moduleForComponent('em-swimlane-blocking-event', 'Integration | Component | em swimlane blocking event', { + integration: true +}); + +test('Basic creation test', function(assert) { + this.set("process", Process.create()); + this.set("events", []); + + this.render(hbs`{{em-swimlane-blocking-event process=process events=events}}`); + + assert.equal(this.$().text().trim(), ''); + + // Template block usage:" + EOL + + this.render(hbs` + {{#em-swimlane-blocking-event process=process events=events}} + template block text + {{/em-swimlane-blocking-event}} + `); + + assert.equal(this.$().text().trim(), ''); +}); + +test('Blocking test', function(assert) { + var blockingEventName = "blockingEvent", + processIndex = 5, + blockingIndex = 7, + processColor = "#123456"; + + this.set("process", Process.create({ + blockingEventName: blockingEventName, + index: processIndex, + getColor: function () { + return processColor; + }, + events: [] + })); + this.set("normalizedEvents", [{ + name: "e1", + pos: 10 + }, { + name: blockingEventName, + pos: 20 + }, { + name: "e2", + pos: 30 + }]); + this.set("blocking", Process.create({ + index: blockingIndex + })); + + this.render(hbs`{{em-swimlane-blocking-event process=process events=normalizedEvents blocking=blocking}}`); + + assert.equal(this.$(".em-swimlane-blocking-event").attr("style").trim(), 'left: 20%;'); + assert.equal(this.$(".event-line").css("height"), ((blockingIndex - processIndex) * 30) + "px"); +}); http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-bar-test.js ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-bar-test.js b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-bar-test.js new file mode 100644 index 0000000..d05924f --- /dev/null +++ b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-bar-test.js @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; + +import Process from 'tez-ui/utils/process'; + +moduleForComponent('em-swimlane-event-bar', 'Integration | Component | em swimlane event bar', { + integration: true +}); + +test('Basic creation test', function(assert) { + this.set("process", Process.create()); + + this.render(hbs`{{em-swimlane-event-bar process=process}}`); + + assert.equal(this.$().text().trim(), ''); + + // Template block usage:" + EOL + + this.render(hbs` + {{#em-swimlane-event-bar process=process}} + template block text + {{/em-swimlane-event-bar}} + `); + + assert.equal(this.$().text().trim(), ''); +}); http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-test.js ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-test.js b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-test.js index 9e9764e..034d288 100644 --- a/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-test.js +++ b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-test.js @@ -19,6 +19,8 @@ import { moduleForComponent, test } from 'ember-qunit'; import hbs from 'htmlbars-inline-precompile'; +import Process from 'tez-ui/utils/process'; + import wait from 'ember-test-helpers/wait'; moduleForComponent('em-swimlane-event', 'Integration | Component | em swimlane event', { @@ -26,15 +28,16 @@ moduleForComponent('em-swimlane-event', 'Integration | Component | em swimlane e }); test('Basic creation test', function(assert) { + this.set("process", Process.create({})); - this.render(hbs`{{em-swimlane-event}}`); + this.render(hbs`{{em-swimlane-event process=process}}`); assert.ok(this.$(".event-bar")); assert.ok(this.$(".event-window")); // Template block usage:" + EOL + this.render(hbs` - {{#em-swimlane-event}} + {{#em-swimlane-event process=process}} template block text {{/em-swimlane-event}} `); @@ -44,8 +47,12 @@ test('Basic creation test', function(assert) { }); test('Event position test', function(assert) { + this.set("process", Process.create()); + this.set("event", { + pos: 60 + }); - this.render(hbs`{{em-swimlane-event position=60}}`); + this.render(hbs`{{em-swimlane-event process=process event=event}}`); return wait().then(() => { assert.equal(this.$(".em-swimlane-event").attr("style").trim(), "left: 60%;", "em-swimlane-event"); http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-process-visual-test.js ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-process-visual-test.js b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-process-visual-test.js index 5a180bb..ffc7b56 100644 --- a/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-process-visual-test.js +++ b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-process-visual-test.js @@ -21,14 +21,14 @@ import hbs from 'htmlbars-inline-precompile'; import wait from 'ember-test-helpers/wait'; +import Process from 'tez-ui/utils/process'; + moduleForComponent('em-swimlane-process-visual', 'Integration | Component | em swimlane process visual', { integration: true }); test('Basic creation test', function(assert) { - this.set("process", { - events: [] - }); + this.set("process", Process.create()); this.render(hbs`{{em-swimlane-process-visual process=process}}`); @@ -47,19 +47,20 @@ test('Basic creation test', function(assert) { }); test('Events test', function(assert) { - this.set("process", { + this.set("process", Process.create({ events: [{ - timestamp: 5 + time: 5 }, { - timestamp: 7 + time: 7 }] - }); + })); this.render(hbs`{{em-swimlane-process-visual process=process startTime=0 timeWindow=10}}`); return wait().then(() => { var events = this.$(".em-swimlane-event"); + assert.equal(events.length, 2); assert.equal(events.eq(0).attr("style").trim(), "left: 50%;", "em-swimlane-event 1 left"); assert.equal(events.eq(1).attr("style").trim(), "left: 70%;", "em-swimlane-event 2 left"); http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-test.js ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-test.js b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-test.js index 1e4c938..59e543d 100644 --- a/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-test.js +++ b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-test.js @@ -19,6 +19,8 @@ import { moduleForComponent, test } from 'ember-qunit'; import hbs from 'htmlbars-inline-precompile'; +import Process from 'tez-ui/utils/process'; + moduleForComponent('em-swimlane', 'Integration | Component | em swimlane', { integration: true }); @@ -27,11 +29,11 @@ test('Basic creation test', function(assert) { var testName1 = "TestName1", testName2 = "TestName2"; - this.set("processes", [{ + this.set("processes", [Process.create({ name: testName1 - }, { + }), Process.create({ name: testName2 - }]); + })]); this.render(hbs`{{em-swimlane processes=processes}}`); @@ -48,3 +50,37 @@ test('Basic creation test', function(assert) { assert.equal(this.$().text().trim().indexOf(testName1), 0); assert.notEqual(this.$().text().trim().indexOf(testName2), -1); }); + +test('Normalization (Blocker based sorting) test - On a graph', function(assert) { + var p1 = Process.create({ + name: "P1" + }), + p2 = Process.create({ + name: "P2" + }), + p3 = Process.create({ + name: "P3", + blockers: [p1, p2] + }), + p4 = Process.create({ + name: "P4", + blockers: [p1] + }), + p5 = Process.create({ + name: "P5", + blockers: [p3, p4] + }); + + this.set("processes", [p5, p4, p3, p2, p1]); + + this.render(hbs`{{em-swimlane processes=processes}}`); + + let names = this.$(".em-swimlane-process-name"); + + assert.equal(names.length, 5); + assert.equal(names.eq(0).text().trim(), p1.name); + assert.equal(names.eq(1).text().trim(), p4.name); + assert.equal(names.eq(2).text().trim(), p2.name); + assert.equal(names.eq(3).text().trim(), p3.name); + assert.equal(names.eq(4).text().trim(), p5.name); +}); http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/tests/unit/controllers/dag/swimlane-test.js ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/tests/unit/controllers/dag/swimlane-test.js b/tez-ui2/src/main/webapp/tests/unit/controllers/dag/swimlane-test.js index 7886251..3013a23 100644 --- a/tez-ui2/src/main/webapp/tests/unit/controllers/dag/swimlane-test.js +++ b/tez-ui2/src/main/webapp/tests/unit/controllers/dag/swimlane-test.js @@ -38,4 +38,49 @@ test('Basic creation test', function(assert) { assert.ok(controller); assert.ok(controller.breadcrumbs); assert.ok(controller.columns); + assert.ok(controller.processes); + assert.ok(controller.eventBars); +}); + +test('Process test', function(assert) { + + var vertices = [Ember.Object.create({ + name: "v1" + }), Ember.Object.create({ + name: "v2" + }), Ember.Object.create({ + name: "v3" + }), Ember.Object.create({ + name: "v4" + })]; + vertices.firstObject = { + dag: { + edges: [{ + inputVertexName: "v1", + outputVertexName: "v3" + }, { + inputVertexName: "v2", + outputVertexName: "v3" + }, { + inputVertexName: "v3", + outputVertexName: "v4" + }] + } + }; + + let controller = this.subject({ + send: Ember.K, + beforeSort: {bind: Ember.K}, + initVisibleColumns: Ember.K, + getCounterColumns: function () { + return []; + }, + model: vertices + }); + + var processes = controller.get("processes"); + + assert.equal(processes[2].blockers[0].vertex, vertices[0]); + assert.equal(processes[2].blockers[1].vertex, vertices[1]); + assert.equal(processes[3].blockers[0].vertex, vertices[2]); }); http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/tests/unit/utils/process-test.js ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/tests/unit/utils/process-test.js b/tez-ui2/src/main/webapp/tests/unit/utils/process-test.js new file mode 100644 index 0000000..ffab868 --- /dev/null +++ b/tez-ui2/src/main/webapp/tests/unit/utils/process-test.js @@ -0,0 +1,147 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Process from '../../../utils/process'; +import { module, test } from 'qunit'; + +module('Unit | Utility | process'); + +test('Basic creation test', function(assert) { + let process = Process.create(); + + assert.ok(process); + assert.ok(process.getColor); + assert.ok(process.startEvent); + assert.ok(process.endEvent); + assert.ok(process.getAllBlockers); +}); + +test('getColor test', function(assert) { + let process = Process.create(); + + assert.equal(process.getColor(), "#0"); + + process.set("color", { + h: 10, + s: 20, + l: 30 + }); + assert.equal(process.getColor(), "hsl( 10, 20%, 30% )"); + assert.equal(process.getColor(0.2), "hsl( 10, 20%, 40% )"); +}); + +test('startEvent test', function(assert) { + let process = Process.create(); + + assert.equal(process.get("startEvent"), undefined); + + process.set("events", [{ + time: 50, + }, { + time: 70, + }, { + time: 20, + }, { + time: 80, + }]); + assert.equal(process.get("startEvent").time, 20); + + process.set("events", [{ + time: 50, + }, { + time: 70, + }, { + time: 80, + }]); + assert.equal(process.get("startEvent").time, 50); +}); + +test('endEvent test', function(assert) { + let process = Process.create(); + + assert.equal(process.get("endEvent"), undefined); + + process.set("events", [{ + time: 50, + }, { + time: 70, + }, { + time: 20, + }, { + time: 80, + }]); + assert.equal(process.get("endEvent").time, 80); + + process.set("events", [{ + time: 50, + }, { + time: 70, + }, { + time: 20, + }]); + assert.equal(process.get("endEvent").time, 70); +}); + +test('getAllBlockers test', function(assert) { + var cyclicProcess = Process.create({ + name: "p3", + }); + cyclicProcess.blockers = [cyclicProcess]; + + var multiLevelCycle1 = Process.create({ + name: "p5", + }); + var multiLevelCycle2 = Process.create({ + name: "p6", + }); + multiLevelCycle1.blockers = [multiLevelCycle2]; + multiLevelCycle2.blockers = [multiLevelCycle1]; + + var process = Process.create({ + blockers: [Process.create({ + name: "p1" + }), Process.create({ + name: "p2", + blockers: [Process.create({ + name: "p21" + }), Process.create({ + name: "p22", + blockers: [Process.create({ + name: "p221" + })] + })] + }), cyclicProcess, Process.create({ + name: "p4" + }), multiLevelCycle1] + }); + + var all = process.getAllBlockers(); + + assert.equal(all.length, 9); + + assert.equal(all[0].get("name"), "p1"); + assert.equal(all[1].get("name"), "p2"); + assert.equal(all[2].get("name"), "p21"); + assert.equal(all[3].get("name"), "p22"); + assert.equal(all[4].get("name"), "p221"); + assert.equal(all[5].get("name"), "p3"); + assert.equal(all[6].get("name"), "p4"); + assert.equal(all[7].get("name"), "p5"); + assert.equal(all[8].get("name"), "p6"); + +}); http://git-wip-us.apache.org/repos/asf/tez/blob/c9c7d809/tez-ui2/src/main/webapp/tests/unit/utils/vertex-process-test.js ---------------------------------------------------------------------- diff --git a/tez-ui2/src/main/webapp/tests/unit/utils/vertex-process-test.js b/tez-ui2/src/main/webapp/tests/unit/utils/vertex-process-test.js new file mode 100644 index 0000000..85c0d0f --- /dev/null +++ b/tez-ui2/src/main/webapp/tests/unit/utils/vertex-process-test.js @@ -0,0 +1,98 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import VertexProcess from '../../../utils/vertex-process'; +import { module, test } from 'qunit'; + +import Ember from 'ember'; + +module('Unit | Utility | vertex process'); + +test('Basic creation test', function(assert) { + let process = VertexProcess.create(); + + assert.ok(process); + + assert.ok(process.name); + assert.ok(process.completeTime); + assert.ok(process.blockingEventName); + + assert.ok(process.events); + assert.ok(process.unblockTime); +}); + +test('unblockTime test', function(assert) { + var process = VertexProcess.create(); + assert.equal(process.get("unblockTime"), undefined); + + process = VertexProcess.create({ + blockers: [VertexProcess.create({ + vertex: { + endTime: 10 + } + }), VertexProcess.create({ + vertex: { + endTime: 15 + } + }), VertexProcess.create({ + vertex: { + endTime: 20 + } + })] + }); + + assert.ok(process.get("unblockTime"), 20); + + process.blockers[2].set("vertex", Ember.Object.create({ + endTime: 12 + })); + assert.ok(process.get("unblockTime"), 15); + + process.blockers[2].vertex.set("endTime", 25); + assert.ok(process.get("unblockTime"), 25); +}); + +test('events test', function(assert) { + var process = VertexProcess.create({ + vertex: Ember.Object.create({ + events: [{ + eventtype: "testEvent1" + },{ + eventtype: "testEvent2" + }], + firstTaskStartTime: 10, + lastTaskFinishTime: 20 + }) + }); + + assert.equal(process.get("events.length"), 4); + + assert.equal(process.get("events.0.name"), "testEvent1"); + assert.equal(process.get("events.1.name"), "testEvent2"); + assert.equal(process.get("events.2.time"), 10); + assert.equal(process.get("events.3.time"), 20); + + process.set("blockers", [VertexProcess.create({ + vertex: { + endTime: 30 + } + })]); + + assert.equal(process.get("events.length"), 5); + assert.equal(process.get("events.4.time"), 30); +});
