From c6e0306a3217f3158de9fab5e5cdb09b04e0ce77 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Wed, 12 Feb 2025 08:16:24 -0800 Subject: [PATCH] Special behavior for Temporal built-in prefixes (#2409) --- .../io/temporal/activity/ActivityMethod.java | 2 + .../metadata/POJOActivityImplMetadata.java | 2 + .../metadata/POJOWorkflowImplMetadata.java | 3 + .../internal/common/InternalUtils.java | 59 +++++++++++ .../internal/nexus/NexusTaskHandlerImpl.java | 2 + .../internal/sync/QueryDispatcher.java | 6 ++ .../internal/sync/SignalDispatcher.java | 6 ++ .../internal/sync/UpdateDispatcher.java | 6 ++ .../io/temporal/workflow/QueryMethod.java | 3 + .../io/temporal/workflow/SignalMethod.java | 2 + .../io/temporal/workflow/UpdateMethod.java | 2 + .../io/temporal/workflow/WorkflowMethod.java | 9 +- .../workflow/WorkflowRestrictedNameTest.java | 82 ++++++++++++++ .../ActivityRestrictedNameTest.java | 87 +++++++++++++++ .../queryTests/QueryRestrictedNameTest.java | 100 ++++++++++++++++++ .../signalTests/SignalRestrictedNameTest.java | 96 +++++++++++++++++ .../updateTest/UpdateRestrictedNameTest.java | 96 +++++++++++++++++ 17 files changed, 562 insertions(+), 1 deletion(-) create mode 100644 temporal-sdk/src/test/java/io/temporal/workflow/WorkflowRestrictedNameTest.java create mode 100644 temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRestrictedNameTest.java create mode 100644 temporal-sdk/src/test/java/io/temporal/workflow/queryTests/QueryRestrictedNameTest.java create mode 100644 temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalRestrictedNameTest.java create mode 100644 temporal-sdk/src/test/java/io/temporal/workflow/updateTest/UpdateRestrictedNameTest.java diff --git a/temporal-sdk/src/main/java/io/temporal/activity/ActivityMethod.java b/temporal-sdk/src/main/java/io/temporal/activity/ActivityMethod.java index 776e5f1449..8fa6aaef2d 100644 --- a/temporal-sdk/src/main/java/io/temporal/activity/ActivityMethod.java +++ b/temporal-sdk/src/main/java/io/temporal/activity/ActivityMethod.java @@ -40,6 +40,8 @@ * *

Be careful with names that contain special characters, as these names can be used as metric * tags. Systems like Prometheus ignore metrics which have tags with unsupported characters. + * + *

Name cannot start with __temporal_ as it is reserved for internal use. */ String name() default ""; } diff --git a/temporal-sdk/src/main/java/io/temporal/common/metadata/POJOActivityImplMetadata.java b/temporal-sdk/src/main/java/io/temporal/common/metadata/POJOActivityImplMetadata.java index 3878c612cf..d9f51f91ef 100644 --- a/temporal-sdk/src/main/java/io/temporal/common/metadata/POJOActivityImplMetadata.java +++ b/temporal-sdk/src/main/java/io/temporal/common/metadata/POJOActivityImplMetadata.java @@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableList; import io.temporal.activity.ActivityMethod; import io.temporal.common.MethodRetry; +import io.temporal.internal.common.InternalUtils; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; @@ -90,6 +91,7 @@ private POJOActivityImplMetadata(Class implClass) { activityInterfaces.add(interfaceMetadata); List methods = interfaceMetadata.getMethodsMetadata(); for (POJOActivityMethodMetadata methodMetadata : methods) { + InternalUtils.checkMethodName(methodMetadata); POJOActivityMethodMetadata registeredMM = byName.put(methodMetadata.getActivityTypeName(), methodMetadata); if (registeredMM != null && !registeredMM.equals(methodMetadata)) { diff --git a/temporal-sdk/src/main/java/io/temporal/common/metadata/POJOWorkflowImplMetadata.java b/temporal-sdk/src/main/java/io/temporal/common/metadata/POJOWorkflowImplMetadata.java index 8a21fc76fd..e65621f1fc 100644 --- a/temporal-sdk/src/main/java/io/temporal/common/metadata/POJOWorkflowImplMetadata.java +++ b/temporal-sdk/src/main/java/io/temporal/common/metadata/POJOWorkflowImplMetadata.java @@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableList; import io.temporal.common.Experimental; +import io.temporal.internal.common.InternalUtils; import io.temporal.internal.common.env.ReflectionUtils; import java.lang.reflect.Constructor; import java.util.*; @@ -145,6 +146,8 @@ private POJOWorkflowImplMetadata( + methodMetadata.getWorkflowMethod() + "\""); } + // Validate the method name is not using any reserved prefixes or names. + InternalUtils.checkMethodName(methodMetadata); switch (methodMetadata.getType()) { case WORKFLOW: workflowMethods.put(methodMetadata.getName(), methodMetadata); diff --git a/temporal-sdk/src/main/java/io/temporal/internal/common/InternalUtils.java b/temporal-sdk/src/main/java/io/temporal/internal/common/InternalUtils.java index f9fa4c637e..a0e0798467 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/common/InternalUtils.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/common/InternalUtils.java @@ -22,11 +22,15 @@ import com.google.common.base.Defaults; import io.nexusrpc.Header; +import io.nexusrpc.handler.ServiceImplInstance; import io.temporal.api.common.v1.Callback; import io.temporal.api.enums.v1.TaskQueueKind; import io.temporal.api.taskqueue.v1.TaskQueue; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; +import io.temporal.common.metadata.POJOActivityMethodMetadata; +import io.temporal.common.metadata.POJOWorkflowMethodMetadata; +import io.temporal.common.metadata.WorkflowMethodType; import io.temporal.internal.client.NexusStartWorkflowRequest; import java.util.Arrays; import java.util.Map; @@ -37,7 +41,11 @@ /** Utility functions shared by the implementation code. */ public final class InternalUtils { + public static String TEMPORAL_RESERVED_PREFIX = "__temporal_"; + private static final Logger log = LoggerFactory.getLogger(InternalUtils.class); + private static String QUERY_TYPE_STACK_TRACE = "__stack_trace"; + private static String ENHANCED_QUERY_TYPE_STACK_TRACE = "__enhanced_stack_trace"; public static TaskQueue createStickyTaskQueue( String stickyTaskQueueName, String normalTaskQueueName) { @@ -135,6 +143,57 @@ public static WorkflowStub createNexusBoundStub( return stub.newInstance(nexusWorkflowOptions.build()); } + /** Check the method name for reserved prefixes or names. */ + public static void checkMethodName(POJOWorkflowMethodMetadata methodMetadata) { + if (methodMetadata.getName().startsWith(TEMPORAL_RESERVED_PREFIX)) { + throw new IllegalArgumentException( + methodMetadata.getType().toString().toLowerCase() + + " name \"" + + methodMetadata.getName() + + "\" must not start with \"" + + TEMPORAL_RESERVED_PREFIX + + "\""); + } + if (methodMetadata.getType().equals(WorkflowMethodType.QUERY) + && (methodMetadata.getName().equals(QUERY_TYPE_STACK_TRACE) + || methodMetadata.getName().equals(ENHANCED_QUERY_TYPE_STACK_TRACE))) { + throw new IllegalArgumentException( + "Query method name \"" + methodMetadata.getName() + "\" is reserved for internal use"); + } + } + + public static void checkMethodName(POJOActivityMethodMetadata methodMetadata) { + if (methodMetadata.getActivityTypeName().startsWith(TEMPORAL_RESERVED_PREFIX)) { + throw new IllegalArgumentException( + "Activity name \"" + + methodMetadata.getActivityTypeName() + + "\" must not start with \"" + + TEMPORAL_RESERVED_PREFIX + + "\""); + } + } + /** Prohibit instantiation */ private InternalUtils() {} + + public static void checkMethodName(ServiceImplInstance instance) { + if (instance.getDefinition().getName().startsWith(TEMPORAL_RESERVED_PREFIX)) { + throw new IllegalArgumentException( + "Service name \"" + + instance.getDefinition().getName() + + "\" must not start with \"" + + TEMPORAL_RESERVED_PREFIX + + "\""); + } + for (String operationName : instance.getDefinition().getOperations().keySet()) { + if (operationName.startsWith(TEMPORAL_RESERVED_PREFIX)) { + throw new IllegalArgumentException( + "Operation name \"" + + operationName + + "\" must not start with \"" + + TEMPORAL_RESERVED_PREFIX + + "\""); + } + } + } } diff --git a/temporal-sdk/src/main/java/io/temporal/internal/nexus/NexusTaskHandlerImpl.java b/temporal-sdk/src/main/java/io/temporal/internal/nexus/NexusTaskHandlerImpl.java index fb7a0d0d3a..ead9ae2989 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/nexus/NexusTaskHandlerImpl.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/nexus/NexusTaskHandlerImpl.java @@ -35,6 +35,7 @@ import io.temporal.common.converter.DataConverter; import io.temporal.common.interceptors.WorkerInterceptor; import io.temporal.failure.ApplicationFailure; +import io.temporal.internal.common.InternalUtils; import io.temporal.internal.common.NexusUtil; import io.temporal.internal.worker.NexusTask; import io.temporal.internal.worker.NexusTaskHandler; @@ -331,6 +332,7 @@ private void registerNexusService(Object nexusService) { throw new IllegalArgumentException("Nexus service object instance expected, not the class"); } ServiceImplInstance instance = ServiceImplInstance.fromInstance(nexusService); + InternalUtils.checkMethodName(instance); if (serviceImplInstances.put(instance.getDefinition().getName(), instance) != null) { throw new TypeAlreadyRegisteredException( instance.getDefinition().getName(), diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/QueryDispatcher.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/QueryDispatcher.java index ac0597a0d8..371c723343 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/sync/QueryDispatcher.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/sync/QueryDispatcher.java @@ -20,6 +20,8 @@ package io.temporal.internal.sync; +import static io.temporal.internal.common.InternalUtils.TEMPORAL_RESERVED_PREFIX; + import io.temporal.api.common.v1.Payloads; import io.temporal.api.sdk.v1.WorkflowInteractionDefinition; import io.temporal.common.converter.DataConverter; @@ -72,6 +74,10 @@ public WorkflowInboundCallsInterceptor.QueryOutput handleInterceptedQuery( public Optional handleQuery(String queryName, Header header, Optional input) { WorkflowOutboundCallsInterceptor.RegisterQueryInput handler = queryCallbacks.get(queryName); Object[] args; + if (queryName.startsWith(TEMPORAL_RESERVED_PREFIX)) { + throw new IllegalArgumentException( + "Unknown query type: " + queryName + ", knownTypes=" + queryCallbacks.keySet()); + } if (handler == null) { if (dynamicQueryHandler == null) { throw new IllegalArgumentException( diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/SignalDispatcher.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/SignalDispatcher.java index 6a0b5c1cf2..1b5c20ab29 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/sync/SignalDispatcher.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/sync/SignalDispatcher.java @@ -20,6 +20,8 @@ package io.temporal.internal.sync; +import static io.temporal.internal.common.InternalUtils.TEMPORAL_RESERVED_PREFIX; + import io.temporal.api.common.v1.Payloads; import io.temporal.api.sdk.v1.WorkflowInteractionDefinition; import io.temporal.common.converter.DataConverter; @@ -86,6 +88,10 @@ public void handleSignal( signalCallbacks.get(signalName); Object[] args; HandlerUnfinishedPolicy policy; + if (signalName.startsWith(TEMPORAL_RESERVED_PREFIX)) { + // Ignore internal signals + return; + } if (handler == null) { if (dynamicSignalHandler == null) { signalBuffer.add(new SignalData(signalName, input, eventId, header)); diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/UpdateDispatcher.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/UpdateDispatcher.java index f4328aa7c8..70856175f2 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/sync/UpdateDispatcher.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/sync/UpdateDispatcher.java @@ -20,6 +20,8 @@ package io.temporal.internal.sync; +import static io.temporal.internal.common.InternalUtils.TEMPORAL_RESERVED_PREFIX; + import io.temporal.api.common.v1.Payloads; import io.temporal.api.sdk.v1.WorkflowInteractionDefinition; import io.temporal.common.converter.DataConverter; @@ -61,6 +63,10 @@ public void handleValidateUpdate( updateCallbacks.get(updateName); Object[] args; HandlerUnfinishedPolicy policy; + if (updateName.startsWith(TEMPORAL_RESERVED_PREFIX)) { + throw new IllegalArgumentException( + "Unknown update name: " + updateName + ", knownTypes=" + updateCallbacks.keySet()); + } if (handler == null) { if (dynamicUpdateHandler == null) { throw new IllegalArgumentException( diff --git a/temporal-sdk/src/main/java/io/temporal/workflow/QueryMethod.java b/temporal-sdk/src/main/java/io/temporal/workflow/QueryMethod.java index c1ceb78d3d..6207da215d 100644 --- a/temporal-sdk/src/main/java/io/temporal/workflow/QueryMethod.java +++ b/temporal-sdk/src/main/java/io/temporal/workflow/QueryMethod.java @@ -41,6 +41,9 @@ * *

Be careful about names that contain special characters. These names can be used as metric * tags. And systems like prometheus ignore metrics which have tags with unsupported characters. + * + *

Name cannot start with __temporal as it is reserved for internal use. The name also cannot + * be __stack_trace or __enhanced_stack_trace as they are reserved for internal use. */ String name() default ""; diff --git a/temporal-sdk/src/main/java/io/temporal/workflow/SignalMethod.java b/temporal-sdk/src/main/java/io/temporal/workflow/SignalMethod.java index b3839720af..57830c2ae9 100644 --- a/temporal-sdk/src/main/java/io/temporal/workflow/SignalMethod.java +++ b/temporal-sdk/src/main/java/io/temporal/workflow/SignalMethod.java @@ -57,6 +57,8 @@ * *

Be careful about names that contain special characters. These names can be used as metric * tags. And systems like prometheus ignore metrics which have tags with unsupported characters. + * + *

Name cannot start with __temporal_ as it is reserved for internal use. */ String name() default ""; diff --git a/temporal-sdk/src/main/java/io/temporal/workflow/UpdateMethod.java b/temporal-sdk/src/main/java/io/temporal/workflow/UpdateMethod.java index 5a52be4e17..0e2d920d44 100644 --- a/temporal-sdk/src/main/java/io/temporal/workflow/UpdateMethod.java +++ b/temporal-sdk/src/main/java/io/temporal/workflow/UpdateMethod.java @@ -39,6 +39,8 @@ * *

Be careful about names that contain special characters. These names can be used as metric * tags. And systems like prometheus ignore metrics which have tags with unsupported characters. + * + *

Name cannot start with __temporal as it is reserved for internal use. */ String name() default ""; diff --git a/temporal-sdk/src/main/java/io/temporal/workflow/WorkflowMethod.java b/temporal-sdk/src/main/java/io/temporal/workflow/WorkflowMethod.java index 1afee4830b..729f6919ca 100644 --- a/temporal-sdk/src/main/java/io/temporal/workflow/WorkflowMethod.java +++ b/temporal-sdk/src/main/java/io/temporal/workflow/WorkflowMethod.java @@ -33,6 +33,13 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface WorkflowMethod { - /** Name of the workflow type. Default is {short class name} */ + /** + * Name of the workflow type. Default is {short class name}. + * + *

Be careful with names that contain special characters, as these names can be used as metric + * tags. Systems like Prometheus ignore metrics which have tags with unsupported characters. + * + *

Name cannot start with __temporal_ as it is reserved for internal use. + */ String name() default ""; } diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowRestrictedNameTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowRestrictedNameTest.java new file mode 100644 index 0000000000..4dc7c8edcd --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowRestrictedNameTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material 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 io.temporal.workflow; + +import io.temporal.testing.internal.SDKTestWorkflowRule; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class WorkflowRestrictedNameTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder().setDoNotStart(true).build(); + + @Test + public void testRegisteringRestrictedWorkflowMethod() { + IllegalArgumentException e = + Assert.assertThrows( + IllegalArgumentException.class, + () -> + testWorkflowRule + .getWorker() + .registerWorkflowImplementationTypes(WorkflowMethodWithOverrideNameImpl.class)); + Assert.assertEquals( + "workflow name \"__temporal_workflow\" must not start with \"__temporal_\"", + e.getMessage()); + + e = + Assert.assertThrows( + IllegalArgumentException.class, + () -> + testWorkflowRule + .getWorker() + .registerWorkflowImplementationTypes(WorkflowMethodRestrictedImpl.class)); + Assert.assertEquals( + "workflow name \"__temporal_workflow\" must not start with \"__temporal_\"", + e.getMessage()); + } + + @WorkflowInterface + public interface WorkflowMethodWithOverrideNameRestricted { + @WorkflowMethod(name = "__temporal_workflow") + void workflowMethod(); + } + + public static class WorkflowMethodWithOverrideNameImpl + implements WorkflowMethodWithOverrideNameRestricted { + + @Override + public void workflowMethod() {} + } + + @WorkflowInterface + public interface __temporal_workflow { + @WorkflowMethod + void workflowMethod(); + } + + public static class WorkflowMethodRestrictedImpl implements __temporal_workflow { + @Override + public void workflowMethod() {} + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRestrictedNameTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRestrictedNameTest.java new file mode 100644 index 0000000000..b0c1eac434 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRestrictedNameTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material 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 io.temporal.workflow.activityTests; + +import io.temporal.activity.*; +import io.temporal.testing.internal.SDKTestWorkflowRule; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class ActivityRestrictedNameTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder().setDoNotStart(true).build(); + + @Test + public void testRegisteringRestrictedActivity() { + IllegalArgumentException e = + Assert.assertThrows( + IllegalArgumentException.class, + () -> + testWorkflowRule + .getWorker() + .registerActivitiesImplementations(new ActivityWithRestrictedNamesImpl())); + Assert.assertEquals( + "Activity name \"__temporal_activity\" must not start with \"__temporal_\"", + e.getMessage()); + + e = + Assert.assertThrows( + IllegalArgumentException.class, + () -> + testWorkflowRule + .getWorker() + .registerActivitiesImplementations( + new ActivityWithRestrictedOverrideNameImpl())); + Assert.assertEquals( + "Activity name \"__temporal_activity\" must not start with \"__temporal_\"", + e.getMessage()); + } + + @ActivityInterface + public interface ActivityWithRestrictedOverrideName { + + @ActivityMethod(name = "__temporal_activity") + String temporalActivity(String workflowId); + } + + public static class ActivityWithRestrictedOverrideNameImpl + implements ActivityWithRestrictedOverrideName { + @Override + public String temporalActivity(String workflowId) { + return null; + } + } + + @ActivityInterface + public interface ActivityWithRestrictedNames { + String __temporal_activity(String workflowId); + } + + public static class ActivityWithRestrictedNamesImpl implements ActivityWithRestrictedNames { + @Override + public String __temporal_activity(String workflowId) { + return null; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/queryTests/QueryRestrictedNameTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/queryTests/QueryRestrictedNameTest.java new file mode 100644 index 0000000000..dbac704283 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/queryTests/QueryRestrictedNameTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material 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 io.temporal.workflow.queryTests; + +import io.temporal.testing.internal.SDKTestWorkflowRule; +import io.temporal.workflow.QueryMethod; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class QueryRestrictedNameTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder().setDoNotStart(true).build(); + + @Test + public void testRegisteringRestrictedQueryMethod() { + IllegalArgumentException e = + Assert.assertThrows( + IllegalArgumentException.class, + () -> + testWorkflowRule + .getWorker() + .registerWorkflowImplementationTypes( + QueryMethodWithOverrideNameRestrictedImpl.class)); + Assert.assertEquals( + "query name \"__temporal_query\" must not start with \"__temporal_\"", e.getMessage()); + + e = + Assert.assertThrows( + IllegalArgumentException.class, + () -> + testWorkflowRule + .getWorker() + .registerWorkflowImplementationTypes(QueryMethodNameRestrictedImpl.class)); + Assert.assertEquals( + "query name \"__temporal_query\" must not start with \"__temporal_\"", e.getMessage()); + } + + @WorkflowInterface + public interface QueryMethodWithOverrideNameRestricted { + @WorkflowMethod + void workflowMethod(); + + @QueryMethod(name = "__temporal_query") + int queryMethod(); + } + + public static class QueryMethodWithOverrideNameRestrictedImpl + implements QueryMethodWithOverrideNameRestricted { + + @Override + public void workflowMethod() {} + + @Override + public int queryMethod() { + return 0; + } + } + + @WorkflowInterface + public interface QueryMethodNameRestricted { + @WorkflowMethod + void workflowMethod(); + + @QueryMethod() + int __temporal_query(); + } + + public static class QueryMethodNameRestrictedImpl implements QueryMethodNameRestricted { + @Override + public void workflowMethod() {} + + @Override + public int __temporal_query() { + return 0; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalRestrictedNameTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalRestrictedNameTest.java new file mode 100644 index 0000000000..fd8396a1dc --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalRestrictedNameTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material 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 io.temporal.workflow.signalTests; + +import io.temporal.testing.internal.SDKTestWorkflowRule; +import io.temporal.workflow.SignalMethod; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class SignalRestrictedNameTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder().setDoNotStart(true).build(); + + @Test + public void testRegisteringRestrictedSignalMethod() { + IllegalArgumentException e = + Assert.assertThrows( + IllegalArgumentException.class, + () -> + testWorkflowRule + .getWorker() + .registerWorkflowImplementationTypes( + SignalMethodWithOverrideNameRestrictedImpl.class)); + Assert.assertEquals( + "signal name \"__temporal_signal\" must not start with \"__temporal_\"", e.getMessage()); + + e = + Assert.assertThrows( + IllegalArgumentException.class, + () -> + testWorkflowRule + .getWorker() + .registerWorkflowImplementationTypes(SignalMethodNameRestrictedImpl.class)); + Assert.assertEquals( + "signal name \"__temporal_signal\" must not start with \"__temporal_\"", e.getMessage()); + } + + @WorkflowInterface + public interface SignalMethodWithOverrideNameRestricted { + @WorkflowMethod + void workflowMethod(); + + @SignalMethod(name = "__temporal_signal") + void signalMethod(); + } + + public static class SignalMethodWithOverrideNameRestrictedImpl + implements SignalMethodWithOverrideNameRestricted { + + @Override + public void workflowMethod() {} + + @Override + public void signalMethod() {} + } + + @WorkflowInterface + public interface SignalMethodNameRestricted { + @WorkflowMethod + void workflowMethod(); + + @SignalMethod() + void __temporal_signal(); + } + + public static class SignalMethodNameRestrictedImpl implements SignalMethodNameRestricted { + @Override + public void workflowMethod() {} + + @Override + public void __temporal_signal() {} + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/updateTest/UpdateRestrictedNameTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/updateTest/UpdateRestrictedNameTest.java new file mode 100644 index 0000000000..dc4e291e32 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/updateTest/UpdateRestrictedNameTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material 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 io.temporal.workflow.updateTest; + +import io.temporal.testing.internal.SDKTestWorkflowRule; +import io.temporal.workflow.UpdateMethod; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class UpdateRestrictedNameTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder().setDoNotStart(true).build(); + + @Test + public void testRegisteringRestrictedUpdateMethod() { + IllegalArgumentException e = + Assert.assertThrows( + IllegalArgumentException.class, + () -> + testWorkflowRule + .getWorker() + .registerWorkflowImplementationTypes( + UpdateMethodWithOverrideNameRestrictedImpl.class)); + Assert.assertEquals( + "update name \"__temporal_update\" must not start with \"__temporal_\"", e.getMessage()); + + e = + Assert.assertThrows( + IllegalArgumentException.class, + () -> + testWorkflowRule + .getWorker() + .registerWorkflowImplementationTypes(UpdateMethodNameRestrictedImpl.class)); + Assert.assertEquals( + "update name \"__temporal_update\" must not start with \"__temporal_\"", e.getMessage()); + } + + @WorkflowInterface + public interface UpdateMethodWithOverrideNameRestricted { + @WorkflowMethod + void workflowMethod(); + + @UpdateMethod(name = "__temporal_update") + void updateMethod(); + } + + public static class UpdateMethodWithOverrideNameRestrictedImpl + implements UpdateMethodWithOverrideNameRestricted { + + @Override + public void workflowMethod() {} + + @Override + public void updateMethod() {} + } + + @WorkflowInterface + public interface UpdateMethodNameRestricted { + @WorkflowMethod + void workflowMethod(); + + @UpdateMethod() + void __temporal_update(); + } + + public static class UpdateMethodNameRestrictedImpl implements UpdateMethodNameRestricted { + @Override + public void workflowMethod() {} + + @Override + public void __temporal_update() {} + } +}