/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.jdb.server;
import com.google.common.collect.ImmutableMap;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.project.ProjectConfig;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.debug.shared.model.Breakpoint;
import org.eclipse.che.api.debug.shared.model.DebuggerInfo;
import org.eclipse.che.api.debug.shared.model.Location;
import org.eclipse.che.api.debug.shared.model.StackFrameDump;
import org.eclipse.che.api.debug.shared.model.Variable;
import org.eclipse.che.api.debug.shared.model.event.BreakpointActivatedEvent;
import org.eclipse.che.api.debug.shared.model.event.DebuggerEvent;
import org.eclipse.che.api.debug.shared.model.event.DisconnectEvent;
import org.eclipse.che.api.debug.shared.model.event.SuspendEvent;
import org.eclipse.che.api.debug.shared.model.impl.BreakpointImpl;
import org.eclipse.che.api.debug.shared.model.impl.LocationImpl;
import org.eclipse.che.api.debug.shared.model.impl.VariableImpl;
import org.eclipse.che.api.debug.shared.model.impl.VariablePathImpl;
import org.eclipse.che.api.debug.shared.model.impl.action.ResumeActionImpl;
import org.eclipse.che.api.debug.shared.model.impl.action.StartActionImpl;
import org.eclipse.che.api.debug.shared.model.impl.action.StepIntoActionImpl;
import org.eclipse.che.api.debug.shared.model.impl.action.StepOutActionImpl;
import org.eclipse.che.api.debug.shared.model.impl.action.StepOverActionImpl;
import org.eclipse.che.api.debugger.server.Debugger;
import org.eclipse.che.api.debugger.server.exceptions.DebuggerException;
import org.eclipse.che.api.project.server.ProjectManager;
import org.eclipse.che.api.project.server.ProjectRegistry;
import org.eclipse.che.api.project.server.WorkspaceProjectsSyncer;
import org.eclipse.che.api.project.server.handlers.ProjectHandlerRegistry;
import org.eclipse.che.api.project.server.importer.ProjectImporterRegistry;
import org.eclipse.che.api.project.server.type.ProjectTypeRegistry;
import org.eclipse.che.api.vfs.impl.file.DefaultFileWatcherNotificationHandler;
import org.eclipse.che.api.vfs.impl.file.FileTreeWatcher;
import org.eclipse.che.api.vfs.impl.file.FileWatcherNotificationHandler;
import org.eclipse.che.api.vfs.impl.file.LocalVirtualFileSystemProvider;
import org.eclipse.che.api.vfs.search.impl.FSLuceneSearcherProvider;
import org.eclipse.che.api.vfs.watcher.FileWatcherManager;
import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
import org.eclipse.che.plugin.java.server.projecttype.JavaProjectType;
import org.eclipse.che.plugin.java.server.projecttype.JavaValueProviderFactory;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.io.File;
import java.nio.file.PathMatcher;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.stream.Collectors;
import static java.util.Collections.singletonList;
import static org.mockito.Mockito.mock;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
/**
* @author Anatolii Bazko
*/
public class JavaDebuggerTest {
private Debugger debugger;
private BlockingQueue<DebuggerEvent> events;
@Test(priority = 1)
public void testGetInfo() throws Exception {
DebuggerInfo info = debugger.getInfo();
assertEquals(info.getHost(), "localhost");
assertEquals(info.getPort(), Integer.parseInt(System.getProperty("debug.port")));
assertNotNull(info.getName());
assertNotNull(info.getVersion());
}
@Test(priority = 2)
public void testStartDebugger() throws Exception {
BreakpointImpl breakpoint = new BreakpointImpl(new LocationImpl("com.HelloWorld", 17), false, null);
debugger.start(new StartActionImpl(singletonList(breakpoint)));
DebuggerEvent debuggerEvent = events.take();
assertTrue(debuggerEvent instanceof BreakpointActivatedEvent);
debuggerEvent = events.take();
assertTrue(debuggerEvent instanceof SuspendEvent);
Location location = ((SuspendEvent)debuggerEvent).getLocation();
assertEquals(location.getLineNumber(), 17);
assertEquals(location.getTarget(), "com.HelloWorld");
}
@Test(priority = 3)
public void testAddBreakpoint() throws Exception {
int breakpointsCount = debugger.getAllBreakpoints().size();
debugger.addBreakpoint(new BreakpointImpl(new LocationImpl("com.HelloWorld", 18), false, null));
DebuggerEvent debuggerEvent = events.take();
assertTrue(debuggerEvent instanceof BreakpointActivatedEvent);
Breakpoint breakpoint = ((BreakpointActivatedEvent)debuggerEvent).getBreakpoint();
assertEquals(breakpoint.getLocation().getLineNumber(), 18);
assertEquals(breakpoint.getLocation().getTarget(), "com.HelloWorld");
assertTrue(breakpoint.isEnabled());
assertEquals(debugger.getAllBreakpoints().size(), breakpointsCount + 1);
}
@Test(priority = 5, expectedExceptions = DebuggerException.class)
public void testAddBreakpointToUnExistedLocation() throws Exception {
debugger.addBreakpoint(new BreakpointImpl(new LocationImpl("com.HelloWorld", 1), false, null));
}
@Test(priority = 6)
public void testRemoveBreakpoint() throws Exception {
debugger.deleteBreakpoint(new LocationImpl("com.HelloWorld", 17));
assertEquals(debugger.getAllBreakpoints().size(), 1);
}
@Test(priority = 7)
public void testRemoveUnExistedBreakpoint() throws Exception {
int breakpointsCount = debugger.getAllBreakpoints().size();
debugger.deleteBreakpoint(new LocationImpl("com.HelloWorld", 2));
assertEquals(debugger.getAllBreakpoints().size(), breakpointsCount);
}
@Test(priority = 8)
public void testGetAllBreakpoints() throws Exception {
assertFalse(debugger.getAllBreakpoints().isEmpty());
debugger.deleteAllBreakpoints();
assertTrue(debugger.getAllBreakpoints().isEmpty());
debugger.addBreakpoint(new BreakpointImpl(new LocationImpl("com.HelloWorld", 18), false, null));
DebuggerEvent debuggerEvent = events.take();
assertTrue(debuggerEvent instanceof BreakpointActivatedEvent);
assertEquals(debugger.getAllBreakpoints().size(), 1);
Breakpoint breakpoint = debugger.getAllBreakpoints().get(0);
assertEquals(breakpoint.getLocation().getLineNumber(), 18);
assertEquals(breakpoint.getLocation().getTarget(), "com.HelloWorld");
assertTrue(breakpoint.isEnabled());
}
@Test(priority = 9)
public void testSteps() throws Exception {
debugger.deleteAllBreakpoints();
debugger.addBreakpoint(new BreakpointImpl(new LocationImpl("com.HelloWorld", 20), false, null));
assertTrue(events.take() instanceof BreakpointActivatedEvent);
debugger.resume(new ResumeActionImpl());
DebuggerEvent debuggerEvent = events.take();
assertTrue(debuggerEvent instanceof SuspendEvent);
Location location = ((SuspendEvent)debuggerEvent).getLocation();
assertEquals(location.getTarget(), "com.HelloWorld");
assertEquals(location.getLineNumber(), 20);
assertEquals(location.getExternalResourceId(), -1);
assertEquals(location.getResourceProjectPath(), "/test");
assertEquals(location.getResourcePath(), "/test/src/com/HelloWorld.java");
debugger.stepInto(new StepIntoActionImpl());
debuggerEvent = events.take();
assertTrue(debuggerEvent instanceof SuspendEvent);
location = ((SuspendEvent)debuggerEvent).getLocation();
assertEquals(location.getTarget(), "com.HelloWorld");
assertEquals(location.getLineNumber(), 28);
debugger.stepOut(new StepOutActionImpl());
debuggerEvent = events.take();
assertTrue(debuggerEvent instanceof SuspendEvent);
location = ((SuspendEvent)debuggerEvent).getLocation();
assertEquals(location.getTarget(), "com.HelloWorld");
assertEquals(location.getLineNumber(), 20);
debugger.stepOver(new StepOverActionImpl());
debuggerEvent = events.take();
assertTrue(debuggerEvent instanceof SuspendEvent);
location = ((SuspendEvent)debuggerEvent).getLocation();
assertEquals(location.getTarget(), "com.HelloWorld");
assertEquals(location.getLineNumber(), 21);
debugger.stepOver(new StepOverActionImpl());
debuggerEvent = events.take();
assertTrue(debuggerEvent instanceof SuspendEvent);
location = ((SuspendEvent)debuggerEvent).getLocation();
assertEquals(location.getTarget(), "com.HelloWorld");
assertEquals(location.getLineNumber(), 23);
debugger.stepOver(new StepOverActionImpl());
debuggerEvent = events.take();
assertTrue(debuggerEvent instanceof SuspendEvent);
location = ((SuspendEvent)debuggerEvent).getLocation();
assertEquals(location.getTarget(), "com.HelloWorld");
assertEquals(location.getLineNumber(), 24);
}
@Test(priority = 10)
public void testEvaluateExpression() throws Exception {
assertEquals(debugger.evaluate("2+2"), "4");
assertEquals(debugger.evaluate("\"hello\""), "\"hello\"");
assertEquals(debugger.evaluate("test"), "\"hello\"");
}
@Test(priority = 11)
public void testSetAndGetValue() throws Exception {
assertEquals(debugger.getValue(new VariablePathImpl("test")).getValue(), "\"hello\"");
assertEquals(debugger.getValue(new VariablePathImpl("msg")).getValue(), "\"Hello, debugger!\"");
debugger.setValue(new VariableImpl("\"new hello\"", (new VariablePathImpl("test"))));
assertEquals(debugger.getValue(new VariablePathImpl("test")).getValue(), "\"new hello\"");
StackFrameDump stackFrameDump = debugger.dumpStackFrame();
Set<String> vars = stackFrameDump.getVariables().stream().map(Variable::getName).collect(Collectors.toSet());
assertTrue(vars.contains("args"));
assertTrue(vars.contains("msg"));
assertTrue(vars.contains("test"));
}
@Test(priority = 12)
public void testDisconnect() throws Exception {
debugger.disconnect();
DebuggerEvent debuggerEvent = events.take();
assertTrue(debuggerEvent instanceof DisconnectEvent);
}
@BeforeClass
protected void initProjectApi() throws Exception {
TestWorkspaceHolder workspaceHolder = new TestWorkspaceHolder(new ArrayList<>());
File root = new File("target/test-classes/workspace");
assertTrue(root.exists());
File indexDir = new File("target/fs_index");
assertTrue(indexDir.mkdirs());
Set<PathMatcher> filters = new HashSet<>();
filters.add(path -> true);
FSLuceneSearcherProvider sProvider = new FSLuceneSearcherProvider(indexDir, filters);
EventService eventService = new EventService();
LocalVirtualFileSystemProvider vfsProvider = new LocalVirtualFileSystemProvider(root, sProvider);
ProjectTypeRegistry projectTypeRegistry = new ProjectTypeRegistry(new HashSet<>());
projectTypeRegistry.registerProjectType(new JavaProjectType(new JavaValueProviderFactory()));
ProjectHandlerRegistry projectHandlerRegistry = new ProjectHandlerRegistry(new HashSet<>());
ProjectRegistry projectRegistry = new ProjectRegistry(workspaceHolder,
vfsProvider,
projectTypeRegistry,
projectHandlerRegistry,
eventService);
projectRegistry.initProjects();
ProjectImporterRegistry importerRegistry = new ProjectImporterRegistry(new HashSet<>());
FileWatcherNotificationHandler fileWatcherNotificationHandler = new DefaultFileWatcherNotificationHandler(vfsProvider);
FileTreeWatcher fileTreeWatcher = new FileTreeWatcher(root, new HashSet<>(), fileWatcherNotificationHandler);
ProjectManager projectManager = new ProjectManager(vfsProvider,
projectTypeRegistry,
projectRegistry,
projectHandlerRegistry,
importerRegistry,
fileWatcherNotificationHandler,
fileTreeWatcher,
workspaceHolder,
mock(FileWatcherManager.class));
ResourcesPlugin resourcesPlugin =
new ResourcesPlugin("target/index",
root.getAbsolutePath(),
() -> projectRegistry,
() -> projectManager);
resourcesPlugin.start();
JavaPlugin javaPlugin = new JavaPlugin(root.getAbsolutePath() + "/.settings", resourcesPlugin, projectRegistry);
javaPlugin.start();
projectRegistry.setProjectType("test", "java", false);
JavaModelManager.getDeltaState().initializeRoots(true);
events = new ArrayBlockingQueue<>(10);
Map<String, String> connectionProperties = ImmutableMap.of("host", "localhost",
"port", System.getProperty("debug.port"));
JavaDebuggerFactory factory = new JavaDebuggerFactory();
debugger = factory.create(connectionProperties, events::add);
}
private static class TestWorkspaceHolder extends WorkspaceProjectsSyncer {
private List<ProjectConfigDto> projects;
TestWorkspaceHolder() {
this.projects = new ArrayList<>();
}
TestWorkspaceHolder(List<ProjectConfigDto> projects) {
this.projects = projects;
}
@Override
public List<? extends ProjectConfig> getProjects() {
return projects;
}
@Override
public String getWorkspaceId() {
return "id";
}
@Override
protected void addProject(ProjectConfig project) throws ServerException {}
@Override
protected void updateProject(ProjectConfig project) throws ServerException {}
@Override
protected void removeProject(ProjectConfig project) throws ServerException {}
}
}