From 04dbd137487f60fb61076d902296b6cb6f652c3c Mon Sep 17 00:00:00 2001 From: Snarr Date: Tue, 3 Dec 2024 20:08:07 -0500 Subject: [PATCH 1/6] fix(server): Use Optionals for optional UserTaskTriggerReference fields --- .../UserTaskTriggerReferenceModel.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/server/src/main/java/io/littlehorse/common/model/getable/core/taskrun/UserTaskTriggerReferenceModel.java b/server/src/main/java/io/littlehorse/common/model/getable/core/taskrun/UserTaskTriggerReferenceModel.java index ec5d3fd4f..c472f5da1 100644 --- a/server/src/main/java/io/littlehorse/common/model/getable/core/taskrun/UserTaskTriggerReferenceModel.java +++ b/server/src/main/java/io/littlehorse/common/model/getable/core/taskrun/UserTaskTriggerReferenceModel.java @@ -1,5 +1,7 @@ package io.littlehorse.common.model.getable.core.taskrun; +import java.util.Optional; + import com.google.protobuf.Message; import io.littlehorse.common.LHSerializable; import io.littlehorse.common.model.getable.core.usertaskrun.UserTaskRunModel; @@ -19,8 +21,8 @@ public class UserTaskTriggerReferenceModel extends LHSerializable userId; + private Optional userGroup; public UserTaskTriggerReferenceModel() {} @@ -29,8 +31,8 @@ public UserTaskTriggerReferenceModel(UserTaskRunModel utr, ProcessorExecutionCon // Trust in the Force userTaskEventNumber = utr.getEvents().size(); - this.userId = utr.getUserId(); - this.userGroup = utr.getUserGroup(); + this.userId = Optional.of(utr.getUserId()); + this.userGroup = Optional.of(utr.getUserGroup()); } @Override @@ -42,9 +44,15 @@ public Class getProtoBaseClass() { public UserTaskTriggerReference.Builder toProto() { UserTaskTriggerReference.Builder out = UserTaskTriggerReference.newBuilder() .setNodeRunId(nodeRunId.toProto()) - .setUserTaskEventNumber(userTaskEventNumber) - .setUserId(this.userId) - .setUserGroup(this.userGroup); + .setUserTaskEventNumber(userTaskEventNumber); + + if (userId.isPresent()) { + out.setUserId(this.userId.get()); + } + + if (userGroup.isPresent()) { + out.setUserGroup(this.userGroup.get()); + } return out; } @@ -54,8 +62,8 @@ public void initFrom(Message proto, ExecutionContext context) { UserTaskTriggerReference p = (UserTaskTriggerReference) proto; nodeRunId = LHSerializable.fromProto(p.getNodeRunId(), NodeRunIdModel.class, context); userTaskEventNumber = p.getUserTaskEventNumber(); - userId = p.getUserId(); - userGroup = p.getUserGroup(); + userId = Optional.ofNullable(p.getUserId()); + userGroup = Optional.ofNullable(p.getUserGroup()); } @Override From 989f6b67c25849c07c80caee972b49364a2e507c Mon Sep 17 00:00:00 2001 From: Snarr Date: Tue, 3 Dec 2024 20:14:04 -0500 Subject: [PATCH 2/6] Remove optionals, check for null --- .../UserTaskTriggerReferenceModel.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/server/src/main/java/io/littlehorse/common/model/getable/core/taskrun/UserTaskTriggerReferenceModel.java b/server/src/main/java/io/littlehorse/common/model/getable/core/taskrun/UserTaskTriggerReferenceModel.java index c472f5da1..9a1c048ee 100644 --- a/server/src/main/java/io/littlehorse/common/model/getable/core/taskrun/UserTaskTriggerReferenceModel.java +++ b/server/src/main/java/io/littlehorse/common/model/getable/core/taskrun/UserTaskTriggerReferenceModel.java @@ -21,8 +21,8 @@ public class UserTaskTriggerReferenceModel extends LHSerializable userId; - private Optional userGroup; + private String userId; + private String userGroup; public UserTaskTriggerReferenceModel() {} @@ -31,8 +31,8 @@ public UserTaskTriggerReferenceModel(UserTaskRunModel utr, ProcessorExecutionCon // Trust in the Force userTaskEventNumber = utr.getEvents().size(); - this.userId = Optional.of(utr.getUserId()); - this.userGroup = Optional.of(utr.getUserGroup()); + this.userId = utr.getUserId(); + this.userGroup = utr.getUserGroup(); } @Override @@ -46,12 +46,12 @@ public UserTaskTriggerReference.Builder toProto() { .setNodeRunId(nodeRunId.toProto()) .setUserTaskEventNumber(userTaskEventNumber); - if (userId.isPresent()) { - out.setUserId(this.userId.get()); + if (userId != null) { + out.setUserId(this.userId); } - - if (userGroup.isPresent()) { - out.setUserGroup(this.userGroup.get()); + + if (userGroup != null) { + out.setUserGroup(this.userGroup); } return out; @@ -62,8 +62,8 @@ public void initFrom(Message proto, ExecutionContext context) { UserTaskTriggerReference p = (UserTaskTriggerReference) proto; nodeRunId = LHSerializable.fromProto(p.getNodeRunId(), NodeRunIdModel.class, context); userTaskEventNumber = p.getUserTaskEventNumber(); - userId = Optional.ofNullable(p.getUserId()); - userGroup = Optional.ofNullable(p.getUserGroup()); + userId = p.getUserId(); + userGroup = p.getUserGroup(); } @Override From 02ee23bf471b561443c1243d37ecddb2dd9501f5 Mon Sep 17 00:00:00 2001 From: Snarr Date: Tue, 3 Dec 2024 20:15:03 -0500 Subject: [PATCH 3/6] Remove optional import --- .../getable/core/taskrun/UserTaskTriggerReferenceModel.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/server/src/main/java/io/littlehorse/common/model/getable/core/taskrun/UserTaskTriggerReferenceModel.java b/server/src/main/java/io/littlehorse/common/model/getable/core/taskrun/UserTaskTriggerReferenceModel.java index 9a1c048ee..1dabbcca6 100644 --- a/server/src/main/java/io/littlehorse/common/model/getable/core/taskrun/UserTaskTriggerReferenceModel.java +++ b/server/src/main/java/io/littlehorse/common/model/getable/core/taskrun/UserTaskTriggerReferenceModel.java @@ -1,7 +1,5 @@ package io.littlehorse.common.model.getable.core.taskrun; -import java.util.Optional; - import com.google.protobuf.Message; import io.littlehorse.common.LHSerializable; import io.littlehorse.common.model.getable.core.usertaskrun.UserTaskRunModel; From 80ded62f556dd75554341ed3d68d9ef0b8583b54 Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 4 Dec 2024 10:56:37 -0500 Subject: [PATCH 4/6] Fix proto comment on UTTR user_group_ --- schemas/littlehorse/user_tasks.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/schemas/littlehorse/user_tasks.proto b/schemas/littlehorse/user_tasks.proto index f414a538c..caf22d190 100644 --- a/schemas/littlehorse/user_tasks.proto +++ b/schemas/littlehorse/user_tasks.proto @@ -214,8 +214,8 @@ message UserTaskTriggerReference { // asigned to a specific user_id. optional string user_id = 3; - // Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not - // asigned to a specific user_id. + // Is the user_group that the UserTaskRun is assigned to. Unset if UserTaskRun is not + // asigned to a specific user_group. optional string user_group = 4; } From 6939266f2200ccd26a717d44579b959faf5cabdf Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 4 Dec 2024 10:57:58 -0500 Subject: [PATCH 5/6] Compile proto --- docs/docs/08-api.md | 2 +- sdk-go/lhproto/user_tasks.pb.go | 4 +-- .../proto/UserTaskTriggerReference.java | 36 +++++++++---------- .../UserTaskTriggerReferenceOrBuilder.java | 12 +++---- sdk-js/src/proto/user_tasks.ts | 4 +-- sdk-python/littlehorse/model/__init__.py | 2 +- 6 files changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/docs/08-api.md b/docs/docs/08-api.md index 8170029e3..506dcc229 100644 --- a/docs/docs/08-api.md +++ b/docs/docs/08-api.md @@ -3228,7 +3228,7 @@ SDK, which allows the Task Method to determine where the TaskRun comes from. | `node_run_id` | | [NodeRunId](#noderunid) | Is the NodeRun that the UserTaskRun belongs to. | | `user_task_event_number` | | int32 | Is the index in the `events` field of the UserTaskRun that the TaskRun corresponds to. | | `user_id` | optional| string | Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not asigned to a specific user_id. | -| `user_group` | optional| string | Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not asigned to a specific user_id. | +| `user_group` | optional| string | Is the user_group that the UserTaskRun is assigned to. Unset if UserTaskRun is not asigned to a specific user_group. | diff --git a/sdk-go/lhproto/user_tasks.pb.go b/sdk-go/lhproto/user_tasks.pb.go index 52e588a08..6fbe3af93 100644 --- a/sdk-go/lhproto/user_tasks.pb.go +++ b/sdk-go/lhproto/user_tasks.pb.go @@ -770,8 +770,8 @@ type UserTaskTriggerReference struct { // Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not // asigned to a specific user_id. UserId *string `protobuf:"bytes,3,opt,name=user_id,json=userId,proto3,oneof" json:"user_id,omitempty"` - // Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not - // asigned to a specific user_id. + // Is the user_group that the UserTaskRun is assigned to. Unset if UserTaskRun is not + // asigned to a specific user_group. UserGroup *string `protobuf:"bytes,4,opt,name=user_group,json=userGroup,proto3,oneof" json:"user_group,omitempty"` } diff --git a/sdk-java/src/main/java/io/littlehorse/sdk/common/proto/UserTaskTriggerReference.java b/sdk-java/src/main/java/io/littlehorse/sdk/common/proto/UserTaskTriggerReference.java index d178ad079..78456a5fe 100644 --- a/sdk-java/src/main/java/io/littlehorse/sdk/common/proto/UserTaskTriggerReference.java +++ b/sdk-java/src/main/java/io/littlehorse/sdk/common/proto/UserTaskTriggerReference.java @@ -174,8 +174,8 @@ public java.lang.String getUserId() { private volatile java.lang.Object userGroup_ = ""; /** *
-   * Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not
-   * asigned to a specific user_id.
+   * Is the user_group that the UserTaskRun is assigned to. Unset if UserTaskRun is not
+   * asigned to a specific user_group.
    * 
* * optional string user_group = 4; @@ -187,8 +187,8 @@ public boolean hasUserGroup() { } /** *
-   * Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not
-   * asigned to a specific user_id.
+   * Is the user_group that the UserTaskRun is assigned to. Unset if UserTaskRun is not
+   * asigned to a specific user_group.
    * 
* * optional string user_group = 4; @@ -209,8 +209,8 @@ public java.lang.String getUserGroup() { } /** *
-   * Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not
-   * asigned to a specific user_id.
+   * Is the user_group that the UserTaskRun is assigned to. Unset if UserTaskRun is not
+   * asigned to a specific user_group.
    * 
* * optional string user_group = 4; @@ -980,8 +980,8 @@ public Builder setUserIdBytes( private java.lang.Object userGroup_ = ""; /** *
-     * Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not
-     * asigned to a specific user_id.
+     * Is the user_group that the UserTaskRun is assigned to. Unset if UserTaskRun is not
+     * asigned to a specific user_group.
      * 
* * optional string user_group = 4; @@ -992,8 +992,8 @@ public boolean hasUserGroup() { } /** *
-     * Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not
-     * asigned to a specific user_id.
+     * Is the user_group that the UserTaskRun is assigned to. Unset if UserTaskRun is not
+     * asigned to a specific user_group.
      * 
* * optional string user_group = 4; @@ -1013,8 +1013,8 @@ public java.lang.String getUserGroup() { } /** *
-     * Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not
-     * asigned to a specific user_id.
+     * Is the user_group that the UserTaskRun is assigned to. Unset if UserTaskRun is not
+     * asigned to a specific user_group.
      * 
* * optional string user_group = 4; @@ -1035,8 +1035,8 @@ public java.lang.String getUserGroup() { } /** *
-     * Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not
-     * asigned to a specific user_id.
+     * Is the user_group that the UserTaskRun is assigned to. Unset if UserTaskRun is not
+     * asigned to a specific user_group.
      * 
* * optional string user_group = 4; @@ -1053,8 +1053,8 @@ public Builder setUserGroup( } /** *
-     * Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not
-     * asigned to a specific user_id.
+     * Is the user_group that the UserTaskRun is assigned to. Unset if UserTaskRun is not
+     * asigned to a specific user_group.
      * 
* * optional string user_group = 4; @@ -1068,8 +1068,8 @@ public Builder clearUserGroup() { } /** *
-     * Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not
-     * asigned to a specific user_id.
+     * Is the user_group that the UserTaskRun is assigned to. Unset if UserTaskRun is not
+     * asigned to a specific user_group.
      * 
* * optional string user_group = 4; diff --git a/sdk-java/src/main/java/io/littlehorse/sdk/common/proto/UserTaskTriggerReferenceOrBuilder.java b/sdk-java/src/main/java/io/littlehorse/sdk/common/proto/UserTaskTriggerReferenceOrBuilder.java index 3052f74d3..01504da4d 100644 --- a/sdk-java/src/main/java/io/littlehorse/sdk/common/proto/UserTaskTriggerReferenceOrBuilder.java +++ b/sdk-java/src/main/java/io/littlehorse/sdk/common/proto/UserTaskTriggerReferenceOrBuilder.java @@ -79,8 +79,8 @@ public interface UserTaskTriggerReferenceOrBuilder extends /** *
-   * Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not
-   * asigned to a specific user_id.
+   * Is the user_group that the UserTaskRun is assigned to. Unset if UserTaskRun is not
+   * asigned to a specific user_group.
    * 
* * optional string user_group = 4; @@ -89,8 +89,8 @@ public interface UserTaskTriggerReferenceOrBuilder extends boolean hasUserGroup(); /** *
-   * Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not
-   * asigned to a specific user_id.
+   * Is the user_group that the UserTaskRun is assigned to. Unset if UserTaskRun is not
+   * asigned to a specific user_group.
    * 
* * optional string user_group = 4; @@ -99,8 +99,8 @@ public interface UserTaskTriggerReferenceOrBuilder extends java.lang.String getUserGroup(); /** *
-   * Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not
-   * asigned to a specific user_id.
+   * Is the user_group that the UserTaskRun is assigned to. Unset if UserTaskRun is not
+   * asigned to a specific user_group.
    * 
* * optional string user_group = 4; diff --git a/sdk-js/src/proto/user_tasks.ts b/sdk-js/src/proto/user_tasks.ts index 74dc7bd9a..45ffd4eaf 100644 --- a/sdk-js/src/proto/user_tasks.ts +++ b/sdk-js/src/proto/user_tasks.ts @@ -347,8 +347,8 @@ export interface UserTaskTriggerReference { | string | undefined; /** - * Is the user_id that the UserTaskRun is assigned to. Unset if UserTaskRun is not - * asigned to a specific user_id. + * Is the user_group that the UserTaskRun is assigned to. Unset if UserTaskRun is not + * asigned to a specific user_group. */ userGroup?: string | undefined; } diff --git a/sdk-python/littlehorse/model/__init__.py b/sdk-python/littlehorse/model/__init__.py index c956189c7..85f573b7e 100644 --- a/sdk-python/littlehorse/model/__init__.py +++ b/sdk-python/littlehorse/model/__init__.py @@ -5,8 +5,8 @@ from .node_run_pb2 import * from .object_id_pb2 import * from .scheduled_wf_run_pb2 import * -from .service_pb2_grpc import * from .service_pb2 import * +from .service_pb2_grpc import * from .task_def_pb2 import * from .task_run_pb2 import * from .user_tasks_pb2 import * From d31a358297887db5cf3b2928bdbd532707655515 Mon Sep 17 00:00:00 2001 From: Snarr Date: Wed, 4 Dec 2024 17:15:45 -0500 Subject: [PATCH 6/6] E2E tests verifying User details passed to WorkerContext --- .../UserTaskTriggerReferenceModel.java | 10 ++- server/src/test/java/e2e/UserTaskTest.java | 87 +++++++++++++++++++ 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/io/littlehorse/common/model/getable/core/taskrun/UserTaskTriggerReferenceModel.java b/server/src/main/java/io/littlehorse/common/model/getable/core/taskrun/UserTaskTriggerReferenceModel.java index 1dabbcca6..bfbc19448 100644 --- a/server/src/main/java/io/littlehorse/common/model/getable/core/taskrun/UserTaskTriggerReferenceModel.java +++ b/server/src/main/java/io/littlehorse/common/model/getable/core/taskrun/UserTaskTriggerReferenceModel.java @@ -60,8 +60,14 @@ public void initFrom(Message proto, ExecutionContext context) { UserTaskTriggerReference p = (UserTaskTriggerReference) proto; nodeRunId = LHSerializable.fromProto(p.getNodeRunId(), NodeRunIdModel.class, context); userTaskEventNumber = p.getUserTaskEventNumber(); - userId = p.getUserId(); - userGroup = p.getUserGroup(); + + if (p.hasUserId()) { + userId = p.getUserId(); + } + + if (p.hasUserGroup()) { + userGroup = p.getUserGroup(); + } } @Override diff --git a/server/src/test/java/e2e/UserTaskTest.java b/server/src/test/java/e2e/UserTaskTest.java index 773f6bbc8..4550ca55f 100644 --- a/server/src/test/java/e2e/UserTaskTest.java +++ b/server/src/test/java/e2e/UserTaskTest.java @@ -13,6 +13,9 @@ import io.littlehorse.sdk.common.proto.SaveUserTaskRunProgressRequest; import io.littlehorse.sdk.common.proto.SaveUserTaskRunProgressRequest.SaveUserTaskRunAssignmentPolicy; import io.littlehorse.sdk.common.proto.SearchWfRunRequest; +import io.littlehorse.sdk.common.proto.TaskRun; +import io.littlehorse.sdk.common.proto.TaskRunId; +import io.littlehorse.sdk.common.proto.TaskStatus; import io.littlehorse.sdk.common.proto.UserTaskEvent; import io.littlehorse.sdk.common.proto.UserTaskEvent.EventCase; import io.littlehorse.sdk.common.proto.UserTaskRun; @@ -62,6 +65,12 @@ public class UserTaskTest { @LHWorkflow("cancel-user-task-on-deadline") private Workflow userTaskCancelOnDeadline; + @LHWorkflow("schedule-reminder-task-without-user-fields-workflow") + private Workflow scheduleReminderTaskWithoutUserFields; + + @LHWorkflow("worker-context-receives-user-details") + private Workflow workerContextReceivesUserDetails; + @LHUserTaskForm(USER_TASK_DEF_NAME) private MyForm myForm = new MyForm(); @@ -296,6 +305,42 @@ void shouldExecuteBusinessExceptionHandlerWhenUserTaskGetsCancelOnDeadline() { .start(); } + @Test + void shouldScheduleAndExecuteReminderTask() { + workflowVerifier + .prepareRun(scheduleReminderTaskWithoutUserFields) + .waitForStatus(ERROR, Duration.ofSeconds(6)) + .thenVerifyNodeRun(0, 1, nodeRun -> { + UserTaskRunId userTaskId = nodeRun.getUserTask().getUserTaskRunId(); + UserTaskRun userTaskRun = client.getUserTaskRun(userTaskId); + UserTaskEvent userTaskEvent = userTaskRun.getEvents(1); + TaskRunId taskRunId = userTaskEvent.getTaskExecuted().getTaskRun(); + TaskRun taskRun = client.getTaskRun(taskRunId); + TaskStatus taskRunStatus = taskRun.getStatus(); + + Assertions.assertThat(taskRunStatus).isEqualTo(TaskStatus.TASK_SUCCESS); + }) + .start(); + } + + @Test + void verifyWorkerContextHasUserIdOrUserGroup() { + workflowVerifier + .prepareRun(workerContextReceivesUserDetails) + .waitForStatus(ERROR, Duration.ofSeconds(6)) + .thenVerifyNodeRun(0, 1, nodeRun -> { + UserTaskRunId userTaskId = nodeRun.getUserTask().getUserTaskRunId(); + UserTaskRun userTaskRun = client.getUserTaskRun(userTaskId); + UserTaskEvent userTaskEvent = userTaskRun.getEvents(1); + TaskRunId taskRunId = userTaskEvent.getTaskExecuted().getTaskRun(); + TaskRun taskRun = client.getTaskRun(taskRunId); + TaskStatus taskRunStatus = taskRun.getStatus(); + + Assertions.assertThat(taskRunStatus).isEqualTo(TaskStatus.TASK_SUCCESS); + }) + .start(); + } + @LHWorkflow("deadline-reassignment-workflow") public Workflow buildDeadlineReassignmentWorkflow() { return new WorkflowImpl("deadline-reassignment-workflow", entrypointThread -> { @@ -315,6 +360,30 @@ public Workflow buildDeadlineReassignmentWorkflow() { }); } + @LHWorkflow("schedule-reminder-task-without-user-fields-workflow") + public Workflow buildReminderTaskWorkflowWithUserGroupField() { + return new WorkflowImpl("reminder-task-without-user-fields-workflow", entrypointThread -> { + UserTaskOutput formOutput = entrypointThread.assignUserTask(USER_TASK_DEF_NAME, "jacob", null); + + // Schedule a reminder immediately + entrypointThread.scheduleReminderTask(formOutput, 0, "reminder-task"); + + entrypointThread.cancelUserTaskRunAfter(formOutput, 5); + }); + } + + @LHWorkflow("worker-context-receives-user-details") + public Workflow workerContextReceivesUserDetails() { + return new WorkflowImpl("worker-context-receives-user-details", entrypointThread -> { + UserTaskOutput formOutput = entrypointThread.assignUserTask(USER_TASK_DEF_NAME, "jacob", null); + + // Schedule a reminder immediately + entrypointThread.scheduleReminderTask(formOutput, 0, "verify-worker-context", "jacob", null); + + entrypointThread.cancelUserTaskRunAfter(formOutput, 5); + }); + } + @LHWorkflow("deadline-reassignment-workflow-user-without-group") public Workflow buildDeadlineReassignmentWorkflowUserWithoutGroup() { return new WorkflowImpl("deadline-reassignment-workflow-user-without-group", entrypointThread -> { @@ -369,6 +438,24 @@ public String userTaskCanceled() { public void doReminder(WorkerContext ctx) { cache.put(ctx.getWfRunId().getId(), "hello there!"); } + + @LHTaskMethod("verify-worker-context") + public void verifyWorkerContext(String userId, String userGroup, WorkerContext ctx) { + if (userId == null && userGroup == null) { + throw new IllegalStateException("At least one of userId or userGroup must be specified"); + } + + if (userId != null) { + if (!userId.equals(ctx.getUserId())) { + throw new IllegalStateException("WorkerContext UserId does not match expected value."); + } + } + if (userGroup != null) { + if (!userGroup.equals(ctx.getUserGroup())) { + throw new IllegalStateException("WorkerContext UserGroup does not match expected value."); + } + } + } } class MyForm {