Skip to content

Commit 4f11a22

Browse files
authored
Implements _Launch on App Engine_ (#1070)
1 parent 1205d85 commit 4f11a22

File tree

17 files changed

+632
-60
lines changed

17 files changed

+632
-60
lines changed

plugins/com.google.cloud.tools.eclipse.appengine.deploy.ui.test/src/com/google/cloud/tools/eclipse/appengine/deploy/ui/standard/StandardDeployCommandHandlerTest.java

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,20 @@
2020
import static org.mockito.Mockito.mock;
2121
import static org.mockito.Mockito.when;
2222

23-
import java.util.Collections;
24-
23+
import com.google.cloud.tools.eclipse.test.util.ui.ExecutionEventBuilder;
24+
import com.google.cloud.tools.eclipse.util.FacetedProjectHelper;
2525
import org.eclipse.core.commands.ExecutionEvent;
2626
import org.eclipse.core.commands.ExecutionException;
27-
import org.eclipse.core.expressions.IEvaluationContext;
2827
import org.eclipse.core.resources.IProject;
2928
import org.eclipse.core.runtime.CoreException;
3029
import org.eclipse.core.runtime.IStatus;
3130
import org.eclipse.core.runtime.Status;
32-
import org.eclipse.jface.viewers.IStructuredSelection;
3331
import org.eclipse.swt.widgets.Shell;
34-
import org.eclipse.ui.ISources;
3532
import org.junit.Test;
3633
import org.junit.runner.RunWith;
3734
import org.mockito.Mock;
3835
import org.mockito.runners.MockitoJUnitRunner;
3936

40-
import com.google.cloud.tools.eclipse.appengine.deploy.ui.standard.StandardDeployCommandHandler;
41-
import com.google.cloud.tools.eclipse.util.FacetedProjectHelper;
42-
4337
@RunWith(MockitoJUnitRunner.class)
4438
public class StandardDeployCommandHandlerTest {
4539

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

5246
when(facetedProjectHelper.getFacetedProject(isA(IProject.class))).thenThrow(getFakeCoreException());
53-
ExecutionEvent event = getTestExecutionEvent(mock(IProject.class));
47+
ExecutionEvent event = new ExecutionEventBuilder().withCurrentSelection(mock(IProject.class))
48+
.withActiveShell(mock(Shell.class)).build();
5449

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

66-
private ExecutionEvent getTestExecutionEvent(Object project) {
67-
IEvaluationContext context = mock(IEvaluationContext.class);
68-
IStructuredSelection selection = mock(IStructuredSelection.class);
69-
when(selection.size()).thenReturn(1);
70-
when(selection.getFirstElement()).thenReturn(project);
71-
when(context.getVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME)).thenReturn(selection);
72-
when(context.getVariable(ISources.ACTIVE_SHELL_NAME)).thenReturn(mock(Shell.class));
73-
return new ExecutionEvent(null /*command */, Collections.EMPTY_MAP, null /* trigger */, context);
74-
}
7561
}

plugins/com.google.cloud.tools.eclipse.appengine.localserver.test/META-INF/MANIFEST.MF

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Require-Bundle: org.hamcrest;bundle-version="1.1.0",
1212
org.eclipse.jst.j2ee.web
1313
Import-Package: com.google.cloud.tools.eclipse.test.util.project,
1414
com.google.cloud.tools.eclipse.test.util.ui,
15+
com.google.cloud.tools.eclipse.util.io,
1516
org.mockito;provider=google;version="1.10.19",
1617
org.mockito.runners;provider=google;version="1.10.19",
1718
org.mockito.stubbing;provider=google;version="1.10.19",

plugins/com.google.cloud.tools.eclipse.appengine.localserver.test/src/com/google/cloud/tools/eclipse/appengine/localserver/EclipseContextHolder.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,10 @@
1818

1919
import org.eclipse.e4.core.contexts.EclipseContextFactory;
2020
import org.eclipse.e4.core.contexts.IEclipseContext;
21-
import org.junit.Rule;
2221
import org.junit.rules.ExternalResource;
2322

