-
Notifications
You must be signed in to change notification settings - Fork 373
Add Dapr.IntegrationTest.Actors integration test project and fix actor HTTP endpoint configuration #1779
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Dapr.IntegrationTest.Actors integration test project and fix actor HTTP endpoint configuration #1779
Changes from 2 commits
4db41e7
08fddef
39f1e5c
bfcd903
458f903
80f9701
3ad5781
79b4c15
7e36f56
dd0d3aa
209a127
9ef7a54
375dfeb
e9fea7f
410434f
3c48728
036a216
fa92455
6b882d6
1e4e1b6
8c7a6f3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| // ------------------------------------------------------------------------ | ||
| // Copyright 2025 The Dapr Authors | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file 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. | ||
| // ------------------------------------------------------------------------ | ||
|
|
||
| using System; | ||
| using System.Threading.Tasks; | ||
| using Dapr.Actors.Runtime; | ||
|
|
||
| namespace Dapr.IntegrationTest.Actors.ExceptionTesting; | ||
|
|
||
| /// <summary> | ||
| /// Implementation of <see cref="IExceptionActor"/> that unconditionally throws to | ||
| /// validate that the Dapr runtime correctly propagates remote exceptions to callers. | ||
| /// </summary> | ||
| public class ExceptionActor : Actor, IExceptionActor | ||
| { | ||
| /// <summary> | ||
| /// Initializes a new instance of <see cref="ExceptionActor"/>. | ||
| /// </summary> | ||
| /// <param name="host">The actor host provided by the Dapr runtime.</param> | ||
| public ExceptionActor(ActorHost host) : base(host) | ||
| { | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public Task Ping() => Task.CompletedTask; | ||
|
|
||
| /// <inheritdoc /> | ||
| public Task ExceptionExample() => | ||
| throw new InvalidOperationException("This exception is intentional."); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| // ------------------------------------------------------------------------ | ||
| // Copyright 2025 The Dapr Authors | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file 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. | ||
| // ------------------------------------------------------------------------ | ||
|
|
||
| using System.Threading.Tasks; | ||
| using Dapr.Actors; | ||
|
|
||
| namespace Dapr.IntegrationTest.Actors.ExceptionTesting; | ||
|
|
||
| /// <summary> | ||
| /// Actor interface that deliberately throws an exception to exercise error propagation. | ||
| /// </summary> | ||
| public interface IExceptionActor : IPingActor, IActor | ||
| { | ||
| /// <summary>Always throws an <see cref="System.Exception"/> to validate remote exception handling.</summary> | ||
| Task ExceptionExample(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| // ------------------------------------------------------------------------ | ||
| // Copyright 2025 The Dapr Authors | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file 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. | ||
| // ------------------------------------------------------------------------ | ||
|
|
||
| using System.Threading.Tasks; | ||
| using Dapr.Actors; | ||
|
|
||
| namespace Dapr.IntegrationTest.Actors; | ||
|
|
||
| /// <summary> | ||
| /// Minimal actor interface used as a readiness probe. | ||
| /// </summary> | ||
| public interface IPingActor : IActor | ||
| { | ||
| /// <summary>Pings the actor to verify that the runtime is available.</summary> | ||
| Task Ping(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| // ------------------------------------------------------------------------ | ||
| // Copyright 2025 The Dapr Authors | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file 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. | ||
| // ------------------------------------------------------------------------ | ||
|
|
||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Threading.Tasks; | ||
| using Dapr.Actors; | ||
|
|
||
| namespace Dapr.IntegrationTest.Actors.Reentrancy; | ||
|
|
||
| /// <summary> | ||
| /// Options controlling how a reentrant call chain is executed. | ||
| /// </summary> | ||
| public sealed class ReentrantCallOptions | ||
| { | ||
| /// <summary>Gets or sets the number of additional reentrant calls remaining to make.</summary> | ||
| public int CallsRemaining { get; set; } | ||
|
|
||
| /// <summary>Gets or sets the zero-based sequence number of the current call.</summary> | ||
| public int CallNumber { get; set; } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Records a single enter or exit event within a reentrant call chain. | ||
| /// </summary> | ||
| public sealed class CallRecord | ||
| { | ||
| /// <summary>Gets or sets a value indicating whether this record represents an entry (<see langword="true"/>) or exit (<see langword="false"/>).</summary> | ||
| public bool IsEnter { get; set; } | ||
|
|
||
| /// <summary>Gets or sets the wall-clock time of this event.</summary> | ||
| public DateTime Timestamp { get; set; } | ||
|
|
||
| /// <summary>Gets or sets the sequence number of the call that produced this record.</summary> | ||
| public int CallNumber { get; set; } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Per-call state kept by <see cref="IReentrantActor"/>. | ||
| /// </summary> | ||
| public sealed class ReentrantCallState | ||
| { | ||
| /// <summary>Gets the ordered list of enter/exit records for a single call number.</summary> | ||
| public List<CallRecord> Records { get; init; } = []; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Actor interface that exercises Dapr actor reentrancy. | ||
| /// </summary> | ||
| public interface IReentrantActor : IPingActor, IActor | ||
| { | ||
| /// <summary>Initiates a reentrant call chain as described by <paramref name="callOptions"/>.</summary> | ||
| /// <param name="callOptions">Controls the depth and sequence number of the reentrant chain.</param> | ||
| Task ReentrantCall(ReentrantCallOptions callOptions); | ||
|
|
||
| /// <summary>Returns the enter/exit records accumulated for the given <paramref name="callNumber"/>.</summary> | ||
| /// <param name="callNumber">The zero-based call number to retrieve state for.</param> | ||
| Task<ReentrantCallState> GetState(int callNumber); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| // ------------------------------------------------------------------------ | ||
| // Copyright 2025 The Dapr Authors | ||
|
WhitWaldo marked this conversation as resolved.
Outdated
|
||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file 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. | ||
| // ------------------------------------------------------------------------ | ||
|
|
||
| using System; | ||
| using System.Threading.Tasks; | ||
| using Dapr.Actors.Runtime; | ||
|
|
||
| namespace Dapr.IntegrationTest.Actors.Reentrancy; | ||
|
|
||
| /// <summary> | ||
| /// Implementation of <see cref="IReentrantActor"/> that recursively calls itself | ||
| /// to produce a chain of reentrant invocations. | ||
| /// </summary> | ||
| public class ReentrantActor : Actor, IReentrantActor | ||
| { | ||
| /// <summary> | ||
| /// Initializes a new instance of <see cref="ReentrantActor"/>. | ||
| /// </summary> | ||
| /// <param name="host">The actor host provided by the Dapr runtime.</param> | ||
| public ReentrantActor(ActorHost host) : base(host) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefer to use primary constructors where possible
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Converted all actor implementations ( |
||
| { | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public Task Ping() => Task.CompletedTask; | ||
|
|
||
| /// <inheritdoc /> | ||
| public async Task ReentrantCall(ReentrantCallOptions callOptions) | ||
| { | ||
| await UpdateState(isEnter: true, callOptions.CallNumber); | ||
|
|
||
| var self = ProxyFactory.CreateActorProxy<IReentrantActor>(Id, "ReentrantActor"); | ||
| if (callOptions.CallsRemaining <= 1) | ||
| { | ||
| await self.Ping(); | ||
| } | ||
| else | ||
| { | ||
| await self.ReentrantCall(new ReentrantCallOptions | ||
| { | ||
| CallsRemaining = callOptions.CallsRemaining - 1, | ||
| CallNumber = callOptions.CallNumber + 1, | ||
| }); | ||
| } | ||
|
|
||
| await UpdateState(isEnter: false, callOptions.CallNumber); | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public Task<ReentrantCallState> GetState(int callNumber) => | ||
| StateManager.GetOrAddStateAsync($"reentrant-record{callNumber}", new ReentrantCallState()); | ||
|
|
||
| private async Task UpdateState(bool isEnter, int callNumber) | ||
| { | ||
| var stateKey = $"reentrant-record{callNumber}"; | ||
| var state = await StateManager.GetOrAddStateAsync(stateKey, new ReentrantCallState()); | ||
| state.Records.Add(new CallRecord | ||
| { | ||
| IsEnter = isEnter, | ||
| Timestamp = DateTime.Now, | ||
| CallNumber = callNumber, | ||
| }); | ||
| await StateManager.SetStateAsync(stateKey, state); | ||
|
|
||
| if (!isEnter) | ||
| { | ||
| await StateManager.SaveStateAsync(); | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.