You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ss...@apache.org on 2015/05/17 14:33:08 UTC

svn commit: r1679849 - in /sling/trunk/testing/mocks/osgi-mock: ./ src/main/java/org/apache/sling/testing/mock/osgi/ src/main/java/org/apache/sling/testing/mock/osgi/context/ src/test/java/org/apache/sling/testing/mock/osgi/

Author: sseifert
Date: Sun May 17 12:33:08 2015
New Revision: 1679849

URL: http://svn.apache.org/r1679849
Log:
SLING-4719 osgi-mock: Add Mock EventAdmin implementation

Added:
    sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/MockEventAdmin.java   (with props)
    sling/trunk/testing/mocks/osgi-mock/src/test/java/org/apache/sling/testing/mock/osgi/MockEventAdminTest.java   (with props)
Modified:
    sling/trunk/testing/mocks/osgi-mock/pom.xml
    sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java
    sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java

Modified: sling/trunk/testing/mocks/osgi-mock/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/testing/mocks/osgi-mock/pom.xml?rev=1679849&r1=1679848&r2=1679849&view=diff
==============================================================================
--- sling/trunk/testing/mocks/osgi-mock/pom.xml (original)
+++ sling/trunk/testing/mocks/osgi-mock/pom.xml Sun May 17 12:33:08 2015
@@ -64,6 +64,13 @@
         </dependency>
     
         <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.osgi</artifactId>
+            <version>2.2.0</version>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
             <version>15.0</version>
@@ -110,6 +117,7 @@
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-scr-plugin</artifactId>
             </plugin>
+
            <plugin>
                 <groupId>org.apache.rat</groupId>
                 <artifactId>apache-rat-plugin</artifactId>

