-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add options to the UI to disable and remove update sites for cases wh…
…ere update sites are not found (#207) Previously, if accumulation of load failures was enabled, all failures were put into a MultiStatus and displayed to the user. This has been changed to use more specific dialogs if possible. If all load failures were caused by repositories not being found, dialogs that allow removing or disabling the affected sites are used. If there is only a single load failure and it was caused by a repository not being found, the "Error Contacting Site" dialog is used. This commit extends the "Error Contacting Site" dialog with buttons for editing, removing or disabling a single site.
- Loading branch information
1 parent
e1d3ea9
commit 0e4707e
Showing
15 changed files
with
728 additions
and
69 deletions.
There are no files selected for viewing
49 changes: 49 additions & 0 deletions
49
...pse.equinox.p2.operations/src/org/eclipse/equinox/internal/p2/operations/LoadFailure.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,49 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2023 Erik Brangs. | ||
* | ||
* This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License 2.0 | ||
* which accompanies this distribution, and is available at | ||
* https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* Erik Brangs - initial implementation | ||
*******************************************************************************/ | ||
package org.eclipse.equinox.internal.p2.operations; | ||
|
||
import java.net.URI; | ||
import org.eclipse.equinox.p2.core.ProvisionException; | ||
|
||
public class LoadFailure { | ||
|
||
private final URI location; | ||
private final ProvisionException provisionException; | ||
|
||
public LoadFailure(URI location, ProvisionException provisionException) { | ||
this.location = location; | ||
this.provisionException = provisionException; | ||
} | ||
|
||
public URI getLocation() { | ||
return location; | ||
} | ||
|
||
public ProvisionException getProvisionException() { | ||
return provisionException; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "LoadFailure [location=" + location + ", provisionException=" + provisionException + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | ||
} | ||
|
||
public static boolean failureRepresentsBadRepositoryLocation(ProvisionException exception) { | ||
int code = exception.getStatus().getCode(); | ||
return code == IStatusCodes.INVALID_REPOSITORY_LOCATION | ||
|| code == ProvisionException.REPOSITORY_INVALID_LOCATION | ||
|| code == ProvisionException.REPOSITORY_NOT_FOUND; | ||
} | ||
|
||
} |
61 changes: 61 additions & 0 deletions
61
....p2.operations/src/org/eclipse/equinox/internal/p2/operations/LoadFailureAccumulator.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,61 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2023 Erik Brangs. | ||
* | ||
* This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License 2.0 | ||
* which accompanies this distribution, and is available at | ||
* https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* Erik Brangs - initial implementation | ||
*******************************************************************************/ | ||
package org.eclipse.equinox.internal.p2.operations; | ||
|
||
import java.net.URI; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import org.eclipse.equinox.p2.core.ProvisionException; | ||
import org.eclipse.equinox.p2.operations.RepositoryTracker; | ||
|
||
/** | ||
* Accumulates information about load failures caused by bad locations. | ||
* <p> | ||
* This class is designed to support the UI in enabling the user to deal with | ||
* bad locations, e.g. by disabling or removing them. Therefore, it does not | ||
* save all informations about the failures. | ||
*/ | ||
public final class LoadFailureAccumulator { | ||
|
||
private RepositoryTracker repositoryTracker; | ||
private int loadFailuresNotCausedByBadRepoLocation; | ||
private List<LoadFailure> loadFailuresCausedByBadRepoLocation; | ||
|
||
public LoadFailureAccumulator(RepositoryTracker repositoryTracker) { | ||
this.repositoryTracker = repositoryTracker; | ||
this.loadFailuresCausedByBadRepoLocation = new ArrayList<>(); | ||
} | ||
|
||
public void recordLoadFailure(ProvisionException e, URI location) { | ||
if (LoadFailure.failureRepresentsBadRepositoryLocation(e)) { | ||
loadFailuresCausedByBadRepoLocation.add(new LoadFailure(location, e)); | ||
repositoryTracker.addNotFound(location); | ||
} else { | ||
loadFailuresNotCausedByBadRepoLocation++; | ||
} | ||
} | ||
|
||
public boolean hasSingleFailureCausedByBadLocation() { | ||
return loadFailuresCausedByBadRepoLocation.size() == 1 && loadFailuresNotCausedByBadRepoLocation == 0; | ||
} | ||
|
||
public boolean allFailuresCausedByBadLocation() { | ||
return loadFailuresCausedByBadRepoLocation.size() >= 1 && loadFailuresNotCausedByBadRepoLocation == 0; | ||
} | ||
|
||
public List<LoadFailure> getLoadFailuresCausedByBadRepoLocation() { | ||
return loadFailuresCausedByBadRepoLocation; | ||
} | ||
|
||
} |
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
93 changes: 93 additions & 0 deletions
93
...2.tests.ui/src/org/eclipse/equinox/p2/tests/ui/operations/LoadFailureAccumulatorTest.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,93 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2023 Erik Brangs. | ||
* | ||
* This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License 2.0 | ||
* which accompanies this distribution, and is available at | ||
* https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* Erik Brangs - initial implementation | ||
*******************************************************************************/ | ||
package org.eclipse.equinox.p2.tests.ui.operations; | ||
|
||
import static org.hamcrest.CoreMatchers.is; | ||
import static org.hamcrest.MatcherAssert.assertThat; | ||
import static org.hamcrest.collection.IsCollectionWithSize.hasSize; | ||
import static org.mockito.Mockito.*; | ||
|
||
import java.net.URI; | ||
import junit.framework.TestCase; | ||
import org.eclipse.core.runtime.IStatus; | ||
import org.eclipse.core.runtime.Status; | ||
import org.eclipse.equinox.internal.p2.operations.LoadFailureAccumulator; | ||
import org.eclipse.equinox.p2.core.ProvisionException; | ||
import org.eclipse.equinox.p2.operations.RepositoryTracker; | ||
import org.mockito.InOrder; | ||
import org.mockito.Mockito; | ||
|
||
public class LoadFailureAccumulatorTest extends TestCase { | ||
|
||
public void testRecordFailureForSingleBadLocation() throws Exception { | ||
RepositoryTracker repositoryTracker = mock(RepositoryTracker.class); | ||
LoadFailureAccumulator loadFailureAccumulator = new LoadFailureAccumulator(repositoryTracker); | ||
ProvisionException exception = buildProvisionExceptionWithCode(ProvisionException.REPOSITORY_INVALID_LOCATION); | ||
URI invalidLocation = new URI("https://example.com/invalid"); | ||
loadFailureAccumulator.recordLoadFailure(exception, invalidLocation); | ||
assertThat(loadFailureAccumulator.allFailuresCausedByBadLocation(), is(true)); | ||
assertThat(loadFailureAccumulator.hasSingleFailureCausedByBadLocation(), is(true)); | ||
assertThat(loadFailureAccumulator.getLoadFailuresCausedByBadRepoLocation(), hasSize(1)); | ||
verify(repositoryTracker, times(1)).addNotFound(invalidLocation); | ||
} | ||
|
||
public void testRecordFailureForMultipleBadLocations() throws Exception { | ||
RepositoryTracker repositoryTracker = mock(RepositoryTracker.class); | ||
LoadFailureAccumulator loadFailureAccumulator = new LoadFailureAccumulator(repositoryTracker); | ||
ProvisionException firstException = buildProvisionExceptionWithCode( | ||
ProvisionException.REPOSITORY_INVALID_LOCATION); | ||
URI firstInvalidLocation = new URI("https://example.com/invalid"); | ||
ProvisionException secondException = buildProvisionExceptionWithCode( | ||
ProvisionException.REPOSITORY_INVALID_LOCATION); | ||
URI secondInvalidLocation = new URI("https://example.com/invalidTwo"); | ||
loadFailureAccumulator.recordLoadFailure(firstException, firstInvalidLocation); | ||
loadFailureAccumulator.recordLoadFailure(secondException, secondInvalidLocation); | ||
assertThat(loadFailureAccumulator.allFailuresCausedByBadLocation(), is(true)); | ||
assertThat(loadFailureAccumulator.hasSingleFailureCausedByBadLocation(), is(false)); | ||
assertThat(loadFailureAccumulator.getLoadFailuresCausedByBadRepoLocation(), hasSize(2)); | ||
InOrder inOrder = Mockito.inOrder(repositoryTracker); | ||
inOrder.verify(repositoryTracker, times(1)).addNotFound(firstInvalidLocation); | ||
inOrder.verify(repositoryTracker, times(1)).addNotFound(secondInvalidLocation); | ||
} | ||
|
||
public void testRecordFailureForMultipleBadLocationsAndOneFailureCausedBySomethingElse() throws Exception { | ||
RepositoryTracker repositoryTracker = mock(RepositoryTracker.class); | ||
LoadFailureAccumulator loadFailureAccumulator = new LoadFailureAccumulator(repositoryTracker); | ||
ProvisionException firstException = buildProvisionExceptionWithCode( | ||
ProvisionException.REPOSITORY_INVALID_LOCATION); | ||
URI firstInvalidLocation = new URI("https://example.com/invalid"); | ||
ProvisionException secondException = buildProvisionExceptionWithCode( | ||
ProvisionException.REPOSITORY_INVALID_LOCATION); | ||
URI secondInvalidLocation = new URI("https://example.com/invalidTwo"); | ||
ProvisionException thirdException = buildProvisionExceptionWithCode( | ||
ProvisionException.REPOSITORY_FAILED_AUTHENTICATION); | ||
URI thirdLocation = new URI("https://example.com/requiresAuthentication"); | ||
loadFailureAccumulator.recordLoadFailure(firstException, firstInvalidLocation); | ||
loadFailureAccumulator.recordLoadFailure(secondException, secondInvalidLocation); | ||
loadFailureAccumulator.recordLoadFailure(thirdException, thirdLocation); | ||
assertThat(loadFailureAccumulator.allFailuresCausedByBadLocation(), is(false)); | ||
assertThat(loadFailureAccumulator.hasSingleFailureCausedByBadLocation(), is(false)); | ||
assertThat(loadFailureAccumulator.getLoadFailuresCausedByBadRepoLocation(), hasSize(2)); | ||
InOrder inOrder = Mockito.inOrder(repositoryTracker); | ||
inOrder.verify(repositoryTracker, times(1)).addNotFound(firstInvalidLocation); | ||
inOrder.verify(repositoryTracker, times(1)).addNotFound(secondInvalidLocation); | ||
verify(repositoryTracker, never()).addNotFound(thirdLocation); | ||
} | ||
|
||
private ProvisionException buildProvisionExceptionWithCode(int code) { | ||
IStatus status = new Status(IStatus.ERROR, "pluginId", code, "message", new RuntimeException()); | ||
return new ProvisionException(status); | ||
} | ||
|
||
} |
58 changes: 58 additions & 0 deletions
58
...e.equinox.p2.tests.ui/src/org/eclipse/equinox/p2/tests/ui/operations/LoadFailureTest.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,58 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2023 Erik Brangs. | ||
* | ||
* This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License 2.0 | ||
* which accompanies this distribution, and is available at | ||
* https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* Erik Brangs - initial implementation | ||
*******************************************************************************/ | ||
package org.eclipse.equinox.p2.tests.ui.operations; | ||
|
||
import junit.framework.TestCase; | ||
import org.eclipse.core.runtime.IStatus; | ||
import org.eclipse.core.runtime.Status; | ||
import org.eclipse.equinox.internal.p2.operations.IStatusCodes; | ||
import org.eclipse.equinox.internal.p2.operations.LoadFailure; | ||
import org.eclipse.equinox.p2.core.ProvisionException; | ||
|
||
public class LoadFailureTest extends TestCase { | ||
|
||
public void testFailureRepresentsBadRepositoryLocationForCodeInvalidRepositoryLocation() throws Exception { | ||
int code = IStatusCodes.INVALID_REPOSITORY_LOCATION; | ||
ProvisionException provisionException = buildProvisionExceptionWithCode(code); | ||
boolean isBadLocation = LoadFailure.failureRepresentsBadRepositoryLocation(provisionException); | ||
assertTrue(isBadLocation); | ||
} | ||
|
||
public void testFailureRepresentsBadRepositoryLocationForCodeRepositoryInvalidLocation() throws Exception { | ||
int code = ProvisionException.REPOSITORY_INVALID_LOCATION; | ||
ProvisionException provisionException = buildProvisionExceptionWithCode(code); | ||
boolean isBadLocation = LoadFailure.failureRepresentsBadRepositoryLocation(provisionException); | ||
assertTrue(isBadLocation); | ||
} | ||
|
||
public void testFailureRepresentsBadRepositoryLocationForCodeRepositoryNotFound() throws Exception { | ||
int code = ProvisionException.REPOSITORY_INVALID_LOCATION; | ||
ProvisionException provisionException = buildProvisionExceptionWithCode(code); | ||
boolean isBadLocation = LoadFailure.failureRepresentsBadRepositoryLocation(provisionException); | ||
assertTrue(isBadLocation); | ||
} | ||
|
||
public void testFailureRepresentsBadRepositoryLocationForOtherCode() throws Exception { | ||
int code = ProvisionException.REPOSITORY_FAILED_READ; | ||
ProvisionException provisionException = buildProvisionExceptionWithCode(code); | ||
boolean isBadLocation = LoadFailure.failureRepresentsBadRepositoryLocation(provisionException); | ||
assertFalse(isBadLocation); | ||
} | ||
|
||
private ProvisionException buildProvisionExceptionWithCode(int code) { | ||
IStatus status = new Status(IStatus.ERROR, "pluginId", code, "message", new RuntimeException()); | ||
return new ProvisionException(status); | ||
} | ||
|
||
} |
92 changes: 92 additions & 0 deletions
92
...2.tests.ui/src/org/eclipse/equinox/p2/tests/ui/operations/LocationNotFoundDialogTest.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,92 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2023 Erik Brangs. | ||
* | ||
* This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License 2.0 | ||
* which accompanies this distribution, and is available at | ||
* https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* Erik Brangs - initial implementation | ||
*******************************************************************************/ | ||
package org.eclipse.equinox.p2.tests.ui.operations; | ||
|
||
import static org.hamcrest.CoreMatchers.is; | ||
import static org.hamcrest.MatcherAssert.assertThat; | ||
import static org.mockito.Mockito.*; | ||
|
||
import java.net.URI; | ||
import org.eclipse.equinox.internal.p2.ui.*; | ||
import org.eclipse.equinox.p2.operations.ProvisioningSession; | ||
import org.eclipse.equinox.p2.tests.AbstractProvisioningTest; | ||
import org.eclipse.equinox.p2.ui.ProvisioningUI; | ||
import org.mockito.InOrder; | ||
import org.mockito.Mockito; | ||
|
||
public class LocationNotFoundDialogTest extends AbstractProvisioningTest { | ||
|
||
public void testCorrectLocation() { | ||
// Set up a composite repo. This was copied from | ||
// ColocatedRepositoryTrackerTest. | ||
final String compositeRepo = "testData/bug338495/good.local"; | ||
final URI compositeRepoURI = getTestData("composite repo", compositeRepo).toURI(); | ||
final String childRepo = "testData/bug338495/good.local/one"; | ||
final URI childRepoOneURI = getTestData("composite repo", childRepo).toURI(); | ||
|
||
ProvisioningUI provUI = mock(ProvisioningUI.class); | ||
ProvisioningSession provisioningSession = mock(ProvisioningSession.class); | ||
when(provUI.getSession()).thenReturn(provisioningSession); | ||
ColocatedRepositoryTracker tracker = mock(ColocatedRepositoryTracker.class); | ||
URI location = compositeRepoURI; | ||
LocationNotFoundDialog dialog = new LocationNotFoundDialog(tracker, provUI, location); | ||
URI correctedLocation = childRepoOneURI; | ||
String repositoryName = "repositoryName"; | ||
InOrder inOrder = Mockito.inOrder(tracker, provUI); | ||
dialog.correctLocation(correctedLocation, repositoryName); | ||
inOrder.verify(provUI, times(1)).signalRepositoryOperationStart(); | ||
inOrder.verify(tracker, times(1)).removeRepositories(new URI[] { location }, provisioningSession); | ||
inOrder.verify(tracker, times(1)).addRepository(correctedLocation, repositoryName, provisioningSession); | ||
inOrder.verify(provUI, times(1)).signalRepositoryOperationComplete(null, true); | ||
} | ||
|
||
public void testRemoveRepository() { | ||
// Set up a composite repo. This was copied from | ||
// ColocatedRepositoryTrackerTest. | ||
final String compositeRepo = "testData/bug338495/good.local"; | ||
final URI compositeRepoURI = getTestData("composite repo", compositeRepo).toURI(); | ||
|
||
ProvisioningUI provUI = mock(ProvisioningUI.class); | ||
ProvisioningSession provisioningSession = mock(ProvisioningSession.class); | ||
when(provUI.getSession()).thenReturn(provisioningSession); | ||
ColocatedRepositoryTracker tracker = mock(ColocatedRepositoryTracker.class); | ||
URI location = compositeRepoURI; | ||
LocationNotFoundDialog dialog = new LocationNotFoundDialog(tracker, provUI, location); | ||
dialog.removeRepository(); | ||
verify(tracker, times(1)).removeRepositories(new URI[] { location }, provisioningSession); | ||
} | ||
|
||
public void testDisableRepository() { | ||
// Set up a composite repo. This was adapted from | ||
// ColocatedRepositoryTrackerTest. | ||
final String compositeRepo = "testData/bug338495/good.local"; | ||
final URI compositeRepoURI = getTestData("composite repo", compositeRepo).toURI(); | ||
final String childRepo = "testData/bug338495/good.local/one"; | ||
final URI childRepoOneURI = getTestData("composite repo", childRepo).toURI(); | ||
|
||
ProvisioningUI provUI = ProvisioningUI.getDefaultUI(); | ||
ProvisioningSession provSession = provUI.getSession(); | ||
|
||
ColocatedRepositoryTracker tracker = new ColocatedRepositoryTracker(provUI); | ||
tracker.addRepository(compositeRepoURI, "main", provSession); | ||
tracker.addRepository(childRepoOneURI, "child", provSession); | ||
|
||
URI location = compositeRepoURI; | ||
LocationNotFoundDialog dialog = new LocationNotFoundDialog(tracker, provUI, location); | ||
dialog.disableRepository(); | ||
assertThat(ProvUI.getMetadataRepositoryManager(provSession).isEnabled(location), is(false)); | ||
assertThat(ProvUI.getArtifactRepositoryManager(provSession).isEnabled(location), is(false)); | ||
} | ||
|
||
} |
Oops, something went wrong.