package org.limewire.core.impl.upload; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import javax.swing.SwingUtilities; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.lib.legacy.ClassImposteriser; import org.limewire.core.api.upload.UploadItem; import org.limewire.core.api.upload.UploadState; import org.limewire.core.settings.SharingSettings; import org.limewire.friend.api.FriendManager; import org.limewire.friend.api.FriendPresence; import org.limewire.lifecycle.ServiceScheduler; import org.limewire.util.BaseTestCase; import org.limewire.util.MatchAndCopy; import ca.odell.glazedlists.EventList; import com.limegroup.gnutella.UploadServices; import com.limegroup.gnutella.Uploader; import com.limegroup.gnutella.Uploader.UploadStatus; import com.limegroup.gnutella.uploader.UploadType; public class CoreUploadListManagerTest extends BaseTestCase { public CoreUploadListManagerTest(String name) { super(name); } /** * Ensure the periodic refresher is registered and the manager is * registered as a listener to the upload listeners list. * <p> * Try to execute the associated runnable to ensure functionality. */ public void testRegister() { Mockery context = new Mockery(); final UploadListenerList uploadListenerList = context.mock(UploadListenerList.class); final ServiceScheduler scheduler = context.mock(ServiceScheduler.class); final ScheduledExecutorService backgroundExecutor = context.mock(ScheduledExecutorService.class); final FriendManager friendManager = context.mock(FriendManager.class); final CoreUploadListManager manager = new CoreUploadListManager(null, friendManager); final MatchAndCopy<Runnable> runnableMatcher = new MatchAndCopy<Runnable>(Runnable.class); context.checking(new Expectations() { { exactly(1).of(scheduler).scheduleWithFixedDelay(with(any(String.class)),with(runnableMatcher), with(any(Integer.class)), with(any(Integer.class)), with(any(TimeUnit.class)), with(same(backgroundExecutor))); exactly(1).of(uploadListenerList).addUploadListener(manager); } }); manager.register(uploadListenerList); manager.register(scheduler, backgroundExecutor); Runnable updater = runnableMatcher.getLastMatch(); updater.run(); } /** * Add a browse host upload to the manager, ensure it is accessible, * signal completion, and ensure it is removed. */ public void testUploaderAddAndRemove() { Mockery context = new Mockery(); final Uploader uploader = context.mock(Uploader.class); final FriendManager friendManager = context.mock(FriendManager.class); final FriendPresence presence = context.mock(FriendPresence.class); final long testSize = 777; final CoreUploadListManager manager = new CoreUploadListManager(null, friendManager); context.checking(new Expectations() { { exactly(3).of(friendManager).getMostRelevantFriendPresence(""); will(returnValue(presence)); allowing(uploader).getUploadType(); will(returnValue(UploadType.BROWSE_HOST)); allowing(uploader).getState(); will(returnValue(UploadStatus.COMPLETE)); // Assertions exactly(1).of(uploader).getFileSize(); will(returnValue(testSize)); // General allowing(uploader); } }); List<UploadItem> items = manager.getUploadItems(); manager.uploadAdded(uploader); assertEquals(testSize, items.get(0).getFileSize()); manager.uploadRemoved(uploader); assertEmpty(items); // Test remove when item not managed manager.uploadRemoved(uploader); context.assertIsSatisfied(); } /** * Test various conditions where adding and removing an uploader will have no effect. * <p> * Add an internal uploader, remove an incomplete upload, remove an upload with the * setting disabled. */ public void testUploaderAddAndRemoveBlocked() { Mockery context = new Mockery(); final Uploader uploaderInternal = context.mock(Uploader.class); final Uploader uploaderNotComplete = context.mock(Uploader.class); final Uploader uploaderSettingDisabled = context.mock(Uploader.class); final FriendPresence presence = context.mock(FriendPresence.class); final FriendManager friendManager = context.mock(FriendManager.class); final CoreUploadListManager manager = new CoreUploadListManager(null, friendManager); context.checking(new Expectations() { { exactly(2).of(friendManager).getMostRelevantFriendPresence(""); will(returnValue(presence)); allowing(uploaderInternal).getUploadType(); will(returnValue(UploadType.MALFORMED_REQUEST)); allowing(uploaderNotComplete).getState(); will(returnValue(UploadStatus.UPLOADING)); allowing(uploaderSettingDisabled).getState(); will(returnValue(UploadStatus.COMPLETE)); allowing(uploaderSettingDisabled).getUploadType(); will(returnValue(UploadType.BROWSE_HOST)); // General allowing(uploaderInternal); allowing(uploaderNotComplete); allowing(uploaderSettingDisabled); }}); List<UploadItem> items = manager.getUploadItems(); manager.uploadAdded(uploaderInternal); assertEmpty(items); items.add(new CoreUploadItem(uploaderNotComplete, presence)); manager.uploadRemoved(uploaderNotComplete); assertGreaterThan(-1, items.size()); // Can't use assertNotEmpty() since it calls toString() on elements! items.clear(); boolean clearUploadOriginal = SharingSettings.CLEAR_UPLOAD.getValue(); SharingSettings.CLEAR_UPLOAD.setValue(false); items.add(new CoreUploadItem(uploaderSettingDisabled, presence)); manager.uploadRemoved(uploaderSettingDisabled); SharingSettings.CLEAR_UPLOAD.setValue(clearUploadOriginal); assertGreaterThan(-1, items.size()); // Can't use assertNotEmpty() since it calls toString() on elements! context.assertIsSatisfied(); } /** * Add a property change listener and trigger an event then verify it is handled, remove the * listener then verify that it is not notified. Verify nothing is notified there are active uploads. */ public void testPropertyChangeListenerUpdates() { Mockery context = new Mockery(); final PropertyChangeListener listener1 = context.mock(PropertyChangeListener.class); final PropertyChangeListener listener2 = context.mock(PropertyChangeListener.class); final FriendManager friendManager = context.mock(FriendManager.class); // Do we really need this dependence in CoreUploadListManager? final UploadServices uploadServices = context.mock(UploadServices.class); final CoreUploadListManager manager = new CoreUploadListManager(uploadServices, friendManager); context.checking(new Expectations() { { exactly(2).of(listener1).propertyChange(with(any(PropertyChangeEvent.class))); exactly(3).of(listener2).propertyChange(with(any(PropertyChangeEvent.class))); // First invocation -- normal empty one(uploadServices).getNumUploads(); will(returnValue(0)); // Second invocation -- bit strange one(uploadServices).getNumUploads(); will(returnValue(-1)); // Third invocation -- normal one(uploadServices).getNumUploads(); will(returnValue(0)); // Final invocation -- has active uploads one(uploadServices).getNumUploads(); will(returnValue(5)); }}); manager.addPropertyChangeListener(listener1); manager.addPropertyChangeListener(listener2); manager.updateUploadsCompleted(); // This should always fire the listeners manager.uploadsCompleted(); manager.removePropertyChangeListener(listener1); manager.updateUploadsCompleted(); manager.updateUploadsCompleted(); manager.updateUploadsCompleted(); context.assertIsSatisfied(); } /** * Ensure the thread safe upload list is consistent with the model. */ public void testGetSwingThreadSafeUploads() throws InterruptedException, InvocationTargetException { Mockery context = new Mockery(); final Uploader uploader = context.mock(Uploader.class); final FriendManager friendManager = context.mock(FriendManager.class); final FriendPresence presence = context.mock(FriendPresence.class); final CoreUploadListManager manager = new CoreUploadListManager(null, friendManager); context.checking(new Expectations() { { exactly(2).of(uploader).getPresenceId(); will(returnValue("")); exactly(2).of(friendManager).getMostRelevantFriendPresence(""); will(returnValue(presence)); allowing(uploader).getUploadType(); will(returnValue(UploadType.BROWSE_HOST)); }}); Runnable edtTask = new Runnable() { @Override public void run() { EventList<UploadItem> uploads = manager.getSwingThreadSafeUploads(); assertEmpty(uploads); manager.uploadAdded(uploader); assertGreaterThan(-1, uploads.size()); manager.remove(uploads.get(0)); assertEmpty(uploads); uploads = manager.getSwingThreadSafeUploads(); assertEmpty(uploads); } }; SwingUtilities.invokeAndWait(edtTask); // context.assertIsSatisfied(); } /** * Adds a number of uploads in various states to the manager then fires the clear * finished action and ensures the completed uploads are removed. */ public void testClearFinished() { Mockery context = new Mockery(); final UploadItem uploadDone = context.mock(UploadItem.class); final UploadItem uploadBrowseHostDone = context.mock(UploadItem.class); final UploadItem uploadUnableToUpload = context.mock(UploadItem.class); final UploadItem uploadUploading1 = context.mock(UploadItem.class); final UploadItem uploadUploading2 = context.mock(UploadItem.class); final UploadItem uploadUploading3 = context.mock(UploadItem.class); final FriendManager friendManager = context.mock(FriendManager.class); final CoreUploadListManager manager = new CoreUploadListManager(null, friendManager); context.checking(new Expectations() { { allowing(uploadDone).getState(); will(returnValue(UploadState.DONE)); ignoring(uploadDone); allowing(uploadBrowseHostDone).getState(); will(returnValue(UploadState.BROWSE_HOST_DONE)); ignoring(uploadBrowseHostDone); allowing(uploadUnableToUpload).getState(); will(returnValue(UploadState.UNABLE_TO_UPLOAD)); ignoring(uploadUnableToUpload); allowing(uploadUploading1).getState(); will(returnValue(UploadState.QUEUED)); ignoring(uploadUploading1); allowing(uploadUploading2).getState(); will(returnValue(UploadState.WAITING)); ignoring(uploadUploading2); allowing(uploadUploading3).getState(); will(returnValue(UploadState.BROWSE_HOST)); ignoring(uploadUploading3); }}); List<UploadItem> items = manager.getUploadItems(); // First pass: Do a clear with only a complete upload items.add(uploadBrowseHostDone); manager.clearFinished(); assertEmpty(items); // Second pass: Do a clear with incomplete uploads; items.add(uploadUploading1); items.add(uploadUploading2); manager.clearFinished(); assertContains(items, uploadUploading1); assertContains(items, uploadUploading2); // Third pass: Updates of variegated status items.add(uploadUploading3); items.add(uploadDone); items.add(uploadUploading1); items.add(uploadBrowseHostDone); items.add(uploadUploading2); items.add(uploadUnableToUpload); items.add(uploadUploading2); // Duplicate manager.clearFinished(); assertNotContains(items, uploadDone); assertNotContains(items, uploadBrowseHostDone); assertNotContains(items, uploadUnableToUpload); assertContains(items, uploadUploading1); assertContains(items, uploadUploading2); assertContains(items, uploadUploading3); context.assertIsSatisfied(); } /** * Verify property listener function on UploadItems by adding an upload and * force firing a change event. Verify only cancelled uploads are * removed from management. Tests end to end integration between listener and manager. */ public void testPropertyListenerSimple() { Mockery context = new Mockery(); final Uploader uploader = context.mock(Uploader.class); final FriendManager friendManager = context.mock(FriendManager.class); final FriendPresence presence = context.mock(FriendPresence.class); final CoreUploadListManager manager = new CoreUploadListManager(null, friendManager); context.checking(new Expectations() { { exactly(1).of(uploader).getPresenceId(); will(returnValue("")); exactly(1).of(friendManager).getMostRelevantFriendPresence(""); will(returnValue(presence)); // Initial probe on add allowing(uploader).getUploadType(); will(returnValue(UploadType.BROWSE_HOST)); one(uploader).getState(); will(returnValue(UploadStatus.CONNECTING)); // First event listener firing should not remove the upload one(uploader).getState(); will(returnValue(UploadStatus.UPLOADING)); // Second event listener firing should remove the upload allowing(uploader).getState(); will(returnValue(UploadStatus.CANCELLED)); // General allowing(uploader); } }); List<UploadItem> items = manager.getUploadItems(); manager.uploadAdded(uploader); CoreUploadItem item = (CoreUploadItem)items.get(0); item.fireDataChanged(); assertContains(items, item); item.fireDataChanged(); assertNotContains(items, item); context.assertIsSatisfied(); } /** * Manually add several upload items of different types to the manager and fire update. * Ensure the correct items have their listeners fired. */ public void testUpdate() { Mockery context = new Mockery() { { setImposteriser(ClassImposteriser.INSTANCE); }}; final CoreUploadItem itemDone = context.mock(CoreUploadItem.class); final CoreUploadItem itemBrowseHostDone = context.mock(CoreUploadItem.class); final CoreUploadItem item1 = context.mock(CoreUploadItem.class); final CoreUploadItem item2 = context.mock(CoreUploadItem.class); final CoreUploadItem item3 = context.mock(CoreUploadItem.class); final FriendManager friendManager = context.mock(FriendManager.class); final CoreUploadListManager manager = new CoreUploadListManager(null, friendManager); context.checking(new Expectations() { { allowing(itemDone).getState(); will(returnValue(UploadState.DONE)); allowing(itemBrowseHostDone).getState(); will(returnValue(UploadState.BROWSE_HOST_DONE)); allowing(item1).getState(); will(returnValue(UploadState.CANCELED)); allowing(item2).getState(); will(returnValue(UploadState.QUEUED)); allowing(item3).getState(); will(returnValue(UploadState.WAITING)); // Assertions exactly(1).of(itemDone).addPropertyChangeListener(with(any(PropertyChangeListener.class))); exactly(1).of(itemBrowseHostDone).addPropertyChangeListener(with(any(PropertyChangeListener.class))); exactly(1).of(item1).addPropertyChangeListener(with(any(PropertyChangeListener.class))); exactly(1).of(item2).addPropertyChangeListener(with(any(PropertyChangeListener.class))); exactly(1).of(item3).addPropertyChangeListener(with(any(PropertyChangeListener.class))); never(itemDone).fireDataChanged(); never(itemBrowseHostDone).fireDataChanged(); exactly(1).of(item1).fireDataChanged(); exactly(1).of(item2).fireDataChanged(); exactly(1).of(item3).fireDataChanged(); }}); List<UploadItem> items = manager.getUploadItems(); items.add(item1); items.add(itemDone); items.add(item2); items.add(item3); items.add(itemBrowseHostDone); manager.update(); context.assertIsSatisfied(); } }