diff --git a/src/Dapr.Actors/ActorReference.cs b/src/Dapr.Actors/ActorReference.cs index 0e199c3ae..d72b6676f 100644 --- a/src/Dapr.Actors/ActorReference.cs +++ b/src/Dapr.Actors/ActorReference.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ // Copyright 2021 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. @@ -16,6 +16,7 @@ namespace Dapr.Actors using System; using System.Runtime.Serialization; using Dapr.Actors.Client; + using Dapr.Actors.Runtime; /// /// Encapsulation of a reference to an actor for serialization. @@ -69,23 +70,28 @@ public object Bind(Type actorInterfaceType) private static ActorReference GetActorReference(object actor) { - if (actor == null) - { - throw new ArgumentNullException("actor"); - } + ArgumentNullException.ThrowIfNull(actor, nameof(actor)); - // try as IActorProxy for backward compatibility as customers's mock framework may rely on it before V2 remoting stack. - if (actor is IActorProxy actorProxy) + var actorReference = actor switch { - return new ActorReference() + // try as IActorProxy for backward compatibility as customers's mock framework may rely on it before V2 remoting stack. + IActorProxy actorProxy => new ActorReference() { ActorId = actorProxy.ActorId, ActorType = actorProxy.ActorType, - }; - } + }, + // Handle case when we want to get ActorReference inside the Actor implementation, + // we gather actor id and actor type from Actor base class. + Actor actorBase => new ActorReference() + { + ActorId = actorBase.Id, + ActorType = actorBase.Host.ActorTypeInfo.ActorTypeName, + }, + // Handle case when we can't cast to IActorProxy or Actor. + _ => throw new ArgumentOutOfRangeException("actor", "Invalid actor object type."), + }; - // TODO check for ActorBase - throw new ArgumentOutOfRangeException("actor"); + return actorReference; } } } diff --git a/test/Dapr.Actors.Test/ActorReferenceTests.cs b/test/Dapr.Actors.Test/ActorReferenceTests.cs new file mode 100644 index 000000000..7450f616c --- /dev/null +++ b/test/Dapr.Actors.Test/ActorReferenceTests.cs @@ -0,0 +1,93 @@ +using System; +using System.Threading.Tasks; +using Dapr.Actors.Client; +using Dapr.Actors.Runtime; +using Dapr.Actors.Test; +using Xunit; + +namespace Dapr.Actors +{ + public class ActorReferenceTests + { + [Fact] + public void Get_WhenActorIsNull_ReturnsNull() + { + // Arrange + object actor = null; + + // Act + var result = ActorReference.Get(actor); + + // Assert + Assert.Null(result); + } + + [Fact] + public void Get_FromActorProxy_ReturnsActorReference() + { + // Arrange + var expectedActorId = new ActorId("abc"); + var expectedActorType = "TestActor"; + var proxy = ActorProxy.Create(expectedActorId, typeof(ITestActor), expectedActorType); + + // Act + var actorReference = ActorReference.Get(proxy); + + // Assert + Assert.NotNull(actorReference); + Assert.Equal(expectedActorId, actorReference.ActorId); + Assert.Equal(expectedActorType, actorReference.ActorType); + } + + [Fact] + public async Task Get_FromActorImplementation_ReturnsActorReference() + { + // Arrange + var expectedActorId = new ActorId("abc"); + var expectedActorType = nameof(ActorReferenceTestActor); + var host = ActorHost.CreateForTest(new ActorTestOptions() { ActorId = expectedActorId }); + var actor = new ActorReferenceTestActor(host); + + // Act + var actorReference = await actor.GetActorReference(); + + // Assert + Assert.NotNull(actorReference); + Assert.Equal(expectedActorId, actorReference.ActorId); + Assert.Equal(expectedActorType, actorReference.ActorType); + } + + [Fact] + public void Get_WithInvalidObjectType_ThrowArgumentOutOfRangeException() + { + // Arrange + var actor = new object(); + + // Act + var act = () => ActorReference.Get(actor); + + // Assert + var exception = Assert.Throws(act); + Assert.Equal("actor", exception.ParamName); + Assert.Equal("Invalid actor object type. (Parameter 'actor')", exception.Message); + } + } + + public interface IActorReferenceTestActor : IActor + { + Task GetActorReference(); + } + + public class ActorReferenceTestActor : Actor, IActorReferenceTestActor + { + public ActorReferenceTestActor(ActorHost host) + : base(host) + { + } + + public Task GetActorReference() + { + return Task.FromResult(ActorReference.Get(this)); + } + } +}