2423
/**
25-
* Helper class to be used with {@link Rule} to make tests easier that depend on
24+
* Helper class to be used with {@link org.junit.Rule} to make tests easier that depend on
2625
* {@link IEclipseContext}. It provides an empty context that can be filled with object needed for
2726
* the test using the {@link #set(Class, Object)} method.
2827
* <p>

plugins/com.google.cloud.tools.eclipse.appengine.localserver.test/src/com/google/cloud/tools/eclipse/appengine/localserver/server/LocalAppEngineServerDelegateTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion;
3232
import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager;
3333
import org.eclipse.wst.server.core.IModule;
34+
import org.eclipse.wst.server.core.IModuleType;
3435
import org.eclipse.wst.server.core.IRuntime;
3536
import org.eclipse.wst.server.core.IRuntimeWorkingCopy;
3637
import org.eclipse.wst.server.core.IServer;
@@ -154,7 +155,7 @@ public void testGetChildModules_noModuleType(){
154155

155156
@Test
156157
public void testGetChildModules_nonWebModuleType(){
157-
ModuleType nonWebModuleType = new ModuleType("non-web", "1.0");
158+
IModuleType nonWebModuleType = ModuleType.getModuleType("non-web", "1.0");
158159
when(module1.getModuleType()).thenReturn(nonWebModuleType);
159160

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

164165
@Test
165166
public void testGetChildModules_webModuleType() {
166-
ModuleType webModuleType = new ModuleType("jst.web", "1.0");
167+
IModuleType webModuleType = ModuleType.getModuleType("jst.web", "1.0");
167168
when(module1.getModuleType()).thenReturn(webModuleType);
168169
when(module1.getId()).thenReturn("module1");
169170
when(module1.loadAdapter(IWebModule.class, null)).thenReturn(webModule1);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* Copyright 2016 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cloud.tools.eclipse.appengine.localserver.ui;
18+
19+
import static org.junit.Assert.assertEquals;
20+
import static org.mockito.Mockito.mock;
21+
import static org.mockito.Mockito.when;
22+
23+
import com.google.cloud.tools.eclipse.appengine.facets.AppEngineStandardFacet;
24+
import com.google.cloud.tools.eclipse.test.util.project.TestProjectCreator;
25+
import com.google.cloud.tools.eclipse.test.util.ui.ExecutionEventBuilder;
26+
import com.google.common.collect.Lists;
27+
import org.eclipse.core.commands.ExecutionEvent;
28+
import org.eclipse.core.commands.ExecutionException;
29+
import org.eclipse.core.runtime.CoreException;
30+
import org.eclipse.core.runtime.SubMonitor;
31+
import org.eclipse.debug.core.ILaunch;
32+
import org.eclipse.debug.core.ILaunchManager;
33+
import org.eclipse.jst.common.project.facet.core.JavaFacet;
34+
import org.eclipse.jst.j2ee.web.project.facet.WebFacetUtils;
35+
import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion;
36+
import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager;
37+
import org.eclipse.wst.server.core.IModule;
38+
import org.eclipse.wst.server.core.IServer;
39+
import org.junit.Before;
40+
import org.junit.Rule;
41+
import org.junit.Test;
42+
import org.junit.runner.RunWith;
43+
import org.mockito.runners.MockitoJUnitRunner;
44+
45+
/**
46+
* Tests for the {@link LaunchAppEngineStandardHandler}.
47+
*/
48+
@RunWith(MockitoJUnitRunner.class)
49+
public class LaunchAppEngineStandardHandlerTest {
50+
private static final IProjectFacetVersion APPENGINE_STANDARD_FACET_VERSION_1 =
51+
ProjectFacetsManager.getProjectFacet(AppEngineStandardFacet.ID).getVersion("1");
52+
53+
@Rule
54+
public ServerTracker tracker = new ServerTracker();
55+
56+
private LaunchAppEngineStandardHandler handler;
57+
private IServer serverToReturn = null;
58+
59+
@Rule
60+
public TestProjectCreator appEngineStandardProject1 =
61+
new TestProjectCreator().withFacetVersions(Lists.newArrayList(JavaFacet.VERSION_1_7,
62+
WebFacetUtils.WEB_25, APPENGINE_STANDARD_FACET_VERSION_1));
63+
@Rule
64+
public TestProjectCreator appEngineStandardProject2 =
65+
new TestProjectCreator().withFacetVersions(Lists.newArrayList(JavaFacet.VERSION_1_7,
66+
WebFacetUtils.WEB_25, APPENGINE_STANDARD_FACET_VERSION_1));
67+
68+
69+
@Before
70+
public void setUp() {
71+
handler = new LaunchAppEngineStandardHandler() {
72+
@Override
73+
protected void launch(IServer server, String launchMode, SubMonitor progress)
74+
throws CoreException {
75+
// do nothing
76+
}
77+
78+
@Override
79+
protected IServer findExistingServer(IModule[] modules, SubMonitor progress) {
80+
if (serverToReturn != null) {
81+
return serverToReturn;
82+
}
83+
return super.findExistingServer(modules, progress);
84+
}
85+
};
86+
}
87+
88+
89+
@Test
90+
public void testWithDefaultModule() throws ExecutionException, CoreException {
91+
IModule module1 = appEngineStandardProject1.getModule();
92+
93+
ExecutionEvent event = new ExecutionEventBuilder().withCurrentSelection(module1).build();
94+
handler.execute(event);
95+
assertEquals("new server should have been created", 1, tracker.getServers().size());
96+
}
97+
98+
@Test
99+
public void testWithTwoModules() throws ExecutionException, CoreException {
100+
appEngineStandardProject1.setAppEngineServiceId("default");
101+
IModule module1 = appEngineStandardProject1.getModule();
102+
appEngineStandardProject2.setAppEngineServiceId("other");
103+
IModule module2 = appEngineStandardProject2.getModule();
104+
105+
ExecutionEvent event =
106+
new ExecutionEventBuilder().withCurrentSelection(module1, module2).build();
107+
handler.execute(event);
108+
assertEquals("new server should have been created", 1, tracker.getServers().size());
109+
}
110+
111+
@Test(expected = ExecutionException.class)
112+
public void failsIfAlreadyLaunched() throws ExecutionException, CoreException {
113+
IModule module1 = appEngineStandardProject1.getModule();
114+
115+
ExecutionEvent event = new ExecutionEventBuilder().withCurrentSelection(module1).build();
116+
serverToReturn = mock(IServer.class);
117+
ILaunch launch = mock(ILaunch.class);
118+
when(serverToReturn.getServerState()).thenReturn(IServer.STATE_STARTED);
119+
when(serverToReturn.getLaunch()).thenReturn(launch);
120+
when(launch.getLaunchMode()).thenReturn(ILaunchManager.DEBUG_MODE);
121+
handler.execute(event);
122+
}
123+
124+
public void testInvariantToModuleOrder() throws ExecutionException, CoreException {
125+
appEngineStandardProject1.setAppEngineServiceId("default");
126+
IModule module1 = appEngineStandardProject1.getModule();
127+
appEngineStandardProject2.setAppEngineServiceId("other");
128+
IModule module2 = appEngineStandardProject2.getModule();
129+
130+
ExecutionEvent event =
131+
new ExecutionEventBuilder().withCurrentSelection(module1, module2).build();
132+
handler.execute(event);
133+
assertEquals("new server should have been created", 1, tracker.getServers().size());
134+
135+
// because we don't actually launch the servers, we won't get an ExecutionException
136+
ExecutionEvent swappedEvent =
137+
new ExecutionEventBuilder().withCurrentSelection(module2, module1).build();
138+
handler.execute(swappedEvent);
139+
assertEquals("no new servers should be created", 1, tracker.getServers().size());
140+
}
141+
142+
@Test(expected = ExecutionException.class)
143+
public void failsWithClashingServiceIds() throws ExecutionException, CoreException {
144+
appEngineStandardProject1.setAppEngineServiceId("other");
145+
IModule module1 = appEngineStandardProject1.getModule();
146+
appEngineStandardProject2.setAppEngineServiceId("other");
147+
IModule module2 = appEngineStandardProject2.getModule();
148+
149+
ExecutionEvent event =
150+
new ExecutionEventBuilder().withCurrentSelection(module1, module2).build();
151+
handler.execute(event);
152+
}
153+
154+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2016 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cloud.tools.eclipse.appengine.localserver.ui;
18+
19+
import java.util.ArrayList;
20+
import java.util.Collections;
21+
import java.util.List;
22+
import org.eclipse.core.runtime.CoreException;
23+
import org.eclipse.wst.server.core.IServer;
24+
import org.eclipse.wst.server.core.IServerLifecycleListener;
25+
import org.eclipse.wst.server.core.ServerCore;
26+
import org.junit.rules.ExternalResource;
27+
28+
/** Track creation of WTP {@link IServer} instances and ensure they are deleted. */
29+
public class ServerTracker extends ExternalResource {
30+
private List<IServer> servers = Collections.synchronizedList(new ArrayList<IServer>());
31+
32+
private IServerLifecycleListener lifecycleListener = new IServerLifecycleListener() {
33+
@Override
34+
public void serverAdded(IServer server) {
35+
servers.add(server);
36+
}
37+
38+
@Override
39+
public void serverChanged(IServer server) {}
40+
41+
@Override
42+
public void serverRemoved(IServer server) {
43+
servers.remove(server);
44+
}
45+
};
46+
47+
@Override
48+
protected void before() {
49+
ServerCore.addServerLifecycleListener(lifecycleListener);
50+
}
51+
52+
public List<IServer> getServers() {
53+
return servers;
54+
}
55+
56+
@Override
57+
protected void after() {
58+
ServerCore.removeServerLifecycleListener(lifecycleListener);
59+
for (IServer server : servers) {
60+
try {
61+
server.delete();
62+
} catch (CoreException ex) {
63+
/* ignore */
64+
}
65+
}
66+
}
67+
}

plugins/com.google.cloud.tools.eclipse.appengine.localserver/plugin.xml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,4 +222,46 @@
222222
typeIds="com.google.cloud.tools.eclipse.appengine.standard.server">
223223
</fragment>
224224
</extension>
225+
<extension
226+
point="org.eclipse.ui.commands">
227+
<command
228+
description="Launch on App Engine development server"
229+
id="com.google.cloud.tools.eclipse.appengine.localserver.launch"
230+
name="Launch on App Engine">
231+
<commandParameter
232+
id="launchMode"
233+
name="Launch mode"
234+
optional="true"
235+
values="com.google.cloud.tools.eclipse.appengine.localserver.ui.LaunchModes">
236+
</commandParameter>
237+
</command>
238+
</extension>
239+
<extension
240+
point="org.eclipse.ui.handlers">
241+
<handler
242+
class="com.google.cloud.tools.eclipse.appengine.localserver.ui.LaunchAppEngineStandardHandler"
243+
commandId="com.google.cloud.tools.eclipse.appengine.localserver.launch">
244+
<enabledWhen>
245+
<or>
246+
<iterate
247+
ifEmpty="false">
248+
<or>
249+
<adapt
250+
type="org.eclipse.wst.server.core.IModule">
251+
</adapt>
252+
<test
253+
property="org.eclipse.wst.server.ui.isRunnable">
254+
</test>
255+
</or>
256+
</iterate>
257+
<with
258+
variable="activeEditor">
259+
<adapt
260+
type="org.eclipse.ui.IEditorPart">
261+
</adapt>
262+
</with>
263+
</or>
264+
</enabledWhen>
265+
</handler>
266+
</extension>
225267
</plugin>

plugins/com.google.cloud.tools.eclipse.appengine.localserver/src/com/google/cloud/tools/eclipse/appengine/localserver/server/LocalAppEngineServerDelegate.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@
4141

4242
@SuppressWarnings("restriction") // For FacetUtil
4343
public class LocalAppEngineServerDelegate extends ServerDelegate {
44+
public static final String RUNTIME_TYPE_ID =
45+
"com.google.cloud.tools.eclipse.appengine.standard.runtime";
46+
public static final String SERVER_TYPE_ID =
47+
"com.google.cloud.tools.eclipse.appengine.standard.server";
48+
4449
private static final IModule[] EMPTY_MODULES = new IModule[0];
4550
private static final String SERVLET_MODULE_FACET = "jst.web"; //$NON-NLS-1$
4651
private static final String ATTR_APP_ENGINE_SERVER_MODULES = "app-engine-server-modules-list"; //$NON-NLS-1$

plugins/com.google.cloud.tools.eclipse.appengine.localserver/src/com/google/cloud/tools/eclipse/appengine/localserver/server/LocalAppEngineServerLaunchConfigurationDelegate.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ public class LocalAppEngineServerLaunchConfigurationDelegate
7171
private final static Logger logger =
7272
Logger.getLogger(LocalAppEngineServerLaunchConfigurationDelegate.class.getName());
7373

74+
public static final String[] SUPPORTED_LAUNCH_MODES =
75+
{ILaunchManager.RUN_MODE, ILaunchManager.DEBUG_MODE};
76+
7477
private static final String DEBUGGER_HOST = "localhost"; //$NON-NLS-1$
7578

7679
private static void validateCloudSdk() throws CoreException {

0 commit comments

Comments
 (0)