ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mithm...@apache.org
Subject [1/2] ambari git commit: AMBARI-18779: Fix the backend for HAWQ View BETA (adenissov via mithmatt)
Date Mon, 07 Nov 2016 21:29:43 GMT
Repository: ambari
Updated Branches:
  refs/heads/branch-2.5 d0bd2a032 -> 921a6350a


http://git-wip-us.apache.org/repos/asf/ambari/blob/921a6350/contrib/views/hawq/src/main/resources/ui/tests/unit/adapters/query-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hawq/src/main/resources/ui/tests/unit/adapters/query-test.js b/contrib/views/hawq/src/main/resources/ui/tests/unit/adapters/query-test.js
index bab0260..4eacd26 100644
--- a/contrib/views/hawq/src/main/resources/ui/tests/unit/adapters/query-test.js
+++ b/contrib/views/hawq/src/main/resources/ui/tests/unit/adapters/query-test.js
@@ -19,20 +19,17 @@
 /*jshint node:true*/
 /* global sinon */
 
-import { moduleFor, test } from 'ember-qunit';
+import {moduleFor, test} from 'ember-qunit';
 import Utils from 'hawq-view/utils/utils';
 
-moduleFor('adapter:query', 'Unit | Adapter | query', {
-  // Specify the other units that are required for this test.
-  // needs: ['serializer:foo']
-});
+moduleFor('adapter:query', 'Unit | Adapter | query', {});
 
