Introducing TargetUpdatedServiceEvent, ActionCreatedServiceEvent, Act… (#2588)

* Introducing TargetUpdatedServiceEvent, ActionCreatedServiceEvent, ActionUpdatedServiceEvent

* Fix ActionServiceEvents with payload annotation and add ActionEvents and ActionService tests to message converters

* Adapted EventVerifier to expect new ServiceEvents

---------

Co-authored-by: vasilchev <vasil.ilchev@bosch.com>
This commit is contained in:
Vasil Ilchev
2025-08-05 10:16:08 +03:00
committed by GitHub
parent 7b24981a1d
commit 1a4df60c59
8 changed files with 216 additions and 34 deletions

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2025 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.event.remote.service;
import java.io.Serial;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
/**
* Service event for {@link ActionCreatedEvent}. Event that needs single replica processing
*/
public class ActionCreatedServiceEvent extends AbstractServiceRemoteEvent<ActionCreatedEvent> {
@Serial
private static final long serialVersionUID = 1L;
@JsonCreator
public ActionCreatedServiceEvent(@JsonProperty("payload") final ActionCreatedEvent remoteEvent) {
super(remoteEvent);
}
}

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2025 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.event.remote.service;
import java.io.Serial;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
/**
* Service event for {@link ActionUpdatedEvent}. Event that needs single replica processing
*/
public class ActionUpdatedServiceEvent extends AbstractServiceRemoteEvent<ActionUpdatedEvent> {
@Serial
private static final long serialVersionUID = 1L;
@JsonCreator
public ActionUpdatedServiceEvent(@JsonProperty("payload") final ActionUpdatedEvent remoteEvent) {
super(remoteEvent);
}
}

View File

@@ -0,0 +1,31 @@
/**
* Copyright (c) 2025 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.event.remote.service;
import java.io.Serial;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
/**
* Service event for {@link TargetUpdatedEvent}. Event that needs single replica processing
*/
public class TargetUpdatedServiceEvent extends AbstractServiceRemoteEvent<TargetUpdatedEvent> {
@Serial
private static final long serialVersionUID = 1L;
@JsonCreator
public TargetUpdatedServiceEvent(@JsonProperty("payload") final TargetUpdatedEvent remoteEvent) {
super(remoteEvent);
}
}

View File

@@ -26,6 +26,8 @@ import org.eclipse.hawkbit.repository.event.remote.DistributionSetTypeDeletedEve
import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionAssignEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
import org.eclipse.hawkbit.repository.event.remote.service.ActionCreatedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.ActionUpdatedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.CancelTargetAssignmentServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.MultiActionAssignServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.MultiActionCancelServiceEvent;
@@ -72,6 +74,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeUpdatedEvent
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TenantConfigurationCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TenantConfigurationUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetUpdatedServiceEvent;
/**
* The {@link EventType} class declares the event-type and it's corresponding
@@ -178,12 +181,15 @@ public class EventType {
// processing events - start from 1000 to leave room for future db events
TYPES.put(1000, TargetCreatedServiceEvent.class);
TYPES.put(1001, TargetDeletedServiceEvent.class);
TYPES.put(1002, TargetAssignDistributionSetServiceEvent.class);
TYPES.put(1003, TargetAttributesRequestedServiceEvent.class);
TYPES.put(1004, CancelTargetAssignmentServiceEvent.class);
TYPES.put(1005, MultiActionAssignServiceEvent.class);
TYPES.put(1006, MultiActionCancelServiceEvent.class);
TYPES.put(1001, TargetUpdatedServiceEvent.class);
TYPES.put(1002, TargetDeletedServiceEvent.class);
TYPES.put(1003, TargetAssignDistributionSetServiceEvent.class);
TYPES.put(1004, TargetAttributesRequestedServiceEvent.class);
TYPES.put(1005, CancelTargetAssignmentServiceEvent.class);
TYPES.put(1006, MultiActionAssignServiceEvent.class);
TYPES.put(1007, MultiActionCancelServiceEvent.class);
TYPES.put(1008, ActionCreatedServiceEvent.class);
TYPES.put(1009, ActionUpdatedServiceEvent.class);
}
/**

View File

@@ -21,7 +21,12 @@ import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.service.ActionCreatedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.ActionUpdatedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.CancelTargetAssignmentServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.MultiActionAssignServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.MultiActionCancelServiceEvent;
@@ -29,6 +34,7 @@ import org.eclipse.hawkbit.repository.event.remote.service.TargetAssignDistribut
import org.eclipse.hawkbit.repository.event.remote.service.TargetAttributesRequestedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetCreatedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetDeletedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetUpdatedServiceEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.stream.function.StreamBridge;
@@ -65,12 +71,15 @@ public final class EventPublisherHolder {
public static final Set<Class<?>> SERVICE_EVENTS = Set.of(
TargetCreatedEvent.class,
TargetUpdatedEvent.class,
TargetDeletedEvent.class,
TargetAssignDistributionSetEvent.class,
CancelTargetAssignmentEvent.class,
TargetAttributesRequestedEvent.class,
MultiActionAssignEvent.class,
MultiActionCancelEvent.class,
TargetAssignDistributionSetEvent.class,
TargetAttributesRequestedEvent.class,
CancelTargetAssignmentEvent.class
ActionCreatedEvent.class,
ActionUpdatedEvent.class
);
@Autowired
@@ -161,20 +170,26 @@ public final class EventPublisherHolder {
}
private AbstractRemoteEvent toServiceEvent(final AbstractRemoteEvent event) {
if (event instanceof TargetAssignDistributionSetEvent targetAssignDistributionSetEvent) {
if (event instanceof TargetCreatedEvent targetCreatedEvent) {
return new TargetCreatedServiceEvent(targetCreatedEvent);
} else if (event instanceof TargetUpdatedEvent targetUpdatedEvent) {
return new TargetUpdatedServiceEvent(targetUpdatedEvent);
} else if (event instanceof TargetDeletedEvent targetDeletedEvent) {
return new TargetDeletedServiceEvent(targetDeletedEvent);
} else if (event instanceof TargetAssignDistributionSetEvent targetAssignDistributionSetEvent) {
return new TargetAssignDistributionSetServiceEvent(targetAssignDistributionSetEvent);
} else if (event instanceof CancelTargetAssignmentEvent cancelTargetAssignmentEvent) {
return new CancelTargetAssignmentServiceEvent(cancelTargetAssignmentEvent);
} else if (event instanceof TargetAttributesRequestedEvent targetAttributesRequestedEvent) {
return new TargetAttributesRequestedServiceEvent(targetAttributesRequestedEvent);
} else if (event instanceof MultiActionAssignEvent multiActionAssignEvent) {
return new MultiActionAssignServiceEvent(multiActionAssignEvent);
} else if (event instanceof MultiActionCancelEvent multiActionCancelEvent) {
return new MultiActionCancelServiceEvent(multiActionCancelEvent);
} else if (event instanceof CancelTargetAssignmentEvent cancelTargetAssignmentEvent) {
return new CancelTargetAssignmentServiceEvent(cancelTargetAssignmentEvent);
} else if (event instanceof TargetDeletedEvent targetDeletedEvent) {
return new TargetDeletedServiceEvent(targetDeletedEvent);
} else if (event instanceof TargetCreatedEvent targetCreatedEvent) {
return new TargetCreatedServiceEvent(targetCreatedEvent);
} else if (event instanceof TargetAttributesRequestedEvent targetAttributesRequestedEvent) {
return new TargetAttributesRequestedServiceEvent(targetAttributesRequestedEvent);
} else if (event instanceof ActionCreatedEvent actionCreatedEvent) {
return new ActionCreatedServiceEvent(actionCreatedEvent);
} else if (event instanceof ActionUpdatedEvent actionUpdatedEvent) {
return new ActionUpdatedServiceEvent(actionUpdatedEvent);
}
return null;
}

View File

@@ -10,8 +10,17 @@
package org.eclipse.hawkbit.event;
import org.eclipse.hawkbit.repository.event.remote.AbstractRemoteEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.service.ActionCreatedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.ActionUpdatedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetCreatedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetDeletedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetUpdatedServiceEvent;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Target;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -35,10 +44,8 @@ abstract class AbstractEventMessageConverterTest {
@Mock
protected Target targetMock;
@BeforeEach
void before() {
when(targetMock.getId()).thenReturn(1L);
}
@Mock
protected Action actionMock;
AbstractEventMessageConverterTest(MessageConverter messageConverter) {
this.messageConverter = messageConverter;
@@ -48,18 +55,62 @@ abstract class AbstractEventMessageConverterTest {
* Verifies that the TargetCreatedEvent can be successfully serialized and deserialized
*/
@Test
void successfullySerializeAndDeserializeEvent() {
final TargetCreatedEvent targetCreatedEvent = new TargetCreatedEvent(targetMock);
// serialize
assertSerializeAndDeserialize(targetCreatedEvent, TargetCreatedEvent.class);
assertSerializeAndDeserialize(targetCreatedEvent, TargetCreatedEvent.class);
void successfullySerializeAndDeserializeTargetEvent() {
assertSerializeAndDeserialize(createTargetCreatedEvent(), TargetCreatedEvent.class);
assertSerializeAndDeserialize(createTargetUpdatedEvent(), TargetUpdatedEvent.class);
assertSerializeAndDeserialize(createTargetDeletedEvent(), TargetDeletedEvent.class);
}
@Test
void successfullySerializeAndDeserializeServiceEvent() {
final TargetCreatedEvent targetCreatedEvent = new TargetCreatedEvent(targetMock);
final TargetCreatedServiceEvent targetCreatedServiceEvent = new TargetCreatedServiceEvent(targetCreatedEvent);
void successfullySerializeAndDeserializeTargetServiceEvent() {
final TargetCreatedServiceEvent targetCreatedServiceEvent = new TargetCreatedServiceEvent(createTargetCreatedEvent());
final TargetUpdatedServiceEvent targetUpdatedServiceEvent = new TargetUpdatedServiceEvent(createTargetUpdatedEvent());
final TargetDeletedServiceEvent targetDeletedServiceEvent = new TargetDeletedServiceEvent(createTargetDeletedEvent());
assertSerializeAndDeserialize(targetCreatedServiceEvent, TargetCreatedServiceEvent.class);
assertSerializeAndDeserialize(targetUpdatedServiceEvent, TargetUpdatedServiceEvent.class);
assertSerializeAndDeserialize(targetDeletedServiceEvent, TargetDeletedServiceEvent.class);
}
@Test
void successfullySerializeAndDeserializeActionEvent() {
final ActionCreatedEvent actionCreatedEvent = createActionCreatedEvent();
final ActionUpdatedEvent actionUpdatedEvent = createActionUpdatedEvent();
assertSerializeAndDeserialize(actionCreatedEvent, ActionCreatedEvent.class);
assertSerializeAndDeserialize(actionUpdatedEvent, ActionUpdatedEvent.class);
}
@Test
void successfullySerializeAndDeserializeActionServiceEvent() {
final ActionCreatedServiceEvent actionCreatedServiceEvent =
new ActionCreatedServiceEvent(createActionCreatedEvent());
final ActionUpdatedServiceEvent actionUpdatedServiceEvent =
new ActionUpdatedServiceEvent(createActionUpdatedEvent());
assertSerializeAndDeserialize(actionCreatedServiceEvent, ActionCreatedServiceEvent.class);
assertSerializeAndDeserialize(actionUpdatedServiceEvent, ActionUpdatedServiceEvent.class);
}
private TargetCreatedEvent createTargetCreatedEvent() {
return new TargetCreatedEvent(targetMock);
}
private TargetUpdatedEvent createTargetUpdatedEvent() {
return new TargetUpdatedEvent(targetMock);
}
private TargetDeletedEvent createTargetDeletedEvent() {
return new TargetDeletedEvent("test_tenant", 1L, Target.class, "test_target", "test_reason");
}
private ActionCreatedEvent createActionCreatedEvent() {
return new ActionCreatedEvent(actionMock, 1L, 2L, 3L);
}
private ActionUpdatedEvent createActionUpdatedEvent() {
return new ActionUpdatedEvent(actionMock, 1L, 2L, 3L);
}
<T extends AbstractRemoteEvent> void assertSerializeAndDeserialize(T event, Class<? extends AbstractRemoteEvent> expectedClass) {
@@ -70,6 +121,7 @@ abstract class AbstractEventMessageConverterTest {
} else if (messageConverter instanceof EventJacksonMessageConverter jackson) {
serializedEvent = jackson.convertToInternal(event, new MessageHeaders(new HashMap<>()), null);
}
assertThat(serializedEvent).isInstanceOf(byte[].class);
// deserialize

View File

@@ -10,7 +10,10 @@
package org.eclipse.hawkbit.repository.event.remote;
import org.eclipse.hawkbit.repository.event.EventPublisherHolder;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.service.CancelTargetAssignmentServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.MultiActionAssignServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetAssignDistributionSetServiceEvent;
@@ -66,13 +69,16 @@ class ServiceEventsTest {
@Test
void testExpectedServiceEvents(){
var expected = Set.of(
TargetCreatedEvent.class,
TargetUpdatedEvent.class,
TargetDeletedEvent.class,
TargetAssignDistributionSetEvent.class,
CancelTargetAssignmentEvent.class,
TargetAttributesRequestedEvent.class,
MultiActionAssignEvent.class,
MultiActionCancelEvent.class,
CancelTargetAssignmentEvent.class,
TargetDeletedEvent.class,
TargetCreatedEvent.class,
TargetAttributesRequestedEvent.class
ActionCreatedEvent.class,
ActionUpdatedEvent.class
);
assertEquals(EventPublisherHolder.SERVICE_EVENTS, expected);
}

View File

@@ -35,6 +35,11 @@ import org.eclipse.hawkbit.repository.event.remote.AbstractRemoteEvent;
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionAssignEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.service.ActionCreatedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.ActionUpdatedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.CancelTargetAssignmentServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.MultiActionAssignServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.MultiActionCancelServiceEvent;
@@ -48,6 +53,7 @@ import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEv
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetUpdatedServiceEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
@@ -110,6 +116,8 @@ public class EventVerifier extends AbstractTestExecutionListener {
final Class<?> type = event.type();
if (type.isAssignableFrom(TargetCreatedEvent.class)) {
modifiedEvents.add(toExpectServiceEvent(TargetCreatedServiceEvent.class, event.count()));
} else if (type.isAssignableFrom(TargetUpdatedEvent.class)) {
modifiedEvents.add(toExpectServiceEvent(TargetUpdatedServiceEvent.class, event.count()));
} else if (type.isAssignableFrom(TargetDeletedEvent.class)) {
modifiedEvents.add(toExpectServiceEvent(TargetDeletedServiceEvent.class, event.count()));
} else if (type.isAssignableFrom(TargetAssignDistributionSetEvent.class)) {
@@ -122,6 +130,10 @@ public class EventVerifier extends AbstractTestExecutionListener {
modifiedEvents.add(toExpectServiceEvent(TargetAttributesRequestedServiceEvent.class, event.count()));
} else if (type.isAssignableFrom(CancelTargetAssignmentEvent.class)) {
modifiedEvents.add(toExpectServiceEvent(CancelTargetAssignmentServiceEvent.class, event.count()));
} else if (type.isAssignableFrom(ActionCreatedEvent.class)) {
modifiedEvents.add(toExpectServiceEvent(ActionCreatedServiceEvent.class, event.count()));
} else if (type.isAssignableFrom(ActionUpdatedEvent.class)) {
modifiedEvents.add(toExpectServiceEvent(ActionUpdatedServiceEvent.class, event.count()));
}
}
return Optional.of(modifiedEvents.toArray(new Expect[0]));