/*******************************************************************************
* Copyright (c) 2016 Pivotal, Inc.
* 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.boot.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.jface.operation.IRunnableContext;
import org.junit.Test;
import org.springframework.ide.eclipse.boot.wizard.content.ContentManager;
import org.springframework.ide.eclipse.boot.wizard.content.ContentManager.DownloadState;
import org.springframework.ide.eclipse.boot.wizard.content.ContentType;
import org.springframework.ide.eclipse.boot.wizard.github.GithubClient;
import org.springframework.ide.eclipse.boot.wizard.guides.GSImportWizardModel;
import org.springsource.ide.eclipse.commons.frameworks.core.util.JobUtil;
import org.springsource.ide.eclipse.commons.frameworks.test.util.ACondition;
import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
import org.springsource.ide.eclipse.commons.livexp.core.LiveVariable;
import org.springsource.ide.eclipse.commons.livexp.core.ValueListener;
import org.springsource.ide.eclipse.commons.livexp.util.ExceptionUtil;
public class GSGWizardModelTest {
@Test
public void testPrefetchingGettingStartedContent() throws Exception {
if (!isEnoughRateLimitAvailable()) {
System.out.println("Skipping testPrefetchingGettingStartedContent: not enough github api limit available!");
// skip test if we'r running low on github rest api rate limit.
return;
}
// Prefetching involves testing the download "states" for two different
// steps that occur in series (prefetching content provider properties,
// followed by prefetching actual content):
// 1. Not started any prefetching
// 2. Is downloading content provider properties
// 3. content provider properties downloading completed
// 4. content provider properties downloaded (final state)
// 5. is downloading actual content
// 6. actual content downloading completed (this tests a distinct state
// that is used for
// refreshing views right after a downloading session has completed)
// 7. actual content downloaded. This is a post-downloading "final"
// state
final GSImportWizardModel model = getModel();
final ContentManager contentManager = model.getContentManager();
// Test the prefetching content provider properties tracker
assertEquals(DownloadState.NOT_STARTED,
contentManager.getPrefetchContentProviderPropertiesTracker().getValue());
// Test the prefetching content tracker
assertEquals(DownloadState.NOT_STARTED, contentManager.getPrefetchContentTracker().getValue());
ContentType<?>[] types = contentManager.getTypes();
assertTrue("Expected no content types registered before prefetching.", types == null || types.length == 0);
List<?> allContent = getContent(types, contentManager);
assertTrue("Expected no content for getting started guides before prefetching.", allContent.size() == 0);
// States to test in order encountered by the listener
final List<DownloadState> actualContentPropertiesDownloadState = new ArrayList<>(0);
final List<DownloadState> actualContentDownloadStates = new ArrayList<>(0);
// Listener tests that each of the expected states occur during content
// provider properties downloading
ValueListener<DownloadState> contentProviderPropertiesDownloadStateListener = new ValueListener<DownloadState>() {
@Override
public void gotValue(LiveExpression<DownloadState> exp, DownloadState actualDownloadState) {
// Add states in the order they are received as the listener
// should be invoked multiple times during the prefetching
// operation
if (!actualContentPropertiesDownloadState.contains(actualDownloadState)) {
actualContentPropertiesDownloadState.add(actualDownloadState);
}
}
};
contentManager.getPrefetchContentProviderPropertiesTracker()
.addListener(contentProviderPropertiesDownloadStateListener);
// Listener tests that each of the expected states occur during content
// downloading
LiveVariable<Throwable> error = new LiveVariable<>(null);
ValueListener<DownloadState> contentDownloadStateListener = new ValueListener<DownloadState>() {
@Override
public void gotValue(LiveExpression<DownloadState> exp, DownloadState actualDownloadState) {
// Add states in the order they are received as the listener
// should be invoked multiple times during the prefetching
// operation
if (!actualContentDownloadStates.contains(actualDownloadState)) {
if (actualDownloadState==DownloadState.DOWNLOADING_FAILED) {
error.setValue(contentManager.getPrefetchContentError());
}
actualContentDownloadStates.add(actualDownloadState);
}
}
};
contentManager.getPrefetchContentTracker().addListener(contentDownloadStateListener);
// BEGIN ACTUAL PREFETCH
contentManager.prefetchInBackground(getRunnableContext());
// Test that the listener gets notified when content provider properties
// has been downloaded
new ACondition(30 * 1000) {
@Override
public boolean test() throws Exception {
if (actualContentPropertiesDownloadState.size() == 4) {
assertEquals(
"Expected the first state when prefetching content provider properties: "
+ DownloadState.NOT_STARTED,
actualContentPropertiesDownloadState.get(0), DownloadState.NOT_STARTED);
assertEquals(
"Expected the second state when prefetching content provider properties: "
+ DownloadState.IS_DOWNLOADING,
actualContentPropertiesDownloadState.get(1), DownloadState.IS_DOWNLOADING);
assertEquals(
"Expected the third state when prefetching content provider properties: "
+ DownloadState.DOWNLOADING_COMPLETED,
actualContentPropertiesDownloadState.get(2), DownloadState.DOWNLOADING_COMPLETED);
assertEquals(
"Expected the fourth state when prefetching content provider properties: "
+ DownloadState.DOWNLOADED,
actualContentPropertiesDownloadState.get(3), DownloadState.DOWNLOADED);
// Final state must be "post downloaded" states
assertEquals(
"Expected final download state for content provider properties to be: "
+ DownloadState.DOWNLOADED,
DownloadState.DOWNLOADED,
contentManager.getPrefetchContentProviderPropertiesTracker().getValue());
ContentType<?>[] types = contentManager.getTypes();
assertTrue("Expected content types for getting started guides after downloading completed.",
types != null && types.length > 0);
return true;
} else {
return false;
}
}
};
// Test that the listener gets notified when content has been downloaded
new ACondition(30 * 1000) {
@Override
public boolean test() throws Exception {
if (actualContentDownloadStates.contains(DownloadState.DOWNLOADING_FAILED)) {
Throwable e = contentManager.getPrefetchContentError();
if (e!=null) {
throw new RuntimeException("Problem downloading: ", e);
}
}
if (actualContentDownloadStates.size() == 4) {
assertEquals(
"First prefetching content download state", DownloadState.NOT_STARTED,
actualContentDownloadStates.get(0));
assertEquals(
"Second prefetching content download state", DownloadState.IS_DOWNLOADING,
actualContentDownloadStates.get(1));
assertEquals(
"Third prefetching content download state", DownloadState.DOWNLOADING_COMPLETED,
actualContentDownloadStates.get(2));
assertEquals(
"Fourth prefetching content download state", DownloadState.DOWNLOADED,
actualContentDownloadStates.get(3));
// Final state must be "post downloaded" state
assertEquals(
"Expected final download state for content provider properties to be: "
+ DownloadState.DOWNLOADED,
DownloadState.DOWNLOADED,
contentManager.getPrefetchContentProviderPropertiesTracker().getValue());
assertEquals("Expected final download state for content to be: " + DownloadState.DOWNLOADED,
DownloadState.DOWNLOADED, contentManager.getPrefetchContentTracker().getValue());
ContentType<?>[] types = contentManager.getTypes();
assertTrue("Expected content types for getting started guides after downloading completed.",
types != null && types.length > 0);
List<?> allContent = getContent(types, contentManager);
assertTrue("Expected content for getting started guides after downloading completed.",
allContent.size() > 0);
return true;
} else {
fail(
"Expected downloadStates not reached.\n" +
"Actual states: "+actualContentDownloadStates+"\n" +
error.getValue()==null
? ""
: "Error: "+ExceptionUtil.stacktrace(error.getValue())
);
return false;
}
}
};
}
/**
* Check github api rate limit has some requests available.
* @return true if there's not enough requests limit available to run the test.
*/
private boolean isEnoughRateLimitAvailable() throws IOException {
GithubClient github = new GithubClient();
int remaining = github.getRateLimit().getRate().getRemaining();
System.out.println("github rate-limit remaining: "+remaining);
return remaining > 8; // Test needs 4 requests... add a bit of margin above that.
}
public static GSImportWizardModel getModel() throws Exception {
return new GSImportWizardModel();
}
public static IRunnableContext getRunnableContext() {
return JobUtil.DEFAULT_BACKGROUND_RUNNABLE_CONTEXT;
}
protected List<?> getContent(ContentType<?>[] types, ContentManager contentManager) {
List<Object> content = new ArrayList<>();
for (ContentType<?> type : types) {
Object[] typeContent = contentManager.get(type);
content.addAll(Arrays.asList(typeContent));
}
return content;
}
}