-test('has the right namespace for testing', function(assert) {
+test('has the right namespace for testing', function (assert) {
   assert.expect(0);
   let spy = sinon.spy(Utils, 'getNamespace');
   let adapter = this.subject();
-  adapter.get('namespace');
+  adapter.buildURL();
 
   sinon.assert.calledOnce(spy);
   Utils.getNamespace.restore();
-});
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/921a6350/contrib/views/hawq/src/main/resources/ui/tests/unit/models/query-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hawq/src/main/resources/ui/tests/unit/models/query-test.js b/contrib/views/hawq/src/main/resources/ui/tests/unit/models/query-test.js
index b83130e..227325d 100644
--- a/contrib/views/hawq/src/main/resources/ui/tests/unit/models/query-test.js
+++ b/contrib/views/hawq/src/main/resources/ui/tests/unit/models/query-test.js
@@ -19,15 +19,12 @@
 /*jshint node:true*/
 /* global sinon */
 
-import { moduleForModel, test } from 'ember-qunit';
+import {moduleForModel, test} from 'ember-qunit';
 import Utils from 'hawq-view/utils/utils';
 
-moduleForModel('query', 'Unit | Model | query', {
-  // Specify the other units that are required for this test.
-  needs: []
-});
+moduleForModel('query', 'Unit | Model | query', {});
 
-test('#computeClientAddress called ', function(assert) {
+test('#computeClientAddress called ', function (assert) {
   assert.expect(0);
   let options = {
     clientHost: 'host',
@@ -42,7 +39,7 @@ test('#computeClientAddress called ', function(assert) {
   Utils.computeClientAddress.restore();
 });
 
-test('#generateStatusString called', function(assert) {
+test('#generateStatusString called', function (assert) {
   assert.expect(0);
   let options = {
     waiting: false,
@@ -55,4 +52,4 @@ test('#generateStatusString called', function(assert) {
   sinon.assert.calledOnce(spy);
   sinon.assert.calledWith(spy, options.waiting, options.waitingResource);
   Utils.generateStatusString.restore();
-});
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/921a6350/contrib/views/hawq/src/main/resources/ui/tests/unit/routes/main-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hawq/src/main/resources/ui/tests/unit/routes/main-test.js b/contrib/views/hawq/src/main/resources/ui/tests/unit/routes/main-test.js
index 7ad0b79..e3367d1 100644
--- a/contrib/views/hawq/src/main/resources/ui/tests/unit/routes/main-test.js
+++ b/contrib/views/hawq/src/main/resources/ui/tests/unit/routes/main-test.js
@@ -16,14 +16,11 @@
  * limitations under the License.
  */
 
-import { moduleFor, test } from 'ember-qunit';
+import {moduleFor, test} from 'ember-qunit';
 
-moduleFor('route:main', 'Unit | Route | main', {
-  // Specify the other units that are required for this test.
-  // needs: ['controller:foo']
-});
+moduleFor('route:main', 'Unit | Route | main', {});
 
-test('it exists', function(assert) {
+test('it exists', function (assert) {
   let route = this.subject();
   assert.ok(route);
-});
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/921a6350/contrib/views/hawq/src/main/resources/ui/tests/unit/serializers/query-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hawq/src/main/resources/ui/tests/unit/serializers/query-test.js
b/contrib/views/hawq/src/main/resources/ui/tests/unit/serializers/query-test.js
index 6cd5f88..e5c9ce9 100644
--- a/contrib/views/hawq/src/main/resources/ui/tests/unit/serializers/query-test.js
+++ b/contrib/views/hawq/src/main/resources/ui/tests/unit/serializers/query-test.js
@@ -16,19 +16,19 @@
  * limitations under the License.
  */
 
-import { moduleForModel, test } from 'ember-qunit';
+import {moduleForModel, test} from 'ember-qunit';
 import Pretender from 'pretender';
-import { getMockPayload } from 'hawq-view/tests/helpers/test-helper';
+import {getMockPayload} from 'hawq-view/tests/helpers/test-helper';
 
 var mockPayload = getMockPayload();
 let server;
 
 moduleForModel('query', 'Unit | Serializer | query', {
-  // Specify the other units that are required for this test.
   needs: ['serializer:query'],
+
   beforeEach() {
-    server = new Pretender(function() {
-      this.get('/queries', function() {
+    server = new Pretender(function () {
+      this.get('/queries', function () {
         return [200, {'Content-Type': 'application/json'}, JSON.stringify(mockPayload)];
       });
     });
@@ -39,10 +39,61 @@ moduleForModel('query', 'Unit | Serializer | query', {
   }
 });
 
-// Replace this with your real tests.
-test('it serializes records', function(assert) {
-  let record = this.subject();
-  let serializedRecord = record.serialize();
-  assert.ok(serializedRecord);
+test('it serializes all records', function (assert) {
+  return this.store().query('query', {fields: '*'}).then(function (queries) {
+    assert.equal(queries.get('length'), 2);
+  });
 });
 
+test('transforms payload correctly', function (assert) {
+  return this.store().query('query', {fields: '*'}).then(function (queries) {
+    let expectedRecords = [
+      {
+        "applicationName": "",
+        "clientHost": "192.168.64.101",
+        "clientPort": 34941,
+        "queryText": "SELECT * FROM pg_stat_activity",
+        "databaseName": "template1",
+        "pid": 116662,
+        "duration": 0.0,
+        "queryStartTime": "2016-10-25 19:31:04",
+        "userName": "gpadmin",
+        "waiting": false,
+        "waitingResource": false
+      },
+      {
+        "applicationName": "",
+        "clientHost": "192.168.64.104",
+        "clientPort": 42811,
+        "queryText": "SELECT * FROM customers",
+        "databaseName": "gpadmin",
+        "pid": 12345,
+        "duration": 0.0,
+        "queryStartTime": "2016-10-25 19:31:24",
+        "userName": "gpadmin",
+        "waiting": true,
+        "waitingResource": true
+      }
+    ];
+
+    const keyList = [
+      "applicationName",
+      "clientHost",
+      "clientPort",
+      "queryText",
+      "databaseName",
+      "pid",
+      "duration",
+      "queryStartTime",
+      "userName",
+      "waiting",
+      "waitingResource"
+    ];
+
+    for (var i = 0, ii = expectedRecords.length; i < ii; i++) {
+      for (var j = 0; j < keyList.length; j++) {
+        assert.equal(queries.objectAtContent(i).get(keyList[j]), expectedRecords[i][keyList[j]]);
+      }
+    }
+  }, this);
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/921a6350/contrib/views/hawq/src/main/resources/ui/tests/unit/utils/utils-test.js
----------------------------------------------------------------------
diff --git a/contrib/views/hawq/src/main/resources/ui/tests/unit/utils/utils-test.js b/contrib/views/hawq/src/main/resources/ui/tests/unit/utils/utils-test.js
index 969ee6d..9d1f73f 100644
--- a/contrib/views/hawq/src/main/resources/ui/tests/unit/utils/utils-test.js
+++ b/contrib/views/hawq/src/main/resources/ui/tests/unit/utils/utils-test.js
@@ -20,86 +20,74 @@
 /* global sinon */
 
 import Utils from 'hawq-view/utils/utils';
-import { module, test } from 'qunit';
+import {module, test} from 'qunit';
 import ENV from 'hawq-view/config/environment';
 
 module('Unit | Utility | utils');
 
-test('#formatTimeOfDay: extracts time of day from a string', function(assert) {
-  assert.equal(Utils.formatTimeOfDay('2016-02-16T16:41:13'), '16:41:13');
+test('#computeClientAddress: compute clientAddress', function (assert) {
+  assert.equal(Utils.computeClientAddress('host', '9999'), 'host:9999');
 });
 
-// TODO:  make this TZ-independent for testing purposes
-//test('#formatTimeOfDay: extracts time of day from a string, in the local time zone', function(assert)
{
-//  assert.equal(Utils.formatTimeOfDay('2016-02-17T00:41:13+00:00'), '16:41:13');
-//});
-
-test('#formatTimeDelta: extracts time difference between two date strings', function(assert)
{
-  var spy = sinon.spy(Utils, 'calculateTimeDelta');
-  let backendStartTime = '2016-02-17T00:41:13-08:00';
-  let queryStartTime = '2016-02-17T01:43:43-08:00';
-  assert.equal(Utils.formatTimeDelta(backendStartTime, queryStartTime).text, '1h 2m 30s');
-  sinon.assert.calledOnce(spy);
-  sinon.assert.calledWith(spy, backendStartTime, queryStartTime);
-  Utils.calculateTimeDelta.restore();
+test('#computeClientAddress: computed host address', function (assert) {
+  assert.equal(Utils.computeClientAddress('host', 7777), 'host:7777', 'invalid computed client
address');
 });
 
-test('#formatTimeDelta: shows "0m 0s" for two identical times', function(assert) {
-  var response = Utils.formatTimeDelta('2016-02-17T00:41:13-08:00', '2016-02-17T00:41:13-08:00');
-  assert.equal(response.text, '0s');
-  assert.equal(response.value, 0);
+test('#computeClientAddress: computed host address, -1 port', function (assert) {
+  assert.equal(Utils.computeClientAddress('host', -1), 'local', 'invalid computed client
address');
 });
 
-test('#formatTimeDelta: shows "0m 0s" for the second time being earlier than the first',
function(assert) {
-  var response = Utils.formatTimeDelta('2016-02-17T00:45:13-08:00', '2016-02-17T00:41:13-08:00');
-  assert.equal(response.text, '0s');
-  assert.equal(response.value, 0);
+test('#computeClientAddress: computed host address, Undefined/Null/Empty Host', function
(assert) {
+  assert.equal(Utils.computeClientAddress(undefined, 7777), 'local', 'Invalid hostname: Undefined
clientHost');
+  assert.equal(Utils.computeClientAddress(null, 7777), 'local', 'Invalid hostname: Null clientHost');
+  assert.equal(Utils.computeClientAddress('', 7777), 'local', 'Invalid hostname: Empty clientHost');
 });
 
-test('#computeClientAddress: compute clientAddress', function(assert) {
-  assert.equal(Utils.computeClientAddress('host', '9999'), 'host:9999');
+test('#formatDuration returns 00:00:00 for null or undefined duration', function (assert)
{
+  assert.equal(Utils.formatDuration(null), "00:00:00");
+  assert.equal(Utils.formatDuration(), "00:00:00");
 });
 
-test('#computeClientAddress: computed host address', function(assert) {
-  assert.equal(Utils.computeClientAddress('host', 7777), 'host:7777', 'invalid computed client
address');
+test('#formatDuration returns correct string for query running for seconds', function (assert)
{
+  assert.equal(Utils.formatDuration(0), "00:00:00");
+  assert.equal(Utils.formatDuration(32), "00:00:32");
+  assert.equal(Utils.formatDuration(59), "00:00:59");
 });
 
-test('#computeClientAddress: computed host address, -1 port', function(assert) {
-  assert.equal(Utils.computeClientAddress('host', -1), 'local', 'invalid computed client
address');
+test('#formatDuration returns correct string for query running for minutes', function (assert)
{
+  assert.equal(Utils.formatDuration(60), "00:01:00");
+  assert.equal(Utils.formatDuration(72), "00:01:12");
+  assert.equal(Utils.formatDuration(3599), "00:59:59");
 });
 
-test('#computeClientAddress: computed host address, Undefined/Null/Empty Host', function(assert)
{
-  assert.equal(Utils.computeClientAddress(undefined, 7777), 'local', 'Invalid hostname: Undefined
clientHost');
-  assert.equal(Utils.computeClientAddress( null, 7777), 'local', 'Invalid hostname: Null
clientHost');
-  assert.equal(Utils.computeClientAddress('', 7777), 'local', 'Invalid hostname: Empty clientHost');
+test('#formatDuration returns correct string for query running for hours', function (assert)
{
+  assert.equal(Utils.formatDuration(3600), "01:00:00");
+  assert.equal(Utils.formatDuration(7272), "02:01:12");
+  assert.equal(Utils.formatDuration(363599), "100:59:59");
 });
 
-test('#getNamespace returns namespace for testing', function(assert) {
+test('#getNamespace returns namespace for testing', function (assert) {
   assert.equal(Utils.getNamespace(), ENV.apiURL);
 });
 
-test('#getNamespace returns namespace for production', function(assert) {
-  var baseNamespace = 'foo/';
+test('#getNamespace returns namespace for production', function (assert) {
+  var baseNamespace = '/views/HAWQ/1.0.0/HAWQView/';
   var oldEnvironment = ENV.environment;
   ENV.environment = 'production';
   sinon.stub(Utils, 'getWindowPathname').returns(baseNamespace);
-  assert.equal(Utils.getNamespace(), baseNamespace + ENV.apiURL);
+  assert.equal(Utils.getNamespace(), '/api/v1/views/HAWQ/versions/1.0.0/instances/HAWQView');
   Utils.getWindowPathname.restore();
   ENV.environment = oldEnvironment;
 });
 
-test('#generateStatusString returns "Running" when waiting and waitingResource are both false',
function(assert) {
+test('#generateStatusString returns "Running" when waiting and waitingResource are both false',
function (assert) {
   assert.equal(Utils.generateStatusString(false, false), 'Running');
 });
 
-test('#generateStatusString returns "Waiting on Lock" when waiting is true', function(assert)
{
+test('#generateStatusString returns "Waiting on Lock" when waiting is true', function (assert)
{
   assert.equal(Utils.generateStatusString(true, false), 'Waiting on Lock');
 });
 
-test('#generateStatusString returns "Queued" when waitingResource is true', function(assert)
{
+test('#generateStatusString returns "Queued" when waitingResource is true', function (assert)
{
   assert.equal(Utils.generateStatusString(true, true), 'Queued');
-});
-
-test('#calculateTimeDelta returns difference between two time objects', function(assert)
{
-  assert.equal(Utils.calculateTimeDelta('2016-02-17T00:41:13-08:00', '2016-02-17T11:52:24-08:00'),
40271000);
-});
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/921a6350/contrib/views/hawq/src/main/resources/view.log4j.properties
----------------------------------------------------------------------
diff --git a/contrib/views/hawq/src/main/resources/view.log4j.properties b/contrib/views/hawq/src/main/resources/view.log4j.properties
new file mode 100644
index 0000000..0bd9102
--- /dev/null
+++ b/contrib/views/hawq/src/main/resources/view.log4j.properties
@@ -0,0 +1,27 @@
+# Copyright 2011 The Apache Software Foundation
+#
+# 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.
+
+log4j.appender.hawqView=org.apache.log4j.RollingFileAppender
+log4j.appender.hawqView.File=${ambari.log.dir}/hawq-view/hawq-view.log
+log4j.appender.hawqView.MaxFileSize=80MB
+log4j.appender.hawqView.MaxBackupIndex=60
+log4j.appender.hawqView.layout=org.apache.log4j.PatternLayout
+log4j.appender.hawqView.layout.ConversionPattern=%d{DATE} %5p [%t] [%X{viewName} %X{viewVersion}
%X{viewInstanceName}] %c{1}:%L - %m%n
+
+log4j.logger.org.apache.ambari.view.hawq=INFO,hawqView
+log4j.additivity.org.apache.ambari.view.hawq=false
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/921a6350/contrib/views/hawq/src/main/resources/view.xml
----------------------------------------------------------------------
diff --git a/contrib/views/hawq/src/main/resources/view.xml b/contrib/views/hawq/src/main/resources/view.xml
index 1421c27..f07e3be 100644
--- a/contrib/views/hawq/src/main/resources/view.xml
+++ b/contrib/views/hawq/src/main/resources/view.xml
@@ -20,6 +20,51 @@
     <version>1.0.0</version>
     <build>${env.BUILD_NUMBER}</build>
 
+    <parameter>
+        <name>hawq.user.name</name>
+        <description>Name of the user to connect to HAWQ.</description>
+        <label>HAWQ User Name</label>
+        <place-holder>gpadmin</place-holder>
+        <default-value>gpadmin</default-value>
+        <required>true</required>
+    </parameter>
+
+    <parameter>
+        <name>hawq.user.password</name>
+        <description>Password of the user to connect to HAWQ.</description>
+        <label>HAWQ User Password</label>
+        <place-holder>gpadmin</place-holder>
+        <default-value>gpadmin</default-value>
+        <required>true</required>
+        <masked>true</masked>
+    </parameter>
+
+    <parameter>
+        <name>hawq.master.host</name>
+        <description>HAWQ Master Host.</description>
+        <label>HAWQ Master Host</label>
+        <cluster-config>hawq-site/hawq_master_address_host</cluster-config>
+        <required>true</required>
+    </parameter>
+
+    <parameter>
+        <name>hawq.master.port</name>
+        <description>HAWQ Master Port.</description>
+        <label>HAWQ Master Port</label>
+        <place-holder>5432</place-holder>
+        <cluster-config>hawq-site/hawq_master_address_port</cluster-config>
+        <required>true</required>
+    </parameter>
+
     <min-ambari-version>2.2.*</min-ambari-version>
 
+    <resource>
+        <name>query</name>
+        <plural-name>queries</plural-name>
+        <id-property>id</id-property>
+        <resource-class>org.apache.ambari.view.hawq.QueryResource</resource-class>
+        <provider-class>org.apache.ambari.view.hawq.QueryResourceProvider</provider-class>
+        <service-class>org.apache.ambari.view.hawq.QueryService</service-class>
+    </resource>
+
 </view>

http://git-wip-us.apache.org/repos/asf/ambari/blob/921a6350/contrib/views/hawq/src/test/java/org/apache/ambari/view/hawq/HAWQDataSourceTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hawq/src/test/java/org/apache/ambari/view/hawq/HAWQDataSourceTest.java
b/contrib/views/hawq/src/test/java/org/apache/ambari/view/hawq/HAWQDataSourceTest.java
new file mode 100644
index 0000000..973d485
--- /dev/null
+++ b/contrib/views/hawq/src/test/java/org/apache/ambari/view/hawq/HAWQDataSourceTest.java
@@ -0,0 +1,170 @@
+/*
+  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.
+ */
+
+package org.apache.ambari.view.hawq;
+
+import com.mchange.v2.c3p0.ComboPooledDataSource;
+import org.apache.ambari.view.SystemException;
+import org.easymock.EasyMockSupport;
+import org.easymock.TestSubject;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.powermock.api.easymock.PowerMock.*;
+import static org.powermock.api.easymock.PowerMock.expectNew;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({HAWQDataSource.class, ComboPooledDataSource.class})
+public class HAWQDataSourceTest extends EasyMockSupport {
+
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    @TestSubject
+    private HAWQDataSource datasource = new HAWQDataSource();
+
+    @Test
+    public void testGetConnection() throws Exception {
+
+        // first invocation, creates new CPDS
+        ComboPooledDataSource cpds1 = createMock(ComboPooledDataSource.class);
+        expectNew(ComboPooledDataSource.class).andReturn(cpds1);
+        cpds1.setDriverClass("org.postgresql.Driver");
+        expectLastCall().once();
+        cpds1.setJdbcUrl("jdbc:postgresql://host:port/template1");
+        expectLastCall().once();
+        cpds1.setUser("user");
+        expectLastCall().once();
+        cpds1.setPassword("password");
+        expectLastCall().once();
+        cpds1.setInitialPoolSize(0);
+        expectLastCall().once();
+        cpds1.setMinPoolSize(0);
+        expectLastCall().once();
+        cpds1.setMaxPoolSize(1);
+        expectLastCall().once();
+        cpds1.setMaxIdleTime(600);
+        expectLastCall().once();
+        cpds1.setAcquireRetryAttempts(5);
+        expectLastCall().once();
+        cpds1.setAcquireRetryDelay(1000);
+        expectLastCall().once();
+
+        Connection conn1 = createMock(Connection.class);
+        expect(cpds1.getConnection()).andReturn(conn1);
+
+        // second invocation, closes old CPDS, creates a new one
+
+        cpds1.close();
+        expectLastCall().once();
+
+        ComboPooledDataSource cpds2 = createStrictMock(ComboPooledDataSource.class);
+        expectNew(ComboPooledDataSource.class).andReturn(cpds2);
+        cpds2.setDriverClass("org.postgresql.Driver");
+        expectLastCall().once();
+        cpds2.setJdbcUrl("jdbc:postgresql://host:port/template1");
+        expectLastCall().once();
+        cpds2.setUser("user2");
+        expectLastCall().once();
+        cpds2.setPassword("password");
+        expectLastCall().once();
+        cpds2.setInitialPoolSize(0);
+        expectLastCall().once();
+        cpds2.setMinPoolSize(0);
+        expectLastCall().once();
+        cpds2.setMaxPoolSize(1);
+        expectLastCall().once();
+        cpds2.setMaxIdleTime(600);
+        expectLastCall().once();
+        cpds2.setAcquireRetryAttempts(5);
+        expectLastCall().once();
+        cpds2.setAcquireRetryDelay(1000);
+        expectLastCall().once();
+
+        Connection conn2 = createMock(Connection.class);
+        expect(cpds2.getConnection()).andReturn(conn2);
+
+        // third invocation, only return the same connection
+        expect(cpds2.getConnection()).andReturn(conn2);
+
+        replay(cpds1, ComboPooledDataSource.class);
+        replay(cpds2, ComboPooledDataSource.class);
+        replay(conn1);
+        replay(conn2);
+
+        Connection connection1 = datasource.getConnection("host", "port", "user", "password");
+        Connection connection2 = datasource.getConnection("host", "port", "user2", "password");
+        Connection connection3 = datasource.getConnection("host", "port", "user2", "password");
+        assertNotEquals(connection1, connection2);
+        assertEquals(connection2, connection3);
+    }
+
+    @Test(expected = SystemException.class)
+    public void testGetConnection_FailToLoadDriver() throws Exception {
+        ComboPooledDataSource cpds = createMock(ComboPooledDataSource.class);
+        expectNew(ComboPooledDataSource.class).andReturn(cpds);
+        cpds.setDriverClass("org.postgresql.Driver");
+        expectLastCall().andThrow(new RuntimeException("driver not found"));
+        replay(cpds, ComboPooledDataSource.class);
+        datasource.getConnection("host", "port", "user", "password");
+    }
+
+    @Test(expected = SQLException.class)
+    public void testGetConnection_FailToGetConnection() throws Exception {
+        ComboPooledDataSource cpds1 = createMock(ComboPooledDataSource.class);
+        expectNew(ComboPooledDataSource.class).andReturn(cpds1);
+        cpds1.setDriverClass("org.postgresql.Driver");
+        expectLastCall().once();
+        cpds1.setJdbcUrl("jdbc:postgresql://host:port/template1");
+        expectLastCall().once();
+        cpds1.setUser("user");
+        expectLastCall().once();
+        cpds1.setPassword("password");
+        expectLastCall().once();
+        cpds1.setInitialPoolSize(0);
+        expectLastCall().once();
+        cpds1.setMinPoolSize(0);
+        expectLastCall().once();
+        cpds1.setMaxPoolSize(1);
+        expectLastCall().once();
+        cpds1.setMaxIdleTime(600);
+        expectLastCall().once();
+        cpds1.setAcquireRetryAttempts(5);
+        expectLastCall().once();
+        cpds1.setAcquireRetryDelay(1000);
+        expectLastCall().once();
+
+        Connection conn1 = createMock(Connection.class);
+        expect(cpds1.getConnection()).andThrow(new SQLException("fail"));
+        replay(cpds1, ComboPooledDataSource.class);
+        replay(conn1);
+        datasource.getConnection("host", "port", "user", "password");
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/921a6350/contrib/views/hawq/src/test/java/org/apache/ambari/view/hawq/QueryResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hawq/src/test/java/org/apache/ambari/view/hawq/QueryResourceProviderTest.java
b/contrib/views/hawq/src/test/java/org/apache/ambari/view/hawq/QueryResourceProviderTest.java
new file mode 100644
index 0000000..819c3be
--- /dev/null
+++ b/contrib/views/hawq/src/test/java/org/apache/ambari/view/hawq/QueryResourceProviderTest.java
@@ -0,0 +1,200 @@
+/*
+  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.
+ */
+
+package org.apache.ambari.view.hawq;
+
+import static org.easymock.EasyMock.anyString;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.junit.Assert.*;
+
+import org.apache.ambari.view.SystemException;
+import org.apache.ambari.view.ViewContext;
+import org.easymock.EasyMockRunner;
+import org.easymock.EasyMockSupport;
+import org.easymock.Mock;
+import org.easymock.TestSubject;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+import java.sql.*;
+import java.util.*;
+
+@RunWith(EasyMockRunner.class)
+public class QueryResourceProviderTest extends EasyMockSupport {
+
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    @TestSubject
+    private QueryResourceProvider provider = new QueryResourceProvider();
+
+    @Mock
+    private ViewContext viewContext;
+
+    @Mock
+    private HAWQDataSource dataSource;
+
+    @Mock
+    private Connection connection;
+
+    @Mock
+    private Statement statement;
+
+    @Mock
+    private ResultSet rs;
+
+    @Mock
+    private ResultSetMetaData rsMetaData;
+
+    @Test
+    public void testGetResources() throws Exception {
+
+        expect(viewContext.getProperties()).andReturn(prepareViewContextProperties()).anyTimes();
+
+        expect(dataSource.getConnection("host1", "1234", "gpadmin-user", "gpadmin-password")).andReturn(connection);
+        expect(connection.createStatement()).andReturn(statement);
+        expect(statement.executeQuery(anyString())).andReturn(rs);
+        expect(rs.getMetaData()).andReturn(rsMetaData);
+        expect(rsMetaData.getColumnCount()).andReturn(2);
+
+        // row 1
+        expect(rs.next()).andReturn(true);
+        // mock only 2 columns
+        expect(rsMetaData.getColumnName(1)).andReturn("procpid");
+        expect(rs.getObject(1)).andReturn(10);
+        expect(rsMetaData.getColumnName(2)).andReturn("text");
+        expect(rs.getObject(2)).andReturn("text-10");
+
+        // row 2
+        expect(rs.next()).andReturn(true);
+        // mock only 2 columns
+        expect(rsMetaData.getColumnName(1)).andReturn("procpid");
+        expect(rs.getObject(1)).andReturn(20);
+        expect(rsMetaData.getColumnName(2)).andReturn("text");
+        expect(rs.getObject(2)).andReturn("text-20");
+
+        expect(rs.next()).andReturn(false);
+        rs.close();
+        expectLastCall().once();
+        statement.close();
+        expectLastCall().once();
+        connection.close();
+        expectLastCall().once();
+
+        replayAll();
+        Set<QueryResource> results = provider.getResources(null);
+
+        assertEquals(2, results.size());
+        Set<String> ids = new HashSet<>();
+        ids.add("10");
+        ids.add("20");
+        for (QueryResource query : results) {
+            String id = query.getId();
+            ids.remove(id);
+            assertEquals(id, query.getAttributes().get("procpid").toString());
+            assertEquals("text-" + id, query.getAttributes().get("text"));
+        }
+        assertTrue(ids.isEmpty());
+
+        verifyAll();
+    }
+
+
+    @Test
+    public void testGetResources_MissingUserName() throws Exception {
+        thrown.expect(SystemException.class);
+        thrown.expectMessage("HAWQ User Name property is not specified for the view instance.");
+
+        Map<String, String> props = prepareViewContextProperties();
+        props.remove("hawq.user.name");
+        expect(viewContext.getProperties()).andReturn(props).anyTimes();
+        replayAll();
+
+        provider.getResources(null);
+    }
+
+    @Test
+    public void testGetResources_MissingUserPassword() throws Exception {
+        thrown.expect(SystemException.class);
+        thrown.expectMessage("HAWQ User Password property is not specified for the view instance.");
+
+        Map<String, String> props = prepareViewContextProperties();
+        props.remove("hawq.user.password");
+        expect(viewContext.getProperties()).andReturn(props).anyTimes();
+        replayAll();
+
+        provider.getResources(null);
+    }
+
+    @Test
+    public void testGetResources_MissingHostName() throws Exception {
+        thrown.expect(SystemException.class);
+        thrown.expectMessage("HAWQ Master Host property is not specified for the view instance.");
+
+        Map<String, String> props = prepareViewContextProperties();
+        props.remove("hawq.master.host");
+        expect(viewContext.getProperties()).andReturn(props).anyTimes();
+        replayAll();
+
+        provider.getResources(null);
+    }
+
+    @Test
+    public void testGetResources_MissingHostPort() throws Exception {
+        thrown.expect(SystemException.class);
+        thrown.expectMessage("HAWQ Master Port property is not specified for the view instance.");
+
+        Map<String, String> props = prepareViewContextProperties();
+        props.remove("hawq.master.port");
+        expect(viewContext.getProperties()).andReturn(props).anyTimes();
+        replayAll();
+
+        provider.getResources(null);
+    }
+
+    @Test
+    public void testGetResources_ExceptionOnExecute() throws Exception {
+        thrown.expect(SystemException.class);
+        thrown.expectMessage("Can't get current queries.");
+
+        expect(viewContext.getProperties()).andReturn(prepareViewContextProperties()).anyTimes();
+
+        expect(dataSource.getConnection("host1", "1234", "gpadmin-user", "gpadmin-password")).andReturn(connection);
+        expect(connection.createStatement()).andReturn(statement);
+        expect(statement.executeQuery(anyString())).andStubThrow(new SQLException("test message"));
+        statement.close();
+        expectLastCall().once();
+        connection.close();
+        expectLastCall().once();
+        replayAll();
+
+        provider.getResources(null);
+    }
+
+    private Map<String, String> prepareViewContextProperties() {
+        Map<String, String> props = new HashMap<>();
+        props.put("hawq.user.name", "gpadmin-user");
+        props.put("hawq.user.password", "gpadmin-password");
+        props.put("hawq.master.host", "host1");
+        props.put("hawq.master.port", "1234");
+        return props;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/921a6350/contrib/views/pom.xml
----------------------------------------------------------------------
diff --git a/contrib/views/pom.xml b/contrib/views/pom.xml
index cc53869..653c708 100644
--- a/contrib/views/pom.xml
+++ b/contrib/views/pom.xml
@@ -74,6 +74,7 @@
             <exclude>pass.txt</exclude>
             <exclude>.DS_Store</exclude>
             <exclude>.iml/</exclude>
+            <exclude>**/*.iml</exclude>
             <exclude>.classpath</exclude>
             <exclude>.project</exclude>
             <exclude>.settings</exclude>


Mime
View raw message