-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes #1350 - Detect if a project does not have App Engine application (
#1426) * WIP * extract ProjectSelectorSelectionChangedListener * extract ProjectSelectorSelectionChangedListener into top level class in internal package * refactor internal classes into top level classes, more tests, extract Google API creation from ProjectRepository * minor changes, javadoc * import org.eclipse.ui.browser * refactor to use OpenUriSelectionListener * add timeout to api calls, rename api methods, make fields static/final * handle long error message, display only error message instead of full json response * test fix * better error message handling * store App Engine application in GcpProject and query it in project selector only if needed, reduce default timeout for GoogleApiFactory * changed message to remove 'Click here' * another tweak to the missing app engine message
- Loading branch information
Showing
28 changed files
with
880 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
...ols/eclipse/appengine/deploy/ui/internal/ProjectSelectorSelectionChangedListenerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
/* | ||
* Copyright 2017 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.deploy.ui.internal; | ||
|
||
import static org.mockito.Matchers.any; | ||
import static org.mockito.Matchers.anyString; | ||
import static org.mockito.Mockito.mock; | ||
import static org.mockito.Mockito.verify; | ||
import static org.mockito.Mockito.when; | ||
|
||
import com.google.api.client.auth.oauth2.Credential; | ||
import com.google.cloud.tools.eclipse.appengine.deploy.ui.internal.ProjectSelectorSelectionChangedListener; | ||
import com.google.cloud.tools.eclipse.login.ui.AccountSelector; | ||
import com.google.cloud.tools.eclipse.projectselector.ProjectRepository; | ||
import com.google.cloud.tools.eclipse.projectselector.ProjectRepositoryException; | ||
import com.google.cloud.tools.eclipse.projectselector.ProjectSelector; | ||
import com.google.cloud.tools.eclipse.projectselector.model.AppEngine; | ||
import com.google.cloud.tools.eclipse.projectselector.model.GcpProject; | ||
import org.eclipse.jface.viewers.SelectionChangedEvent; | ||
import org.eclipse.jface.viewers.StructuredSelection; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.mockito.Mock; | ||
import org.mockito.runners.MockitoJUnitRunner; | ||
|
||
@RunWith(MockitoJUnitRunner.class) | ||
public class ProjectSelectorSelectionChangedListenerTest { | ||
|
||
private static final String EXPECTED_LINK = | ||
"https://console.cloud.google.com/appengine/create?lang=java&project=projectId"; | ||
private static final String EXPECTED_MESSAGE_WHEN_NO_APPLICATION = | ||
"This project does not have an App Engine application which is\n" | ||
+ "required for deployment. <a href=\"" + EXPECTED_LINK + "\">Create an App Engine " | ||
+ "application in the\nCloud Console</a>."; | ||
private static final String EXPECTED_MESSAGE_WHEN_EXCEPTION = | ||
"An error occurred while retrieving App Engine application:\ntestException"; | ||
|
||
@Mock private AccountSelector accountSelector; | ||
@Mock private ProjectSelector projectSelector; | ||
@Mock private ProjectRepository projectRepository; | ||
@Mock private SelectionChangedEvent event; | ||
|
||
private ProjectSelectorSelectionChangedListener listener; | ||
|
||
@Before | ||
public void setUp() throws Exception { | ||
listener = new ProjectSelectorSelectionChangedListener(accountSelector, projectRepository, | ||
projectSelector); | ||
} | ||
|
||
@Test | ||
public void testSelectionChanged_emptySelection() { | ||
when(event.getSelection()).thenReturn(new StructuredSelection()); | ||
listener.selectionChanged(event); | ||
verify(projectSelector).clearStatusLink(); | ||
} | ||
|
||
@Test | ||
public void testSelectionChanged_repositoryException() throws ProjectRepositoryException { | ||
initSelectionAndAccountSelector(); | ||
when(projectRepository.getAppEngineApplication(any(Credential.class), anyString())) | ||
.thenThrow(new ProjectRepositoryException("testException")); | ||
|
||
listener.selectionChanged(event); | ||
verify(projectSelector).setStatusLink(EXPECTED_MESSAGE_WHEN_EXCEPTION, null /* tooltip */); | ||
} | ||
|
||
@Test | ||
public void testSelectionChanged_noAppEngineApplication() throws ProjectRepositoryException { | ||
initSelectionAndAccountSelector(); | ||
when(projectRepository.getAppEngineApplication(any(Credential.class), anyString())) | ||
.thenReturn(AppEngine.NO_APPENGINE_APPLICATION); | ||
|
||
listener.selectionChanged(event); | ||
verify(projectSelector).setStatusLink(EXPECTED_MESSAGE_WHEN_NO_APPLICATION, EXPECTED_LINK); | ||
} | ||
|
||
@Test | ||
public void testSelectionChanged_hasAppEngineApplication() throws ProjectRepositoryException { | ||
initSelectionAndAccountSelector(); | ||
when(projectRepository.getAppEngineApplication(any(Credential.class), anyString())) | ||
.thenReturn(AppEngine.withId("id")); | ||
|
||
listener.selectionChanged(event); | ||
verify(projectSelector).clearStatusLink(); | ||
} | ||
|
||
private void initSelectionAndAccountSelector() { | ||
StructuredSelection selection = | ||
new StructuredSelection(new GcpProject("projectName", "projectId")); | ||
when(event.getSelection()).thenReturn(selection); | ||
when(accountSelector.getSelectedCredential()).thenReturn(mock(Credential.class)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
...d/tools/eclipse/appengine/deploy/ui/internal/ProjectSelectorSelectionChangedListener.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/* | ||
* Copyright 2017 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.deploy.ui.internal; | ||
|
||
import com.google.api.client.auth.oauth2.Credential; | ||
import com.google.cloud.tools.eclipse.appengine.deploy.ui.Messages; | ||
import com.google.cloud.tools.eclipse.login.ui.AccountSelector; | ||
import com.google.cloud.tools.eclipse.projectselector.ProjectRepository; | ||
import com.google.cloud.tools.eclipse.projectselector.ProjectRepositoryException; | ||
import com.google.cloud.tools.eclipse.projectselector.ProjectSelector; | ||
import com.google.cloud.tools.eclipse.projectselector.model.AppEngine; | ||
import com.google.cloud.tools.eclipse.projectselector.model.GcpProject; | ||
import java.text.MessageFormat; | ||
import org.eclipse.jface.viewers.ISelectionChangedListener; | ||
import org.eclipse.jface.viewers.IStructuredSelection; | ||
import org.eclipse.jface.viewers.SelectionChangedEvent; | ||
|
||
public class ProjectSelectorSelectionChangedListener implements ISelectionChangedListener { | ||
|
||
private static String CREATE_APP_LINK = | ||
"https://console.cloud.google.com/appengine/create?lang=java&project={0}"; | ||
|
||
private final AccountSelector accountSelector; | ||
private final ProjectRepository projectRepository; | ||
private final ProjectSelector projectSelector; | ||
|
||
public ProjectSelectorSelectionChangedListener(AccountSelector accountSelector, | ||
ProjectRepository projectRepository, | ||
ProjectSelector projectSelector) { | ||
this.accountSelector = accountSelector; | ||
this.projectRepository = projectRepository; | ||
this.projectSelector = projectSelector; | ||
} | ||
|
||
@Override | ||
public void selectionChanged(SelectionChangedEvent event) { | ||
IStructuredSelection selection = (IStructuredSelection) event.getSelection(); | ||
try { | ||
if (!selection.isEmpty()) { | ||
GcpProject project = (GcpProject) selection.getFirstElement(); | ||
boolean hasAppEngineApplication = hasAppEngineApplication(project); | ||
if (!hasAppEngineApplication) { | ||
String link = MessageFormat.format(CREATE_APP_LINK, project.getId()); | ||
projectSelector.setStatusLink( | ||
Messages.getString("projectselector.missing.appengine.application.link", | ||
link), link); | ||
} else { | ||
projectSelector.clearStatusLink(); | ||
} | ||
} else { | ||
projectSelector.clearStatusLink(); | ||
} | ||
} catch (ProjectRepositoryException ex) { | ||
projectSelector.setStatusLink(Messages.getString("projectselector.retrieveapplication.error.message", | ||
ex.getLocalizedMessage()), | ||
null /* tooltip */); | ||
} | ||
} | ||
|
||
/** | ||
* Lazily queries the backend whether the specified project has an App Engine application. | ||
* <p> | ||
* The result of the query is stored in the object and the next time it is returned from there | ||
* saving a roundtrip to the backend. | ||
*/ | ||
private boolean hasAppEngineApplication(GcpProject project) throws ProjectRepositoryException { | ||
if (!project.hasAppEngineInfo()) { | ||
Credential selectedCredential = accountSelector.getSelectedCredential(); | ||
AppEngine appEngine = | ||
projectRepository.getAppEngineApplication(selectedCredential, project.getId()); | ||
project.setAppEngine(appEngine); | ||
} | ||
return project.getAppEngine() != AppEngine.NO_APPENGINE_APPLICATION; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
...elector.test/src/com/google/cloud/tools/eclipse/projectselector/GoogleApiFactoryTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
* Copyright 2017 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.projectselector; | ||
|
||
import static org.hamcrest.CoreMatchers.containsString; | ||
import static org.junit.Assert.assertThat; | ||
import static org.mockito.Mockito.mock; | ||
|
||
import com.google.api.client.auth.oauth2.Credential; | ||
import com.google.api.services.appengine.v1.Appengine.Apps; | ||
import com.google.api.services.cloudresourcemanager.CloudResourceManager.Projects; | ||
import com.google.cloud.tools.eclipse.util.CloudToolsInfo; | ||
import java.io.IOException; | ||
import org.junit.Test; | ||
|
||
public class GoogleApiFactoryTest { | ||
|
||
@Test | ||
public void testNewAppsApi_userAgentIsSet() throws IOException { | ||
Apps api = new GoogleApiFactory().newAppsApi(mock(Credential.class)); | ||
assertThat(api.get("").getRequestHeaders().getUserAgent(), | ||
containsString(CloudToolsInfo.USER_AGENT)); | ||
} | ||
|
||
@Test | ||
public void testNewProjectsApi_userAgentIsSet() throws IOException { | ||
Projects api = new GoogleApiFactory().newProjectsApi(mock(Credential.class)); | ||
assertThat(api.get("").getRequestHeaders().getUserAgent(), | ||
containsString(CloudToolsInfo.USER_AGENT)); | ||
} | ||
} |
Oops, something went wrong.