You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2023/02/21 01:16:10 UTC
[james-project] 07/09: JAMES-3885 Allow to resume username change from a given step
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 484a3d35ddef9f9531340a869c1a27f362ea10ae
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Feb 17 09:01:44 2023 +0700
JAMES-3885 Allow to resume username change from a given step
From a sysadmin perspective this eases the error management in
case a step fails...
---
.../webadmin/routes/UsernameChangeRoutes.java | 7 ++-
.../webadmin/service/UsernameChangeService.java | 55 +++++++++++++++++-----
.../james/webadmin/service/UsernameChangeTask.java | 26 +++++++---
...UsernameChangeTaskAdditionalInformationDTO.java | 16 +++++--
.../webadmin/service/UsernameChangeTaskDTO.java | 19 ++++++--
.../webadmin/routes/UsernameChangeRoutesTest.java | 42 +++++++++++++++++
.../UsernameChangeTaskSerializationTest.java | 41 +++++++++++++++-
7 files changed, 177 insertions(+), 29 deletions(-)
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/UsernameChangeRoutes.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/UsernameChangeRoutes.java
index 40bb9c6b15..f87dfecb51 100644
--- a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/UsernameChangeRoutes.java
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/UsernameChangeRoutes.java
@@ -19,10 +19,13 @@
package org.apache.james.webadmin.routes;
+import java.util.Optional;
+
import javax.inject.Inject;
import org.apache.james.core.Username;
import org.apache.james.task.TaskManager;
+import org.apache.james.user.api.UsernameChangeTaskStep.StepName;
import org.apache.james.user.api.UsersRepository;
import org.apache.james.webadmin.Routes;
import org.apache.james.webadmin.service.UsernameChangeService;
@@ -73,7 +76,9 @@ public class UsernameChangeRoutes implements Routes {
Preconditions.checkArgument(usersRepository.contains(oldUser), "'oldUser' parameter should be an existing user");
Preconditions.checkArgument(usersRepository.contains(newUser), "'newUser' parameter should be an existing user");
- return new UsernameChangeTask(service, oldUser, newUser);
+ Optional<StepName> fromStep = Optional.ofNullable(request.queryParams("fromStep")).map(StepName::new);
+
+ return new UsernameChangeTask(service, oldUser, newUser, fromStep);
}).asRoute(taskManager);
}
}
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeService.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeService.java
index 6e87f8aab1..a62b726818 100644
--- a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeService.java
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeService.java
@@ -21,6 +21,7 @@ package org.apache.james.webadmin.service;
import java.util.Comparator;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -28,6 +29,7 @@ import javax.inject.Inject;
import org.apache.james.core.Username;
import org.apache.james.user.api.UsernameChangeTaskStep;
+import org.apache.james.user.api.UsernameChangeTaskStep.StepName;
import com.google.common.collect.ImmutableMap;
@@ -40,33 +42,38 @@ public class UsernameChangeService {
IN_PROGRESS,
DONE,
FAILED,
- ABORTED
+ ABORTED,
+ SKIPPED
}
public static class UsernameChangeStatus {
- private final Map<UsernameChangeTaskStep.StepName, StepState> states;
+ private final Map<StepName, StepState> states;
public UsernameChangeStatus(Set<UsernameChangeTaskStep> steps) {
states = new ConcurrentHashMap<>(steps.stream()
- .collect(ImmutableMap.toImmutableMap(step -> step.name(), any -> StepState.WAITING)));
+ .collect(ImmutableMap.toImmutableMap(UsernameChangeTaskStep::name, any -> StepState.WAITING)));
}
- public void beginStep(UsernameChangeTaskStep.StepName step) {
+ public void beginStep(StepName step) {
states.put(step, StepState.IN_PROGRESS);
}
- public void endStep(UsernameChangeTaskStep.StepName step) {
+ public void endStep(StepName step) {
states.put(step, StepState.DONE);
}
- public void failedStep(UsernameChangeTaskStep.StepName step) {
+ public void failedStep(StepName step) {
states.put(step, StepState.FAILED);
}
- public void abortStep(UsernameChangeTaskStep.StepName step) {
+ public void abortStep(StepName step) {
states.put(step, StepState.ABORTED);
}
+ public void skipStep(StepName step) {
+ states.put(step, StepState.SKIPPED);
+ }
+
public void abort() {
states.entrySet()
.stream()
@@ -74,7 +81,7 @@ public class UsernameChangeService {
.forEach(entry -> abortStep(entry.getKey()));
}
- public Map<UsernameChangeTaskStep.StepName, StepState> getStates() {
+ public Map<StepName, StepState> getStates() {
return ImmutableMap.copyOf(states);
}
}
@@ -82,15 +89,20 @@ public class UsernameChangeService {
public static class Performer {
private final Set<UsernameChangeTaskStep> steps;
private final UsernameChangeStatus status;
+ private final Optional<Integer> correspondingPriority;
- public Performer(Set<UsernameChangeTaskStep> steps, UsernameChangeStatus status) {
+ public Performer(Set<UsernameChangeTaskStep> steps, UsernameChangeStatus status, Optional<StepName> fromStep) {
this.steps = steps;
this.status = status;
+ this.correspondingPriority = fromStep.map(this::correspondingPriority);
}
public Mono<Void> changeUsername(Username oldUsername, Username newUsername) {
- return Flux.fromIterable(steps)
- .sort(Comparator.comparingInt(UsernameChangeTaskStep::priority))
+ correspondingPriority.ifPresent(priority -> steps.stream()
+ .filter(step -> step.priority() < priority)
+ .forEach(step -> status.skipStep(step.name())));
+
+ return steps()
.concatMap(step -> Mono.fromRunnable(() -> status.beginStep(step.name()))
.then(Mono.from(step.changeUsername(oldUsername, newUsername)))
.then(Mono.fromRunnable(() -> status.endStep(step.name())))
@@ -99,6 +111,23 @@ public class UsernameChangeService {
.then();
}
+ private Flux<UsernameChangeTaskStep> steps() {
+ return correspondingPriority
+ .map(priority -> Flux.fromIterable(steps)
+ .filter(step -> step.priority() >= priority)
+ .sort(Comparator.comparingInt(UsernameChangeTaskStep::priority)))
+ .orElseGet(() -> Flux.fromIterable(steps)
+ .sort(Comparator.comparingInt(UsernameChangeTaskStep::priority)));
+ }
+
+ private int correspondingPriority(StepName stepName) {
+ return steps.stream()
+ .filter(step -> step.name().equals(stepName))
+ .map(UsernameChangeTaskStep::priority)
+ .findAny()
+ .orElseThrow(() -> new IllegalArgumentException("Starting step not found: " + stepName.asString()));
+ }
+
public UsernameChangeStatus getStatus() {
return status;
}
@@ -111,7 +140,7 @@ public class UsernameChangeService {
this.steps = steps;
}
- public Performer performer() {
- return new Performer(steps, new UsernameChangeStatus(steps));
+ public Performer performer(Optional<StepName> fromStep) {
+ return new Performer(steps, new UsernameChangeStatus(steps), fromStep);
}
}
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTask.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTask.java
index cab6908686..677ff961d0 100644
--- a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTask.java
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTask.java
@@ -28,7 +28,7 @@ import org.apache.james.core.Username;
import org.apache.james.task.Task;
import org.apache.james.task.TaskExecutionDetails;
import org.apache.james.task.TaskType;
-import org.apache.james.user.api.UsernameChangeTaskStep;
+import org.apache.james.user.api.UsernameChangeTaskStep.StepName;
import reactor.core.publisher.Mono;
@@ -39,13 +39,19 @@ public class UsernameChangeTask implements Task {
private final Instant timestamp;
private final Username oldUser;
private final Username newUser;
- private final Map<UsernameChangeTaskStep.StepName, UsernameChangeService.StepState> status;
+ private final Map<StepName, UsernameChangeService.StepState> status;
+ private final Optional<StepName> fromStep;
- public AdditionalInformation(Instant timestamp, Username oldUser, Username newUser, Map<UsernameChangeTaskStep.StepName, UsernameChangeService.StepState> status) {
+ public AdditionalInformation(Instant timestamp, Username oldUser, Username newUser, Map<StepName, UsernameChangeService.StepState> status, Optional<StepName> fromStep) {
this.timestamp = timestamp;
this.oldUser = oldUser;
this.newUser = newUser;
this.status = status;
+ this.fromStep = fromStep;
+ }
+
+ public Optional<StepName> getFromStep() {
+ return fromStep;
}
public Username getOldUser() {
@@ -56,7 +62,7 @@ public class UsernameChangeTask implements Task {
return newUser;
}
- public Map<UsernameChangeTaskStep.StepName, UsernameChangeService.StepState> getStatus() {
+ public Map<StepName, UsernameChangeService.StepState> getStatus() {
return status;
}
@@ -69,12 +75,14 @@ public class UsernameChangeTask implements Task {
private final Username oldUser;
private final Username newUser;
private final UsernameChangeService.Performer performer;
+ private final Optional<StepName> fromStep;
- public UsernameChangeTask(UsernameChangeService service, Username oldUser, Username newUser) {
+ public UsernameChangeTask(UsernameChangeService service, Username oldUser, Username newUser, Optional<StepName> fromStep) {
this.oldUser = oldUser;
this.newUser = newUser;
- this.performer = service.performer();
+ this.performer = service.performer(fromStep);
+ this.fromStep = fromStep;
}
@@ -96,7 +104,7 @@ public class UsernameChangeTask implements Task {
@Override
public Optional<TaskExecutionDetails.AdditionalInformation> details() {
- return Optional.of(new AdditionalInformation(Clock.systemUTC().instant(), oldUser, newUser, performer.getStatus().getStates()));
+ return Optional.of(new AdditionalInformation(Clock.systemUTC().instant(), oldUser, newUser, performer.getStatus().getStates(), fromStep));
}
public Username getOldUser() {
@@ -106,4 +114,8 @@ public class UsernameChangeTask implements Task {
public Username getNewUser() {
return newUser;
}
+
+ public Optional<StepName> getFromStep() {
+ return fromStep;
+ }
}
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTaskAdditionalInformationDTO.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTaskAdditionalInformationDTO.java
index 14e41f4e0c..76f670c439 100644
--- a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTaskAdditionalInformationDTO.java
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTaskAdditionalInformationDTO.java
@@ -20,12 +20,13 @@ package org.apache.james.webadmin.service;
import java.time.Instant;
import java.util.Map;
+import java.util.Optional;
import org.apache.james.core.Username;
import org.apache.james.json.DTOModule;
import org.apache.james.server.task.json.dto.AdditionalInformationDTO;
import org.apache.james.server.task.json.dto.AdditionalInformationDTOModule;
-import org.apache.james.user.api.UsernameChangeTaskStep;
+import org.apache.james.user.api.UsernameChangeTaskStep.StepName;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableMap;
@@ -40,8 +41,9 @@ public class UsernameChangeTaskAdditionalInformationDTO implements AdditionalInf
Username.of(dto.newUser),
dto.status.entrySet().stream()
.collect(ImmutableMap.toImmutableMap(
- entry -> new UsernameChangeTaskStep.StepName(entry.getKey()),
- entry -> UsernameChangeService.StepState.valueOf(entry.getValue())))))
+ entry -> new StepName(entry.getKey()),
+ entry -> UsernameChangeService.StepState.valueOf(entry.getValue()))),
+ dto.fromStep.map(StepName::new)))
.toDTOConverter((details, type) -> new UsernameChangeTaskAdditionalInformationDTO(
type,
details.getOldUser().asString(),
@@ -50,6 +52,7 @@ public class UsernameChangeTaskAdditionalInformationDTO implements AdditionalInf
.collect(ImmutableMap.toImmutableMap(
entry -> entry.getKey().asString(),
entry -> entry.getValue().toString())),
+ details.getFromStep().map(StepName::asString),
details.timestamp()))
.typeName(UsernameChangeTask.TYPE.asString())
.withFactory(AdditionalInformationDTOModule::new);
@@ -59,18 +62,21 @@ public class UsernameChangeTaskAdditionalInformationDTO implements AdditionalInf
private final String oldUser;
private final String newUser;
private final Map<String, String> status;
+ private final Optional<String> fromStep;
private final Instant timestamp;
public UsernameChangeTaskAdditionalInformationDTO(@JsonProperty("type") String type,
@JsonProperty("oldUser") String oldUser,
@JsonProperty("newUser") String newUser,
@JsonProperty("status") Map<String, String> status,
+ @JsonProperty("fromStep") Optional<String> fromStep,
@JsonProperty("timestamp") Instant timestamp) {
this.type = type;
this.oldUser = oldUser;
this.newUser = newUser;
this.status = status;
this.timestamp = timestamp;
+ this.fromStep = fromStep;
}
public String getOldUser() {
@@ -89,6 +95,10 @@ public class UsernameChangeTaskAdditionalInformationDTO implements AdditionalInf
return timestamp;
}
+ public Optional<String> getFromStep() {
+ return fromStep;
+ }
+
@Override
public String getType() {
return type;
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTaskDTO.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTaskDTO.java
index b833c9f1f8..7c558f66f9 100644
--- a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTaskDTO.java
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UsernameChangeTaskDTO.java
@@ -18,10 +18,13 @@
****************************************************************/
package org.apache.james.webadmin.service;
+import java.util.Optional;
+
import org.apache.james.core.Username;
import org.apache.james.json.DTOModule;
import org.apache.james.server.task.json.dto.TaskDTO;
import org.apache.james.server.task.json.dto.TaskDTOModule;
+import org.apache.james.user.api.UsernameChangeTaskStep.StepName;
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -38,23 +41,29 @@ public class UsernameChangeTaskDTO implements TaskDTO {
}
public static UsernameChangeTaskDTO toDTO(UsernameChangeTask domainObject, String typeName) {
- return new UsernameChangeTaskDTO(typeName, domainObject.getOldUser().asString(), domainObject.getNewUser().asString());
+ return new UsernameChangeTaskDTO(typeName,
+ domainObject.getOldUser().asString(),
+ domainObject.getNewUser().asString(),
+ domainObject.getFromStep().map(StepName::asString));
}
private final String type;
private final String oldUser;
private final String newUser;
+ private final Optional<String> fromStep;
public UsernameChangeTaskDTO(@JsonProperty("type") String type,
@JsonProperty("oldUser") String oldUser,
- @JsonProperty("newUser") String newUser) {
+ @JsonProperty("newUser") String newUser,
+ @JsonProperty("fromStep") Optional<String> fromStep) {
this.type = type;
this.oldUser = oldUser;
this.newUser = newUser;
+ this.fromStep = fromStep;
}
public UsernameChangeTask fromDTO(UsernameChangeService service) {
- return new UsernameChangeTask(service, Username.of(oldUser), Username.of(newUser));
+ return new UsernameChangeTask(service, Username.of(oldUser), Username.of(newUser), fromStep.map(StepName::new));
}
@Override
@@ -69,4 +78,8 @@ public class UsernameChangeTaskDTO implements TaskDTO {
public String getNewUser() {
return newUser;
}
+
+ public Optional<String> getFromStep() {
+ return fromStep;
+ }
}
diff --git a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/UsernameChangeRoutesTest.java b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/UsernameChangeRoutesTest.java
index 5d441aec07..9c5598515b 100644
--- a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/UsernameChangeRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/UsernameChangeRoutesTest.java
@@ -242,5 +242,47 @@ class UsernameChangeRoutesTest {
assertThat(behaviour1.get()).isTrue();
assertThat(behaviour2.get()).isFalse();
}
+
+ @Test
+ void shouldSupportSkipWhenFailure() {
+ String taskId = with()
+ .queryParam("action", "rename")
+ .queryParam("fromStep", "B")
+ .post("/users/" + OLD_USER.asString() + "/rename/" + NEW_USER.asString())
+ .jsonPath()
+ .get("taskId");
+
+ given()
+ .basePath(TasksRoutes.BASE)
+ .when()
+ .get(taskId + "/await")
+ .then()
+ .body("type", is("UsernameChangeTask"))
+ .body("status", is("failed"))
+ .body("additionalInformation.type", is("UsernameChangeTask"))
+ .body("additionalInformation.oldUser", is("jessy.jones@domain.tld"))
+ .body("additionalInformation.newUser", is("jessy.smith@domain.tld"))
+ .body("additionalInformation.status.A", is("SKIPPED"))
+ .body("additionalInformation.status.B", is("FAILED"))
+ .body("additionalInformation.status.C", is("ABORTED"));
+
+ assertThat(behaviour1.get()).isFalse();
+ assertThat(behaviour2.get()).isFalse();
+ }
+
+ @Test
+ void shouldRejectInvalidFromStep() {
+ given()
+ .queryParam("action", "rename")
+ .queryParam("fromStep", "invalid")
+ .when()
+ .post("/users/" + OLD_USER.asString() + "/rename/" + NEW_USER.asString())
+ .then()
+ .statusCode(HttpStatus.BAD_REQUEST_400)
+ .body("statusCode", Matchers.is(400))
+ .body("type", Matchers.is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+ .body("message", Matchers.is("Invalid arguments supplied in the user request"))
+ .body("details", Matchers.is("Starting step not found: invalid"));
+ }
}
}
\ No newline at end of file
diff --git a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/UsernameChangeTaskSerializationTest.java b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/UsernameChangeTaskSerializationTest.java
index d17a7c2ecb..b03e4ed3dc 100644
--- a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/UsernameChangeTaskSerializationTest.java
+++ b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/service/UsernameChangeTaskSerializationTest.java
@@ -20,6 +20,7 @@
package org.apache.james.webadmin.service;
import java.time.Instant;
+import java.util.Optional;
import org.apache.james.JsonSerializationVerifier;
import org.apache.james.core.Username;
@@ -65,6 +66,7 @@ class UsernameChangeTaskSerializationTest {
}
private static final String SERIALIZED_TASK = "{\"newUser\":\"geraldine\",\"oldUser\":\"user\",\"type\":\"UsernameChangeTask\"}";
+ private static final String SERIALIZED_TASK_WITH_FROM_STEP = "{\"newUser\":\"geraldine\",\"fromStep\":\"B\",\"oldUser\":\"user\",\"type\":\"UsernameChangeTask\"}";
private static final String SERIALIZED_ADDITIONAL_INFORMATION = "{" +
" \"newUser\":\"geraldine\"," +
" \"oldUser\":\"user\"," +
@@ -76,17 +78,37 @@ class UsernameChangeTaskSerializationTest {
" \"timestamp\":\"2018-11-13T12:00:55Z\"," +
" \"type\":\"UsernameChangeTask\"" +
"}";
+ private static final String SERIALIZED_ADDITIONAL_INFORMATION_WITH_STEP_NAME = "{" +
+ " \"newUser\":\"geraldine\"," +
+ " \"oldUser\":\"user\"," +
+ " \"fromStep\":\"B\"," +
+ " \"status\":{" +
+ " \"A\":\"DONE\"," +
+ " \"B\":\"WAITING\"," +
+ " \"C\":\"FAILED\"," +
+ " \"D\":\"ABORTED\"}," +
+ " \"timestamp\":\"2018-11-13T12:00:55Z\"," +
+ " \"type\":\"UsernameChangeTask\"" +
+ "}";
private static final UsernameChangeService SERVICE = new UsernameChangeService(ImmutableSet.of(A, B, C, D));
@Test
void taskShouldBeSerializable() throws Exception {
JsonSerializationVerifier.dtoModule(UsernameChangeTaskDTO.module(SERVICE))
- .bean(new UsernameChangeTask(SERVICE, OLD_USERNAME, NEW_USERNAME))
+ .bean(new UsernameChangeTask(SERVICE, OLD_USERNAME, NEW_USERNAME, Optional.empty()))
.json(SERIALIZED_TASK)
.verify();
}
+ @Test
+ void taskShouldBeSerializableWithFromStep() throws Exception {
+ JsonSerializationVerifier.dtoModule(UsernameChangeTaskDTO.module(SERVICE))
+ .bean(new UsernameChangeTask(SERVICE, OLD_USERNAME, NEW_USERNAME, Optional.of(STEP_B)))
+ .json(SERIALIZED_TASK_WITH_FROM_STEP)
+ .verify();
+ }
+
@Test
void additionalInformationShouldBeSerializable() throws Exception {
JsonSerializationVerifier.dtoModule(UsernameChangeTaskAdditionalInformationDTO.module())
@@ -97,8 +119,23 @@ class UsernameChangeTaskSerializationTest {
ImmutableMap.of(STEP_A, UsernameChangeService.StepState.DONE,
STEP_B, UsernameChangeService.StepState.WAITING,
STEP_C, UsernameChangeService.StepState.FAILED,
- STEP_D, UsernameChangeService.StepState.ABORTED)))
+ STEP_D, UsernameChangeService.StepState.ABORTED), Optional.empty()))
.json(SERIALIZED_ADDITIONAL_INFORMATION)
.verify();
}
+
+ @Test
+ void additionalInformationShouldBeSerializableWithStepName() throws Exception {
+ JsonSerializationVerifier.dtoModule(UsernameChangeTaskAdditionalInformationDTO.module())
+ .bean(new UsernameChangeTask.AdditionalInformation(
+ TIMESTAMP,
+ OLD_USERNAME,
+ NEW_USERNAME,
+ ImmutableMap.of(STEP_A, UsernameChangeService.StepState.DONE,
+ STEP_B, UsernameChangeService.StepState.WAITING,
+ STEP_C, UsernameChangeService.StepState.FAILED,
+ STEP_D, UsernameChangeService.StepState.ABORTED), Optional.of(STEP_B)))
+ .json(SERIALIZED_ADDITIONAL_INFORMATION_WITH_STEP_NAME)
+ .verify();
+ }
}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org