/*******************************************************************************
* Copyright (c) 2007-2016 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v 1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributor:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.openshift.ui.bot.test.application.v3.debug;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.swt.graphics.Point;
import org.eclipse.wst.jsdt.debug.core.model.JavaScriptDebugModel;
import org.hamcrest.Matcher;
import org.jboss.reddeer.common.condition.AbstractWaitCondition;
import org.jboss.reddeer.common.exception.WaitTimeoutExpiredException;
import org.jboss.reddeer.common.wait.TimePeriod;
import org.jboss.reddeer.common.wait.WaitUntil;
import org.jboss.reddeer.common.wait.WaitWhile;
import org.jboss.reddeer.core.condition.JobIsRunning;
import org.jboss.reddeer.core.condition.ShellWithTextIsAvailable;
import org.jboss.reddeer.core.exception.CoreLayerException;
import org.jboss.reddeer.core.matcher.WithTextMatcher;
import org.jboss.reddeer.eclipse.jdt.ui.ProjectExplorer;
import org.jboss.reddeer.eclipse.ui.perspectives.DebugPerspective;
import org.jboss.reddeer.junit.requirement.inject.InjectRequirement;
import org.jboss.reddeer.junit.runner.RedDeerSuite;
import org.jboss.reddeer.requirements.openperspective.OpenPerspectiveRequirement.OpenPerspective;
import org.jboss.reddeer.swt.api.Tree;
import org.jboss.reddeer.swt.api.TreeItem;
import org.jboss.reddeer.swt.impl.button.FinishButton;
import org.jboss.reddeer.swt.impl.menu.ContextMenu;
import org.jboss.reddeer.swt.impl.shell.DefaultShell;
import org.jboss.reddeer.swt.impl.tree.DefaultTree;
import org.jboss.reddeer.workbench.condition.EditorWithTitleIsActive;
import org.jboss.reddeer.workbench.impl.editor.TextEditor;
import org.jboss.reddeer.workbench.impl.view.WorkbenchView;
import org.jboss.tools.openshift.reddeer.condition.ServerAdapterExists;
import org.jboss.tools.openshift.reddeer.exception.OpenShiftToolsException;
import org.jboss.tools.openshift.reddeer.requirement.OpenShiftCommandLineToolsRequirement.OCBinary;
import org.jboss.tools.openshift.reddeer.requirement.OpenShiftConnectionRequirement;
import org.jboss.tools.openshift.reddeer.requirement.OpenShiftConnectionRequirement.RequiredBasicConnection;
import org.jboss.tools.openshift.reddeer.requirement.OpenShiftProjectRequirement;
import org.jboss.tools.openshift.reddeer.requirement.OpenShiftProjectRequirement.RequiredProject;
import org.jboss.tools.openshift.reddeer.requirement.OpenShiftResources;
import org.jboss.tools.openshift.reddeer.requirement.OpenShiftServiceRequirement;
import org.jboss.tools.openshift.reddeer.requirement.OpenShiftServiceRequirement.RequiredService;
import org.jboss.tools.openshift.reddeer.utils.OpenShiftLabel;
import org.jboss.tools.openshift.reddeer.utils.TestUtils;
import org.jboss.tools.openshift.reddeer.view.OpenShiftExplorerView;
import org.jboss.tools.openshift.reddeer.view.resources.OpenShift3Connection;
import org.jboss.tools.openshift.reddeer.view.resources.OpenShiftProject;
import org.jboss.tools.openshift.reddeer.view.resources.ServerAdapter;
import org.jboss.tools.openshift.reddeer.view.resources.ServerAdapter.Version;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
*
* @author psrna
*
*/
@OpenPerspective(DebugPerspective.class)
@RunWith(RedDeerSuite.class)
@OCBinary
@RequiredBasicConnection
@RequiredProject
@RequiredService(service = OpenShiftResources.NODEJS_SERVICE, template = OpenShiftResources.NODEJS_TEMPLATE)
public class NodeJSAppDebugTest {
@InjectRequirement
private OpenShiftProjectRequirement requiredProject;
@InjectRequirement
private OpenShiftConnectionRequirement requiredConnection;
@InjectRequirement
private OpenShiftServiceRequirement requiredService;
private OpenShift3Connection connection;
private OpenShiftProject project;
private ServerAdapter adapter;
private static int BREAKPOINT_LINE = 85;
private static String APP_URL = "http://nodejs-example-test-project.rhel-cdk.10.1.2.2.xip.io/pagecount";
private static String VAR_db = "db";
private static String VAR_VALUE_db = "null";
private static String VAR_initDb = "initDb";
private static String VAR_VALUE_initDb = "[Function]";
private static String VAR_require = "require";
private static String VAR_VALUE_require = "[Function]";
@Before
public void setUp() {
TestUtils.setUpOcBinary();
TestUtils.cleanupGitFolder(OpenShiftResources.NODEJS_GIT_NAME);
OpenShiftExplorerView explorer = new OpenShiftExplorerView();
explorer.open();
this.connection = explorer.getOpenShift3Connection(requiredConnection.getConnection());
this.project = connection.getProject(requiredProject.getProjectName());
this.project.expand();
// import application
this.project.getService(OpenShiftResources.NODEJS_SERVICE).select();
new ContextMenu(OpenShiftLabel.ContextMenu.IMPORT_APPLICATION).select();
new DefaultShell(OpenShiftLabel.Shell.IMPORT_APPLICATION);
new FinishButton().click();
new WaitWhile(new ShellWithTextIsAvailable(OpenShiftLabel.Shell.IMPORT_APPLICATION));
// setup server adapter
explorer.activate();
this.project.getService(OpenShiftResources.NODEJS_SERVICE).select();
new ContextMenu(OpenShiftLabel.ContextMenu.NEW_ADAPTER_FROM_EXPLORER).select();
new DefaultShell(OpenShiftLabel.Shell.SERVER_ADAPTER_SETTINGS);
new FinishButton().click();
new WaitWhile(new ShellWithTextIsAvailable(""), TimePeriod.LONG);
new WaitWhile(new JobIsRunning(), TimePeriod.VERY_LONG);
assertTrue("OpenShift 3 server adapter was not created.",
new ServerAdapterExists(Version.OPENSHIFT3, OpenShiftResources.NODEJS_SERVICE, "Service").test());
// restart in debug
this.adapter = new ServerAdapter(Version.OPENSHIFT3, OpenShiftResources.NODEJS_SERVICE, "Service");
this.adapter.select();
new ContextMenu("Restart in Debug").select();
new WaitWhile(new JobIsRunning(), TimePeriod.VERY_LONG);
}
@After
public void clean() {
ProjectExplorer pe = new ProjectExplorer();
pe.open();
pe.deleteAllProjects();
try {
new WaitWhile(new JobIsRunning(), TimePeriod.LONG);
new ServerAdapter(Version.OPENSHIFT3, OpenShiftResources.NODEJS_SERVICE).delete();
} catch (OpenShiftToolsException ex) {
// do nothing, adapter does not exists
}
}
@Test
public void testDebuggerStopsAtBreakpoint() throws CoreException, IOException {
ProjectExplorer pe = new ProjectExplorer();
pe.open();
pe.getProject(OpenShiftResources.NODEJS_GIT_NAME).getProjectItem("server.js").open();
new WaitUntil(new EditorWithTitleIsActive("server.js"));
TextEditor editor = new TextEditor("server.js");
setLineBreakpoint(editor, BREAKPOINT_LINE);
triggerDebugSession();
try {
new WaitUntil(new EditorWithTitleIsActive("server.js"), TimePeriod.LONG);
new WaitUntil(new CursorPositionIsOnLine(editor, BREAKPOINT_LINE));
} catch (WaitTimeoutExpiredException e) {
Assert.fail("Debugger hasn't stopped on breakpoint");
}
}
@Test
public void testVariablesAvailableInView() throws CoreException, IOException {
ProjectExplorer pe = new ProjectExplorer();
pe.open();
pe.getProject(OpenShiftResources.NODEJS_GIT_NAME).getProjectItem("server.js").open();
new WaitUntil(new EditorWithTitleIsActive("server.js"));
TextEditor editor = new TextEditor("server.js");
setLineBreakpoint(editor, BREAKPOINT_LINE);
triggerDebugSession();
// test couple of js variables
TreeItem var_db = getVariable(VAR_db);
TreeItem var_initDb = getVariable(VAR_initDb);
TreeItem var_require = getVariable(VAR_require);
assertTrue("Variable '" + VAR_db + "' not found in view!", var_db != null);
assertThat(var_db.getCell(0), is(VAR_db));
assertThat(var_db.getCell(1), containsString(VAR_VALUE_db));
assertTrue("Variable '" + VAR_initDb + "' not found in view!", var_initDb != null);
assertThat(var_initDb.getCell(0), is(VAR_initDb));
assertThat(var_initDb.getCell(1), containsString(VAR_VALUE_initDb));
assertTrue("Variable '" + VAR_require + "' not found in view!", var_require != null);
assertThat(var_require.getCell(0), is(VAR_require));
assertThat(var_require.getCell(1), containsString(VAR_VALUE_require));
}
private void setLineBreakpoint(TextEditor editor, int lineNumber) throws CoreException {
editor.activate();
IResource resource = (IResource) editor.getEditorPart().getEditorInput().getAdapter(IResource.class);
JavaScriptDebugModel.createLineBreakpoint(resource, lineNumber, -1, -1, new HashMap<String, Object>(), true);
}
/**
* getVariable from Variables view.
*
* @param variable
* name
* @return TreeItem
*/
protected TreeItem getVariable(String name) {
WorkbenchView variables = new WorkbenchView("Variables");
variables.activate();
DefaultTree variablesTree = new DefaultTree();
TreeItem var = null;
try {
new WaitUntil(new TreeContainsItem(variablesTree, new WithTextMatcher(name), false));
} catch (WaitTimeoutExpiredException e) {
// not found
return null;
}
List<TreeItem> vars = variablesTree.getItems();
for (TreeItem i : vars) {
if (i.getText().equals(name)) {
var = i;
}
}
return var;
}
private void triggerDebugSession() {
new Thread(new Runnable() {
public void run() {
try {
URL url = new URL(APP_URL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.connect();
connection.getResponseCode();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
public class CursorPositionIsOnLine extends AbstractWaitCondition {
private TextEditor editor;
private int line;
/**
* Constructs CursorPositionIsOnLine wait condition. Condition is met
* when the specified editor has cursor set on a line specified in
* param.
*
* @param editor
* editor where to look for the cursor position
* @param line
* - line counting starts from 1
*/
public CursorPositionIsOnLine(TextEditor editor, int line) {
this.editor = editor;
this.line = line;
}
@Override
public boolean test() {
Point p = editor.getCursorPosition();
if (p.x + 1 == line) {
return true;
} else {
return false;
}
}
@Override
public String description() {
return "editor cursor position is on line '" + line;
}
}
public class TreeContainsItem extends AbstractWaitCondition {
private Tree tree;
private Matcher matcher;
private boolean recursive = true;
/**
* Constructs TreeContainsItem wait condition. Condition is met when the
* specified tree contains the tree item with specified text.
*
* @param tree
* tree where to look for an item
* @param matcher
* to match the text of the item
*/
public TreeContainsItem(Tree tree, Matcher matcher) {
this.tree = tree;
this.matcher = matcher;
}
public TreeContainsItem(Tree tree, Matcher matcher, boolean recursive) {
this.tree = tree;
this.matcher = matcher;
this.recursive = recursive;
}
@Override
public boolean test() {
try {
List<TreeItem> list = recursive ? tree.getAllItems() : tree.getItems();
for (TreeItem i : list) {
if (matcher.matches(i.getText())) {
return true;
}
}
} catch (CoreLayerException e) {
return false;
}
return false;
}
@Override
public String description() {
return "tree contains item '" + matcher.toString();
}
}
}