You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by nc...@apache.org on 2016/11/08 20:25:18 UTC
[10/22] ambari git commit: AMBARI-18779: Fix the backend for HAWQ
View BETA (adenissov via mithmatt)
http://git-wip-us.apache.org/repos/asf/ambari/blob/8ac9fa10/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/8ac9fa10/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/8ac9fa10/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/8ac9fa10/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/8ac9fa10/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/8ac9fa10/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/8ac9fa10/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/8ac9fa10/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/8ac9fa10/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/8ac9fa10/contrib/views/pom.xml
----------------------------------------------------------------------
diff --git a/contrib/views/pom.xml b/contrib/views/pom.xml
index 39560b5..94f8421 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>