Copilot commented on code in PR #772: URL: https://github.com/apache/unomi/pull/772#discussion_r3398746201
########## services/src/test/java/org/apache/unomi/services/impl/TestEventAdmin.java: ########## @@ -0,0 +1,465 @@ +/* + * 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.unomi.services.impl; + +import org.osgi.service.event.Event; +import org.osgi.service.event.EventAdmin; +import org.osgi.service.event.EventHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Mock implementation of OSGi EventAdmin for unit tests. + * + * This implementation complies with the OSGi EventAdmin Service Specification (OSGi Compendium 8.1+): + * + * 1. postEvent(Event event): Asynchronous, ordered delivery + * - Returns immediately (non-blocking) per spec: "returns to the caller before delivery is complete" + * - Events are delivered to handlers in the order they were posted per spec: "Events are delivered in the order posted" + * - Each handler receives events in the order they were posted + * - Null events are ignored (early return) + * - Events with null topics are ignored (logged and skipped) + * + * 2. sendEvent(Event event): Synchronous delivery + * - Does not return until all handlers have processed the event per spec: "does not return until all event handlers have been called" + * - Handlers are called directly in the current thread (synchronous) + * - Null events are ignored (early return) + * - Events with null topics are ignored (logged and skipped) + * + * 3. Exception handling: Exceptions from handlers do not stop delivery to other handlers + * - Per spec: exceptions should be caught and logged (using LogService if available, SLF4J otherwise) + * - Delivery continues to remaining handlers + * + * 4. Topic matching: Supports OSGi hierarchical topic matching + * - EVENT_TOPIC service property: array of topic patterns + * - Empty EVENT_TOPIC matches all topics (defaults to "*") + * - Wildcard "*" matches all topics + * - Wildcard "**" at end matches all subtopics (e.g., "org/apache/unomi/**") + * - Single-level wildcard "*" at end matches one level (e.g., "org/apache/unomi/*") + * - Exact topic matching + * - Topics are hierarchical, separated by '/' character + * + * 5. Handler registration: Manual registration for tests (in real OSGi, handlers are registered via service registry) + * - Handlers specify topics via EVENT_TOPIC property (mapped to topics parameter) + * - EVENT_FILTER property is optional and not implemented (minimal compliance) + * + * Threading model: + * - postEvent(): Uses a single-threaded executor to process events in order + * - sendEvent(): Calls handlers directly in the current thread (synchronous) + * - Each handler has a dedicated queue to guarantee ordered delivery per handler + * + * Note: Security (TopicPermission) is not enforced in this test mock, as it's not required for minimal compliance + * in a test environment. Real OSGi implementations must enforce TopicPermission checks. + */ +public class TestEventAdmin implements EventAdmin { + + private static final Logger LOGGER = LoggerFactory.getLogger(TestEventAdmin.class); + + /** + * Registry of event handlers with their topic filters. + * Key: EventHandler instance + * Value: Set of topic patterns (from EVENT_TOPIC service property) + */ + private final Map<EventHandler, Set<String>> handlers = new ConcurrentHashMap<>(); + + /** + * Single-threaded executor for processing asynchronous events in order. + * This ensures events are delivered to handlers in the order they were posted. + */ + private final ExecutorService asyncExecutor; + + /** + * Queue per handler to guarantee event sequencing. + * Each handler has its own queue, ensuring events are processed in order. + */ + private final Map<EventHandler, BlockingQueue<Event>> handlerQueues = new ConcurrentHashMap<>(); + + /** + * Worker threads per handler to process events from their queues sequentially. + */ + private final Map<EventHandler, Future<?>> handlerWorkers = new ConcurrentHashMap<>(); + + /** + * Counter for tracking posted events (for test verification). + */ + private final AtomicInteger postedEventCount = new AtomicInteger(0); + + /** + * Counter for tracking sent events (for test verification). + */ + private final AtomicInteger sentEventCount = new AtomicInteger(0); + + /** + * List of all events posted (for test verification). + */ + private final List<Event> postedEvents = new CopyOnWriteArrayList<>(); + + /** + * List of all events sent (for test verification). + */ + private final List<Event> sentEvents = new CopyOnWriteArrayList<>(); + + /** + * Creates a TestEventAdmin with a single-threaded executor for ordered event delivery. + */ + public TestEventAdmin() { + // Use single-threaded executor to guarantee ordered delivery + this.asyncExecutor = Executors.newSingleThreadExecutor(r -> { + Thread t = new Thread(r, "TestEventAdmin-Async-" + System.identityHashCode(this)); + t.setDaemon(true); + return t; + }); Review Comment: `registerHandler` submits one long-running worker per handler onto `asyncExecutor`, but `asyncExecutor` is a *single-thread* executor. The first worker blocks on `queue.take()` forever, preventing subsequent handler workers from ever running, so only the first registered handler will receive async events. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
