You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by pr...@apache.org on 2018/01/11 03:41:46 UTC

[6/6] zeppelin git commit: [ZEPPELIN-3127] Upgrade selenium version

[ZEPPELIN-3127] Upgrade selenium version

### What is this PR for?
We are currently using a very old selenium version (i.e. 2.48.2) this is to upgrade it to 3.8.1

### What type of PR is it?
[Improvement]

### What is the Jira issue?
* [ZEPPELIN-3127](https://issues.apache.org/jira/browse/ZEPPELIN-3127)

### How should this be tested?
* CI should be green

### Questions:
* Does the licenses files need update? yes
* Is there breaking changes for older versions?
* Does this needs documentation?

Author: prabhjyotsingh <pr...@gmail.com>
Author: Prabhjyot Singh <pr...@gmail.com>

Closes #2717 from prabhjyotsingh/ZEPPELIN-3127 and squashes the following commits:

e78896356 [prabhjyotsingh] rollback to FF31
6c5be28a8 [Prabhjyot Singh] remove `endToEndTestEnabled (System.getenv("TEST_SELENIUM"))` as with this PR selenium is in different profile.
01632943e [prabhjyotsingh] removing LogEntries as this is no longer required for Selenium-3.x
aab48b857 [prabhjyotsingh] run only selenium for this matrix (4)
873ee324a [prabhjyotsingh] remove scala and set firefoxOptions.setHeadless(true);
e7d3c8dce [Prabhjyot Singh] try FF56
a7ec96f2e [prabhjyotsingh] Fix scala not running
cbb365aef [prabhjyotsingh] start/stop plugin
2689dff8c [prabhjyotsingh] fix dependencies issue
88c07bab1 [prabhjyotsingh] ZEPPELIN-3127: Upgrade selenium version
1ca024f84 [prabhjyotsingh] ZEPPELIN-3127: Upgrade selenium version (reverted from commit 65c11b8178a4ebe58ae84e4e074bbddb522900f7)
260056f18 [prabhjyotsingh] review comment (reverted from commit 52a16816e73a282439060aaf2cf0e80b1b3a8093)
b28774430 [prabhjyotsingh] fix build (reverted from commit 840a5d78a33a1643a7424c8e94521510a5db1184)
840a5d78a [Prabhjyot Singh] fix build
52a16816e [Prabhjyot Singh] review comment
65c11b817 [prabhjyotsingh] ZEPPELIN-3127: Upgrade selenium version


Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo
Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/7bff131a
Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/7bff131a
Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/7bff131a

Branch: refs/heads/master
Commit: 7bff131a5bcc96754aaccce555b8d6d3917f445a
Parents: dd1be03
Author: prabhjyotsingh <pr...@gmail.com>
Authored: Tue Jan 9 00:35:41 2018 +0530
Committer: Prabhjyot Singh <pr...@gmail.com>
Committed: Thu Jan 11 09:11:31 2018 +0530

----------------------------------------------------------------------
 .travis.yml                                     |   8 +-
 LICENSE                                         |   1 +
 pom.xml                                         |   7 +
 zeppelin-integration/pom.xml                    | 220 +++++
 .../org/apache/zeppelin/AbstractZeppelinIT.java | 138 +++
 .../org/apache/zeppelin/CommandExecutor.java    |  74 ++
 .../java/org/apache/zeppelin/ProcessData.java   | 256 ++++++
 .../org/apache/zeppelin/WebDriverManager.java   | 215 +++++
 .../org/apache/zeppelin/ZeppelinITUtils.java    |  60 ++
 .../zeppelin/integration/AuthenticationIT.java  | 302 +++++++
 .../zeppelin/integration/InterpreterIT.java     |  73 ++
 .../integration/InterpreterModeActionsIT.java   | 877 ++++++++++++++++++
 .../integration/ParagraphActionsIT.java         | 824 +++++++++++++++++
 .../integration/PersonalizeActionsIT.java       | 339 +++++++
 .../zeppelin/integration/SparkParagraphIT.java  | 232 +++++
 .../apache/zeppelin/integration/ZeppelinIT.java | 326 +++++++
 .../src/test/resources/log4j.properties         |  46 +
 .../ScreenCaptureHtmlUnitDriver.java            | 224 -----
 .../org/apache/zeppelin/AbstractZeppelinIT.java | 146 ---
 .../org/apache/zeppelin/CommandExecutor.java    |  74 --
 .../java/org/apache/zeppelin/ProcessData.java   | 249 ------
 .../org/apache/zeppelin/WebDriverManager.java   | 195 ----
 .../org/apache/zeppelin/ZeppelinITUtils.java    |  16 -
 .../zeppelin/integration/AuthenticationIT.java  | 321 -------
 .../zeppelin/integration/InterpreterIT.java     |  82 --
 .../integration/InterpreterModeActionsIT.java   | 892 -------------------
 .../integration/ParagraphActionsIT.java         | 888 ------------------
 .../integration/PersonalizeActionsIT.java       | 354 --------
 .../zeppelin/integration/SparkParagraphIT.java  | 250 ------
 .../apache/zeppelin/integration/ZeppelinIT.java | 343 -------
 .../zeppelin/AbstractFunctionalSuite.scala      |  84 --
 .../org/apache/zeppelin/WelcomePageSuite.scala  |  37 -
 32 files changed, 3995 insertions(+), 4158 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zeppelin/blob/7bff131a/.travis.yml
----------------------------------------------------------------------
diff --git a/.travis.yml b/.travis.yml
index 7db41bf..3d78595 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -69,9 +69,11 @@ matrix:
       env: PYTHON="3" SCALA_VER="2.11" SPARK_VER="2.2.0" HADOOP_VER="2.6" PROFILE="-Pspark-2.2 -Pweb-ci -Pscalding -Phelium-dev -Pexamples -Pscala-2.11" BUILD_FLAG="package -Pbuild-distr -DskipRat" TEST_FLAG="verify -Pusing-packaged-distr -DskipRat" MODULES="-pl ${INTERPRETERS}" TEST_PROJECTS="-Dtests.to.exclude=**/ZeppelinSparkClusterTest.java,**/org.apache.zeppelin.spark.*,**/HeliumApplicationFactoryTest.java -DfailIfNoTests=false"
 
     # Test selenium with spark module for 1.6.3
-    - jdk: "oraclejdk7"
-      dist: precise
-      env: PYTHON="2" TEST_SELENIUM="true" SCALA_VER="2.10" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pspark-1.6 -Phadoop-2.6 -Phelium-dev -Pexamples" BUILD_FLAG="package -DskipTests -DskipRat" TEST_FLAG="verify -DskipRat" TEST_PROJECTS="-pl .,zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark,python -Dtest=org.apache.zeppelin.AbstractFunctionalSuite -DfailIfNoTests=false"
+    - jdk: "oraclejdk8"
+      dist: trusty
+      addons:
+        firefox: "31.0"
+      env: PYTHON="2" SCALA_VER="2.10" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pspark-1.6 -Phadoop-2.6 -Phelium-dev -Pexamples -Pintegration" BUILD_FLAG="package -DskipTests -DskipRat" TEST_FLAG="verify -DskipRat" TEST_PROJECTS="-pl .,zeppelin-integration -DfailIfNoTests=false"
 
     # Test interpreter modules
     - jdk: "oraclejdk7"

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/7bff131a/LICENSE
----------------------------------------------------------------------
diff --git a/LICENSE b/LICENSE
index f42b12c..2252d65 100644
--- a/LICENSE
+++ b/LICENSE
@@ -258,6 +258,7 @@ The text of each license is also included at licenses/LICENSE-[project]-[version
     (Apache 2.0) Roboto Font (https://github.com/google/roboto/)
     (Apache 2.0) Gson extra (https://github.com/DanySK/gson-extras)
     (Apache 2.0) Nimbus JOSE+JWT (https://bitbucket.org/connect2id/nimbus-jose-jwt/wiki/Home)
+    (Apache 2.0) jarchivelib (https://github.com/thrau/jarchivelib)
 
 ========================================================================
 BSD 3-Clause licenses

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/7bff131a/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 641880e..b6f93de 100644
--- a/pom.xml
+++ b/pom.xml
@@ -766,6 +766,13 @@
     </profile>
 
     <profile>
+      <id>integration</id>
+      <modules>
+        <module>zeppelin-integration</module>
+      </modules>
+    </profile>
+
+    <profile>
       <id>r</id>
       <modules>
         <module>r</module>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/7bff131a/zeppelin-integration/pom.xml
----------------------------------------------------------------------
diff --git a/zeppelin-integration/pom.xml b/zeppelin-integration/pom.xml
new file mode 100644
index 0000000..e939a63
--- /dev/null
+++ b/zeppelin-integration/pom.xml
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <artifactId>zeppelin</artifactId>
+    <groupId>org.apache.zeppelin</groupId>
+    <version>0.8.0-SNAPSHOT</version>
+    <relativePath>..</relativePath>
+  </parent>
+
+  <groupId>org.apache.zeppelin</groupId>
+  <artifactId>zeppelin-integration</artifactId>
+  <packaging>jar</packaging>
+  <version>0.8.0-SNAPSHOT</version>
+  <name>Zeppelin: Integration Test</name>
+
+  <!-- See https://github.com/eirslett/frontend-maven-plugin/issues/229 -->
+  <prerequisites>
+    <maven>3.1.0</maven>
+  </prerequisites>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+
+    <!--test library versions-->
+    <selenium.java.version>3.8.1</selenium.java.version>
+    <commons.lang3.version>3.4</commons.lang3.version>
+
+    <!--plugin library versions-->
+    <plugin.failsafe.version>2.16</plugin.failsafe.version>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>com.google.code.gson</groupId>
+      <artifactId>gson</artifactId>
+      <version>2.8.2</version>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+      <version>23.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.seleniumhq.selenium</groupId>
+      <artifactId>selenium-java</artifactId>
+      <version>${selenium.java.version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>com.google.code.gson</groupId>
+          <artifactId>gson</artifactId>
+        </exclusion>
+      </exclusions>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>zeppelin-zengine</artifactId>
+      <version>${project.version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>com.google.guava</groupId>
+          <artifactId>guava</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>com.google.code.gson</groupId>
+          <artifactId>gson</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.apache.hadoop</groupId>
+          <artifactId>hadoop-common</artifactId>
+        </exclusion>
+      </exclusions>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+      <version>${commons.lang3.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.rauschig</groupId>
+      <artifactId>jarchivelib</artifactId>
+      <version>0.7.1</version>
+      <exclusions>
+        <exclusion>
+          <groupId>org.apache.commons</groupId>
+          <artifactId>commons-compress</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+    </dependency>
+
+    <!--test libraries-->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-failsafe-plugin</artifactId>
+        <version>${plugin.failsafe.version}</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>integration-test</goal>
+              <goal>verify</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <argLine>-Xmx2048m</argLine>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>${plugin.surefire.version}</version>
+        <configuration combine.children="append">
+          <argLine>-Xmx2g -Xms1g -Dfile.encoding=UTF-8</argLine>
+          <excludes>
+            <exclude>${tests.to.exclude}</exclude>
+          </excludes>
+          <environmentVariables>
+            <ZEPPELIN_FORCE_STOP>1</ZEPPELIN_FORCE_STOP>
+          </environmentVariables>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>start-zeppelin</id>
+            <phase>pre-integration-test</phase>
+            <configuration>
+              <target unless="skipTests">
+                <exec executable="./zeppelin-daemon.sh" dir="${zeppelin.daemon.package.base}"
+                  spawn="true">
+                  <arg value="start"/>
+                </exec>
+              </target>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>stop-zeppelin</id>
+            <phase>post-integration-test</phase>
+            <configuration>
+              <target unless="skipTests">
+                <exec executable="./zeppelin-daemon.sh" dir="${zeppelin.daemon.package.base}"
+                  spawn="false">
+                  <arg value="stop"/>
+                </exec>
+              </target>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+  <profiles>
+    <profile>
+      <id>using-source-tree</id>
+      <activation>
+        <activeByDefault>true</activeByDefault>
+      </activation>
+      <properties>
+        <zeppelin.daemon.package.base>
+          ../bin
+        </zeppelin.daemon.package.base>
+      </properties>
+    </profile>
+    <profile>
+      <id>using-packaged-distr</id>
+      <activation>
+        <activeByDefault>false</activeByDefault>
+      </activation>
+      <properties>
+        <zeppelin.daemon.package.base>
+          ../zeppelin-distribution/target/zeppelin-${project.version}/zeppelin-${project.version}/bin
+        </zeppelin.daemon.package.base>
+      </properties>
+    </profile>
+  </profiles>
+
+</project>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/7bff131a/zeppelin-integration/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java
----------------------------------------------------------------------
diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java
new file mode 100644
index 0000000..b4ebfe9
--- /dev/null
+++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java
@@ -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.
+ */
+
+package org.apache.zeppelin;
+
+
+import com.google.common.base.Function;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.FileUtils;
+import org.openqa.selenium.*;
+import org.openqa.selenium.logging.LogEntries;
+import org.openqa.selenium.logging.LogEntry;
+import org.openqa.selenium.logging.LogType;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.FluentWait;
+import org.openqa.selenium.support.ui.Wait;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+abstract public class AbstractZeppelinIT {
+  protected static WebDriver driver;
+
+  protected final static Logger LOG = LoggerFactory.getLogger(AbstractZeppelinIT.class);
+  protected static final long MIN_IMPLICIT_WAIT = 5;
+  protected static final long MAX_IMPLICIT_WAIT = 30;
+  protected static final long MAX_BROWSER_TIMEOUT_SEC = 30;
+  protected static final long MAX_PARAGRAPH_TIMEOUT_SEC = 120;
+
+  protected void setTextOfParagraph(int paragraphNo, String text) {
+    String editorId = driver.findElement(By.xpath(getParagraphXPath(paragraphNo) + "//div[contains(@class, 'editor')]")).getAttribute("id");
+    if (driver instanceof JavascriptExecutor) {
+      ((JavascriptExecutor) driver).executeScript("ace.edit('" + editorId + "'). setValue('" + text + "')");
+    } else {
+      throw new IllegalStateException("This driver does not support JavaScript!");
+    }
+  }
+
+  protected void runParagraph(int paragraphNo) {
+    driver.findElement(By.xpath(getParagraphXPath(paragraphNo) + "//span[@class='icon-control-play']")).click();
+  }
+
+
+  protected String getParagraphXPath(int paragraphNo) {
+    return "(//div[@ng-controller=\"ParagraphCtrl\"])[" + paragraphNo + "]";
+  }
+
+  protected String getNoteFormsXPath() {
+    return "(//div[@id='noteForms'])";
+  }
+
+  protected boolean waitForParagraph(final int paragraphNo, final String state) {
+    By locator = By.xpath(getParagraphXPath(paragraphNo)
+        + "//div[contains(@class, 'control')]//span[2][contains(.,'" + state + "')]");
+    WebElement element = pollingWait(locator, MAX_PARAGRAPH_TIMEOUT_SEC);
+    return element.isDisplayed();
+  }
+
+  protected String getParagraphStatus(final int paragraphNo) {
+    By locator = By.xpath(getParagraphXPath(paragraphNo)
+        + "//div[contains(@class, 'control')]/span[2]");
+
+    return driver.findElement(locator).getText();
+  }
+
+  protected boolean waitForText(final String txt, final By locator) {
+    try {
+      WebElement element = pollingWait(locator, MAX_BROWSER_TIMEOUT_SEC);
+      return txt.equals(element.getText());
+    } catch (TimeoutException e) {
+      return false;
+    }
+  }
+
+  protected WebElement pollingWait(final By locator, final long timeWait) {
+    Wait<WebDriver> wait = new FluentWait<>(driver)
+        .withTimeout(timeWait, TimeUnit.SECONDS)
+        .pollingEvery(1, TimeUnit.SECONDS)
+        .ignoring(NoSuchElementException.class);
+
+    return wait.until(new Function<WebDriver, WebElement>() {
+      public WebElement apply(WebDriver driver) {
+        return driver.findElement(locator);
+      }
+    });
+  }
+
+  protected void createNewNote() {
+    clickAndWait(By.xpath("//div[contains(@class, \"col-md-4\")]/div/h5/a[contains(.,'Create new" +
+        " note')]"));
+
+    WebDriverWait block = new WebDriverWait(driver, MAX_BROWSER_TIMEOUT_SEC);
+    block.until(ExpectedConditions.visibilityOfElementLocated(By.id("noteCreateModal")));
+    clickAndWait(By.id("createNoteButton"));
+    block.until(ExpectedConditions.invisibilityOfElementLocated(By.className("pull-right")));
+  }
+
+  protected void deleteTestNotebook(final WebDriver driver) {
+    WebDriverWait block = new WebDriverWait(driver, MAX_BROWSER_TIMEOUT_SEC);
+    driver.findElement(By.xpath(".//*[@id='main']//button[@ng-click='moveNoteToTrash(note.id)']"))
+        .sendKeys(Keys.ENTER);
+    block.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(".//*[@id='main']//button[@ng-click='moveNoteToTrash(note.id)']")));
+    driver.findElement(By.xpath("//div[@class='modal-dialog'][contains(.,'This note will be moved to trash')]" +
+        "//div[@class='modal-footer']//button[contains(.,'OK')]")).click();
+    ZeppelinITUtils.sleep(100, true);
+  }
+
+  protected void clickAndWait(final By locator) {
+    pollingWait(locator, MAX_IMPLICIT_WAIT).click();
+    ZeppelinITUtils.sleep(1000, true);
+  }
+
+  protected void handleException(String message, Exception e) throws Exception {
+    LOG.error(message, e);
+    File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
+    LOG.error("ScreenShot::\ndata:image/png;base64," + new String(Base64.encodeBase64(FileUtils.readFileToByteArray(scrFile))));
+    throw e;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/7bff131a/zeppelin-integration/src/test/java/org/apache/zeppelin/CommandExecutor.java
----------------------------------------------------------------------
diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/CommandExecutor.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/CommandExecutor.java
new file mode 100644
index 0000000..6a55f3e
--- /dev/null
+++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/CommandExecutor.java
@@ -0,0 +1,74 @@
+/*
+ * 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.zeppelin;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class CommandExecutor {
+
+  public final static Logger LOG = LoggerFactory.getLogger(CommandExecutor.class);
+
+  public enum IGNORE_ERRORS {
+    TRUE,
+    FALSE
+  }
+
+  public static int NORMAL_EXIT = 0;
+
+  private static IGNORE_ERRORS DEFAULT_BEHAVIOUR_ON_ERRORS = IGNORE_ERRORS.TRUE;
+
+  public static Object executeCommandLocalHost(String[] command, boolean printToConsole, ProcessData.Types_Of_Data type, IGNORE_ERRORS ignore_errors) {
+    List<String> subCommandsAsList = new ArrayList<>(Arrays.asList(command));
+    String mergedCommand = StringUtils.join(subCommandsAsList, " ");
+
+    LOG.info("Sending command \"" + mergedCommand + "\" to localhost");
+
+    ProcessBuilder processBuilder = new ProcessBuilder(command);
+    Process process = null;
+    try {
+      process = processBuilder.start();
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+
+    ProcessData data_of_process = new ProcessData(process, printToConsole);
+    Object output_of_process = data_of_process.getData(type);
+    int exit_code = data_of_process.getExitCodeValue();
+
+    if (!printToConsole)
+      LOG.trace(output_of_process.toString());
+    else
+      LOG.debug(output_of_process.toString());
+    if (ignore_errors == IGNORE_ERRORS.FALSE && exit_code != NORMAL_EXIT) {
+      LOG.error(String.format("*********************Command '%s' failed with exitcode %s *********************", mergedCommand, exit_code));
+    }
+    return output_of_process;
+  }
+
+  public static Object executeCommandLocalHost(String command, boolean printToConsole, ProcessData.Types_Of_Data type) {
+    return executeCommandLocalHost(new String[]{"bash", "-c", command}, printToConsole, type, DEFAULT_BEHAVIOUR_ON_ERRORS);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/7bff131a/zeppelin-integration/src/test/java/org/apache/zeppelin/ProcessData.java
----------------------------------------------------------------------
diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/ProcessData.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/ProcessData.java
new file mode 100644
index 0000000..2a05b1f
--- /dev/null
+++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/ProcessData.java
@@ -0,0 +1,256 @@
+/*
+ * 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.zeppelin;
+
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.concurrent.TimeUnit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ProcessData {
+  public enum Types_Of_Data {
+    OUTPUT,
+    ERROR,
+    EXIT_CODE,
+    STREAMS_MERGED,
+    PROCESS_DATA_OBJECT
+  }
+
+  public final static Logger LOG = LoggerFactory.getLogger(ProcessData.class);
+
+  private Process checked_process;
+  private boolean printToConsole = false;
+  private boolean removeRedundantOutput = true;
+
+  public ProcessData(Process connected_process, boolean printToConsole, int silenceTimeout, TimeUnit timeUnit) {
+    this.checked_process = connected_process;
+    this.printToConsole = printToConsole;
+    this.silenceTimeout = TimeUnit.MILLISECONDS.convert(silenceTimeout, timeUnit);
+  }
+
+  public ProcessData(Process connected_process, boolean printToConsole, int silenceTimeoutSec) {
+    this.checked_process = connected_process;
+    this.printToConsole = printToConsole;
+    this.silenceTimeout = TimeUnit.MILLISECONDS.convert(silenceTimeoutSec, TimeUnit.SECONDS);
+  }
+
+  public ProcessData(Process connected_process, boolean printToConsole) {
+    this.checked_process = connected_process;
+    this.printToConsole = printToConsole;
+  }
+
+  public ProcessData(Process connected_process) {
+    this.checked_process = connected_process;
+    this.printToConsole = true;
+  }
+
+
+  boolean returnCodeRetrieved = false;
+
+  private String outPutStream = null;
+  private String errorStream = null;
+  private int returnCode;
+  private long silenceTimeout = 10 * 60 * 1000;
+  private final long unconditionalExitDelayMinutes = 30;
+
+  public static boolean isRunning(Process process) {
+    try {
+      process.exitValue();
+      return false;
+    } catch (IllegalThreadStateException e) {
+      return true;
+    }
+  }
+
+  public Object getData(Types_Of_Data type) {
+    //TODO get rid of Pseudo-terminal will not be allocated because stdin is not a terminal.
+    switch (type) {
+      case OUTPUT: {
+        return this.getOutPutStream();
+      }
+      case ERROR: {
+        return this.getErrorStream();
+      }
+      case EXIT_CODE: {
+        return this.getExitCodeValue();
+      }
+      case STREAMS_MERGED: {
+        return this.getOutPutStream() + "\n" + this.getErrorStream();
+      }
+      case PROCESS_DATA_OBJECT: {
+        this.getErrorStream();
+        return this;
+      }
+      default: {
+        throw new IllegalArgumentException("Data Type " + type + " not supported yet!");
+      }
+    }
+  }
+
+  public int getExitCodeValue() {
+    try {
+      if (!returnCodeRetrieved) {
+        this.checked_process.waitFor();
+        this.returnCode = this.checked_process.exitValue();
+        this.returnCodeRetrieved = true;
+        this.checked_process.destroy();
+      }
+    } catch (Exception inter) {
+      throw new RuntimeException("Couldn't finish waiting for process " + this.checked_process + " termination", inter);
+    }
+    return this.returnCode;
+  }
+
+  public String getOutPutStream() {
+    if (this.outPutStream == null) {
+      try {
+        buildOutputAndErrorStreamData();
+      } catch (Exception e) {
+        throw new RuntimeException("Couldn't retrieve Output Stream data from process: " + this.checked_process.toString(), e);
+
+      }
+    }
+    this.outPutStream = this.outPutStream.replace("Pseudo-terminal will not be allocated because stdin is not a terminal.", "");
+    this.errorStream = this.errorStream.replace("Pseudo-terminal will not be allocated because stdin is not a terminal.", "");
+    return this.outPutStream;
+  }
+
+  public String getErrorStream() {
+    if (this.errorStream == null) {
+      try {
+        buildOutputAndErrorStreamData();
+      } catch (Exception e) {
+        throw new RuntimeException("Couldn't retrieve Error Stream data from process: " + this.checked_process.toString(), e);
+
+      }
+    }
+    this.outPutStream = this.outPutStream.replace("Pseudo-terminal will not be allocated because stdin is not a terminal.", "");
+    this.errorStream = this.errorStream.replace("Pseudo-terminal will not be allocated because stdin is not a terminal.", "");
+    return this.errorStream;
+  }
+
+  public String toString() {
+    StringBuilder result = new StringBuilder();
+    result.append(String.format("[OUTPUT STREAM]\n%s\n", this.outPutStream));
+    result.append(String.format("[ERROR STREAM]\n%s\n", this.errorStream));
+    result.append(String.format("[EXIT CODE]\n%d", this.returnCode));
+    return result.toString();
+  }
+
+  private void buildOutputAndErrorStreamData() throws IOException {
+    StringBuilder sbInStream = new StringBuilder();
+    StringBuilder sbErrorStream = new StringBuilder();
+
+    try {
+      InputStream in = this.checked_process.getInputStream();
+      InputStream inErrors = this.checked_process.getErrorStream();
+      BufferedReader inReader = new BufferedReader(new InputStreamReader(in));
+      BufferedReader inReaderErrors = new BufferedReader(new InputStreamReader(inErrors));
+      LOG.trace("Started retrieving data from streams of attached process: " + this.checked_process);
+
+      long lastStreamDataTime = System.currentTimeMillis();   //Store start time to be able to finish method if command hangs
+      long unconditionalExitTime = System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(unconditionalExitDelayMinutes, TimeUnit.MINUTES); // Stop after 'unconditionalExitDelayMinutes' even if process is alive and sending output
+      final int BUFFER_LEN = 300;
+      char charBuffer[] = new char[BUFFER_LEN];     //Use char buffer to read output, size can be tuned.
+      boolean outputProduced = true;                //Flag to check if previous iteration produced any output
+      while (isRunning(this.checked_process) || outputProduced) {   //Continue if process is alive or some output was produced on previous iteration and there may be still some data to read.
+        outputProduced = false;
+        ZeppelinITUtils.sleep(100, false);                                  //Some local commands can exit fast, but immediate stream reading will give no output and after iteration, 'while' condition will be false so we will not read out any output while it is still there, just need to wait for some time for it to appear in streams.
+
+        StringBuilder tempSB = new StringBuilder();
+        while (inReader.ready()) {
+          tempSB.setLength(0);                                // clean temporary StringBuilder
+          int readCount = inReader.read(charBuffer, 0, BUFFER_LEN); //read up to 'BUFFER_LEN' chars to buffer
+          if (readCount < 1) {                                     // if nothing read or error occurred
+            break;
+          }
+          tempSB.append(charBuffer, 0, readCount);
+
+          sbInStream.append(tempSB);
+          if (tempSB.length() > 0) {
+            outputProduced = true;                                //set flag to know that we read something and there may be moire data, even if process already exited
+          }
+
+          lastStreamDataTime = System.currentTimeMillis();        //remember last time data was read from streams to be sure we are not looping infinitely
+        }
+
+        tempSB = new StringBuilder();                               //Same, but for error stream
+        while (inReaderErrors.ready()) {
+          tempSB.setLength(0);
+          int readCount = inReaderErrors.read(charBuffer, 0, BUFFER_LEN);
+          if (readCount < 1) {
+            break;
+          }
+          tempSB.append(charBuffer, 0, readCount);
+          sbErrorStream.append(tempSB);
+          if (tempSB.length() > 0) {
+            outputProduced = true;
+            String temp = new String(tempSB);
+            temp = temp.replaceAll("Pseudo-terminal will not be allocated because stdin is not a terminal.", "");
+            //TODO : error stream output need to be improved, because it outputs downloading information.
+            if (printToConsole) {
+              if (!temp.trim().equals("")) {
+                if (temp.toLowerCase().contains("error") || temp.toLowerCase().contains("failed")) {
+                  LOG.warn(temp.trim());
+                } else {
+                  LOG.debug(temp.trim());
+                }
+              }
+            }
+          }
+          lastStreamDataTime = System.currentTimeMillis();
+        }
+
+
+        if ((System.currentTimeMillis() - lastStreamDataTime > silenceTimeout) ||     //Exit if silenceTimeout ms has passed from last stream read. Means process is alive but not sending any data.
+            (System.currentTimeMillis() > unconditionalExitTime)) {                    //Exit unconditionally - guards against alive process continuously sending data.
+          LOG.info("Conditions: " + (System.currentTimeMillis() - lastStreamDataTime > silenceTimeout) + " " +
+              (System.currentTimeMillis() > unconditionalExitTime));
+          this.checked_process.destroy();
+          try {
+            if ((System.currentTimeMillis() > unconditionalExitTime)) {
+              LOG.error(
+                  "!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@Unconditional exit occured@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@!\nsome process hag up for more than "
+                      + unconditionalExitDelayMinutes + " minutes.");
+            }
+            LOG.error("!##################################!");
+            StringWriter sw = new StringWriter();
+            Exception e = new Exception("Exited from buildOutputAndErrorStreamData by timeout");
+            e.printStackTrace(new PrintWriter(sw)); //Get stack trace
+            LOG.error(String.valueOf(e), e);
+          } catch (Exception ignore) {
+            LOG.info("Exception in ProcessData while buildOutputAndErrorStreamData ", ignore);
+          }
+          break;
+        }
+      }
+
+      in.close();
+      inErrors.close();
+    } finally {
+      this.outPutStream = sbInStream.toString();
+      this.errorStream = sbErrorStream.toString();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/7bff131a/zeppelin-integration/src/test/java/org/apache/zeppelin/WebDriverManager.java
----------------------------------------------------------------------
diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/WebDriverManager.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/WebDriverManager.java
new file mode 100644
index 0000000..768113f
--- /dev/null
+++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/WebDriverManager.java
@@ -0,0 +1,215 @@
+/*
+ * 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.zeppelin;
+
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.concurrent.TimeUnit;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.SystemUtils;
+import org.openqa.selenium.By;
+import org.openqa.selenium.TimeoutException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.firefox.FirefoxBinary;
+import org.openqa.selenium.firefox.FirefoxDriver;
+import org.openqa.selenium.firefox.FirefoxDriver.SystemProperty;
+import org.openqa.selenium.firefox.FirefoxOptions;
+import org.openqa.selenium.firefox.FirefoxProfile;
+import org.openqa.selenium.firefox.GeckoDriverService;
+import org.openqa.selenium.safari.SafariDriver;
+import org.openqa.selenium.support.ui.ExpectedCondition;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import org.rauschig.jarchivelib.Archiver;
+import org.rauschig.jarchivelib.ArchiverFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class WebDriverManager {
+
+  public final static Logger LOG = LoggerFactory.getLogger(WebDriverManager.class);
+
+  private static String downLoadsDir = "";
+
+  private static String GECKODRIVER_VERSION = "0.19.1";
+
+  public static WebDriver getWebDriver() {
+    WebDriver driver = null;
+
+    if (driver == null) {
+      try {
+        FirefoxBinary ffox = new FirefoxBinary();
+        if ("true".equals(System.getenv("TRAVIS"))) {
+          ffox.setEnvironmentProperty("DISPLAY", ":99"); // xvfb is supposed to
+          // run with DISPLAY 99
+        }
+        int firefoxVersion = WebDriverManager.getFirefoxVersion();
+        LOG.info("Firefox version " + firefoxVersion + " detected");
+
+        downLoadsDir = FileUtils.getTempDirectory().toString();
+
+        String tempPath = downLoadsDir + "/firefox/";
+
+        downloadGeekoDriver(firefoxVersion, tempPath);
+
+        FirefoxProfile profile = new FirefoxProfile();
+        profile.setPreference("browser.download.folderList", 2);
+        profile.setPreference("browser.download.dir", downLoadsDir);
+        profile.setPreference("browser.helperApps.alwaysAsk.force", false);
+        profile.setPreference("browser.download.manager.showWhenStarting", false);
+        profile.setPreference("browser.download.manager.showAlertOnComplete", false);
+        profile.setPreference("browser.download.manager.closeWhenDone", true);
+        profile.setPreference("app.update.auto", false);
+        profile.setPreference("app.update.enabled", false);
+        profile.setPreference("dom.max_script_run_time", 0);
+        profile.setPreference("dom.max_chrome_script_run_time", 0);
+        profile.setPreference("browser.helperApps.neverAsk.saveToDisk",
+            "application/x-ustar,application/octet-stream,application/zip,text/csv,text/plain");
+        profile.setPreference("network.proxy.type", 0);
+
+        System.setProperty(GeckoDriverService.GECKO_DRIVER_EXE_PROPERTY, tempPath + "geckodriver");
+        System.setProperty(SystemProperty.DRIVER_USE_MARIONETTE, "false");
+
+        FirefoxOptions firefoxOptions = new FirefoxOptions();
+        firefoxOptions.setBinary(ffox);
+        firefoxOptions.setProfile(profile);
+        driver = new FirefoxDriver(firefoxOptions);
+      } catch (Exception e) {
+        LOG.error("Exception in WebDriverManager while FireFox Driver ", e);
+      }
+    }
+
+    if (driver == null) {
+      try {
+        driver = new ChromeDriver();
+      } catch (Exception e) {
+        LOG.error("Exception in WebDriverManager while ChromeDriver ", e);
+      }
+    }
+
+    if (driver == null) {
+      try {
+        driver = new SafariDriver();
+      } catch (Exception e) {
+        LOG.error("Exception in WebDriverManager while SafariDriver ", e);
+      }
+    }
+
+    String url;
+    if (System.getenv("url") != null) {
+      url = System.getenv("url");
+    } else {
+      url = "http://localhost:8080";
+    }
+
+    long start = System.currentTimeMillis();
+    boolean loaded = false;
+    driver.manage().timeouts().implicitlyWait(AbstractZeppelinIT.MAX_IMPLICIT_WAIT,
+        TimeUnit.SECONDS);
+    driver.get(url);
+
+    while (System.currentTimeMillis() - start < 60 * 1000) {
+      // wait for page load
+      try {
+        (new WebDriverWait(driver, 30)).until(new ExpectedCondition<Boolean>() {
+          @Override
+          public Boolean apply(WebDriver d) {
+            return d.findElement(By.xpath("//i[@uib-tooltip='WebSocket Connected']"))
+                .isDisplayed();
+          }
+        });
+        loaded = true;
+        break;
+      } catch (TimeoutException e) {
+        LOG.info("Exception in WebDriverManager while WebDriverWait ", e);
+        driver.navigate().to(url);
+      }
+    }
+
+    if (loaded == false) {
+      fail();
+    }
+
+    driver.manage().window().maximize();
+    return driver;
+  }
+
+  public static void downloadGeekoDriver(int firefoxVersion, String tempPath) {
+    String geekoDriverUrlString =
+        "https://github.com/mozilla/geckodriver/releases/download/v" + GECKODRIVER_VERSION
+            + "/geckodriver-v" + GECKODRIVER_VERSION + "-";
+
+    LOG.info("Geeko version: " + firefoxVersion + ", will be downloaded to " + tempPath);
+    try {
+      if (SystemUtils.IS_OS_WINDOWS) {
+        if (System.getProperty("sun.arch.data.model").equals("64")) {
+          geekoDriverUrlString += "win64.zip";
+        } else {
+          geekoDriverUrlString += "win32.zip";
+        }
+      } else if (SystemUtils.IS_OS_LINUX) {
+        if (System.getProperty("sun.arch.data.model").equals("64")) {
+          geekoDriverUrlString += "linux64.tar.gz";
+        } else {
+          geekoDriverUrlString += "linux32.tar.gz";
+        }
+      } else if (SystemUtils.IS_OS_MAC_OSX) {
+        geekoDriverUrlString += "macos.tar.gz";
+      }
+
+      File geekoDriver = new File(tempPath + "geckodriver");
+      File geekoDriverZip = new File(tempPath + "geckodriver.tar");
+      File geekoDriverDir = new File(tempPath);
+      URL geekoDriverUrl = new URL(geekoDriverUrlString);
+      if (!geekoDriver.exists()) {
+        FileUtils.copyURLToFile(geekoDriverUrl, geekoDriverZip);
+        if (SystemUtils.IS_OS_WINDOWS) {
+          Archiver archiver = ArchiverFactory.createArchiver("zip");
+          archiver.extract(geekoDriverZip, geekoDriverDir);
+        } else {
+          Archiver archiver = ArchiverFactory.createArchiver("tar", "gz");
+          archiver.extract(geekoDriverZip, geekoDriverDir);
+        }
+      }
+
+    } catch (IOException e) {
+      LOG.error("Download of Geeko version: " + firefoxVersion + ", falied in path " + tempPath);
+    }
+    LOG.info("Download of Geeko version: " + firefoxVersion + ", successful");
+  }
+
+  public static int getFirefoxVersion() {
+    try {
+      String firefoxVersionCmd = "firefox -v";
+      if (System.getProperty("os.name").startsWith("Mac OS")) {
+        firefoxVersionCmd = "/Applications/Firefox.app/Contents/MacOS/" + firefoxVersionCmd;
+      }
+      String versionString = (String) CommandExecutor
+          .executeCommandLocalHost(firefoxVersionCmd, false, ProcessData.Types_Of_Data.OUTPUT);
+      return Integer
+          .valueOf(versionString.replaceAll("Mozilla Firefox", "").trim().substring(0, 2));
+    } catch (Exception e) {
+      LOG.error("Exception in WebDriverManager while getWebDriver ", e);
+      return -1;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/7bff131a/zeppelin-integration/src/test/java/org/apache/zeppelin/ZeppelinITUtils.java
----------------------------------------------------------------------
diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/ZeppelinITUtils.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/ZeppelinITUtils.java
new file mode 100644
index 0000000..402a18d
--- /dev/null
+++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/ZeppelinITUtils.java
@@ -0,0 +1,60 @@
+/*
+ * 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.zeppelin;
+
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.openqa.selenium.WebDriver;
+import java.util.concurrent.TimeUnit;
+
+public class ZeppelinITUtils {
+
+  public final static Logger LOG = LoggerFactory.getLogger(ZeppelinITUtils.class);
+
+  public static void sleep(long millis, boolean logOutput) {
+    if (logOutput) {
+      LOG.info("Starting sleeping for " + (millis / 1000) + " seconds...");
+      LOG.info("Caller: " + Thread.currentThread().getStackTrace()[2]);
+    }
+    try {
+      Thread.sleep(millis);
+    } catch (InterruptedException e) {
+      LOG.error("Exception in WebDriverManager while getWebDriver ", e);
+    }
+    if (logOutput) {
+      LOG.info("Finished.");
+    }
+  }
+
+  public static void restartZeppelin() {
+    CommandExecutor.executeCommandLocalHost("../bin/zeppelin-daemon.sh restart",
+        false, ProcessData.Types_Of_Data.OUTPUT);
+    //wait for server to start.
+    sleep(5000, false);
+  }
+
+  public static void turnOffImplicitWaits(WebDriver driver) {
+    driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
+  }
+
+  public static void turnOnImplicitWaits(WebDriver driver) {
+    driver.manage().timeouts().implicitlyWait(AbstractZeppelinIT.MAX_IMPLICIT_WAIT,
+        TimeUnit.SECONDS);
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/7bff131a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/AuthenticationIT.java
----------------------------------------------------------------------
diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/AuthenticationIT.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/AuthenticationIT.java
new file mode 100644
index 0000000..4c194f3
--- /dev/null
+++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/AuthenticationIT.java
@@ -0,0 +1,302 @@
+/*
+ * 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.zeppelin.integration;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.zeppelin.AbstractZeppelinIT;
+import org.apache.zeppelin.WebDriverManager;
+import org.apache.zeppelin.ZeppelinITUtils;
+import org.apache.zeppelin.conf.ZeppelinConfiguration;
+import org.hamcrest.CoreMatchers;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ErrorCollector;
+import org.openqa.selenium.By;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.TimeoutException;
+import org.openqa.selenium.WebElement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Created for org.apache.zeppelin.integration on 13/06/16.
+ */
+public class AuthenticationIT extends AbstractZeppelinIT {
+  private static final Logger LOG = LoggerFactory.getLogger(AuthenticationIT.class);
+
+  @Rule
+  public ErrorCollector collector = new ErrorCollector();
+  static String shiroPath;
+  static String authShiro = "[users]\n" +
+      "admin = password1, admin\n" +
+      "finance1 = finance1, finance\n" +
+      "finance2 = finance2, finance\n" +
+      "hr1 = hr1, hr\n" +
+      "hr2 = hr2, hr\n" +
+      "[main]\n" +
+      "sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager\n" +
+      "securityManager.sessionManager = $sessionManager\n" +
+      "securityManager.sessionManager.globalSessionTimeout = 86400000\n" +
+      "shiro.loginUrl = /api/login\n" +
+      "anyofroles = org.apache.zeppelin.utils.AnyOfRolesAuthorizationFilter\n" +
+      "[roles]\n" +
+      "admin = *\n" +
+      "hr = *\n" +
+      "finance = *\n" +
+      "[urls]\n" +
+      "/api/version = anon\n" +
+      "/api/interpreter/** = authc, anyofroles[admin, finance]\n" +
+      "/** = authc";
+
+  static String originalShiro = "";
+
+
+  @BeforeClass
+  public static void startUp() {
+    try {
+      System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_HOME.getVarName(), new File("../").getAbsolutePath());
+      ZeppelinConfiguration conf = ZeppelinConfiguration.create();
+      shiroPath = conf.getRelativeDir(String.format("%s/shiro.ini", conf.getConfDir()));
+      File file = new File(shiroPath);
+      if (file.exists()) {
+        originalShiro = StringUtils.join(FileUtils.readLines(file, "UTF-8"), "\n");
+      }
+      FileUtils.write(file, authShiro, "UTF-8");
+    } catch (IOException e) {
+      LOG.error("Error in AuthenticationIT startUp::", e);
+    }
+    ZeppelinITUtils.restartZeppelin();
+    driver = WebDriverManager.getWebDriver();
+  }
+
+
+  @AfterClass
+  public static void tearDown() {
+    try {
+      if (!StringUtils.isBlank(shiroPath)) {
+        File file = new File(shiroPath);
+        if (StringUtils.isBlank(originalShiro)) {
+          FileUtils.deleteQuietly(file);
+        } else {
+          FileUtils.write(file, originalShiro, "UTF-8");
+        }
+      }
+    } catch (IOException e) {
+      LOG.error("Error in AuthenticationIT tearDown::", e);
+    }
+    ZeppelinITUtils.restartZeppelin();
+    driver.quit();
+  }
+
+  public void authenticationUser(String userName, String password) {
+    pollingWait(By.xpath(
+        "//div[contains(@class, 'navbar-collapse')]//li//button[contains(.,'Login')]"),
+        MAX_BROWSER_TIMEOUT_SEC).click();
+    ZeppelinITUtils.sleep(1000, false);
+    pollingWait(By.xpath("//*[@id='userName']"), MAX_BROWSER_TIMEOUT_SEC).sendKeys(userName);
+    pollingWait(By.xpath("//*[@id='password']"), MAX_BROWSER_TIMEOUT_SEC).sendKeys(password);
+    pollingWait(By.xpath("//*[@id='loginModalContent']//button[contains(.,'Login')]"),
+        MAX_BROWSER_TIMEOUT_SEC).click();
+    ZeppelinITUtils.sleep(1000, false);
+  }
+
+  private void testShowNotebookListOnNavbar() throws Exception {
+    try {
+      pollingWait(By.xpath("//li[@class='dropdown notebook-list-dropdown']"),
+          MAX_BROWSER_TIMEOUT_SEC).click();
+      assertTrue(driver.findElements(By.xpath("//a[@class=\"notebook-list-item ng-scope\"]")).size() > 0);
+      pollingWait(By.xpath("//li[@class='dropdown notebook-list-dropdown']"),
+              MAX_BROWSER_TIMEOUT_SEC).click();
+      pollingWait(By.xpath("//li[@class='dropdown notebook-list-dropdown']"),
+              MAX_BROWSER_TIMEOUT_SEC).click();
+    } catch (Exception e) {
+      handleException("Exception in ParagraphActionsIT while testShowNotebookListOnNavbar ", e);
+    }
+  }
+
+  public void logoutUser(String userName) throws URISyntaxException {
+    ZeppelinITUtils.sleep(500, false);
+    driver.findElement(By.xpath("//div[contains(@class, 'navbar-collapse')]//li[contains(.,'" +
+        userName + "')]")).click();
+    ZeppelinITUtils.sleep(500, false);
+    driver.findElement(By.xpath("//div[contains(@class, 'navbar-collapse')]//li[contains(.,'" +
+        userName + "')]//a[@ng-click='navbar.logout()']")).click();
+    ZeppelinITUtils.sleep(2000, false);
+    if (driver.findElement(By.xpath("//*[@id='loginModal']//div[contains(@class, 'modal-header')]/button"))
+        .isDisplayed()) {
+      driver.findElement(By.xpath("//*[@id='loginModal']//div[contains(@class, 'modal-header')]/button")).click();
+    }
+    driver.get(new URI(driver.getCurrentUrl()).resolve("/#/").toString());
+    ZeppelinITUtils.sleep(500, false);
+  }
+
+  //  @Test
+  public void testSimpleAuthentication() throws Exception {
+    try {
+      AuthenticationIT authenticationIT = new AuthenticationIT();
+      authenticationIT.authenticationUser("admin", "password1");
+
+      collector.checkThat("Check is user logged in", true,
+          CoreMatchers.equalTo(driver.findElement(By.partialLinkText("Create new note"))
+              .isDisplayed()));
+
+      authenticationIT.logoutUser("admin");
+    } catch (Exception e) {
+      handleException("Exception in AuthenticationIT while testCreateNewButton ", e);
+    }
+  }
+
+  @Test
+  public void testAnyOfRoles() throws Exception {
+    try {
+      AuthenticationIT authenticationIT = new AuthenticationIT();
+      authenticationIT.authenticationUser("admin", "password1");
+
+      pollingWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"),
+          MAX_BROWSER_TIMEOUT_SEC).click();
+      clickAndWait(By.xpath("//li/a[contains(@href, '#/interpreter')]"));
+
+      collector.checkThat("Check is user has permission to view this page", true,
+          CoreMatchers.equalTo(pollingWait(By.xpath(
+              "//div[@id='main']/div/div[2]"),
+              MIN_IMPLICIT_WAIT).isDisplayed())
+      );
+
+      authenticationIT.logoutUser("admin");
+
+      authenticationIT.authenticationUser("finance1", "finance1");
+
+      pollingWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"),
+          MAX_BROWSER_TIMEOUT_SEC).click();
+      clickAndWait(By.xpath("//li/a[contains(@href, '#/interpreter')]"));
+
+      collector.checkThat("Check is user has permission to view this page", true,
+          CoreMatchers.equalTo(pollingWait(By.xpath(
+              "//div[@id='main']/div/div[2]"),
+              MIN_IMPLICIT_WAIT).isDisplayed())
+      );
+      
+      authenticationIT.logoutUser("finance1");
+
+      authenticationIT.authenticationUser("hr1", "hr1");
+
+      pollingWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"),
+          MAX_BROWSER_TIMEOUT_SEC).click();
+      clickAndWait(By.xpath("//li/a[contains(@href, '#/interpreter')]"));
+
+      try {
+        collector.checkThat("Check is user has permission to view this page",
+            true, CoreMatchers.equalTo(
+                pollingWait(By.xpath("//li[contains(@class, 'ng-toast__message')]//span/span"),
+                    MIN_IMPLICIT_WAIT).isDisplayed()));
+      } catch (TimeoutException e) {
+        throw new Exception("Expected ngToast not found", e);
+      }
+      authenticationIT.logoutUser("hr1");
+
+    } catch (Exception e) {
+      handleException("Exception in AuthenticationIT while testAnyOfRoles ", e);
+    }
+  }
+
+  @Test
+  public void testGroupPermission() throws Exception {
+    try {
+      AuthenticationIT authenticationIT = new AuthenticationIT();
+      authenticationIT.authenticationUser("finance1", "finance1");
+      createNewNote();
+
+      String noteId = driver.getCurrentUrl().substring(driver.getCurrentUrl().lastIndexOf("/") + 1);
+
+      pollingWait(By.xpath("//span[@uib-tooltip='Note permissions']"),
+          MAX_BROWSER_TIMEOUT_SEC).click();
+      pollingWait(By.xpath(".//*[@id='selectOwners']/following::span//input"),
+          MAX_BROWSER_TIMEOUT_SEC).sendKeys("finance ");
+      pollingWait(By.xpath(".//*[@id='selectReaders']/following::span//input"),
+          MAX_BROWSER_TIMEOUT_SEC).sendKeys("finance ");
+      pollingWait(By.xpath(".//*[@id='selectRunners']/following::span//input"),
+              MAX_BROWSER_TIMEOUT_SEC).sendKeys("finance ");
+      pollingWait(By.xpath(".//*[@id='selectWriters']/following::span//input"),
+          MAX_BROWSER_TIMEOUT_SEC).sendKeys("finance ");
+      pollingWait(By.xpath("//button[@ng-click='savePermissions()']"), MAX_BROWSER_TIMEOUT_SEC)
+          .sendKeys(Keys.ENTER);
+
+      pollingWait(By.xpath("//div[@class='modal-dialog'][contains(.,'Permissions Saved ')]" +
+              "//div[@class='modal-footer']//button[contains(.,'OK')]"),
+          MAX_BROWSER_TIMEOUT_SEC).click();
+      authenticationIT.logoutUser("finance1");
+
+      authenticationIT.authenticationUser("hr1", "hr1");
+      try {
+        WebElement element = pollingWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"),
+            MAX_BROWSER_TIMEOUT_SEC);
+        collector.checkThat("Check is user has permission to view this note link", false,
+            CoreMatchers.equalTo(element.isDisplayed()));
+      } catch (Exception e) {
+        //This should have failed, nothing to worry.
+      }
+
+      driver.get(new URI(driver.getCurrentUrl()).resolve("/#/notebook/" + noteId).toString());
+
+      List<WebElement> privilegesModal = driver.findElements(
+          By.xpath("//div[@class='modal-content']//div[@class='bootstrap-dialog-header']" +
+              "//div[contains(.,'Insufficient privileges')]"));
+      collector.checkThat("Check is user has permission to view this note", 1,
+          CoreMatchers.equalTo(privilegesModal.size()));
+      driver.findElement(
+          By.xpath("//div[@class='modal-content'][contains(.,'Insufficient privileges')]" +
+              "//div[@class='modal-footer']//button[2]")).click();
+      authenticationIT.logoutUser("hr1");
+
+      authenticationIT.authenticationUser("finance2", "finance2");
+      try {
+        WebElement element = pollingWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"),
+            MAX_BROWSER_TIMEOUT_SEC);
+        collector.checkThat("Check is user has permission to view this note link", true,
+            CoreMatchers.equalTo(element.isDisplayed()));
+      } catch (Exception e) {
+        //This should have failed, nothing to worry.
+      }
+
+      driver.get(new URI(driver.getCurrentUrl()).resolve("/#/notebook/" + noteId).toString());
+
+      privilegesModal = driver.findElements(
+          By.xpath("//div[@class='modal-content']//div[@class='bootstrap-dialog-header']" +
+              "//div[contains(.,'Insufficient privileges')]"));
+      collector.checkThat("Check is user has permission to view this note", 0,
+          CoreMatchers.equalTo(privilegesModal.size()));
+      deleteTestNotebook(driver);
+      authenticationIT.logoutUser("finance2");
+
+
+    } catch (Exception e) {
+      handleException("Exception in AuthenticationIT while testGroupPermission ", e);
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/7bff131a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/InterpreterIT.java
----------------------------------------------------------------------
diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/InterpreterIT.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/InterpreterIT.java
new file mode 100644
index 0000000..d2e31a0
--- /dev/null
+++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/InterpreterIT.java
@@ -0,0 +1,73 @@
+/*
+ * 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.zeppelin.integration;
+
+import org.apache.zeppelin.AbstractZeppelinIT;
+import org.apache.zeppelin.WebDriverManager;
+import org.hamcrest.CoreMatchers;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ErrorCollector;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.Select;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class InterpreterIT extends AbstractZeppelinIT {
+  private static final Logger LOG = LoggerFactory.getLogger(InterpreterIT.class);
+
+  @Rule
+  public ErrorCollector collector = new ErrorCollector();
+
+  @Before
+  public void startUp() {
+    driver = WebDriverManager.getWebDriver();
+  }
+
+  @After
+  public void tearDown() {
+    driver.quit();
+  }
+
+  @Test
+  public void testShowDescriptionOnInterpreterCreate() throws Exception {
+    try {
+      // navigate to interpreter page
+      WebElement settingButton = driver.findElement(By.xpath("//button[@class='nav-btn dropdown-toggle ng-scope']"));
+      settingButton.click();
+      WebElement interpreterLink = driver.findElement(By.xpath("//a[@href='#/interpreter']"));
+      interpreterLink.click();
+
+      WebElement createButton = driver.findElement(By.xpath("//button[contains(., 'Create')]"));
+      createButton.click();
+
+      Select select = new Select(driver.findElement(By.xpath("//select[@ng-change='newInterpreterGroupChange()']")));
+      select.selectByVisibleText("spark");
+
+      collector.checkThat("description of interpreter property is displayed",
+          driver.findElement(By.xpath("//tr/td[contains(text(), 'spark.app.name')]/following-sibling::td[3]")).getText(),
+          CoreMatchers.equalTo("The name of spark application."));
+
+    } catch (Exception e) {
+      handleException("Exception in InterpreterIT while testShowDescriptionOnInterpreterCreate ", e);
+    }
+  }
+}