diff --git a/src/Temporalio/Bridge/EphemeralServer.cs b/src/Temporalio/Bridge/EphemeralServer.cs
index 42aa8bbf..df6b2b68 100644
--- a/src/Temporalio/Bridge/EphemeralServer.cs
+++ b/src/Temporalio/Bridge/EphemeralServer.cs
@@ -40,12 +40,12 @@ private unsafe EphemeralServer(
public bool HasTestService { get; private init; }
///
- /// Start Temporalite.
+ /// Start dev server.
///
/// Runtime to use.
/// Options to use.
/// Started server.
- public static async Task StartTemporaliteAsync(
+ public static async Task StartDevServerAsync(
Runtime runtime,
Testing.WorkflowEnvironmentStartLocalOptions options)
{
diff --git a/src/Temporalio/Bridge/OptionsExtensions.cs b/src/Temporalio/Bridge/OptionsExtensions.cs
index 80c09ef8..be0a89e3 100644
--- a/src/Temporalio/Bridge/OptionsExtensions.cs
+++ b/src/Temporalio/Bridge/OptionsExtensions.cs
@@ -352,6 +352,17 @@ public static unsafe Interop.DevServerOptions ToInteropOptions(
// Use TargetHost to get IP + Port
options.ParseTargetHost(out string? ip, out int? port);
ip ??= "127.0.0.1";
+
+ // If there are search attributes, prepend them to the args
+ var args = options.DevServerOptions.ExtraArgs;
+ if (options.SearchAttributes is { } attrs && attrs.Count > 0)
+ {
+ args = attrs.
+ SelectMany(v => new[] { "--search-attribute", $"{v.Name}={v.ValueType}" }).
+ Concat(args ?? Enumerable.Empty()).
+ ToArray();
+ }
+
return new Interop.DevServerOptions()
{
test_server = scope.Pointer(
@@ -363,7 +374,7 @@ public static unsafe Interop.DevServerOptions ToInteropOptions(
download_version = scope.ByteArray(options.DevServerOptions.DownloadVersion),
download_dest_dir = scope.ByteArray(options.DownloadDirectory),
port = (ushort)(port ?? 0),
- extra_args = scope.NewlineDelimited(options.DevServerOptions.ExtraArgs),
+ extra_args = scope.NewlineDelimited(args),
}),
namespace_ = scope.ByteArray(options.Namespace),
ip = scope.ByteArray(ip),
diff --git a/src/Temporalio/Testing/WorkflowEnvironment.cs b/src/Temporalio/Testing/WorkflowEnvironment.cs
index e26d88d6..6dc67d01 100644
--- a/src/Temporalio/Testing/WorkflowEnvironment.cs
+++ b/src/Temporalio/Testing/WorkflowEnvironment.cs
@@ -67,7 +67,7 @@ public static async Task StartLocalAsync(
{
options ??= new();
var runtime = options.Runtime ?? TemporalRuntime.Default;
- var server = await Bridge.EphemeralServer.StartTemporaliteAsync(
+ var server = await Bridge.EphemeralServer.StartDevServerAsync(
runtime.Runtime,
options).ConfigureAwait(false);
return await StartEphemeralAsync(server, options).ConfigureAwait(false);
diff --git a/src/Temporalio/Testing/WorkflowEnvironmentStartLocalOptions.cs b/src/Temporalio/Testing/WorkflowEnvironmentStartLocalOptions.cs
index 4bc33f54..6e3db018 100644
--- a/src/Temporalio/Testing/WorkflowEnvironmentStartLocalOptions.cs
+++ b/src/Temporalio/Testing/WorkflowEnvironmentStartLocalOptions.cs
@@ -1,3 +1,6 @@
+using System.Collections.Generic;
+using Temporalio.Common;
+
namespace Temporalio.Testing
{
///
@@ -18,6 +21,11 @@ public class WorkflowEnvironmentStartLocalOptions : Client.TemporalClientConnect
///
public bool UI { get; set; }
+ ///
+ /// Gets or sets search attributes registered on the dev server on start.
+ ///
+ public IReadOnlyCollection? SearchAttributes { get; set; }
+
///
/// Gets or sets unstable dev server options.
///
diff --git a/tests/Temporalio.Tests/Testing/WorkflowEnvironmentTests.cs b/tests/Temporalio.Tests/Testing/WorkflowEnvironmentTests.cs
index 3bb60884..045100bd 100644
--- a/tests/Temporalio.Tests/Testing/WorkflowEnvironmentTests.cs
+++ b/tests/Temporalio.Tests/Testing/WorkflowEnvironmentTests.cs
@@ -7,6 +7,7 @@ namespace Temporalio.Tests.Testing;
using Temporalio.Activities;
using Temporalio.Api.Enums.V1;
using Temporalio.Client;
+using Temporalio.Common;
using Temporalio.Exceptions;
using Temporalio.Testing;
using Temporalio.Worker;
@@ -199,4 +200,54 @@ await env.Client.ExecuteWorkflowAsync(
});
});
}
+
+ [Fact]
+ public async Task StartLocal_SearchAttributes_ProperlyRegistered()
+ {
+ // Prepare attrs
+ var attrBool = SearchAttributeKey.CreateBool("DotNetTemporalTestBool");
+ var attrDateTime = SearchAttributeKey.CreateDateTimeOffset("DotNetTemporalTestDateTime");
+ var attrDouble = SearchAttributeKey.CreateDouble("DotNetTemporalTestDouble");
+ var attrKeyword = SearchAttributeKey.CreateKeyword("DotNetTemporalTestKeyword");
+ var attrKeywordList = SearchAttributeKey.CreateKeywordList("DotNetTemporalTestKeywordList");
+ var attrLong = SearchAttributeKey.CreateLong("DotNetTemporalTestLong");
+ var attrText = SearchAttributeKey.CreateText("DotNetTemporalTestText");
+ var attrVals = new SearchAttributeCollection.Builder().
+ Set(attrBool, true).
+ Set(attrDateTime, new DateTimeOffset(2001, 1, 1, 0, 0, 0, TimeSpan.Zero)).
+ Set(attrDouble, 123.45).
+ Set(attrKeyword, "SomeKeyword").
+ Set(attrKeywordList, new[] { "SomeKeyword1", "SomeKeyword2" }).
+ Set(attrLong, 678).
+ Set(attrText, "SomeText").
+ ToSearchAttributeCollection();
+ var attrs = new SearchAttributeKey[]
+ {
+ attrBool, attrDateTime, attrDouble, attrKeyword, attrKeywordList, attrLong, attrText,
+ };
+
+ // Confirm that when used in env without SAs it fails
+ await using var env1 = await WorkflowEnvironment.StartLocalAsync();
+ var exc = await Assert.ThrowsAsync(
+ () => env1.Client.StartWorkflowAsync(
+ "my-workflow",
+ Array.Empty