ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From alexantone...@apache.org
Subject [1/3] ambari git commit: AMBARI-10997. Improve Error Handling - hive view (alexantonenko)
Date Fri, 08 May 2015 18:02:43 GMT
Repository: ambari
Updated Branches:
  refs/heads/trunk c0da0a1d9 -> 642fd46cb


http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/visual-explain.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/visual-explain.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/visual-explain.hbs
index a831b8c..9cd9126 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/visual-explain.hbs
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/visual-explain.hbs
@@ -16,65 +16,72 @@
 * limitations under the License.
 }}
 
-<div id="visual-explain">
+<div id="visual-explain" class="index-overlay">
   {{#panel-widget headingTranslation="titles.query.visualExplain"}}
 
-  {{#each edge in view.edges}}
-    <div class="edge">
-      <div class="edge-path" {{bind-attr style="edge.style"}}>
-        {{edge.type}}
+  {{#unless json}}
+    <div class="spinner"></div>
+  {{/unless}}
+
+  <div id="visual-explain-graph">
+    {{#each edge in view.edges}}
+      <div class="edge">
+        <div class="edge-path" {{bind-attr style="edge.style"}}>
+          {{edge.type}}
+        </div>
+       {{!--  <div class="edge-arrow" ></div> --}}
       </div>
-     {{!--  <div class="edge-arrow" ></div> --}}
-    </div>
-  {{/each}}
+    {{/each}}
 
-  <div class="nodes">
-    {{#each group in view.verticesGroups}}
-      <div class="node-container">
-        {{#if group.contents}}
-          {{#each node in group.contents}}
-            <div {{bind-attr class="node.isTableNode:table-node node.isOutputNode:output-node :node" title="node.id"}}>
-              {{#if node.isTableNode}}
-                <p><strong>{{t 'labels.table'}}</strong></p>
-                {{node.label}}
-              {{else}}
-                {{#if node.isOutputNode}}
+    <div class="nodes">
+      {{#each group in view.verticesGroups}}
+        <div class="node-container">
+          {{#if group.contents}}
+            {{#each node in group.contents}}
+              <div {{bind-attr class="node.isTableNode:table-node node.isOutputNode:output-node :node" title="node.id"}}>
+                {{#if node.isTableNode}}
+                  <p><strong>{{t 'labels.table'}}</strong></p>
                   {{node.label}}
                 {{else}}
-                  <div class="node-heading">
-                    <strong>{{node.label}}</strong>
-                  </div>
-                  <div class="node-content">
-                    {{#each section in node.contents}}
-                      <p>
-                        {{#popover-widget classNames="fa fa-info-circle" titleTranslation="popover.visualExplain.statistics" }}
-                          {{section.statistics}}
-                        {{/popover-widget}}
-                        <strong>
-                          {{section.index}}. {{section.title}}
-                        </strong>
-                        {{section.value}}
-                      </p>
+                  {{#if node.isOutputNode}}
+                    {{node.label}}
+                  {{else}}
+                    <div class="node-heading">
+                      <strong>{{node.label}}</strong>
+                    </div>
+                    <div class="node-content">
+                      {{#each section in node.contents}}
+                        <p>
+                          {{#popover-widget classNames="fa fa-info-circle" titleTranslation="popover.visualExplain.statistics" }}
+                            {{section.statistics}}
+                          {{/popover-widget}}
+                          <strong>
+                            {{section.index}}. {{section.title}}
+                          </strong>
+                          {{section.value}}
+                        </p>
 
-                      {{#each field in section.fields}}
-                        {{#if field.value}}
-                          <p>{{field.label}} {{field.value}}</p>
-                        {{/if}}
+                        {{#each field in section.fields}}
+                          {{#if field.value}}
+                            <p>{{field.label}} {{field.value}}</p>
+                          {{/if}}
+                        {{/each}}
                       {{/each}}
-                    {{/each}}
-                  </div>
+                    </div>
+                    {{progress-widget value=node.progress}}
+                  {{/if}}
                 {{/if}}
-              {{/if}}
+              </div>
+            {{/each}}
+          {{else}}
+            <div class="node" {{bind-attr title="group.label"}}>
+              {{group.label}}
             </div>
-          {{/each}}
-        {{else}}
-          <div class="node" {{bind-attr title="group.label"}}>
-            {{group.label}}
-          </div>
-        {{/if}}
-      </div>
-    {{/each}}
+          {{/if}}
+        </div>
+      {{/each}}
+    </div>
   </div>
 
   {{/panel-widget}}
-</div>
\ No newline at end of file
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/constants.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/constants.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/constants.js
index b099ce6..595da4a 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/constants.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/constants.js
@@ -80,74 +80,75 @@ export default Ember.Object.create({
     databaseSearch: 'databases-search-results',
     tables: 'tables',
     columns: 'columns',
-    settings: 'settings'
+    settings: 'settings',
+    jobProgress: 'job-progress',
+    queryTabs: 'query-tabs'
   },
 
   hiveParameters: [
     {
       name: 'hive.tez.container.size',
-      values: [
-        Ember.Object.create({ value: 'true' }),
-        Ember.Object.create({ value: 'false' })
-      ]
+      validate: helpers.regexes.digits
     },
     {
       name: 'hive.prewarm.enabled',
-      validate: helpers.regexes.digits
+      values: helpers.validationValues.bool
     },
     {
       name: 'hive.prewarm.numcontainers',
-      values: [
-        Ember.Object.create({ value: 'one' }),
-        Ember.Object.create({ value: 'two' }),
-        Ember.Object.create({ value: 'three' })
-      ]
+      validate: helpers.regexes.digits
     },
     {
       name: 'hive.tez.auto.reducer.parallelism',
-      value: 'test'
-    },
-    {
-      name: 'hive.execution.engine'
-    },
-    {
-      name: 'hive.vectorized.execution.enabled'
+      values: helpers.validationValues.bool
     },
     {
-      name: 'tez.am.resource.memory.mb'
+      name: 'hive.execution.engine',
+      values: helpers.validationValues.execEngine
     },
     {
-      name: 'tez.am.container.idle.release-timeout-min.millis'
+      name: 'hive.vectorized.execution.enabled',
+      values: helpers.validationValues.bool
     },
     {
-      name: 'tez.am.container.idle.release-timeout-max.millis'
+      name: 'tez.am.resource.memory.mb',
+      validate: helpers.regexes.digits
     },
     {
-      name: 'tez.queue.name'
+      name: 'tez.am.container.idle.release-timeout-min.millis',
+      validate: helpers.regexes.digits
     },
     {
-      name: 'tez.runtime.io.sort.mb'
+      name: 'tez.am.container.idle.release-timeout-max.millis',
+      validate: helpers.regexes.digits
     },
     {
-      name: 'tez.runtime.sort.threads'
+      name: 'tez.queue.name',
+      validate: helpers.regexes.name
     },
     {
-      name: 'tez.runtime.optimize.shared.fetch'
+      name: 'tez.runtime.io.sort.mb',
+      validate: helpers.regexes.digits
     },
     {
-      name: 'tez.runtime.compress.codec'
+      name: 'tez.runtime.sort.threads',
+      validate: helpers.regexes.digits
     },
     {
-      name: 'tez.runtime.shuffle.keep-alive.enabled'
+      name: 'tez.runtime.compress.codec',
+      validate: helpers.regexes.dotPath
     },
     {
-      name: 'tez.grouping.min-size'
+      name: 'tez.grouping.min-size',
+      validate: helpers.regexes.digits
     },
     {
-      name: 'tez.grouping.max-size'
+      name: 'tez.grouping.max-size',
+      validate: helpers.regexes.digits
     },
     {
-      name: 'tez.generate.debug.artifacts'
+      name: 'tez.generate.debug.artifacts',
+      values: helpers.validationValues.bool
     }
   ],
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/dag-rules.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/dag-rules.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/dag-rules.js
index f4b7f5d..c854892 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/dag-rules.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/dag-rules.js
@@ -138,4 +138,4 @@ export default Ember.ArrayProxy.create({
       }
     ]
   )
-});
\ No newline at end of file
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/functions.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/functions.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/functions.js
index a63dc5b..a1901c7 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/functions.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/functions.js
@@ -25,14 +25,29 @@ export default Ember.Object.create({
     return !isNaN(x);
   },
 
-  isDate: function(date) {
+  isDate: function (date) {
     return moment(date).isValid();
   },
 
   regexes: {
     allUppercase: /^[^a-z]*$/,
     whitespaces: /^(\s*).*$/,
-    digits: /^\d+$/
+    digits: /^\d+$/,
+    name: /\w+/ig,
+    dotPath: /[a-z.]+/i,
+    setSetting: /^set\s+[\w-.]+(\s+|\s?)=(\s+|\s?)[\w-.]+(\s+|\s?);/gim
+  },
+
+  validationValues: {
+    bool: [
+      Ember.Object.create({ value: 'true' }),
+      Ember.Object.create({ value: 'false' })
+    ],
+
+    execEngine: [
+      Ember.Object.create({ value: 'tez' }),
+      Ember.Object.create({ value: 'mr' })
+    ]
   },
 
   insensitiveCompare: function (sourceString) {
@@ -46,4 +61,4 @@ export default Ember.Object.create({
       return sourceString.match(new RegExp('^' + arg + '$', 'i'));
     });
   }
-});
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/app/views/message.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/views/message.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/views/message.js
index dd32a15..45b0236 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/views/message.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/views/message.js
@@ -25,11 +25,11 @@ export default NotificationView.extend({
   removeMessage: 'removeMessage',
 
   actions: {
-    expand: function() {
+    expand: function () {
       this.toggleProperty('isExpanded');
     },
 
-    close: function() {
+    close: function () {
       this.get('controller').send('removeMessage', this.get('notification'));
     }
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/app/views/messages.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/views/messages.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/views/messages.js
new file mode 100644
index 0000000..73a7b76
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/views/messages.js
@@ -0,0 +1,35 @@
+/**
+ * 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.View.extend({
+  didInsertElement: function () {
+    var target = this.$('#messages');
+
+    target.css('min-height', $('.main-content').height());
+    target.animate({ width: $('.main-content').width() }, 'fast');
+  },
+
+  willDestroyElement: function () {
+    var target = this.$('#messages');
+
+    target.css('min-height', 0);
+    target.css('width', 0);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/app/views/notification.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/views/notification.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/views/notification.js
index 291bfeb..1fd2ce8 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/views/notification.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/views/notification.js
@@ -19,18 +19,18 @@
 import Ember from 'ember';
 
 export default Ember.View.extend({
-  closeAfter         : 500000,
+  closeAfter         : 5000,
   isHovering         : false,
   templateName       : 'notification',
   removeNotification : 'removeNotification',
 
-  setup: function() {
+  setup: function () {
     this.set('typeClass', this.get('notification.type.typeClass'));
     this.set('typeIcon', this.get('notification.type.typeIcon'));
   }.on('init'),
 
-  removeLater: function() {
-    Ember.run.later(this, function() {
+  removeLater: function () {
+    Ember.run.later(this, function () {
       if (this.get('isHovering')) {
         this.removeLater();
       } else if (this.element) {
@@ -39,11 +39,11 @@ export default Ember.View.extend({
     }, this.get('closeAfter'));
   }.on('didInsertElement'),
 
-  mouseEnter: function() { this.set('isHovering', true);  },
-  mouseLeave: function() { this.set('isHovering', false); },
+  mouseEnter: function () { this.set('isHovering', true);  },
+  mouseLeave: function () { this.set('isHovering', false); },
 
   actions: {
-    close: function() {
+    close: function () {
       this.remove();
       this.get('parentView').send('removeNotification', this.get('notification'));
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/app/views/visual-explain.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/views/visual-explain.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/views/visual-explain.js
index 07baedb..8d90b7e 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/views/visual-explain.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/views/visual-explain.js
@@ -16,6 +16,8 @@
  * limitations under the License.
  */
 
+/* globals dagre */
+
 import Ember from 'ember';
 import dagRules from '../utils/dag-rules';
 
@@ -24,10 +26,6 @@ export default Ember.View.extend({
     this.set('verticesGroups', []);
     this.set('edges', []);
     this.set('graph', new dagre.graphlib.Graph());
-
-    if (this.get('controller.json')) {
-      this.renderDag();
-    }
   },
 
   didInsertElement: function () {
@@ -38,7 +36,7 @@ export default Ember.View.extend({
     target.css('min-height', $('.main-content').height());
     target.animate({ width: $('.main-content').width() }, 'fast');
 
-    Ember.run.scheduleOnce('afterRender', this, this.afterRenderEvent);
+    this.$('#visual-explain-graph').draggable();
   },
 
   willDestroyElement: function () {
@@ -48,6 +46,31 @@ export default Ember.View.extend({
     target.css('width', 0);
   },
 
+  updateProgress: function () {
+    var verticesProgress = this.get('controller.verticesProgress');
+    var verticesGroups = this.get('verticesGroups');
+
+    if (!verticesGroups || !verticesProgress || !verticesProgress.length) {
+      return;
+    }
+
+    verticesGroups.forEach(function (verticesGroup) {
+      verticesGroup.contents.forEach(function (node) {
+        var progress = verticesProgress.findBy('name', node.get('label'));
+
+        if (progress) {
+          node.set('progress', progress.get('value'));
+        }
+      });
+    });
+  }.observes('controller.verticesProgress', 'verticesGroups'),
+
+  jsonChanged: function () {
+    if (this.get('controller.json')) {
+      this.renderDag();
+    }
+  }.observes('controller.json'),
+
   getOffset: function (el) {
     var _x = 0;
     var _y = 0;
@@ -106,24 +129,6 @@ export default Ember.View.extend({
     });
   },
 
-  afterRenderEvent : function () {
-    var g = this.get('graph');
-    var self = this;
-
-    //draw edges after the slide aniamtion for the visual explain container is done
-    Ember.run.later(function () {
-      g.edges().forEach(function (value) {
-        var edge = g.edge(value);
-        var v = value.v;
-
-        var firstNode = self.$("[title='" + value.v + "']")[0];
-        var secondNode = self.$("[title='" + value.w + "']")[0];
-
-        self.addEdge(firstNode, secondNode, 2, g.edge(value).type);
-      });
-    }, 300);
-  },
-
   getNodeContents: function (operator, contents, table, vertex) {
     var currentTable = table,
       contents = contents || [],
@@ -132,6 +137,8 @@ export default Ember.View.extend({
       ruleNode,
       nodeLabelValue,
       self = this;
+    
+    contents = contents || [];  
 
     if (operator.constructor === Array) {
       operator.forEach(function (childOperator) {
@@ -165,7 +172,7 @@ export default Ember.View.extend({
             return {
               label: field.label,
               value: value
-            }
+            };
           })
         });
 
@@ -222,19 +229,17 @@ export default Ember.View.extend({
       var currentTable;
 
       if (vertex.name.indexOf('Map') > -1) {
-        operator = vertex.value['Map Operator Tree:'][0];
-        currentTable = operator["TableScan"]["alias:"];
+        if (vertex.value && vertex.value['Map Operator Tree:']) {
+          operator = vertex.value['Map Operator Tree:'][0];
+          currentTable = operator["TableScan"]["alias:"];
+        } else {
+          //https://hortonworks.jira.com/browse/BUG-36168
+          operator = "None";
+        }
       } else if (vertex.name.indexOf('Reducer') > -1) {
         operator = vertex.value['Reduce Operator Tree:'];
       }
 
-      // else if (vertex.name.indexOf('Union') > -1) {
-      //   g.setNode(vertex, {
-      //     id: vertex.name,
-      //     label: vertex.name
-      //   });
-      // }
-
       if (operator) {
         contents = self.getNodeContents(operator, null, currentTable, vertex.name);
 
@@ -251,7 +256,6 @@ export default Ember.View.extend({
 
   //sets edges between operator nodes
   setEdges: function (edges) {
-    var i;
     var g = this.get('graph');
     var invalidEdges = [];
     var edgesToBeRemoved = [];
@@ -296,6 +300,7 @@ export default Ember.View.extend({
     });
 
     invalidEdges.forEach(function (invalidEdge) {
+      var parent;
       var targetEdge = g.edges().find(function (graphEdge) {
         return graphEdge.v === invalidEdge.edge.parent ||
                graphEdge.w === invalidEdge.edge.parent;
@@ -335,7 +340,7 @@ export default Ember.View.extend({
       var table;
       var id;
 
-      if (vertex.name.indexOf('Map') > -1) {
+      if (vertex.name.indexOf('Map') > -1 && vertex.value && vertex.value['Map Operator Tree:']) {
         operator = vertex.value['Map Operator Tree:'][0];
         for (var node in operator) {
           table = operator[node]['alias:'];
@@ -350,6 +355,8 @@ export default Ember.View.extend({
       }
     });
 
+    dagre.layout(g);
+
     return this;
   },
 
@@ -368,10 +375,10 @@ export default Ember.View.extend({
         if (!existentRow) {
            groupedNodes.pushObject({
               topOffset: node.y,
-              contents: [ node ]
+              contents: [ Ember.Object.create(node) ]
            });
         } else {
-          existentRow.contents.pushObject(node);
+          existentRow.contents.pushObject(Ember.Object.create(node));
         }
       }
     });
@@ -388,12 +395,28 @@ export default Ember.View.extend({
     g.setEdge(fileOutputOperator.title, lastRowNode.id);
 
     groupedNodes.pushObject({
-      contents: [ g.node(fileOutputOperator.title) ]
+      contents: [ Ember.Object.create(g.node(fileOutputOperator.title)) ]
     });
 
     lastRowNode.contents.removeObject(fileOutputOperator);
 
     this.set('verticesGroups', groupedNodes);
+
+    return this;
+  },
+
+  renderEdges: function () {
+    var self = this;
+    var g = this.get('graph');
+
+    Ember.run.later(function () {
+      g.edges().forEach(function (value) {
+        var firstNode = self.$("[title='" + value.v + "']")[0];
+        var secondNode = self.$("[title='" + value.w + "']")[0];
+
+        self.addEdge(firstNode, secondNode, 2, g.edge(value).type);
+      });
+    }, 200);
   },
 
   renderDag: function () {
@@ -427,10 +450,9 @@ export default Ember.View.extend({
 
     this.setNodes(vertices)
         .setEdges(edges)
-        .setTableNodesAndEdges(vertices);
-
-    dagre.layout(g);
-
-    this.createNodeGroups();
+        .setTableNodesAndEdges(vertices)
+        .createNodeGroups()
+        .renderEdges();
   }
 });
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/package.json
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/package.json b/contrib/views/hive/src/main/resources/ui/hive-web/package.json
index 95f6897..8b5f669 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/package.json
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/package.json
@@ -25,7 +25,7 @@
     "broccoli-asset-rev": "^2.0.0",
     "broccoli-sass": "0.6.3",
     "ember-cli": "0.2.2",
-    "ember-cli-blanket": "^0.4.0",
+    "ember-cli-blanket": "^0.5.0",
     "ember-cli-content-security-policy": "0.3.0",
     "ember-cli-font-awesome": "0.0.4",
     "ember-cli-htmlbars": "0.7.4",

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/blanket-options.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/blanket-options.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/blanket-options.js
index a5580a9..63e022b 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/blanket-options.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/blanket-options.js
@@ -16,10 +16,21 @@
  * limitations under the License.
  */
 
-/* globals blanket */
+/*globals blanket, module */
 
-blanket.options({
-   filter: "//.*hive/.*/",
-   antifilter: ["//.*(tests).*/", "//.*(templates).*/"],
-   loaderExclusions: ['ember-cli-jquery-ui']
-});
+var options = {
+  modulePrefix: "hive",
+  filter: "//.*hive/.*/",
+  antifilter: "//.*(tests|template).*/",
+  loaderExclusions: ['ember-cli-jquery-ui', 'hive/config/environment'],
+  enableCoverage: true,
+  cliOptions: {
+    reporters: ['json']
+  }
+};
+
+if (typeof exports === 'undefined') {
+  blanket.options(options);
+} else {
+  module.exports = options;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/helpers/api-mock.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/helpers/api-mock.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/helpers/api-mock.js
index 8567f30..39487fa 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/helpers/api-mock.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/helpers/api-mock.js
@@ -37,7 +37,20 @@ export default function() {
         ['table2'],
         ['table3']
       ]
-    }
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(tables)];
+  });
+
+  this.get(baseUrl + '/resources/ddl/database/db1/table', function (req) {
+    var tables = {
+      tables: [
+        ['table1'],
+        ['table2'],
+        ['table3']
+      ],
+      database: 'db1'
+    };
 
     return [200, {"Content-Type": "application/json"}, JSON.stringify(tables)];
   });
@@ -49,7 +62,7 @@ export default function() {
         ['column2', 'STRING'],
         ['column3', 'STRING']
       ]
-    }
+    };
 
     return [200, {"Content-Type": "application/json"}, JSON.stringify(columns)];
   });

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/index.html
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/index.html b/contrib/views/hive/src/main/resources/ui/hive-web/tests/index.html
index b8928ff..9faecc6 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/index.html
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/index.html
@@ -30,6 +30,7 @@
     <link rel="stylesheet" href="assets/vendor.css">
     <link rel="stylesheet" href="assets/hive.css">
     <link rel="stylesheet" href="assets/test-support.css">
+    <style>#blanket-main { position: relative; z-index: 99999; }</style>
     <style>
       #ember-testing-container {
         position: absolute;

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/database-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/database-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/database-test.js
index 0a6b12c..604da58 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/database-test.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/integration/database-test.js
@@ -79,8 +79,6 @@ test('Expanding a table will retrieve the first page of columns for that table.'
       click(targetTable);
 
       andThen(function () {
-        console.log(find('.columns'));
-
         equal(find('.columns').length, 1, 'Columns container was loaded.');
         equal(find('.columns strong').length, 3, '3 columns were loaded for selected table.');
       });

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/adapters/application.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/adapters/application.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/adapters/application.js
index da39a39..09e3c1b 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/adapters/application.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/adapters/application.js
@@ -44,5 +44,5 @@ test('buildUrl returns an url with default values for version and instance param
 
   var url = adapter.buildURL();
 
-  equal(url, constants.adapter.apiPrefix + '0.0.1' + constants.adapter.instancePrefix + 'Hive');
+  equal(url, constants.adapter.apiPrefix + '0.2.0' + constants.adapter.instancePrefix + 'Hive');
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/collapsible-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/collapsible-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/collapsible-widget-test.js
index 3af6d7d..2f25bab 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/collapsible-widget-test.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/collapsible-widget-test.js
@@ -35,7 +35,7 @@ test('Component expand/collapse toggle action', function () {
     expanded: 'expanded'
   });
 
-  var $component = this.append();
+  var $component = this.render();
 
   Ember.run(function() {
     component.set('isExpanded', false);

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/column-filter-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/column-filter-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/column-filter-widget-test.js
index 315dbbc..2afe669 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/column-filter-widget-test.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/column-filter-widget-test.js
@@ -45,7 +45,7 @@ test('if a filterValue is set when the element is inserted, an action is being s
   component.set('columnFiltered', 'externalAction');
   component.set('targetObject', targetObject);
 
-  var $component = this.append();
+  var $component = this.render();
 });
 
 test('isSorted returns true if the table is sorted by this column property', function () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/date-range-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/date-range-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/date-range-widget-test.js
index e8004cc..13a3e89 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/date-range-widget-test.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/date-range-widget-test.js
@@ -42,12 +42,14 @@ test('Date fields are set correctly', function() {
     max: max.toString()
   });
 
+  component.set('dateRange', Ember.Object.create());
+
+  var $component = this.render();
+
   Ember.run(function() {
     component.set('dateRange', dateRange);
   });
 
-  var $component = this.append();
-
   equal($component.find('.fromDate').val(), moment(from).format('MM/DD/YYYY'), "From date is set correctly");
   equal($component.find('.toDate').val(), moment(to).format('MM/DD/YYYY'), "To date is set correctly");
 });
@@ -73,7 +75,7 @@ test('Date fields updates when the date is changed', function() {
     component.set('dateRange', dateRange);
   });
 
-  var $component = this.append();
+  var $component = this.render();
   $component.find('.fromDate').datepicker('setDate', '10/10/2014');
   $component.find('.toDate').datepicker('setDate', '11/11/2014');
 
@@ -123,7 +125,7 @@ test('If from/to are not passed they are set to min/max', function() {
     component.set('dateRange', dateRange);
   });
 
-  var $component = this.append();
+  var $component = this.render();
 
   equal(component.get('dateRange.from'), min.toString(), "From date is to min date");
   equal(component.get('dateRange.to'), max.toString(), "To date is set to max date");

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/expander-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/expander-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/expander-widget-test.js
index 65a50d1..2b34af5 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/expander-widget-test.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/expander-widget-test.js
@@ -26,7 +26,7 @@ test('should set the heading when provided.', function () {
   expect(2);
 
   var component = this.subject();
-  var $component = this.append();
+  var $component = this.render();
   var heading = 'some header';
 
   equal($component.find('.accordion-toggle').text(), '');
@@ -42,7 +42,7 @@ test('should correctly toggle isExpanded property.', function () {
   expect(2);
 
   var component = this.subject();
-  this.append();
+  this.render();
 
   Ember.run(function(){
     component.send('toggle');

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/extended-input-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/extended-input-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/extended-input-test.js
index 3ef5cf9..7a3fcbf 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/extended-input-test.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/extended-input-test.js
@@ -29,7 +29,7 @@ test('Component has dynamicValue and dynamicContext', function () {
     dynamicContext: Ember.Object.create({ 'dynamicValue' : 'test' })
   });
 
-  var $component = this.append();
+  var $component = this.render();
 
   equal(component.get('value'), 'test', 'Value is set to dynamicValue value');
 });
@@ -39,7 +39,7 @@ test('Component has no dynamicValue and dynamicContext', function () {
   expect(1);
 
   var component = this.subject();
-  var $component = this.append();
+  var $component = this.render();
 
   ok(!component.get('value'), 'Value is not set as dynamicValue value');
 });
@@ -52,7 +52,7 @@ test("Component's dynamicValue is set", function () {
     dynamicContext: Ember.Object.create({ 'dynamicValue' : 'test' })
   });
 
-  var $component = this.append();
+  var $component = this.render();
 
   Ember.run(function() {
     component.sendValueChanged();
@@ -69,7 +69,7 @@ test("Component's dynamicValue is not set", function () {
     dynamicContext: Ember.Object.create({ })
   });
 
-  var $component = this.append();
+  var $component = this.render();
 
   Ember.run(function() {
     component.sendValueChanged();

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/no-bubbling-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/no-bubbling-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/no-bubbling-test.js
index 4ce4ac3..2d158ae 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/no-bubbling-test.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/no-bubbling-test.js
@@ -37,7 +37,7 @@ test('External actions', function() {
     data: 'data'
   });
 
-  var $component = this.append();
+  var $component = this.render();
 
   $component.trigger('click');
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/number-range-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/number-range-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/number-range-widget-test.js
index dc95cf7..92d892e 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/number-range-widget-test.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/number-range-widget-test.js
@@ -27,7 +27,7 @@ moduleForComponent('number-range-widget', 'NumberRangeWidgetComponent', {
 
 
 test('Component is initialized correctly', function() {
-  expect(3);
+  expect(2);
 
   var numberRange = Ember.Object.create({
     max: 1,
@@ -35,9 +35,7 @@ test('Component is initialized correctly', function() {
   });
 
   var component = this.subject({ numberRange: numberRange });
-  var $component = this.append();
-
-  ok(component.get('slider'), 'Slider is set');
+  var $component = this.render();
 
   equal(component.get('numberRange.from'), numberRange.get('min'), 'from is set to min');
   equal(component.get('numberRange.to'), numberRange.get('max'), 'to is set to max');
@@ -64,9 +62,9 @@ test('external change action is called', function() {
     rangeChanged: 'rangeChanged'
   });
 
-  var $component = this.append();
+  var $component = this.render();
 
   Ember.run(function() {
-    component.get('slider').slider('value', 1);
+    $component.find('.slider').slider('value', 1);
   });
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/popover-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/popover-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/popover-widget-test.js
index dd6ddd9..b75148d 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/popover-widget-test.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/popover-widget-test.js
@@ -27,7 +27,7 @@ test('Component initializes correctly', function () {
   var component = this.subject({
     template: Ember.Handlebars.compile("test")
   });
-  var $component = this.append();
+  var $component = this.render();
 
   ok($component, "Popover element is initialized");
   equal($component.attr('data-content').trim(), "test", "data-content is populated");

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/progress-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/progress-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/progress-widget-test.js
index 169dc7f..4e081bd 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/progress-widget-test.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/progress-widget-test.js
@@ -19,7 +19,7 @@
 import Ember from 'ember';
 import { moduleForComponent, test } from 'ember-qunit';
 
-moduleForComponent('progress-widget', 'ProgressWidgetComponent');
+moduleForComponent('progress-widget_', 'ProgressWidgetComponent');
 
 test('Setting progress attributes', function () {
   expect(3);
@@ -33,7 +33,7 @@ test('Setting progress attributes', function () {
     formattedStages: Ember.ArrayProxy.create({ content: [] })
   });
 
-  var $component = this.append();
+  var $component = this.render();
 
   Ember.run(function() {
     component.formatStages();

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/query-editor-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/query-editor-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/query-editor-test.js
index 0656ee1..0b993d4 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/query-editor-test.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/query-editor-test.js
@@ -28,7 +28,7 @@ test('initEditor sets the editor on didInsertElement', function () {
 
   equal(component.get('editor'), undefined, 'element not rendered. Editor not set.');
 
-  this.append();
+  this.render();
 
   ok(component.get('editor'), 'element rendered. Editor set.');
 });
@@ -40,7 +40,7 @@ test('updateValue sets the query value on the editor.', function () {
 
   var query = 'select something';
 
-  this.append();
+  this.render();
 
   Ember.run(function () {
     component.set(('query'), query);

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/select-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/select-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/select-widget-test.js
index 9187d00..b1175f2 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/select-widget-test.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/select-widget-test.js
@@ -89,7 +89,7 @@ test('renders an li tag for each item in the items collection.', function () {
   expect(2);
 
   var component = this.subject();
-  var $component = this.append();
+  var $component = this.render();
 
   equal($component.find('li').length, 0, 'items collection is not set. No li tags are rendered.');
 
@@ -111,7 +111,7 @@ test('if no selected item nor defaultLabel set the selected value with first ite
   ];
 
   var component = this.subject({ items: items });
-  var $component = this.append();
+  var $component = this.render();
 
   equal(component.get('selectedValue'), 'item1', 'selectedValue is set to first item')
 });
@@ -140,7 +140,7 @@ test('component actions', function() {
     targetObject: targetObject
   });
 
-  var $component = this.append();
+  var $component = this.render();
 
   equal(component.get('selectedValue'), 'item', 'selectedValue is set to first item');
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/tabs-wiget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/tabs-wiget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/tabs-wiget-test.js
index f3a1c5f..8eaddbe 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/tabs-wiget-test.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/tabs-wiget-test.js
@@ -32,7 +32,7 @@ test('First tab active by default', function() {
   ])});
 
   var component = this.subject({ tabs: tabs });
-  var $component = this.append();
+  var $component = this.render();
 
   ok(component.get('tabs.firstObject.active'), 'First tab is active');
   ok(!component.get('tabs.lastObject.active'), 'Second tab is not active');

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/typeahead-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/typeahead-widget-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/typeahead-widget-test.js
index 3f2312b..e36499e 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/typeahead-widget-test.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/components/typeahead-widget-test.js
@@ -38,7 +38,7 @@ test('Component is initialized correctly', function () {
     optionValuePath: 'content.id',
     optionLabelPath: 'content.name'
   });
-  var $component = this.append();
+  var $component = this.render();
 
   equal(component.get('content.length'), items.length, 'Items are set');
   equal(component.get('selection'), items[0], 'First object is set as default value');

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/index-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/index-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/index-test.js
index 7d7b531..cc7d953 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/index-test.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/index-test.js
@@ -27,7 +27,8 @@ moduleFor('controller:index', 'IndexController', {
           'controller:index/history-query/explain',
           'controller:settings',
           'adapter:database', 'controller:tables', 'controller:columns',
-          'controller:visual-explain', 'controller:tez-ui'
+          'controller:visual-explain', 'controller:tez-ui',
+          'adapter:application'
         ]
 });
 
@@ -106,13 +107,14 @@ test('bindQueryParams replaces same param multiple times', function() {
 });
 
 test('parseQueryParams sets queryParams when query changes', function() {
-  expect(3);
+  expect(4);
 
 
   var query = Ember.Object.create({
     id: 1,
     fileContent: "select $what from $where"
   });
+  var updatedQuery = "select $what from $where and $where";
 
   var controller = this.subject({
     model: query
@@ -126,6 +128,12 @@ test('parseQueryParams sets queryParams when query changes', function() {
   equal(controller.get('queryParams.length'), 2, '2 queryParams parsed');
   equal(controller.get('queryParams').objectAt(0).name, '$what', 'First param parsed correctly');
   equal(controller.get('queryParams').objectAt(1).name, '$where', 'Second param parsed correctly');
+
+  Ember.run(function() {
+    controller.set('openQueries.currentQuery.fileContent', updatedQuery);
+  });
+
+  equal(controller.get('queryParams.length'), 2, 'Can use same param multiple times');
 });
 
 test('canExecute return false if query is executing', function() {
@@ -184,3 +192,94 @@ test('canExecute return false if queryParams doesnt\'t have values', function()
 
   ok(controller.get('canExecute'), 'Params with values => canExecute return true');
 });
+
+test('csvUrl returns if the current query is not a job', function() {
+  expect(1);
+  var content = Ember.Object.create({
+      constructor: {
+        typeKey: 'notJob'
+      }
+  });
+
+  var controller = this.subject({ content: content });
+  ok(!controller.get('csvUrl'), 'returns if current query is not a job');
+});
+
+test('csvUrl returns is status in not SUCCEEDED', function() {
+  expect(1);
+  var content= Ember.Object.create({
+      constructor: {
+        typeKey: 'job'
+      },
+      status: 'notSuccess'
+  });
+
+  var controller = this.subject({ content: content });
+  ok(!controller.get('csvUrl'), 'returns if current status is not success');
+});
+
+test('csvUrl return the download results as csv link', function() {
+  expect(1);
+  var content = Ember.Object.create({
+      constructor: {
+        typeKey: 'job'
+      },
+      status: 'SUCCEEDED',
+      id: 1
+  });
+
+  var controller = this.subject({ content: content });
+  ok(controller.get('csvUrl'));
+});
+
+test('donwloadMenu returns null if status is not succes and results are not visible ', function() {
+  expect(1);
+  var content = Ember.Object.create({
+      status: 'notSuccess',
+      queryProcessTabs: [{
+        path: 'index.historyQuery.results',
+        visible: false
+      }]
+  });
+
+  var controller = this.subject({ content: content });
+  ok(!controller.get('downloadMenu'), 'Returns null');
+});
+
+test('donwloadMenu returns only saveToHDFS if csvUrl is false', function() {
+  expect(1);
+  var content = Ember.Object.create({
+      constructor: {
+        typeKey: 'notjob'
+      },
+      status: 'SUCCEEDED'
+  });
+
+  var controller = this.subject({ content: content });
+  Ember.run(function() {
+    var tabs = controller.get('queryProcessTabs');
+    var results = tabs.findBy('path', 'index.historyQuery.results');
+    results.set('visible', true);
+  });
+
+  equal(controller.get('downloadMenu.length'), 1, 'Returns only saveToHDFS');
+});
+
+test('donwloadMenu returns saveToHDFS and csvUrl', function() {
+  expect(1);
+  var content = Ember.Object.create({
+      constructor: {
+        typeKey: 'job'
+      },
+      status: 'SUCCEEDED'
+  });
+
+  var controller = this.subject({ content: content });
+  Ember.run(function() {
+    var tabs = controller.get('queryProcessTabs');
+    var results = tabs.findBy('path', 'index.historyQuery.results');
+    results.set('visible', true);
+  });
+
+  equal(controller.get('downloadMenu.length'), 2, 'Returns saveToHDFS and csvUrl');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/settings-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/settings-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/settings-test.js
index 0101ceb..8d2adbd 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/settings-test.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/settings-test.js
@@ -106,7 +106,6 @@ test('validate', function() {
   });
 
   var currentSettings = controller.get('model.firstObject.settings');
-  console.log(currentSettings);
   ok(!currentSettings.get('firstObject.valid'), "First setting doesn\' pass validataion");
   ok(currentSettings.get('lastObject.valid'), 'Second setting passes validation');
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/visual-explain-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/visual-explain-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/visual-explain-test.js
index 1ab84e2..622b615 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/visual-explain-test.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/controllers/visual-explain-test.js
@@ -23,7 +23,7 @@ import {
 
 moduleFor('controller:visual-explain', 'VisualExplainController', {
   // Specify the other units that are required for this test.
-  // needs: ['controller:foo']
+  needs: ['controller:index']
 });
 
 // Replace this with your real tests.

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/services/notify-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/services/notify-test.js b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/services/notify-test.js
new file mode 100644
index 0000000..45b8936
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/tests/unit/services/notify-test.js
@@ -0,0 +1,153 @@
+/**
+ * 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 { moduleFor, test } from 'ember-qunit';
+
+moduleFor('service:notify', 'NotifyService', {});
+
+test('Service initialized correctly', function () {
+  expect(3);
+
+  var service = this.subject();
+
+  equal(service.get('messages.length'), 0, 'No messages');
+  equal(service.get('notifications.length'), 0, 'No notifications');
+  equal(service.get('unseenMessages.length'), 0, 'No unseenMessages');
+});
+
+test('Can add notification', function() {
+  expect(3);
+  var service = this.subject();
+
+  service.add('notif', 'message', 'body');
+
+  equal(service.get('messages.length'), 1, 'one message added');
+  equal(service.get('notifications.length'), 1, 'one notifications added');
+  equal(service.get('unseenMessages.length'), 1, 'one unseenMessages added');
+});
+
+test('Can add info notification', function() {
+  expect(1);
+  var service = this.subject();
+
+  service.info('message', 'body');
+  equal(service.get('messages.lastObject.type.typeClass'), 'alert-info', 'Info notification added');
+});
+
+test('Can add warn notification', function() {
+  expect(1);
+  var service = this.subject();
+
+  service.warn('message', 'body');
+  equal(service.get('messages.lastObject.type.typeClass'), 'alert-warning', 'Warn notification added');
+});
+
+test('Can add error notification', function() {
+  expect(1);
+  var service = this.subject();
+
+  service.error('message', 'body');
+  equal(service.get('messages.lastObject.type.typeClass'), 'alert-danger', 'Error notification added');
+});
+
+test('Can add success notification', function() {
+  expect(1);
+  var service = this.subject();
+
+  service.success('message', 'body');
+  equal(service.get('messages.lastObject.type.typeClass'), 'alert-success', 'Success notification added');
+});
+
+test('Can format message body', function() {
+  expect(3);
+
+  var objectBody = {
+    k1: 'v1',
+    k2: 'v2'
+  };
+  var formatted = "\n\nk1:\nv1\n\nk2:\nv2";
+  var service = this.subject();
+
+  ok(!service.formatMessageBody(), 'Return nothing if no body is passed');
+  equal(service.formatMessageBody('some string'), 'some string', 'Return the body if it is a string');
+  equal(service.formatMessageBody(objectBody), formatted, 'Parse the keys and return a string if it is an object');
+});
+
+test('Can removeMessage', function() {
+  expect(4);
+
+  var service = this.subject();
+  var messagesCount = service.get('messages.length');
+  var notificationCount = service.get('notifications.length');
+
+  service.add('type', 'message', 'body');
+
+  equal(service.get('messages.length'), messagesCount + 1, 'Message added');
+  equal(service.get('notifications.length'), notificationCount + 1, 'Notification added');
+
+  var message = service.get('messages.lastObject');
+  service.removeMessage(message);
+
+  equal(service.get('messages.length'), messagesCount, 'Message removed');
+  equal(service.get('notifications.length'), notificationCount, 'Notification removed');
+});
+
+test('Can removeNotification', function() {
+  expect(2);
+
+  var service = this.subject();
+  var notificationCount = service.get('notifications.length');
+
+  service.add('type', 'message', 'body');
+
+  equal(service.get('notifications.length'), notificationCount + 1, 'Notification added');
+
+  var notification = service.get('notifications.lastObject');
+  service.removeNotification(notification);
+
+  equal(service.get('notifications.length'), notificationCount, 'Notification removed');
+});
+
+test('Can removeAllMessages', function() {
+  expect(2);
+
+  var service = this.subject();
+
+  service.add('type', 'message', 'body');
+  service.add('type', 'message', 'body');
+  service.add('type', 'message', 'body');
+
+  ok(service.get('messages.length'), 'Messages are present');
+  service.removeAllMessages();
+  equal(service.get('messages.length'), 0, 'No messages found');
+});
+
+test('Can markMessagesAsSeen', function() {
+  expect(2);
+
+  var service = this.subject();
+
+  service.add('type', 'message', 'body');
+  service.add('type', 'message', 'body');
+  service.add('type', 'message', 'body');
+
+  ok(service.get('unseenMessages.length'), 'There are unseen messages');
+  service.markMessagesAsSeen();
+  equal(service.get('unseenMessages.length'), 0, 'No unseen messages');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/main/resources/view.xml
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/view.xml b/contrib/views/hive/src/main/resources/view.xml
index 9c8b103..41bcfeb 100644
--- a/contrib/views/hive/src/main/resources/view.xml
+++ b/contrib/views/hive/src/main/resources/view.xml
@@ -17,7 +17,7 @@
 <view>
     <name>HIVE</name>
     <label>Hive</label>
-    <version>0.2.0</version>
+    <version>0.3.0</version>
 
     <min-ambari-version>1.7.*</min-ambari-version>
 
@@ -51,9 +51,9 @@
     <!-- General Configs -->
 
     <parameter>
-        <name>dataworker.username</name>
-        <description>The dataworker username. By default, users the currently logged-in Ambari user.</description>
-        <label>Dataworker Username</label>
+        <name>views.tez.instance</name>
+        <description>Instance name of Tez view.</description>
+        <label>Instance name of Tez view</label>
         <required>false</required>
     </parameter>
 
@@ -104,10 +104,19 @@
     <parameter>
         <name>yarn.ats.url</name>
         <description>The URL to the YARN Application Timeline Server, used to provide Jobs information, typically, this is the yarn.timeline-service.webapp.address property in the yarn-site.xml configuration.</description>
+        <label>YARN Application Timeline Server URL</label>
         <placeholder>http://yarn.ats.address:8188</placeholder>
         <required>true</required>
     </parameter>
 
+    <parameter>
+        <name>yarn.resourcemanager.url</name>
+        <description>The URL to the YARN ResourceManager, used to provide YARN Application data.</description>
+        <label>YARN ResourceManager URL</label>
+        <placeholder>http://yarn.resourcemanager.address:8088</placeholder>
+        <required>true</required>
+    </parameter>
+
     <resource>
         <name>savedQuery</name>
         <plural-name>savedQueries</plural-name>

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/ATSParserTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/ATSParserTest.java b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/ATSParserTest.java
index c5cc52b..a0cf57a 100644
--- a/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/ATSParserTest.java
+++ b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/ATSParserTest.java
@@ -6,9 +6,9 @@
  * 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
- *
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
  * 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.
@@ -90,6 +90,11 @@ public class ATSParserTest {
     }
 
     @Override
+    public String tezVerticesListForDAGUrl(String dagId) {
+      return null;
+    }
+
+    @Override
     public JSONObject hiveQueryIdList(String username) {
       return (JSONObject) JSONValue.parse(
           "{ \"entities\" : [ { \"domain\" : \"DEFAULT\",\n" +
@@ -116,12 +121,12 @@ public class ATSParserTest {
       );
     }
 
-      @Override
-      public JSONObject hiveQueryIdByOperationId(String operationId) {
-          throw new NotImplementedException();
-      }
+    @Override
+    public JSONObject hiveQueryIdByOperationId(String operationId) {
+      throw new NotImplementedException();
+    }
 
-      @Override
+    @Override
     public JSONObject tezDagByName(String name) {
       return (JSONObject) JSONValue.parse(
           "{ \"entities\" : [ { \"domain\" : \"DEFAULT\",\n" +
@@ -428,5 +433,10 @@ public class ATSParserTest {
               "      } ] }"
       );
     }
+
+    @Override
+    public JSONObject tezVerticesListForDAG(String dagId) {
+      return null;
+    }
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/642fd46c/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/AggregatorTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/AggregatorTest.java b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/AggregatorTest.java
index 10d052a..de691e0 100644
--- a/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/AggregatorTest.java
+++ b/contrib/views/hive/src/test/java/org/apache/ambari/view/hive/resources/jobs/AggregatorTest.java
@@ -24,6 +24,7 @@ import org.apache.ambari.view.hive.resources.IResourceManager;
 import org.apache.ambari.view.hive.resources.jobs.atsJobs.HiveQueryId;
 import org.apache.ambari.view.hive.resources.jobs.atsJobs.IATSParser;
 import org.apache.ambari.view.hive.resources.jobs.atsJobs.TezDagId;
+import org.apache.ambari.view.hive.resources.jobs.atsJobs.TezVertexId;
 import org.apache.ambari.view.hive.resources.jobs.viewJobs.Job;
 import org.apache.ambari.view.hive.resources.jobs.viewJobs.JobImpl;
 import org.apache.hive.service.cli.thrift.TOperationHandle;
@@ -307,6 +308,16 @@ public class AggregatorTest {
     }
 
     @Override
+    public List<Job> getHandleRelatedJobs(StoredOperationHandle operationHandle) {
+      return new LinkedList<Job>();
+    }
+
+    @Override
+    public Job getJobByHandle(StoredOperationHandle handle) throws ItemNotFound {
+      throw new ItemNotFound();
+    }
+
+    @Override
     public void putHandleForJob(TOperationHandle h, Job job) {
 
     }
@@ -317,11 +328,11 @@ public class AggregatorTest {
     }
 
     @Override
-    public TOperationHandle getHandleForJob(Job job) throws ItemNotFound {
+    public StoredOperationHandle getHandleForJob(Job job) throws ItemNotFound {
       List<StoredOperationHandle> handles = readJobRelatedHandles(job);
       if (handles.size() == 0)
         throw new ItemNotFound();
-      return handles.get(0).toTOperationHandle();
+      return handles.get(0);
     }
 
     @Override
@@ -376,6 +387,21 @@ public class AggregatorTest {
     }
 
     @Override
+    public List<TezVertexId> getVerticesForDAGId(String dagId) {
+      List<TezVertexId> vertices = new LinkedList<TezVertexId>();
+      TezVertexId tezVertexId1 = new TezVertexId();
+      tezVertexId1.entity = "vertex_1234567_99_99_01";
+      tezVertexId1.vertexName = "Map 1";
+      vertices.add(tezVertexId1);
+
+      TezVertexId tezVertexId2 = new TezVertexId();
+      tezVertexId2.entity = "vertex_1234567_99_99_00";
+      tezVertexId2.vertexName = "Reduce 1";
+      vertices.add(tezVertexId2);
+      return vertices;
+    }
+
+    @Override
     public HiveQueryId getHiveQueryIdByOperationId(String guid) {
       return new HiveQueryId();
     }
@@ -393,4 +419,4 @@ public class AggregatorTest {
       this.hiveQueryIds = hiveQueryIds;
     }
   }
-}
\ No newline at end of file
+}


Mime
View raw message