Added: sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/MockEventAdmin.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/MockEventAdmin.java?rev=1679849&view=auto
==============================================================================
--- sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/MockEventAdmin.java (added)
+++ sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/MockEventAdmin.java Sun May 17 12:33:08 2015
@@ -0,0 +1,169 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.testing.mock.osgi;
+
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.ReferencePolicy;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.commons.osgi.ServiceUtil;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.event.EventHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Mock implementation of {@link EventAdmin}.
+ * From {@link EventConstants} currently only {@link EventConstants#EVENT_TOPIC} is supported. 
+ */
+@Component(immediate = true)
+@Service(value = EventAdmin.class)
+public final class MockEventAdmin implements EventAdmin {
+    
+    @Reference(name="eventHandler", referenceInterface=EventHandler.class,
+            cardinality=ReferenceCardinality.OPTIONAL_MULTIPLE, policy=ReferencePolicy.DYNAMIC)
+    private final Map<Object, EventHandlerItem> eventHandlers = new TreeMap<Object, EventHandlerItem>();
+
+    private ExecutorService asyncHandler = Executors.newCachedThreadPool();
+    
+    private static final Logger log = LoggerFactory.getLogger(MockEventAdmin.class);
+
+    @Override
+    public void postEvent(final Event event) {
+        asyncHandler.execute(new Runnable() {
+            @Override
+            public void run() {
+                distributeEvent(event);
+            }
+        });
+    }
+
+    @Override
+    public void sendEvent(final Event event) {
+        distributeEvent(event);
+    }
+    
+    private void distributeEvent(Event event) {
+        synchronized (eventHandlers) {
+            for (EventHandlerItem item : eventHandlers.values()) {
+                if (item.matches(event)) {
+                    try {
+                        item.getEventHandler().handleEvent(event);
+                    }
+                    catch (Throwable ex) {
+                        log.error("Error handlihng event {} in {}", event, item.getEventHandler());
+                    }
+                }
+            }
+        }
+    }
+    
+    protected void bindEventHandler(EventHandler eventHandler, Map<String, Object> props) {
+        synchronized (eventHandlers) {
+            eventHandlers.put(ServiceUtil.getComparableForServiceRanking(props), new EventHandlerItem(eventHandler, props));
+        }
+    }
+
+    protected void unbindEventHandler(EventHandler eventHandler, Map<String, Object> props) {
+        synchronized (eventHandlers) {
+            eventHandlers.remove(ServiceUtil.getComparableForServiceRanking(props));
+        }
+    }
+    
+    private static class EventHandlerItem {
+        
+        private final EventHandler eventHandler;
+        private final Pattern[] topicPatterns;
+
+        private static final Pattern WILDCARD_PATTERN = Pattern.compile("[^*]+|(\\*)");
+        
+        public EventHandlerItem(EventHandler eventHandler, Map<String, Object> props) {
+            this.eventHandler = eventHandler;
+            topicPatterns = generateTopicPatterns(props.get(EventConstants.EVENT_TOPIC));
+        }
+        
+        public boolean matches(Event event) {
+            if (topicPatterns.length == 0) {
+                return true;
+            }
+            String topic = event.getTopic();
+            if (topic != null) {
+                for (Pattern topicPattern : topicPatterns) {
+                    if (topicPattern.matcher(topic).matches()) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+        
+        public EventHandler getEventHandler() {
+            return eventHandler;
+        }
+
+        private static Pattern[] generateTopicPatterns(Object topic) {
+            String[] topics;
+            if (topic == null) {
+                topics = new String[0];
+            }
+            else if (topic instanceof String) {
+                topics = new String[] { (String)topic };
+            }
+            else if (topic instanceof String[]) {
+                topics = (String[])topic;
+            }
+            else {
+                throw new IllegalArgumentException("Invalid topic: " + topic);
+            }
+            Pattern[] patterns = new Pattern[topics.length];
+            for (int i=0; i<topics.length; i++) {
+                patterns[i] = toWildcardPattern(topics[i]);
+            }
+            return patterns;
+        }
+        
+        /**
+         * Converts a wildcard string with * to a regex pattern (from http://stackoverflow.com/questions/24337657/wildcard-matching-in-java)
+         * @param wildcard
+         * @return Regexp pattern
+         */
+        private static Pattern toWildcardPattern(String wildcard) {
+            Matcher matcher = WILDCARD_PATTERN.matcher(wildcard);
+            StringBuffer result = new StringBuffer();
+            while (matcher.find()) {
+                if(matcher.group(1) != null) matcher.appendReplacement(result, ".*");
+                else matcher.appendReplacement(result, "\\\\Q" + matcher.group(0) + "\\\\E");
+            }
+            matcher.appendTail(result);
+            return Pattern.compile(result.toString());
+        }
+        
+    }
+
+}

Propchange: sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/MockEventAdmin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/MockEventAdmin.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Sun May 17 12:33:08 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/MockEventAdmin.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java?rev=1679849&r1=1679848&r2=1679849&view=diff
==============================================================================
--- sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java (original)
+++ sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java Sun May 17 12:33:08 2015
@@ -24,6 +24,7 @@ import java.util.Hashtable;
 import java.util.Map;
 
 import org.apache.commons.lang3.ArrayUtils;
+import org.apache.sling.testing.mock.osgi.MockEventAdmin;
 import org.apache.sling.testing.mock.osgi.MockOsgi;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
@@ -45,7 +46,7 @@ public class OsgiContextImpl {
      * Setup actions before test method execution
      */
     protected void setUp() {
-        // can be overridden by subclasses
+        registerDefaultServices();
     }
     
     /**
@@ -56,6 +57,13 @@ public class OsgiContextImpl {
     }
 
     /**
+     * Default services that should be available for every unit test
+     */
+    private void registerDefaultServices() {
+        registerInjectActivateService(new MockEventAdmin());
+    }
+    
+    /**
      * @return OSGi component context
      */
     public final ComponentContext componentContext() {

Modified: sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java?rev=1679849&r1=1679848&r2=1679849&view=diff
==============================================================================
--- sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java (original)
+++ sling/trunk/testing/mocks/osgi-mock/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java Sun May 17 12:33:08 2015
@@ -19,5 +19,5 @@
 /**
  * Mock implementation of selected OSGi APIs.
  */
-@aQute.bnd.annotation.Version("2.0")
+@aQute.bnd.annotation.Version("2.1")
 package org.apache.sling.testing.mock.osgi;

Added: sling/trunk/testing/mocks/osgi-mock/src/test/java/org/apache/sling/testing/mock/osgi/MockEventAdminTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/mocks/osgi-mock/src/test/java/org/apache/sling/testing/mock/osgi/MockEventAdminTest.java?rev=1679849&view=auto
==============================================================================
--- sling/trunk/testing/mocks/osgi-mock/src/test/java/org/apache/sling/testing/mock/osgi/MockEventAdminTest.java (added)
+++ sling/trunk/testing/mocks/osgi-mock/src/test/java/org/apache/sling/testing/mock/osgi/MockEventAdminTest.java Sun May 17 12:33:08 2015
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.testing.mock.osgi;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.event.EventHandler;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class MockEventAdminTest {
+    
+    private static final String TOPIC_SAMPLE_1 = "sample/topic1";
+    private static final String TOPIC_SAMPLE_2 = "sample/topic2";
+    private static final String TOPIC_SAMPLE_ALL = "sample/*";
+    private static final String TOPIC_OTHER_3 = "other/topic3";
+    
+    private static final Event EVENT_SAMPLE_1 = new Event(TOPIC_SAMPLE_1, null);
+    private static final Event EVENT_SAMPLE_2 = new Event(TOPIC_SAMPLE_2, null);
+    private static final Event EVENT_OTHER_3 = new Event(TOPIC_OTHER_3, null);
+    
+    @Rule
+    public OsgiContext context = new OsgiContext();
+    
+    private DummyEventHandler eventHandler1;
+    private DummyEventHandler eventHandler12;
+    private DummyEventHandler eventHandlerSampleAll;
+    private DummyEventHandler eventHandlerAll;
+    
+    @Before
+    public void setUp() {
+        eventHandler1 = (DummyEventHandler)context.registerService(EventHandler.class, new DummyEventHandler(),
+                ImmutableMap.<String, Object>of(EventConstants.EVENT_TOPIC, TOPIC_SAMPLE_1));
+        eventHandler12 = (DummyEventHandler)context.registerService(EventHandler.class, new DummyEventHandler(),
+                ImmutableMap.<String, Object>of(EventConstants.EVENT_TOPIC, new String[] { TOPIC_SAMPLE_1, TOPIC_SAMPLE_2 }));
+        eventHandlerSampleAll = (DummyEventHandler)context.registerService(EventHandler.class, new DummyEventHandler(),
+                ImmutableMap.<String, Object>of(EventConstants.EVENT_TOPIC, TOPIC_SAMPLE_ALL));
+        eventHandlerAll = (DummyEventHandler)context.registerService(EventHandler.class, new DummyEventHandler());
+    }
+    
+    @Test
+    public void testSendEvent_Sample1() {
+        EventAdmin eventAdmin = context.getService(EventAdmin.class);
+        eventAdmin.sendEvent(EVENT_SAMPLE_1);
+        
+        assertEquals(ImmutableList.of(EVENT_SAMPLE_1), eventHandler1.getReceivedEvents());
+        assertEquals(ImmutableList.of(EVENT_SAMPLE_1), eventHandler12.getReceivedEvents());
+        assertEquals(ImmutableList.of(EVENT_SAMPLE_1), eventHandlerSampleAll.getReceivedEvents());
+        assertEquals(ImmutableList.of(EVENT_SAMPLE_1), eventHandlerAll.getReceivedEvents());
+    }
+
+    @Test
+    public void testSendEvent_Sample2() {
+        EventAdmin eventAdmin = context.getService(EventAdmin.class);
+        eventAdmin.sendEvent(EVENT_SAMPLE_2);
+        
+        assertEquals(ImmutableList.of(), eventHandler1.getReceivedEvents());
+        assertEquals(ImmutableList.of(EVENT_SAMPLE_2), eventHandler12.getReceivedEvents());
+        assertEquals(ImmutableList.of(EVENT_SAMPLE_2), eventHandlerSampleAll.getReceivedEvents());
+        assertEquals(ImmutableList.of(EVENT_SAMPLE_2), eventHandlerAll.getReceivedEvents());
+    }
+
+    @Test
+    public void testSendEvent_Other3() {
+        EventAdmin eventAdmin = context.getService(EventAdmin.class);
+        eventAdmin.sendEvent(EVENT_OTHER_3);
+        
+        assertEquals(ImmutableList.of(), eventHandler1.getReceivedEvents());
+        assertEquals(ImmutableList.of(), eventHandler12.getReceivedEvents());
+        assertEquals(ImmutableList.of(), eventHandlerSampleAll.getReceivedEvents());
+        assertEquals(ImmutableList.of(EVENT_OTHER_3), eventHandlerAll.getReceivedEvents());
+    }
+
+    @Test(timeout = 1000)
+    public void testPostEvents() {
+        EventAdmin eventAdmin = context.getService(EventAdmin.class);
+        eventAdmin.postEvent(EVENT_SAMPLE_2);
+        eventAdmin.postEvent(EVENT_OTHER_3);
+        
+        // wait until result is as expected (with timeout)
+        boolean expectedResult = false;
+        while (!expectedResult) {
+            expectedResult = ObjectUtils.equals(ImmutableList.of(), eventHandler1.getReceivedEvents())
+                    && ObjectUtils.equals(ImmutableList.of(EVENT_SAMPLE_2), eventHandler12.getReceivedEvents())
+                    && ObjectUtils.equals(ImmutableList.of(EVENT_SAMPLE_2), eventHandlerSampleAll.getReceivedEvents())
+                    && ObjectUtils.equals(ImmutableList.of(EVENT_SAMPLE_2, EVENT_OTHER_3), eventHandlerAll.getReceivedEvents());
+        }
+    }
+
+    private static class DummyEventHandler implements EventHandler {
+        
+        private final List<Event> receivedEvents = new ArrayList<Event>();
+
+        @Override
+        public void handleEvent(Event event) {
+            receivedEvents.add(event);
+        }
+
+        public List<Event> getReceivedEvents() {
+            return ImmutableList.copyOf(receivedEvents);
+        }
+        
+    }
+
+}

Propchange: sling/trunk/testing/mocks/osgi-mock/src/test/java/org/apache/sling/testing/mock/osgi/MockEventAdminTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/testing/mocks/osgi-mock/src/test/java/org/apache/sling/testing/mock/osgi/MockEventAdminTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Sun May 17 12:33:08 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/testing/mocks/osgi-mock/src/test/java/org/apache/sling/testing/mock/osgi/MockEventAdminTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain