/* * The MIT License * * Copyright 2011 Sony Mobile Communications Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.sonymobile.tools.gerrit.gerritevents; import com.sonymobile.tools.gerrit.gerritevents.dto.GerritEvent; import com.sonymobile.tools.gerrit.gerritevents.dto.attr.Account; import com.sonymobile.tools.gerrit.gerritevents.dto.attr.Provider; import com.sonymobile.tools.gerrit.gerritevents.dto.events.ChangeAbandoned; import com.sonymobile.tools.gerrit.gerritevents.dto.events.ChangeMerged; import com.sonymobile.tools.gerrit.gerritevents.dto.events.ChangeRestored; import com.sonymobile.tools.gerrit.gerritevents.dto.events.CommentAdded; import com.sonymobile.tools.gerrit.gerritevents.dto.events.DraftPublished; import com.sonymobile.tools.gerrit.gerritevents.dto.events.MergeFailed; import com.sonymobile.tools.gerrit.gerritevents.dto.events.PatchsetCreated; import com.sonymobile.tools.gerrit.gerritevents.dto.events.RefUpdated; import com.sonymobile.tools.gerrit.gerritevents.dto.events.ReviewerAdded; import com.sonymobile.tools.gerrit.gerritevents.dto.events.TopicChanged; import com.sonymobile.tools.gerrit.gerritevents.dto.events.ProjectCreated; import com.sonymobile.tools.gerrit.gerritevents.dto.events.PrivateStateChanged; import com.sonymobile.tools.gerrit.gerritevents.dto.events.WipStateChanged; import com.sonymobile.tools.gerrit.gerritevents.dto.events.HashtagsChanged; import com.sonymobile.tools.gerrit.gerritevents.dto.events.VoteDeleted; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.reflect.Whitebox; import java.util.Collection; import java.util.HashSet; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.collection.IsIn.isIn; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.only; //CS IGNORE MagicNumber FOR NEXT 600 LINES. REASON: Test data. /** * Tests for {@link com.sonymobile.tools.gerrit.gerritevents.GerritHandler}. * * @author Robert Sandell <[email protected]> */ @RunWith(PowerMockRunner.class) public class GerritHandlerTest { private GerritHandler handler; /** * Creates a GerritHandler. */ @Before public void setup() { handler = new GerritHandler(); } /** * Shuts down the GerritHandler. */ @After public void shutDown() { if (handler != null) { handler.shutdown(true); } handler = null; } /** * Tests {@link GerritHandler#addListener(GerritEventListener)}. * * @throws Exception if so. */ @Test public void testAddListener() throws Exception { GerritEventListener listenerMock = mock(GerritEventListener.class); handler.addListener(listenerMock); Collection<GerritEventListener> gerritEventListeners = Whitebox.getInternalState(handler, "gerritEventListeners"); assertThat(listenerMock, isIn(gerritEventListeners)); assertEquals(1, gerritEventListeners.size()); } /** * Tests {@link com.sonymobile.tools.gerrit.gerritevents.GerritHandler#addListener(GerritEventListener)}. * With 10000 listeners added by 10 threads at the same time. * * @throws Exception if so. */ @Test public void testAddListenerManyAtTheSameTime() throws Exception { final int nrOfListeners = 100000; BlockingQueue<Runnable> listeners = new LinkedBlockingQueue<Runnable>(nrOfListeners); System.out.print("Creating Listeners"); for (int i = 0; i < nrOfListeners; i++) { listeners.add(new Runnable() { GerritEventListener listener = new ListenerMock(); @Override public void run() { handler.addListener(listener); } }); if (i % 1000 == 0) { System.out.print("."); } } System.out.println(".Done!"); ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 100, 1, TimeUnit.MINUTES, listeners); executor.prestartAllCoreThreads(); executor.shutdown(); do { System.out.printf("Waiting for listeners to be added...Running#: %5d Left#: %5d Count#: %5d\n", executor.getActiveCount(), listeners.size(), handler.getEventListenersCount()); } while (!executor.awaitTermination(1, TimeUnit.SECONDS)); System.out.printf(" Listeners are added...Running#: %5d Left#: %5d Count#: %5d\n", executor.getActiveCount(), listeners.size(), handler.getEventListenersCount()); assertEquals(nrOfListeners, handler.getEventListenersCount()); } /** * Tests {@link GerritHandler#addEventListeners(java.util.Map)}. * * @throws Exception if so. */ @Test public void testAddEventListeners() throws Exception { Collection<GerritEventListener> listeners = new HashSet<GerritEventListener>(); GerritEventListener listenerMock = mock(GerritEventListener.class); listeners.add(listenerMock); listenerMock = mock(GerritEventListener.class); listeners.add(listenerMock); listenerMock = mock(GerritEventListener.class); listeners.add(listenerMock); listenerMock = mock(GerritEventListener.class); listeners.add(listenerMock); listenerMock = mock(GerritEventListener.class); listeners.add(listenerMock); handler.addEventListeners(listeners); Collection<GerritEventListener> gerritEventListeners = Whitebox.getInternalState(handler, "gerritEventListeners"); assertThat(listenerMock, isIn(gerritEventListeners)); assertEquals(5, gerritEventListeners.size()); } /** * Tests {@link com.sonymobile.tools.gerrit.gerritevents.GerritHandler#removeListener(GerritEventListener)}. * * @throws Exception if so. */ @Test public void testRemoveListener() throws Exception { GerritEventListener listenerMock = mock(GerritEventListener.class); handler.addListener(listenerMock); handler.removeListener(listenerMock); Collection<GerritEventListener> gerritEventListeners = Whitebox.getInternalState(handler, "gerritEventListeners"); assertTrue(gerritEventListeners.isEmpty()); } /** * Tests {@link com.sonymobile.tools.gerrit.gerritevents.GerritHandler#removeAllEventListeners()}. * * @throws Exception if so. */ @Test public void testRemoveAllEventListeners() throws Exception { Collection<GerritEventListener> listeners = new HashSet<GerritEventListener>(); GerritEventListener listenerMock = mock(GerritEventListener.class); listeners.add(listenerMock); listenerMock = mock(GerritEventListener.class); listeners.add(listenerMock); listenerMock = mock(GerritEventListener.class); listeners.add(listenerMock); listenerMock = mock(GerritEventListener.class); listeners.add(listenerMock); listenerMock = mock(GerritEventListener.class); listeners.add(listenerMock); handler.addEventListeners(listeners); listeners = handler.removeAllEventListeners(); assertThat(listenerMock, isIn(listeners)); assertEquals(5, listeners.size()); listeners = Whitebox.getInternalState(handler, "gerritEventListeners"); assertTrue(listeners.isEmpty()); } /** * Tests {@link com.sonymobile.tools.gerrit.gerritevents.GerritHandler#removeAllEventListeners()} when * one listener's hashCode has changed mid air. * * @throws Exception if so. */ @Test public void testRemoveAllEventListenersOneChanged() throws Exception { Collection<GerritEventListener> listeners = new HashSet<GerritEventListener>(); ListenerMock listenerMock = new ListenerMock(); listeners.add(listenerMock); listenerMock = new ListenerMock(); listeners.add(listenerMock); listenerMock = new ListenerMock(); listeners.add(listenerMock); listenerMock = new ListenerMock(); listeners.add(listenerMock); listenerMock = new ListenerMock(); listeners.add(listenerMock); handler.addEventListeners(listeners); listenerMock.code = (10000); listeners = handler.removeAllEventListeners(); assertThat(listenerMock, isIn(listeners)); assertEquals(5, listeners.size()); listeners = Whitebox.getInternalState(handler, "gerritEventListeners"); assertTrue(listeners.isEmpty()); } /** * Tests to remove all eventlisteners and then re add them. * * @throws Exception if so. */ @Test public void testReAddAllEventListenersOneChanged() throws Exception { Collection<GerritEventListener> listeners = new HashSet<GerritEventListener>(); ListenerMock listenerMock = new ListenerMock(); listeners.add(listenerMock); listenerMock = new ListenerMock(); listeners.add(listenerMock); listenerMock = new ListenerMock(); listeners.add(listenerMock); listenerMock = new ListenerMock(); listeners.add(listenerMock); listenerMock = new ListenerMock(); listeners.add(listenerMock); handler.addEventListeners(listeners); listenerMock.code = (10000); listeners = handler.removeAllEventListeners(); assertThat(listenerMock, isIn(listeners)); assertEquals(5, listeners.size()); Collection<GerritEventListener> gerritEventListeners = Whitebox.getInternalState(handler, "gerritEventListeners"); assertTrue(gerritEventListeners.isEmpty()); handler.addEventListeners(listeners); gerritEventListeners = Whitebox.getInternalState(handler, "gerritEventListeners"); assertThat(listenerMock, isIn(gerritEventListeners)); assertEquals(5, gerritEventListeners.size()); } /** * Tests that ignoreEMails is handled correctly. * @throws Exception if so. */ @Test public void testIgnoreEMails() throws Exception { String email = "[email protected]"; String server = "testserver"; handler.setIgnoreEMail(server, email); assertEquals(email, handler.getIgnoreEMail(server)); handler.setIgnoreEMail(server, null); assertEquals(null, handler.getIgnoreEMail(server)); } /** * Tests that CommentAdded events are ignored correctly. * @throws Exception if so. */ @Test public void testIgnoreCommentAdded() throws Exception { String server = "testserver"; handler.setIgnoreEMail(server, "ignore-mail.com"); ListenerMock listenerMock = mock(ListenerMock.class); handler.addListener(listenerMock); Account account = new Account("name", "[email protected]"); Provider provider = new Provider(); provider.setName(server); CommentAdded ca = new CommentAdded(); ca.setAccount(account); ca.setProvider(provider); handler.notifyListeners(ca); verifyNoMoreInteractions(listenerMock); } /** * Tests that CommentAdded events are ignored correctly. * @throws Exception if so. */ @Test public void testIgnoreCommentAddedWithNullMail() throws Exception { String server = "testserver"; handler.setIgnoreEMail(server, "ignore-mail.com"); ListenerMock listenerMock = mock(ListenerMock.class); handler.addListener(listenerMock); Account account = new Account("name", null); Provider provider = new Provider(); provider.setName(server); CommentAdded ca = new CommentAdded(); ca.setAccount(account); ca.setProvider(provider); handler.notifyListeners(ca); verify(listenerMock, only()).gerritEvent(ca); } /** * Tests that CommentAdded events are ignored correctly. * @throws Exception if so. */ @Test public void testCommentAddedWithEmptyIgnoreMail() throws Exception { String server = "testserver"; handler.setIgnoreEMail(server, ""); ListenerMock listenerMock = mock(ListenerMock.class); handler.addListener(listenerMock); Account account = new Account("name", "[email protected]"); Provider provider = new Provider(); provider.setName(server); CommentAdded ca = new CommentAdded(); ca.setAccount(account); ca.setProvider(provider); handler.notifyListeners(ca); verify(listenerMock, only()).gerritEvent(ca); } /** * A GerritListener mock that can change it's hashCode */ static class ListenerMock implements GerritEventListener { private static int count = 0; int code; /** * Default constructor. */ ListenerMock() { code = 54 + count++; } @Override public void gerritEvent(GerritEvent event) { } @Override public int hashCode() { return code; } } /** * Tests that event notification using the default method. */ @Test public void testEventNotificationWithDefaultListenerImplemention() { GerritEventListener listenerMock = mock(GerritEventListener.class); handler.addListener(listenerMock); ChangeAbandoned changeAbandoned = new ChangeAbandoned(); handler.notifyListeners(changeAbandoned); verify(listenerMock, times(1)).gerritEvent(changeAbandoned); ChangeMerged changeMerged = new ChangeMerged(); handler.notifyListeners(changeMerged); verify(listenerMock, times(1)).gerritEvent(changeMerged); ChangeRestored changeRestored = new ChangeRestored(); handler.notifyListeners(changeRestored); verify(listenerMock, times(1)).gerritEvent(changeRestored); CommentAdded commentAdded = new CommentAdded(); handler.notifyListeners(commentAdded); verify(listenerMock, times(1)).gerritEvent(commentAdded); DraftPublished draftPublished = new DraftPublished(); handler.notifyListeners(draftPublished); verify(listenerMock, times(1)).gerritEvent(draftPublished); PatchsetCreated patchsetCreated = new PatchsetCreated(); handler.notifyListeners(patchsetCreated); verify(listenerMock, times(1)).gerritEvent(patchsetCreated); RefUpdated refUpdated = new RefUpdated(); handler.notifyListeners(refUpdated); verify(listenerMock, times(1)).gerritEvent(refUpdated); ProjectCreated projectCreated = new ProjectCreated(); handler.notifyListeners(projectCreated); verify(listenerMock, times(1)).gerritEvent(projectCreated); TopicChanged topicChanged = new TopicChanged(); handler.notifyListeners(topicChanged); verify(listenerMock, times(1)).gerritEvent(topicChanged); ReviewerAdded reviewerAdded = new ReviewerAdded(); handler.notifyListeners(reviewerAdded); verify(listenerMock, times(1)).gerritEvent(reviewerAdded); MergeFailed mergeFailed = new MergeFailed(); handler.notifyListeners(mergeFailed); verify(listenerMock, times(1)).gerritEvent(mergeFailed); PrivateStateChanged privateStateChanged = new PrivateStateChanged(); handler.notifyListeners(privateStateChanged); verify(listenerMock, times(1)).gerritEvent(privateStateChanged); WipStateChanged wipStateChanged = new WipStateChanged(); handler.notifyListeners(wipStateChanged); verify(listenerMock, times(1)).gerritEvent(wipStateChanged); HashtagsChanged hashtagsChanged = new HashtagsChanged(); handler.notifyListeners(hashtagsChanged); verify(listenerMock, times(1)).gerritEvent(hashtagsChanged); VoteDeleted voteDeleted = new VoteDeleted(); handler.notifyListeners(voteDeleted); verify(listenerMock, times(1)).gerritEvent(voteDeleted); } /** * Tests that ChangeAbandoned event are going in the method with * that type as parameter and that other type of events are going * in the default method. */ @Test public void testEventNotificationWithListenerChangeAbandonedMethodSignature() { SpecificEventListener changeAbandonedListener = new SpecificEventListener() { @SuppressWarnings("unused") //method is called by reflection public void gerritEvent(ChangeAbandoned event) { specificMethodCalled = true; } }; testListenerWithSpecificSignature(changeAbandonedListener, new ChangeAbandoned()); } /** * Tests that ChangeMerged event are going in the method with * that type as parameter and that other type of events are going * in the default method. */ @Test public void testEventNotificationWithListenerChangeMergedMethodSignature() { SpecificEventListener changeMergedListener = new SpecificEventListener() { @SuppressWarnings("unused") //method is called by reflection public void gerritEvent(ChangeMerged event) { specificMethodCalled = true; } }; testListenerWithSpecificSignature(changeMergedListener, new ChangeMerged()); } /** * Tests that ChangeRestored event are going in the method with * that type as parameter and that other type of events are going * in the default method. */ @Test public void testEventNotificationWithListenerChangeRestoredMethodSignature() { SpecificEventListener changeRestoredListener = new SpecificEventListener() { @SuppressWarnings("unused") //method is called by reflection public void gerritEvent(ChangeRestored event) { specificMethodCalled = true; } }; testListenerWithSpecificSignature(changeRestoredListener, new ChangeRestored()); } /** * Tests that CommentAdded event are going in the method with * that type as parameter and that other type of events are going * in the default method. */ @Test public void testEventNotificationWithListenerCommentAddedMethodSignature() { SpecificEventListener commentAddedListener = new SpecificEventListener() { @SuppressWarnings("unused") //method is called by reflection public void gerritEvent(CommentAdded event) { specificMethodCalled = true; } }; testListenerWithSpecificSignature(commentAddedListener, new CommentAdded()); } /** * Tests that DraftPublished event are going in the method with * that type as parameter and that other type of events are going * in the default method. */ @Test public void testEventNotificationWithListenerDraftPublishedMethodSignature() { SpecificEventListener draftPublishedListener = new SpecificEventListener() { @SuppressWarnings("unused") //method is called by reflection public void gerritEvent(DraftPublished event) { specificMethodCalled = true; } }; testListenerWithSpecificSignature(draftPublishedListener, new DraftPublished()); } /** * Tests that PatchsetCreated event are going in the method with * that type as parameter and that other type of events are going * in the default method. */ @Test public void testEventNotificationWithListenerPatchsetCreatedMethodSignature() { SpecificEventListener patchsetCreatedListener = new SpecificEventListener() { @SuppressWarnings("unused") //method is called by reflection public void gerritEvent(PatchsetCreated event) { specificMethodCalled = true; } }; testListenerWithSpecificSignature(patchsetCreatedListener, new PatchsetCreated()); } /** * Tests that RefUpdated event are going in the method with * that type as parameter and that other type of events are going * in the default method. */ @Test public void testEventNotificationWithListenerRefUpdatedMethodSignature() { SpecificEventListener refUpdatedListener = new SpecificEventListener() { @SuppressWarnings("unused") //method is called by reflection public void gerritEvent(RefUpdated event) { specificMethodCalled = true; } }; testListenerWithSpecificSignature(refUpdatedListener, new RefUpdated()); } /** * Tests that ProjectCreated event are going in the method with * that type as parameter and that other type of events are going * in the default method. */ @Test public void testEventNotificationWithListenerProjectCreatedMethodSignature() { SpecificEventListener projectCreatedListener = new SpecificEventListener() { @SuppressWarnings("unused") //method is called by reflection public void gerritEvent(ProjectCreated event) { specificMethodCalled = true; } }; testListenerWithSpecificSignature(projectCreatedListener, new ProjectCreated()); } /** * Tests that TopicChanged events are going in the method with * that type as parameter and that other type of events are going * in the default method. */ @Test public void testEventNotificationWithListenerTopicChangedMethodSignature() { SpecificEventListener topicChangedListener = new SpecificEventListener() { @SuppressWarnings("unused") //method is called by reflection public void gerritEvent(TopicChanged event) { specificMethodCalled = true; } }; testListenerWithSpecificSignature(topicChangedListener, new TopicChanged()); } /** * Tests that ReviewerAdded events are going in the method with * that type as parameter and that other type of events are going * in the default method. */ @Test public void testEventNotificationWithListenerReviewerAddedMethodSignature() { SpecificEventListener reviewerAddedListener = new SpecificEventListener() { @SuppressWarnings("unused") //method is called by reflection public void gerritEvent(ReviewerAdded event) { specificMethodCalled = true; } }; testListenerWithSpecificSignature(reviewerAddedListener, new ReviewerAdded()); } /** * Tests that MergeFailed events are going in the method with * that type as parameter and that other type of events are going * in the default method. */ @Test public void testEventNotificationWithListenerMergeFailedMethodSignature() { SpecificEventListener mergeFailedListener = new SpecificEventListener() { @SuppressWarnings("unused") //method is called by reflection public void gerritEvent(MergeFailed event) { specificMethodCalled = true; } }; testListenerWithSpecificSignature(mergeFailedListener, new MergeFailed()); } /** * Tests that PrivateStateChanged events are going in the method with * that type as parameter and that other type of events are going * in the default method. */ @Test public void testEventNotificationWithListenerPrivateStateChangedMethodSignature() { SpecificEventListener stateChangedListener = new SpecificEventListener() { @SuppressWarnings("unused") //method is called by reflection public void gerritEvent(PrivateStateChanged event) { specificMethodCalled = true; } }; testListenerWithSpecificSignature(stateChangedListener, new PrivateStateChanged()); } /** * Tests that WipStateChanged events are going in the method with * that type as parameter and that other type of events are going * in the default method. */ @Test public void testEventNotificationWithListenerWipStateChangedMethodSignature() { SpecificEventListener stateChangedListener = new SpecificEventListener() { @SuppressWarnings("unused") //method is called by reflection public void gerritEvent(WipStateChanged event) { specificMethodCalled = true; } }; testListenerWithSpecificSignature(stateChangedListener, new WipStateChanged()); } /** * Tests that HashtagsChanged events are going in the method with * that type as parameter and that other type of events are going * in the default method. */ @Test public void testEventNotificationWithListenerHashtagsChangedMethodSignature() { SpecificEventListener stateChangedListener = new SpecificEventListener() { @SuppressWarnings("unused") //method is called by reflection public void gerritEvent(HashtagsChanged event) { specificMethodCalled = true; } }; testListenerWithSpecificSignature(stateChangedListener, new HashtagsChanged()); } /** * Tests that VoteDeleted events are going in the method with * that type as parameter and that other type of events are going * in the default method. */ @Test public void testEventNotificationWithListenerVoteDeletedMethodSignature() { SpecificEventListener stateChangedListener = new SpecificEventListener() { @SuppressWarnings("unused") //method is called by reflection public void gerritEvent(VoteDeleted event) { specificMethodCalled = true; } }; testListenerWithSpecificSignature(stateChangedListener, new VoteDeleted()); } /** * Base test listener implementation. */ private abstract static class SpecificEventListener implements GerritEventListener { boolean defautMethodCalled = false; boolean specificMethodCalled = false; @Override public void gerritEvent(GerritEvent event) { defautMethodCalled = true; } /** * Reset the listener. */ public void reset() { defautMethodCalled = false; specificMethodCalled = false; } } /** * Test that the specific method of a listener is called for the specific * type and that any the default method of the listener is called for any * other type of events. * @param listener the specific listener * @param specificEvent the specific event */ private void testListenerWithSpecificSignature(SpecificEventListener listener, GerritEvent specificEvent) { GerritEvent[] allEvents = new GerritEvent[]{new ChangeAbandoned(), new ChangeMerged(), new ChangeRestored(), new ChangeAbandoned(), new DraftPublished(), new PatchsetCreated(), new RefUpdated(), new ProjectCreated(), new PrivateStateChanged(), new WipStateChanged(), new VoteDeleted(), }; handler.addListener(listener); // Validate that event was sent to the specific method handler.notifyListeners(specificEvent); assertFalse(listener.defautMethodCalled); assertTrue(listener.specificMethodCalled); listener.reset(); // Validate that other events are going in the default method for (GerritEvent gerritEvent : allEvents) { if (gerritEvent.getEventType() != specificEvent.getEventType()) { handler.notifyListeners(gerritEvent); assertTrue(listener.defautMethodCalled); assertFalse(listener.specificMethodCalled); listener.reset(); } } } }