You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jl...@apache.org on 2016/06/27 23:36:32 UTC

[06/34] ambari git commit: AMBARI-17355 & AMBARI-17354: POC: FE & BE changes for first class support for Yarn hosted services

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/api-mock.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/api-mock.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/api-mock.js
new file mode 100644
index 0000000..ed4822d
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/api-mock.js
@@ -0,0 +1,291 @@
+/**
+ * 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 applicationAdapter from 'hive/adapters/database';
+
+export default function() {
+  var baseUrl = applicationAdapter.create().buildURL();
+  var databases = ['db1', 'db2', 'db3'];
+
+  this.get(baseUrl + '/resources/ddl/database', function (req) {
+    var db = {
+      databases: databases
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(db)];
+  });
+
+  this.get(baseUrl + '/resources/ddl/database/db1/table.page', function (req) {
+    var tables = {
+      rows: [
+        ['table1'],
+        ['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)];
+  });
+
+  this.get(baseUrl + '/resources/ddl/database/db1/table/table1.page', function (req) {
+    var columns = {
+      rows: [
+        ['column1', 'STRING'],
+        ['column2', 'STRING'],
+        ['column3', 'STRING']
+      ]
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(columns)];
+  });
+
+  this.get(baseUrl + '/udfs', function (req) {
+    var udf = {
+      "udfs": [{
+        "name": "TestColumn",
+        "classname": "TestClassName",
+        "fileResource": 1,
+        "id": 1,
+        "owner": "owner1"
+      },
+      {
+        "name": "Test2Columns",
+        "classname": "Test2ClassName",
+        "fileResource": 1,
+        "id": 2,
+        "owner": "owner2"
+      }]
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(udf)];
+  });
+
+  this.post(baseUrl + '/jobs', function (req) {
+    var job = {
+      "job": {
+        "status":"Finished",
+        "dataBase":"db1",
+        "dateSubmitted":1421677418,
+        "logFile":"job1/logs",
+        "properties":{},
+        "fileResources":[],
+        "statusDir":"job1",
+        "id":1,
+        "title":"Worksheet",
+        "duration":2,
+        "forcedContent":"",
+        "owner":"admin",
+        "confFile":"job1/conf",
+        "queryId":null,
+        "queryFile":"job1.hql"
+      }
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(job)];
+  });
+
+  this.get(baseUrl + '/resources/file/job1.hql', function (req) {
+    var file = {
+      "file": {
+        "filePath": "job1.hql",
+        "fileContent": "select * from big",
+        "hasNext": false,
+        "page": 0,
+        "pageCount": 1
+      }
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(file)];
+  });
+
+  this.get(baseUrl + '/savedQueries', function(req) {
+    var savedQueries = {
+      "savedQueries": [{
+        "queryFile": "saved1.hql",
+        "dataBase": "db1",
+        "title": "saved1",
+        "shortQuery": "",
+        "id": 1,
+        "owner": "owner1"
+      }, {
+        "queryFile": "saved2.hql",
+        "dataBase": "db2",
+        "title": "saved2",
+        "shortQuery": "select count(field_0) from big;",
+        "id": 2,
+        "owner": "owner2"
+      }]
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(savedQueries)];
+  });
+
+  this.get(baseUrl + '/savedQueries/defaultSettings', function (req) {
+    var defaultSettings = {
+      "defaultSettings" : []
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(defaultSettings)];
+  });
+
+  this.get(baseUrl + '/resources/file/saved1.hql', function (req) {
+    var file = {
+      "file": {
+        "filePath": "saved1.hql",
+        "fileContent": "select * from saved1",
+        "hasNext": false,
+        "page": 0,
+        "pageCount": 0
+      }
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(file)];
+  });
+
+  this.get(baseUrl + '/jobs', function (req) {
+    var jobs = {
+      "jobs": [
+        {
+          "title": "Query1",
+          "queryFile": "saved1.hql",
+          "statusDir": "statusdir",
+          "dateSubmitted": 1421240048,
+          "duration": 97199,
+          "status": "Finished",
+          "forcedContent": "",
+          "id": 1,
+          "owner": "admin",
+          "logFile": "logs1",
+          "confFile": "conf1"
+        },
+        {
+          "title": "Query2",
+          "queryFile": "saved1.hql",
+          "statusDir": "statusdir",
+          "dateSubmitted": 1421240048,
+          "duration": 97199,
+          "status": "Finished",
+          "forcedContent": "",
+          "id": 2,
+          "owner": "admin",
+          "logFile": "logs2",
+          "confFile": "conf2"
+        },
+        {
+          "title": "Query3",
+          "queryFile": "saved1.hql",
+          "statusDir": "statusdir",
+          "dateSubmitted": 1421240048,
+          "duration": 97199,
+          "status": "Running",
+          "forcedContent": "",
+          "id": 3,
+          "owner": "admin",
+          "logFile": "logs3",
+          "confFile": "conf3"
+        },
+        {
+          "title": "Query4",
+          "queryFile": "saved1.hql",
+          "statusDir": "statusdir",
+          "dateSubmitted": 1421240048,
+          "duration": 97199,
+          "status": "Error",
+          "forcedContent": "",
+          "id": 4,
+          "owner": "admin",
+          "logFile": "logs4",
+          "confFile": "con51"
+        }
+      ]
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(jobs)];
+  });
+
+  this.get(baseUrl + '/fileResources', function (req) {
+    var files = {
+      "fileResources": [
+        {
+          "name": "TestName",
+          "path": "TestPath",
+          "id": 1,
+          "owner": "owner1"
+        }
+      ]
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(files)];
+  });
+
+  this.get(baseUrl + '/fileResources/1', function (req) {
+    var files = {
+      "fileResources": [
+        {
+          "name": "TestName",
+          "path": "TestPath",
+          "id": 1,
+          "owner": "owner1"
+        }
+      ]
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(files)];
+  });
+
+  this.get(baseUrl + '/api/v1/views/TEZ', function (req) {
+    var data = {
+      versions: [
+        {
+          href: baseUrl + '/api/v1/view/TEZ/versions/1',
+          ViewVersionInfo: {version: '1', view_name: 'TEZ'}
+        }
+      ]
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(data)];
+  });
+
+  this.get(baseUrl + '/api/v1/views/TEZ/versions/1', function (req) {
+    var data = {
+      instances: [
+        {
+          ViewInstanceInfo: {
+            instance_name: 'tez',
+            version: 1
+          }
+        }
+      ]
+    };
+
+    return [200, {"Content-Type": "application/json"}, JSON.stringify(data)];
+  });
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/resolver.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/resolver.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/resolver.js
new file mode 100644
index 0000000..f94998c
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/resolver.js
@@ -0,0 +1,29 @@
+/**
+ * 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 Resolver from 'ember/resolver';
+import config from '../../config/environment';
+
+var resolver = Resolver.create();
+
+resolver.namespace = {
+  modulePrefix: config.modulePrefix,
+  podModulePrefix: config.podModulePrefix
+};
+
+export default resolver;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/start-app.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/start-app.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/start-app.js
new file mode 100644
index 0000000..ab1a9d2
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/helpers/start-app.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 Ember from 'ember';
+import Application from '../../app';
+import Router from '../../router';
+import config from '../../config/environment';
+
+export default function startApp(attrs) {
+  var App;
+
+  var attributes = Ember.merge({}, config.APP);
+  attributes = Ember.merge(attributes, attrs); // use defaults, but you can override;
+
+  Router.reopen({
+    location: 'none'
+  });
+
+  Ember.run(function() {
+    App = Application.create(attributes);
+    App.setupForTesting();
+    App.injectTestHelpers();
+  });
+
+  // App.reset(); // this shouldn't be needed, i want to be able to "start an app at a specific URL"
+
+  return App;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/img/spinner.gif
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/img/spinner.gif b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/img/spinner.gif
new file mode 100644
index 0000000..e921e36
Binary files /dev/null and b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/img/spinner.gif differ

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/index.html
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/index.html b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/index.html
new file mode 100644
index 0000000..9faecc6
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/index.html
@@ -0,0 +1,71 @@
+<!--
+ * 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.
+-->
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <title>Hive Tests</title>
+    <meta name="description" content="">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+
+    {{content-for 'head'}}
+    {{content-for 'test-head'}}
+
+    <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;
+        background: white;
+        bottom: 0;
+        right: 0;
+        width: 640px;
+        height: 384px;
+        overflow: auto;
+        z-index: 9999;
+        border: 1px solid #ccc;
+      }
+      #ember-testing {
+        zoom: 50%;
+      }
+    </style>
+
+    {{content-for 'head-footer'}}
+    {{content-for 'test-head-footer'}}
+  </head>
+  <body>
+    <div id="qunit"></div>
+    <div id="qunit-fixture"></div>
+
+    {{content-for 'body'}}
+    {{content-for 'test-body'}}
+    <script src="assets/vendor.js"></script>
+    <script src="assets/test-support.js"></script>
+    <script src="assets/hive.js"></script>
+    <script src="assets/blanket-options.js"></script>
+    <script src="assets/blanket-loader.js"></script>
+    <script src="testem.js"></script>
+    <script src="assets/test-loader.js"></script>
+
+    {{content-for 'body-footer'}}
+    {{content-for 'test-body-footer'}}
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/database-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/database-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/database-test.js
new file mode 100644
index 0000000..52cda77
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/database-test.js
@@ -0,0 +1,103 @@
+/**
+ * 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 { test } from 'ember-qunit';
+import startApp from '../helpers/start-app';
+import api from '../helpers/api-mock';
+
+var App;
+var server;
+
+module('Integration: Databases', {
+  setup: function() {
+    App = startApp();
+    /* global Pretender: true */
+    server = new Pretender(api);
+  },
+  teardown: function() {
+    Ember.run(App, App.destroy);
+    server.shutdown();
+  }
+});
+
+test('Database Explorer is displayed and populated with databases from server.', function (assert) {
+  assert.expect(2);
+
+  visit('/');
+
+  andThen(function() {
+    equal(find('.database-explorer').length, 1, 'Databases panel is visible.');
+    equal(find('.database-explorer .databases').children().length, 3, 'Databases are listed.');
+  });
+});
+
+test('Expanding a database will retrieve the first page of tables for that database.', function () {
+  expect(1);
+
+  visit('/');
+
+  andThen(function () {
+    var targetDB = find('.fa-database').first();
+
+    click(targetDB);
+
+    andThen(function () {
+      equal(find('.fa-table').length, 3);
+    });
+  });
+});
+
+test('Expanding a table will retrieve the first page of columns for that table.', function () {
+  expect(2);
+
+  visit('/');
+
+  andThen(function () {
+    var targetDB = find('.fa-database').first();
+
+    click(targetDB);
+
+    andThen(function () {
+      var targetTable = find('.fa-table').first();
+
+      click(targetTable);
+
+      andThen(function () {
+        equal(find('.columns').length, 1, 'Columns container was loaded.');
+        equal(find('.columns strong').length, 3, '3 columns were loaded for selected table.');
+      });
+    });
+  });
+});
+
+test('Searching for a table will display table results and column search field', function () {
+  expect(2);
+
+  visit('/');
+
+  andThen(function () {
+    fillIn(find('input').first(), 'table');
+    keyEvent(find('input').first(), 'keyup', 13);
+
+    andThen(function () {
+      equal(find('input').length, 2, 'Columns search input has been rendered.');
+      equal(find('.nav-tabs li').length, 2, 'Results tab has been redendered.');
+    });
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/history-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/history-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/history-test.js
new file mode 100644
index 0000000..35a950d
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/history-test.js
@@ -0,0 +1,95 @@
+/**
+ * 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 { test } from 'ember-qunit';
+import startApp from '../helpers/start-app';
+import api from '../helpers/api-mock';
+
+var App;
+var server;
+
+module('Integration: History', {
+  setup: function() {
+    App = startApp();
+    /* global Pretender: true */
+    server = new Pretender(api);
+  },
+
+  teardown: function() {
+    Ember.run(App, App.destroy);
+    server.shutdown();
+  }
+});
+
+test('Save Queries should list saved queries', function() {
+  expect(1);
+
+  visit("/history");
+
+  andThen(function() {
+    equal(find('#content .table tbody tr').length, 4);
+  });
+});
+
+test('User should be able to filter the jobs', function() {
+  expect(4);
+
+  visit("/history");
+
+  fillIn('column-filter input[placeholder=title]', "Query1");
+  keyEvent('column-filter input[placeholder=title]', 'keyup');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 1, 'User is able to filter by title');
+  });
+
+  click('.clear-filters');
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 4);
+  });
+
+
+  fillIn('column-filter input[placeholder=status]', "Finished");
+  keyEvent('column-filter input[placeholder=status]', 'keyup');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 2, 'User is able to filter by status');
+  });
+
+  click('.clear-filters');
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 4);
+  });
+});
+
+test('A query item should expand to show the HQL', function() {
+  expect(3);
+  visit("/history");
+
+  andThen(function() {
+    equal(find('.table-expandable tbody .secondary-row').length, 0, 'All queries are collapsed');
+  });
+
+  click('.table-expandable tbody tr:first-child');
+
+  andThen(function() {
+    equal(find('.table-expandable tbody .secondary-row').length, 1, 'One query is expanded');
+    ok(find('.table-expandable tbody tr:first-child').next().hasClass('secondary-row'), 'Clicked query is expanded');
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/query-editor-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/query-editor-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/query-editor-test.js
new file mode 100644
index 0000000..b409e12
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/query-editor-test.js
@@ -0,0 +1,106 @@
+/**
+ * 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 { test } from 'ember-qunit';
+import startApp from '../helpers/start-app';
+import api from '../helpers/api-mock';
+
+var App;
+var server;
+
+module('Integration: Query Editor', {
+  setup: function() {
+    App = startApp();
+    /* global Pretender: true */
+    server = new Pretender(api);
+  },
+
+  teardown: function() {
+    Ember.run(App, App.destroy);
+    server.shutdown();
+  }
+});
+
+test('Query Editor is visible', function() {
+  expect(1);
+
+  visit("/");
+
+  andThen(function() {
+    equal(find('.query-editor-panel').length, 1, 'Query Editor is visible');
+  });
+});
+
+test('Can execute query either with full or partial selection', function() {
+  expect(3);
+
+  var query1 = "select count(*) from table1;",
+      query2 = "select color from z;",
+      query3 = "select fruit from z;",
+      query4 = query2 + "\n" + query3,
+      editor;
+
+  visit("/");
+
+  Ember.run(function() {
+    editor = find('.CodeMirror').get(0).CodeMirror;
+    editor.setValue(query1);
+  });
+
+  click('.execute-query');
+
+  andThen(function() {
+    equal(find('.query-process-results-panel').length, 1, 'Job tabs are visible.');
+  });
+
+  Ember.run(function() {
+    editor.setValue(query4);
+    editor.setSelection({ line: 1, ch: 0 }, { line: 1, ch: 20 });
+  });
+
+  click('.execute-query');
+
+  andThen(function() {
+    equal(editor.getValue(), query4, 'Editor value didn\'t change');
+    equal(editor.getSelection(), query3, 'Query 3 is selected');
+  });
+});
+
+
+test('Can save query', function() {
+  expect(2);
+
+  visit("/");
+
+  andThen(function() {
+    equal(find('.modal-dialog').length, 0, 'Modal dialog is hidden');
+  });
+
+  Ember.run(function() {
+    find('.CodeMirror').get(0).CodeMirror.setValue('select count(*) from table1');
+  });
+
+  click('.save-query-as');
+
+  andThen(function() {
+    equal(find('.modal-dialog').length, 1, 'Modal dialog is shown');
+  });
+
+  click('.modal-footer .btn-danger');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/saved-queries-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/saved-queries-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/saved-queries-test.js
new file mode 100644
index 0000000..c444523
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/saved-queries-test.js
@@ -0,0 +1,126 @@
+/**
+ * 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 { test } from 'ember-qunit';
+import startApp from '../helpers/start-app';
+import api from '../helpers/api-mock';
+
+var App;
+var server;
+
+module('Integration: Saved Queries', {
+  setup: function() {
+    App = startApp();
+    /* global Pretender: true */
+    server = new Pretender(api);
+  },
+
+  teardown: function() {
+    Ember.run(App, App.destroy);
+    server.shutdown();
+  }
+});
+
+test('Save Queries should list saved queries', function() {
+  expect(1);
+
+  visit("/queries");
+
+
+  andThen(function() {
+    equal(find('#content .table tbody tr').length, 2);
+  });
+});
+
+test('User should be able to filter the queries', function() {
+  expect(8);
+
+  visit("/queries");
+
+  fillIn('column-filter input[placeholder=preview]', "select count");
+  keyEvent('column-filter input[placeholder=preview]', 'keyup');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 1, 'User is able to filter by short query form.');
+  });
+
+  click('.clear-filters');
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 2);
+  });
+
+  fillIn('column-filter input[placeholder=title]', "saved1");
+  keyEvent('column-filter input[placeholder=title]', 'keyup');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 1, 'User is able to filter by title');
+  });
+
+  click('.clear-filters');
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 2);
+  });
+
+  fillIn('column-filter input[placeholder=database]', "db1");
+  keyEvent('column-filter input[placeholder=database]', 'keyup');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 1, 'User is able to filter by database');
+  });
+
+  click('.clear-filters');
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 2);
+  });
+
+  fillIn('column-filter input[placeholder=owner]', "owner1");
+  keyEvent('column-filter input[placeholder=owner]', 'keyup');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 1, 'User is able to filter by owner');
+  });
+
+  click('.clear-filters');
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 2);
+  });
+});
+
+test('User is able to load a query from saved queries', function() {
+  expect(1);
+
+  visit("/queries");
+  click('#content .table tbody tr:first-child td:first-child a');
+
+  andThen(function() {
+    equal(currentURL(), "/queries/1", 'User is redirected');
+  });
+});
+
+test('Saved Query options menu', function() {
+  expect(2);
+
+  visit("/queries");
+  click('.fa-gear');
+
+  andThen(function() {
+    equal(find('.dropdown-menu:visible').length, 1, 'Query menu is visible');
+    equal(find('.dropdown-menu:visible li').length, 2, 'Query menu has 2 options');
+  });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/tez-ui-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/tez-ui-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/tez-ui-test.js
new file mode 100644
index 0000000..f64dcb2
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/tez-ui-test.js
@@ -0,0 +1,49 @@
+/**
+ * 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 { test } from 'ember-qunit';
+import startApp from '../helpers/start-app';
+import api from '../helpers/api-mock';
+
+var App;
+var server;
+
+module('Integration: Tez UI', {
+  setup: function() {
+    App = startApp();
+    /* global Pretender: true */
+    server = new Pretender(api);
+  },
+
+  teardown: function() {
+    Ember.run(App, App.destroy);
+    server.shutdown();
+  }
+});
+
+test('An error is show when there is no dag', function() {
+  expect(1);
+
+  visit("/");
+  click('#tez-icon');
+
+  andThen(function() {
+    ok(find('.panel .alert .alert-danger'), 'Error is visible');
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/udfs-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/udfs-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/udfs-test.js
new file mode 100644
index 0000000..95a0043
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/integration/udfs-test.js
@@ -0,0 +1,91 @@
+/**
+ * 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 { test } from 'ember-qunit';
+import startApp from '../helpers/start-app';
+import api from '../helpers/api-mock';
+
+var App;
+var server;
+
+module('Integration: Udfs', {
+  setup: function() {
+    App = startApp();
+    /* global Pretender: true */
+    server = new Pretender(api);
+  },
+
+  teardown: function() {
+    Ember.run(App, App.destroy);
+    server.shutdown();
+  }
+});
+
+test('Save Queries should list saved queries', function() {
+  expect(1);
+
+  visit("/udfs");
+
+  andThen(function() {
+    equal(find('#content .table tbody tr').length, 2);
+  });
+});
+
+test('User should be able to filter the udfs', function() {
+  expect(4);
+
+  visit("/udfs");
+
+  fillIn('column-filter input[placeholder="udf name"]', "TestColumn");
+  keyEvent('column-filter input[placeholder="udf name"]', 'keyup');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 1, 'User is able to filter by name');
+  });
+
+  click('.clear-filters');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 2);
+  });
+
+  fillIn('column-filter input[placeholder="udf class name"]', "TestClassName");
+  keyEvent('column-filter input[placeholder="udf class name"]', 'keyup');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 1, 'User is able to filter by class name');
+  });
+
+  click('.clear-filters');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr:visible').length, 2);
+  });
+});
+
+test('User is able to add udf', function() {
+  expect(1);
+
+  visit("/udfs");
+  click('.add-udf');
+
+  andThen(function() {
+    equal(find('#content .table tbody tr').length, 3);
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/test-helper.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/test-helper.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/test-helper.js
new file mode 100644
index 0000000..96975ee
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/test-helper.js
@@ -0,0 +1,24 @@
+/**
+ * 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 resolver from './helpers/resolver';
+import {
+  setResolver
+} from 'ember-qunit';
+
+setResolver(resolver);

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/.gitkeep
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/.gitkeep b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/adapters/application.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/adapters/application.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/adapters/application.js
new file mode 100644
index 0000000..6e28a40
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/adapters/application.js
@@ -0,0 +1,48 @@
+/**
+ * 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 {
+  moduleFor,
+  test
+} from 'ember-qunit';
+
+import constants from 'hive/utils/constants';
+
+moduleFor('adapter:application', 'ApplicationAdapter', {
+  // Specify the other units that are required for this test.
+  // needs: ['serializer:foo']
+});
+
+// Replace this with your real tests.
+test('X-Requested-By header is set.', function() {
+  expect(1);
+
+  var adapter = this.subject();
+
+  ok(adapter.get('headers.X-Requested-By'), 'X-Requested-By is set to a truthy value.');
+});
+
+test('buildUrl returns an url with default values for version and instance paramters if not running within an Ambari instance.', function () {
+  expect(1);
+
+  var adapter = this.subject();
+
+  var url = adapter.buildURL();
+
+  equal(url, constants.adapter.apiPrefix + constants.adapter.version + constants.adapter.instancePrefix + 'Hive');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/adapters/file.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/adapters/file.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/adapters/file.js
new file mode 100644
index 0000000..ea70232
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/adapters/file.js
@@ -0,0 +1,39 @@
+/**
+ * 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 {
+  moduleFor,
+  test
+} from 'ember-qunit';
+
+import constants from 'hive/utils/constants';
+
+moduleFor('adapter:file', 'FileAdapter', {
+  // Specify the other units that are required for this test.
+  // needs: ['serializer:foo']
+});
+
+// Replace this with your real tests.
+test('pathForType returns correct path.', function() {
+  expect(1);
+
+  var adapter = this.subject();
+  var type = 'dummy';
+
+  equal(adapter.pathForType(type), constants.adapter.resourcePrefix + type);
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/alert-message-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/alert-message-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/alert-message-widget-test.js
new file mode 100644
index 0000000..8f0f245
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/alert-message-widget-test.js
@@ -0,0 +1,91 @@
+/**
+ * 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 { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('alert-message-widget', 'AlertMessageWidgetComponent', {
+  needs: []
+});
+
+test('isExpanded is toggled on click', function() {
+  expect(2);
+
+  var message = Ember.Object.create({ isExpanded: false});
+
+  var component = this.subject({
+    message: message
+  });
+
+  Ember.run(function() {
+    component.send('toggleMessage');
+  });
+
+  equal(component.get('message.isExpanded'), true, 'isExpanded is set to true');
+
+  Ember.run(function() {
+    component.send('toggleMessage');
+  });
+
+  equal(component.get('message.isExpanded'), false, 'isExpanded is set to false');
+});
+
+test('removeLater should be called when the message is toggled', function() {
+  expect(1);
+
+  var message = Ember.Object.create({ isExpanded: false});
+
+  var targetObject = {
+    removeLater: function() {
+      ok(true, 'External removeLater called');
+    }
+  };
+
+  var component = this.subject({
+    targetObject: targetObject,
+    removeLater: 'removeLater',
+    message: message
+  });
+
+  Ember.run(function() {
+    component.send('toggleMessage');
+  });
+
+  Ember.run(function() {
+    component.send('toggleMessage');
+  });
+});
+
+test('remove action should call external removeMessage', function() {
+  expect(1);
+
+  var targetObject = {
+    removeMessage: function() {
+      ok(true, 'External removeMessage called');
+    }
+  };
+
+  var component = this.subject({
+    targetObject: targetObject,
+    removeMessage: 'removeMessage'
+  });
+
+  Ember.run(function() {
+    component.send('remove', {});
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/collapsible-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/collapsible-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/collapsible-widget-test.js
new file mode 100644
index 0000000..96a551f
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/collapsible-widget-test.js
@@ -0,0 +1,46 @@
+/**
+ * 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 { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('collapsible-widget', 'CollapsibleWidgetComponent', {
+  unit: true
+});
+
+test('Component expand/collapse toggle action', function () {
+  expect(1);
+
+  var targetObject = {
+    expanded: function() {
+      ok(true, 'External expanded called');
+    }
+  };
+
+  var component = this.subject({
+    targetObject: targetObject,
+    isExpanded: 'isExpanded',
+    expanded: 'expanded'
+  });
+
+  var $component = this.render();
+
+  Ember.run(function() {
+    component.set('isExpanded', false);
+    component.send('toggle', {});
+   });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/column-filter-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/column-filter-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/column-filter-widget-test.js
new file mode 100644
index 0000000..be8bdc4
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/column-filter-widget-test.js
@@ -0,0 +1,138 @@
+/**
+ * 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 { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('column-filter-widget', 'ColumnFilterWidgetComponent', {
+  needs: ['component:extended-input']
+});
+
+test('if a filterValue is set when the element is inserted, an action is being sent announcing a filter change', function () {
+  expect(1);
+
+  var column = Ember.Object.create({
+    caption: 'missing.translation'
+  });
+
+  var component = this.subject({ column: column });
+
+  Ember.run(function () {
+    component.set('filterValue', 'initial filter value');
+  });
+
+  var targetObject = {
+    externalAction: function(){
+      ok(true, 'initial filterValue set. Action has been sent.');
+    }
+  };
+
+  component.set('columnFiltered', 'externalAction');
+  component.set('targetObject', targetObject);
+
+  var $component = this.$();
+});
+
+test('isSorted returns true if the table is sorted by this column property', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  var column = Ember.Object.create({
+    property: 'some prop'
+  });
+
+  Ember.run(function () {
+    component.set('column', column);
+    component.set('sortProperties', [column.property]);
+  });
+
+  ok(component.get('isSorted'));
+});
+
+test('isSorted returns false if the table is sorted by some other column', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  var column = Ember.Object.create({
+    property: 'some prop'
+  });
+
+  Ember.run(function () {
+    component.set('column', column);
+    component.set('sortProperties', ['other prop']);
+  });
+
+  ok(!component.get('isSorted'));
+});
+
+test('isSorted returns false if the table is not sorted by any column', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  var column = Ember.Object.create({
+    property: 'some prop'
+  });
+
+  Ember.run(function () {
+    component.set('column', column);
+    component.set('sortProperties', []);
+  });
+
+  ok(!component.get('isSorted'));
+});
+
+test('when sendSort gets called, the columnSorted action gets sent.', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  var targetObject = {
+    externalAction: function(){
+      ok(true, 'columnSorted action has been intercepted.');
+    }
+  };
+
+  Ember.run(function () {
+    component.set('targetObject', targetObject);
+    component.set('columnSorted', 'externalAction');
+
+    component.send('sendSort');
+  });
+});
+
+test('when sendFilter gets called, the columnFiltered action gets sent.', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  var targetObject = {
+    externalAction: function(){
+      ok(true, 'columnFiltered action has been intercepted.');
+    }
+  };
+
+  Ember.run(function () {
+    component.set('targetObject', targetObject);
+    component.set('columnFiltered', 'externalAction');
+
+    component.send('sendFilter');
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/date-range-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/date-range-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/date-range-widget-test.js
new file mode 100644
index 0000000..766e9ee
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/date-range-widget-test.js
@@ -0,0 +1,132 @@
+/**
+ * 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.
+ */
+
+/* global moment */
+
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('date-range-widget', 'DateRangeWidgetComponent', {
+  needs: ['component:extended-input']
+});
+
+test('Date fields are set correctly', function() {
+  expect(2);
+
+  var component = this.subject();
+
+  var min = moment('04/11/2014', 'DD/MM/YYYY');
+  var max = moment('04/12/2014', 'DD/MM/YYYY');
+  var from = moment('04/11/2014', 'DD/MM/YYYY');
+  var to = moment('04/12/2014', 'DD/MM/YYYY');
+
+  var dateRange = Ember.Object.create({
+    from: from.toString(),
+    to: to.toString(),
+    min: min.toString(),
+    max: max.toString()
+  });
+
+  component.set('dateRange', Ember.Object.create());
+
+  var $component = this.$();
+
+  Ember.run(function() {
+    component.set('dateRange', dateRange);
+  });
+
+  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");
+});
+
+test('Date fields updates when the date is changed', function() {
+  expect(2);
+
+  var component = this.subject();
+
+  var min = moment('04/11/2014', 'DD/MM/YYYY');
+  var max = moment('04/12/2014', 'DD/MM/YYYY');
+  var from = moment('04/11/2014', 'DD/MM/YYYY');
+  var to = moment('04/12/2014', 'DD/MM/YYYY');
+
+  var dateRange = Ember.Object.create({
+    from: from.toString(),
+    to: to.toString(),
+    min: min.toString(),
+    max: max.toString()
+  });
+
+  Ember.run(function() {
+    component.set('dateRange', dateRange);
+  });
+
+  var $component = this.$();
+  $component.find('.fromDate').datepicker('setDate', '10/10/2014');
+  $component.find('.toDate').datepicker('setDate', '11/11/2014');
+
+  equal($component.find('.fromDate').val(), '10/10/2014', "From date field is updated");
+  equal($component.find('.toDate').val(), '11/11/2014', "To date field is updated");
+});
+
+test('Display dates are formatted correctly', function(){
+  expect(2);
+
+  var component = this.subject();
+
+  var min = moment('04/11/2014', 'DD/MM/YYYY');
+  var max = moment('04/12/2014', 'DD/MM/YYYY');
+  var from = moment('04/11/2014', 'DD/MM/YYYY');
+  var to = moment('04/12/2014', 'DD/MM/YYYY');
+
+  var dateRange = Ember.Object.create({
+    from: from.toString(),
+    to: to.toString(),
+    min: min.toString(),
+    max: max.toString()
+  });
+
+  Ember.run(function () {
+    component.set('dateRange', dateRange);
+  });
+
+  equal(component.get('displayFromDate'), '11/04/2014', "displayFromDate is formatted correctly");
+  equal(component.get('displayToDate'), '12/04/2014', "displayToDate is formatted correctly");
+});
+
+test('If from/to are not passed they are set to min/max', function() {
+  expect(2);
+
+  var component = this.subject();
+
+  var min = moment('04/11/2014', 'DD/MM/YYYY');
+  var max = moment('04/12/2014', 'DD/MM/YYYY');
+
+  var dateRange = Ember.Object.create({
+    min: min.toString(),
+    max: max.toString()
+  });
+
+  Ember.run(function () {
+    component.set('dateRange', dateRange);
+  });
+
+  var $component = this.$();
+
+  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/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/expander-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/expander-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/expander-widget-test.js
new file mode 100644
index 0000000..8d1f07a
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/expander-widget-test.js
@@ -0,0 +1,59 @@
+/**
+ * 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 { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('expander-widget', 'ExpanderWidgetComponent', {
+  unit: true
+});
+
+test('should set the heading when provided.', function () {
+  expect(2);
+
+  var component = this.subject();
+  var $component = this.$();
+  var heading = 'some header';
+
+  equal($component.find('.accordion-toggle').text(), '');
+
+  Ember.run(function () {
+    component.set('heading', heading);
+  });
+
+  equal($component.find('.accordion-toggle').text(), heading);
+});
+
+test('should correctly toggle isExpanded property.', function () {
+  expect(2);
+
+  var component = this.subject();
+  this.$();
+
+  Ember.run(function(){
+    component.send('toggle');
+  });
+
+  equal(component.get('isExpanded'), true);
+
+  Ember.run(function(){
+    component.send('toggle');
+  });
+
+  equal(component.get('isExpanded'), false);
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/extended-input-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/extended-input-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/extended-input-test.js
new file mode 100644
index 0000000..aa861aa
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/extended-input-test.js
@@ -0,0 +1,81 @@
+/**
+ * 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 { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('extended-input', 'ExtendedInputComponent', {
+  unit: true
+});
+
+test('Component has dynamicValue and dynamicContext', function () {
+  expect(1);
+
+  var component = this.subject({
+    dynamicValue: 'dynamicValue',
+    dynamicContext: Ember.Object.create({ 'dynamicValue' : 'test' })
+  });
+
+  var $component = this.$();
+
+  equal(component.get('value'), 'test', 'Value is set to dynamicValue value');
+});
+
+
+test('Component has no dynamicValue and dynamicContext', function () {
+  expect(1);
+
+  var component = this.subject();
+  var $component = this.$();
+
+  ok(!component.get('value'), 'Value is not set as dynamicValue value');
+});
+
+test("Component's dynamicValue is set", function () {
+  expect(1);
+
+  var component = this.subject({
+    dynamicValue: 'dynamicValue',
+    dynamicContext: Ember.Object.create({ 'dynamicValue' : 'test' })
+  });
+
+  var $component = this.$();
+
+  Ember.run(function() {
+    component.sendValueChanged();
+
+    equal(component.get('value'), component.dynamicContext.get('dynamicValue'), "Value is set and dynamicValue is set");
+  });
+});
+
+test("Component's dynamicValue is not set", function () {
+  expect(1);
+
+  var component = this.subject({
+    dynamicValue: 'dynamicValue',
+    dynamicContext: Ember.Object.create({ })
+  });
+
+  var $component = this.$();
+
+  Ember.run(function() {
+    component.sendValueChanged();
+
+    equal(component.get('value'), undefined, "Value is not set");
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/job-tr-view-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/job-tr-view-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/job-tr-view-test.js
new file mode 100644
index 0000000..d39a85e
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/job-tr-view-test.js
@@ -0,0 +1,62 @@
+/**
+ * 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 constants from 'hive/utils/constants';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('job-tr-view', 'JobTrViewComponent', {
+  unit: true
+});
+
+test('Statuses are computed correctly', function (assert) {
+  assert.expect(5);
+
+  var component = this.subject();
+
+  Ember.run(function() {
+    component.set('job', Ember.Object.create());
+    component.set('job.status', constants.statuses.running);
+  });
+
+  assert.equal(component.get('canStop'), true, 'Status is running canStop returns true');
+
+  Ember.run(function() {
+    component.set('job.status', constants.statuses.initialized);
+  });
+
+  assert.equal(component.get('canStop'), true, 'Status is initialized canStop returns true');
+
+  Ember.run(function() {
+    component.set('job.status', constants.statuses.pending);
+  });
+
+  assert.equal(component.get('canStop'), true, 'Status is pending canStop returns true');
+
+  Ember.run(function() {
+    component.set('job.status', constants.statuses.canceled);
+  });
+
+  assert.equal(component.get('canStop'), false, 'Status is canceled canStop returns false');
+
+  Ember.run(function() {
+    component.set('job.status', constants.statuses.unknown);
+  });
+
+  assert.equal(component.get('canStop'), false, 'Status is unknown canStop returns false');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/modal-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/modal-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/modal-widget-test.js
new file mode 100644
index 0000000..3016444
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/modal-widget-test.js
@@ -0,0 +1,69 @@
+/**
+ * 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 constants from 'hive/utils/constants';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('modal-widget', 'ModalWidgetComponent', {
+  needs: ['helper:tb-helper']
+});
+
+test('It send ok action on keyPress enter', function(assert) {
+  assert.expect(1);
+
+  Ember.run.debounce = function(target, func) {
+    func.call(target);
+  };
+
+  var component = this.subject({
+    ok: 'ok',
+    targetObject: {
+      ok: function() {
+        assert.ok(1, 'OK action sent');
+      }
+    }
+  });
+
+  var $component = this.$();
+
+  component.keyPress({ which: 13 });
+  Ember.$('.modal-backdrop').remove(); // remove overlay
+});
+
+test('It send close action on keyPress escape', function(assert) {
+  assert.expect(1);
+
+  Ember.run.debounce = function(target, func) {
+    func.call(target);
+  };
+
+  var component = this.subject({
+    close: 'close',
+    targetObject: {
+      close: function() {
+        assert.ok(1, 'Close action sent');
+      }
+    }
+  });
+
+  var $component = this.$();
+
+  component.keyPress({ which: 27 });
+  Ember.$('.modal-backdrop').remove(); // remove overlay
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/no-bubbling-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/no-bubbling-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/no-bubbling-test.js
new file mode 100644
index 0000000..47a1a0f
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/no-bubbling-test.js
@@ -0,0 +1,44 @@
+/**
+ * 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 { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('no-bubbling', 'NoBubblingWidgetComponent', {
+  unit: true
+});
+
+
+test('External actions', function() {
+  expect(2);
+
+  var component = this.subject({
+    targetObject: {
+      click: function(data) {
+        ok(true, 'External click action called');
+        equal(data, 'data', 'Data is sent with the action');
+      }
+    },
+    click: 'click',
+    data: 'data'
+  });
+
+  var $component = this.$();
+
+  $component.trigger('click');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/number-range-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/number-range-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/number-range-widget-test.js
new file mode 100644
index 0000000..edc65b1
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/number-range-widget-test.js
@@ -0,0 +1,70 @@
+/**
+ * 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.
+ */
+
+/* global moment */
+
+import Ember from 'ember';
+import { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('number-range-widget', 'NumberRangeWidgetComponent', {
+  needs: ['component:extended-input']
+});
+
+
+test('Component is initialized correctly', function() {
+  expect(2);
+
+  var numberRange = Ember.Object.create({
+    max: 1,
+    min: 0
+  });
+
+  var component = this.subject({ numberRange: numberRange });
+  var $component = this.$();
+
+  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');
+
+});
+
+test('external change action is called', function() {
+  expect(1);
+
+  var targetObject = {
+    rangeChanged: function() {
+      ok(true, 'rangeChanged external action called');
+    }
+  };
+
+  var numberRange = Ember.Object.create({
+    max: 1,
+    min: 0
+  });
+
+  var component = this.subject({
+    numberRange: numberRange,
+    targetObject: targetObject,
+    rangeChanged: 'rangeChanged'
+  });
+
+  var $component = this.$();
+
+  Ember.run(function() {
+    $component.find('.slider').slider('value', 1);
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/popover-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/popover-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/popover-widget-test.js
new file mode 100644
index 0000000..84bec76
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/popover-widget-test.js
@@ -0,0 +1,36 @@
+/**
+ * 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 { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('popover-widget', 'PopoverWidgetComponent', {
+  unit: true
+});
+
+test('Component initializes correctly', function () {
+  expect(2);
+
+  var component = this.subject({
+    template: Ember.Handlebars.compile("test")
+  });
+  var $component = this.$();
+
+  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/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/progress-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/progress-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/progress-widget-test.js
new file mode 100644
index 0000000..3984f62
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/progress-widget-test.js
@@ -0,0 +1,40 @@
+/**
+ * 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 { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('progress-widget', 'ProgressWidgetComponent', {
+  unit: true
+});
+
+test('Percentage is updated on value change', function() {
+  var component = this.subject({
+    value: 0
+  });
+
+  this.$();
+
+  equal(component.get('percentage'), '0%', 'Progress is at 0%');
+
+  Ember.run(function() {
+    component.set('value', 50);
+  });
+
+  equal(component.get('percentage'), '50%', 'Progress is at 50%');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/query-editor-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/query-editor-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/query-editor-test.js
new file mode 100644
index 0000000..e70b5ee
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/query-editor-test.js
@@ -0,0 +1,52 @@
+/**
+ * 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 { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('query-editor', 'QueryEditorComponent', {
+  unit: true
+});
+
+test('initEditor sets the editor on didInsertElement', function () {
+  expect(2);
+
+  var component = this.subject();
+
+  equal(component.get('editor'), undefined, 'element not rendered. Editor not set.');
+
+  this.$();
+
+  ok(component.get('editor'), 'element rendered. Editor set.');
+});
+
+test('updateValue sets the query value on the editor.', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  var query = 'select something';
+
+  this.$();
+
+  Ember.run(function () {
+    component.set(('query'), query);
+  });
+
+  equal(component.get('editor').getValue(), query, 'set query property. Updated editor value property.');
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/select-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/select-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/select-widget-test.js
new file mode 100644
index 0000000..a186508
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/select-widget-test.js
@@ -0,0 +1,158 @@
+/**
+ * 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 { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('select-widget', 'SelectWidgetComponent', {
+  needs: ['helper:path-binding']
+});
+
+test('selectedLabel returns the selectedValue property indicated by labelPath if selectedValue and labelPath are set.', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  var selectedValue = Ember.Object.extend({
+    label: 'db'
+  }).create();
+
+  var labelPath = 'label';
+
+  Ember.run(function () {
+    component.set('labelPath', labelPath);
+    component.set('selectedValue', selectedValue);
+  });
+
+  equal(component.get('selectedLabel'), selectedValue.label, 'selectedValue and labelPath are set. selectedLabel returns selectedValue[labelPath].');
+});
+
+test('selectedLabel returns defaultLabel if selectedValue is falsy and defaultLabel is set.', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  var defaultLabel = 'select...';
+
+  Ember.run(function () {
+    component.set('defaultLabel', defaultLabel);
+  });
+
+  equal(component.get('selectedLabel'), defaultLabel, 'selectedValue falsy and defaultLabel set. selectedLabel returns defaultLabel.');
+});
+
+test('selectedLabel returns undefined if neither selectedValue nor defaultLabel are set.', function () {
+  expect(1);
+
+  var component = this.subject();
+
+  equal(component.get('selectedLabel'), undefined, 'selectedValue and defaultLabel are falsy. selectedLabel returns undefined.');
+});
+
+test('selectedLabel is computed when selectedValue changes.', function () {
+  expect(2);
+
+  var component = this.subject();
+
+  var selectedValue = Ember.Object.extend({
+    label: 'db'
+  }).create();
+
+  var labelPath = 'label';
+
+  equal(component.get('selectedLabel'), undefined, 'selectedValue and defaultLabel are falsy. selectedLabel returns undefined.');
+
+  Ember.run(function () {
+    component.set('labelPath', labelPath);
+    component.set('selectedValue', selectedValue);
+  });
+
+  equal(component.get('selectedLabel'), selectedValue.label, 'selectedValue and labelPath are set. selectedLabel returns selectedValue[labelPath].');
+});
+
+test('renders an li tag for each item in the items collection.', function () {
+  expect(2);
+
+  var component = this.subject();
+  var $component = this.$();
+
+  equal($component.find('li').length, 0, 'items collection is not set. No li tags are rendered.');
+
+  Ember.run(function() {
+    var items = Ember.ArrayProxy.create({ content: Ember.A([Ember.Object.create(), Ember.Object.create()])});
+    component.set('labelPath', 'name');
+    component.set('items', items);
+  });
+
+  equal($component.find('li').length, 2, 'items collection is set containing one item. One li tag is rendered.');
+});
+
+test('if no selected item nor defaultLabel set the selected value with first item', function () {
+  expect(1);
+
+  var items = [
+    'item1',
+    'item2'
+  ];
+
+  var component = this.subject({ items: items });
+  var $component = this.$();
+
+  equal(component.get('selectedValue'), 'item1', 'selectedValue is set to first item')
+});
+
+test('component actions', function() {
+  expect(7);
+
+  var targetObject = {
+    itemAdded: function() {
+      ok(true, 'External action itemAdded called')
+    },
+    itemEdited: function(item) {
+      ok(true, 'External action itemEdited called');
+      equal(item, 'editedItem', 'Data is sent with action');
+    },
+    itemRemoved: function(item) {
+      ok(true, 'External action itemRemoved called');
+      equal(item, 'removedItem', 'Data is sent with action');
+    }
+  };
+  var component = this.subject({
+    items: ['item'],
+    itemAdded: 'itemAdded',
+    itemEdited: 'itemEdited',
+    itemRemoved: 'itemRemoved',
+    targetObject: targetObject
+  });
+
+  var $component = this.$();
+
+  equal(component.get('selectedValue'), 'item', 'selectedValue is set to first item');
+
+  Ember.run(function() {
+    component.send('select', 'newItem');
+    component.send('add');
+    component.send('edit', 'editedItem');
+    component.send('remove', 'removedItem');
+  });
+
+  equal(component.get('selectedValue'), 'newItem', 'selectedValue is set to newItem');
+
+
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/tabs-wiget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/tabs-wiget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/tabs-wiget-test.js
new file mode 100644
index 0000000..17b2242
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/tabs-wiget-test.js
@@ -0,0 +1,117 @@
+/**
+ * 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 { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('tabs-widget', 'TabsWidgetComponent', {
+  needs: []
+});
+
+test('First tab active by default', function() {
+  expect(2);
+
+  var tabs = Ember.ArrayProxy.create({content: Ember.A([
+    Ember.Object.create(),
+    Ember.Object.create()
+  ])});
+
+  var component = this.subject({ tabs: tabs });
+  var $component = this.$();
+
+  ok(component.get('tabs.firstObject.active'), 'First tab is active');
+  ok(!component.get('tabs.lastObject.active'), 'Second tab is not active');
+});
+
+
+test('Set active tab on init', function() {
+  expect(2);
+
+  var tabs = Ember.ArrayProxy.create({content: Ember.A([
+    Ember.Object.create(),
+    Ember.Object.create(),
+    Ember.Object.create({ active: true })
+  ])});
+
+  var component = this.subject({ tabs: tabs });
+
+  ok(!component.get('tabs.firstObject.active'), 'First tab is not active');
+  ok(component.get('tabs.lastObject.active'), 'Last tab is active');
+});
+
+
+test('Set active tab', function() {
+  expect(3);
+
+  var tabs = Ember.ArrayProxy.create({content: Ember.A([
+    Ember.Object.create(),
+    Ember.Object.create(),
+    Ember.Object.create({ active: true })
+  ])});
+
+  var component = this.subject({ tabs: tabs });
+
+  ok(!component.get('tabs.firstObject.active'), 'First tab is not active');
+  ok(component.get('tabs.lastObject.active'), 'Last tab is active');
+
+  Ember.run(function() {
+    component.send('selectTab', tabs.objectAt(1));
+  });
+
+  ok(component.get('tabs').objectAt(1).get('active'), 'Second tab is active');
+});
+
+test('removeEnabled tabs', function() {
+  expect(2);
+
+  var tabs = Ember.ArrayProxy.create({content: Ember.A([
+    Ember.Object.create(),
+    Ember.Object.create(),
+    Ember.Object.create({ active: true })
+  ])});
+
+  var component = this.subject({ tabs: tabs, canRemove: true });
+
+  ok(component.get('removeEnabled'), 'More than one tab removeEnabled returns true');
+
+  Ember.run(function() {
+    component.get('tabs').popObject();
+    component.get('tabs').popObject();
+  });
+
+  ok(!component.get('removeEnabled'), 'Only one tab removeEnabled returns false');
+});
+
+test('remove tab', function () {
+  expect(1);
+
+  var targetObject = {
+    removeTabAction: function() {
+      ok(true, 'External remove tab action called');
+    }
+  };
+
+  var component = this.subject({
+    'removeClicked': 'removeTabAction',
+    'targetObject': targetObject
+  });
+
+  Ember.run(function() {
+    component.send('remove', {});
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/b88db3cc/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/typeahead-widget-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/typeahead-widget-test.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/typeahead-widget-test.js
new file mode 100644
index 0000000..7d989a4
--- /dev/null
+++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/tests/unit/components/typeahead-widget-test.js
@@ -0,0 +1,46 @@
+/**
+ * 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 { moduleForComponent, test } from 'ember-qunit';
+
+moduleForComponent('typeahead-widget', 'TypeaheadWidgetComponent', {
+  needs: ['component:ember-selectize']
+});
+
+test('Component is initialized correctly', function () {
+  expect(2);
+
+  var items = [
+    {name: 'item 1', id: 1},
+    {name: 'item 2', id: 2},
+    {name: 'item 3', id: 3},
+    {name: 'item 4', id: 4}
+  ];
+
+  var component = this.subject({
+    content: items,
+    optionValuePath: 'content.id',
+    optionLabelPath: 'content.name'
+  });
+
+  this.$();
+
+  equal(component.get('content.length'), items.length, 'Items are set');
+  equal(component.get('selection'), items[0], 'First object is set as default value');
+});