Skip to content

Commit

Permalink
Implements _Launch on App Engine_ (#1070)
Browse files Browse the repository at this point in the history
  • Loading branch information
briandealwis authored Dec 8, 2016
1 parent 1205d85 commit 4f11a22
Show file tree
Hide file tree
Showing 17 changed files with 632 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,20 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.util.Collections;

import com.google.cloud.tools.eclipse.test.util.ui.ExecutionEventBuilder;
import com.google.cloud.tools.eclipse.util.FacetedProjectHelper;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.ISources;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import com.google.cloud.tools.eclipse.appengine.deploy.ui.standard.StandardDeployCommandHandler;
import com.google.cloud.tools.eclipse.util.FacetedProjectHelper;

@RunWith(MockitoJUnitRunner.class)
public class StandardDeployCommandHandlerTest {

Expand All @@ -50,7 +44,8 @@ public void testExecute_facetedProjectCreationThrowsException() throws Execution
StandardDeployCommandHandler handler = new StandardDeployCommandHandler(facetedProjectHelper);

when(facetedProjectHelper.getFacetedProject(isA(IProject.class))).thenThrow(getFakeCoreException());
ExecutionEvent event = getTestExecutionEvent(mock(IProject.class));
ExecutionEvent event = new ExecutionEventBuilder().withCurrentSelection(mock(IProject.class))
.withActiveShell(mock(Shell.class)).build();

handler.execute(event);
}
Expand All @@ -63,13 +58,4 @@ private Status getFakeErrorStatus() {
return new Status(IStatus.ERROR, "fakePluginId", "test exception");
}

private ExecutionEvent getTestExecutionEvent(Object project) {
IEvaluationContext context = mock(IEvaluationContext.class);
IStructuredSelection selection = mock(IStructuredSelection.class);
when(selection.size()).thenReturn(1);
when(selection.getFirstElement()).thenReturn(project);
when(context.getVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME)).thenReturn(selection);
when(context.getVariable(ISources.ACTIVE_SHELL_NAME)).thenReturn(mock(Shell.class));
return new ExecutionEvent(null /*command */, Collections.EMPTY_MAP, null /* trigger */, context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Require-Bundle: org.hamcrest;bundle-version="1.1.0",
org.eclipse.jst.j2ee.web
Import-Package: com.google.cloud.tools.eclipse.test.util.project,
com.google.cloud.tools.eclipse.test.util.ui,
com.google.cloud.tools.eclipse.util.io,
org.mockito;provider=google;version="1.10.19",
org.mockito.runners;provider=google;version="1.10.19",
org.mockito.stubbing;provider=google;version="1.10.19",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@

import org.eclipse.e4.core.contexts.EclipseContextFactory;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.junit.Rule;
import org.junit.rules.ExternalResource;

/**
* Helper class to be used with {@link Rule} to make tests easier that depend on
* Helper class to be used with {@link org.junit.Rule} to make tests easier that depend on
* {@link IEclipseContext}. It provides an empty context that can be filled with object needed for
* the test using the {@link #set(Class, Object)} method.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion;
import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager;
import org.eclipse.wst.server.core.IModule;
import org.eclipse.wst.server.core.IModuleType;
import org.eclipse.wst.server.core.IRuntime;
import org.eclipse.wst.server.core.IRuntimeWorkingCopy;
import org.eclipse.wst.server.core.IServer;
Expand Down Expand Up @@ -154,7 +155,7 @@ public void testGetChildModules_noModuleType(){

@Test
public void testGetChildModules_nonWebModuleType(){
ModuleType nonWebModuleType = new ModuleType("non-web", "1.0");
IModuleType nonWebModuleType = ModuleType.getModuleType("non-web", "1.0");
when(module1.getModuleType()).thenReturn(nonWebModuleType);

IModule[] childModules = delegate.getChildModules(new IModule[]{module1});
Expand All @@ -163,7 +164,7 @@ public void testGetChildModules_nonWebModuleType(){

@Test
public void testGetChildModules_webModuleType() {
ModuleType webModuleType = new ModuleType("jst.web", "1.0");
IModuleType webModuleType = ModuleType.getModuleType("jst.web", "1.0");
when(module1.getModuleType()).thenReturn(webModuleType);
when(module1.getId()).thenReturn("module1");
when(module1.loadAdapter(IWebModule.class, null)).thenReturn(webModule1);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/*
* Copyright 2016 Google Inc.
*
* Licensed 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 com.google.cloud.tools.eclipse.appengine.localserver.ui;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import com.google.cloud.tools.eclipse.appengine.facets.AppEngineStandardFacet;
import com.google.cloud.tools.eclipse.test.util.project.TestProjectCreator;
import com.google.cloud.tools.eclipse.test.util.ui.ExecutionEventBuilder;
import com.google.common.collect.Lists;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.jst.common.project.facet.core.JavaFacet;
import org.eclipse.jst.j2ee.web.project.facet.WebFacetUtils;
import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion;
import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager;
import org.eclipse.wst.server.core.IModule;
import org.eclipse.wst.server.core.IServer;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;

/**
* Tests for the {@link LaunchAppEngineStandardHandler}.
*/
@RunWith(MockitoJUnitRunner.class)
public class LaunchAppEngineStandardHandlerTest {
private static final IProjectFacetVersion APPENGINE_STANDARD_FACET_VERSION_1 =
ProjectFacetsManager.getProjectFacet(AppEngineStandardFacet.ID).getVersion("1");

@Rule
public ServerTracker tracker = new ServerTracker();

private LaunchAppEngineStandardHandler handler;
private IServer serverToReturn = null;

@Rule
public TestProjectCreator appEngineStandardProject1 =
new TestProjectCreator().withFacetVersions(Lists.newArrayList(JavaFacet.VERSION_1_7,
WebFacetUtils.WEB_25, APPENGINE_STANDARD_FACET_VERSION_1));
@Rule
public TestProjectCreator appEngineStandardProject2 =
new TestProjectCreator().withFacetVersions(Lists.newArrayList(JavaFacet.VERSION_1_7,
WebFacetUtils.WEB_25, APPENGINE_STANDARD_FACET_VERSION_1));


@Before
public void setUp() {
handler = new LaunchAppEngineStandardHandler() {
@Override
protected void launch(IServer server, String launchMode, SubMonitor progress)
throws CoreException {
// do nothing
}

@Override
protected IServer findExistingServer(IModule[] modules, SubMonitor progress) {
if (serverToReturn != null) {
return serverToReturn;
}
return super.findExistingServer(modules, progress);
}
};
}


@Test
public void testWithDefaultModule() throws ExecutionException, CoreException {
IModule module1 = appEngineStandardProject1.getModule();

ExecutionEvent event = new ExecutionEventBuilder().withCurrentSelection(module1).build();
handler.execute(event);
assertEquals("new server should have been created", 1, tracker.getServers().size());
}

@Test
public void testWithTwoModules() throws ExecutionException, CoreException {
appEngineStandardProject1.setAppEngineServiceId("default");
IModule module1 = appEngineStandardProject1.getModule();
appEngineStandardProject2.setAppEngineServiceId("other");
IModule module2 = appEngineStandardProject2.getModule();

ExecutionEvent event =
new ExecutionEventBuilder().withCurrentSelection(module1, module2).build();
handler.execute(event);
assertEquals("new server should have been created", 1, tracker.getServers().size());
}

@Test(expected = ExecutionException.class)
public void failsIfAlreadyLaunched() throws ExecutionException, CoreException {
IModule module1 = appEngineStandardProject1.getModule();

ExecutionEvent event = new ExecutionEventBuilder().withCurrentSelection(module1).build();
serverToReturn = mock(IServer.class);
ILaunch launch = mock(ILaunch.class);
when(serverToReturn.getServerState()).thenReturn(IServer.STATE_STARTED);
when(serverToReturn.getLaunch()).thenReturn(launch);
when(launch.getLaunchMode()).thenReturn(ILaunchManager.DEBUG_MODE);
handler.execute(event);
}

public void testInvariantToModuleOrder() throws ExecutionException, CoreException {
appEngineStandardProject1.setAppEngineServiceId("default");
IModule module1 = appEngineStandardProject1.getModule();
appEngineStandardProject2.setAppEngineServiceId("other");
IModule module2 = appEngineStandardProject2.getModule();

ExecutionEvent event =
new ExecutionEventBuilder().withCurrentSelection(module1, module2).build();
handler.execute(event);
assertEquals("new server should have been created", 1, tracker.getServers().size());

// because we don't actually launch the servers, we won't get an ExecutionException
ExecutionEvent swappedEvent =
new ExecutionEventBuilder().withCurrentSelection(module2, module1).build();
handler.execute(swappedEvent);
assertEquals("no new servers should be created", 1, tracker.getServers().size());
}

@Test(expected = ExecutionException.class)
public void failsWithClashingServiceIds() throws ExecutionException, CoreException {
appEngineStandardProject1.setAppEngineServiceId("other");
IModule module1 = appEngineStandardProject1.getModule();
appEngineStandardProject2.setAppEngineServiceId("other");
IModule module2 = appEngineStandardProject2.getModule();

ExecutionEvent event =
new ExecutionEventBuilder().withCurrentSelection(module1, module2).build();
handler.execute(event);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2016 Google Inc.
*
* Licensed 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 com.google.cloud.tools.eclipse.appengine.localserver.ui;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.wst.server.core.IServer;
import org.eclipse.wst.server.core.IServerLifecycleListener;
import org.eclipse.wst.server.core.ServerCore;
import org.junit.rules.ExternalResource;

/** Track creation of WTP {@link IServer} instances and ensure they are deleted. */
public class ServerTracker extends ExternalResource {
private List<IServer> servers = Collections.synchronizedList(new ArrayList<IServer>());

private IServerLifecycleListener lifecycleListener = new IServerLifecycleListener() {
@Override
public void serverAdded(IServer server) {
servers.add(server);
}

@Override
public void serverChanged(IServer server) {}

@Override
public void serverRemoved(IServer server) {
servers.remove(server);
}
};

@Override
protected void before() {
ServerCore.addServerLifecycleListener(lifecycleListener);
}

public List<IServer> getServers() {
return servers;
}

@Override
protected void after() {
ServerCore.removeServerLifecycleListener(lifecycleListener);
for (IServer server : servers) {
try {
server.delete();
} catch (CoreException ex) {
/* ignore */
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -222,4 +222,46 @@
typeIds="com.google.cloud.tools.eclipse.appengine.standard.server">
</fragment>
</extension>
<extension
point="org.eclipse.ui.commands">
<command
description="Launch on App Engine development server"
id="com.google.cloud.tools.eclipse.appengine.localserver.launch"
name="Launch on App Engine">
<commandParameter
id="launchMode"
name="Launch mode"
optional="true"
values="com.google.cloud.tools.eclipse.appengine.localserver.ui.LaunchModes">
</commandParameter>
</command>
</extension>
<extension
point="org.eclipse.ui.handlers">
<handler
class="com.google.cloud.tools.eclipse.appengine.localserver.ui.LaunchAppEngineStandardHandler"
commandId="com.google.cloud.tools.eclipse.appengine.localserver.launch">
<enabledWhen>
<or>
<iterate
ifEmpty="false">
<or>
<adapt
type="org.eclipse.wst.server.core.IModule">
</adapt>
<test
property="org.eclipse.wst.server.ui.isRunnable">
</test>
</or>
</iterate>
<with
variable="activeEditor">
<adapt
type="org.eclipse.ui.IEditorPart">
</adapt>
</with>
</or>
</enabledWhen>
</handler>
</extension>
</plugin>
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@

@SuppressWarnings("restriction") // For FacetUtil
public class LocalAppEngineServerDelegate extends ServerDelegate {
public static final String RUNTIME_TYPE_ID =
"com.google.cloud.tools.eclipse.appengine.standard.runtime";
public static final String SERVER_TYPE_ID =
"com.google.cloud.tools.eclipse.appengine.standard.server";

private static final IModule[] EMPTY_MODULES = new IModule[0];
private static final String SERVLET_MODULE_FACET = "jst.web"; //$NON-NLS-1$
private static final String ATTR_APP_ENGINE_SERVER_MODULES = "app-engine-server-modules-list"; //$NON-NLS-1$
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ public class LocalAppEngineServerLaunchConfigurationDelegate
private final static Logger logger =
Logger.getLogger(LocalAppEngineServerLaunchConfigurationDelegate.class.getName());

public static final String[] SUPPORTED_LAUNCH_MODES =
{ILaunchManager.RUN_MODE, ILaunchManager.DEBUG_MODE};

private static final String DEBUGGER_HOST = "localhost"; //$NON-NLS-1$

private static void validateCloudSdk() throws CoreException {
Expand Down
Loading

0 comments on commit 4f11a22

Please sign in to comment.