Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4d1d018
created stub and test
franciscolopezsancho Sep 24, 2021
99c870b
first test passing
franciscolopezsancho Sep 26, 2021
f5cd830
following suggestions
franciscolopezsancho Sep 27, 2021
ff352a7
following review suggestion
franciscolopezsancho Sep 27, 2021
0010b1c
added ActionTestkitGenerator
franciscolopezsancho Sep 28, 2021
d0edaef
changing order expected,actualValue
franciscolopezsancho Sep 28, 2021
df0528a
Codegen already functional
franciscolopezsancho Oct 4, 2021
28a9b8a
Added test example generation
franciscolopezsancho Oct 4, 2021
f56765a
Merge branch 'main' of github.com:franciscolopezsancho/akkaserverless…
franciscolopezsancho Oct 4, 2021
91c01c0
adding docs
franciscolopezsancho Oct 4, 2021
742af2c
adding FIXME
franciscolopezsancho Oct 4, 2021
f240b9d
formatting
franciscolopezsancho Oct 5, 2021
1dd9b12
adding tag to docs
franciscolopezsancho Oct 5, 2021
b862130
Merge branch 'main' of github.com:franciscolopezsancho/akkaserverless…
franciscolopezsancho Oct 5, 2021
ee4f266
adding missing import
franciscolopezsancho Oct 5, 2021
e79b1c3
changing selectInput/Output from ModelBuilder.Commands
franciscolopezsancho Oct 5, 2021
75deb3d
Update docs/src/modules/java/pages/actions.adoc
franciscolopezsancho Oct 5, 2021
e417a83
Update docs/src/modules/java/pages/actions.adoc
franciscolopezsancho Oct 5, 2021
b221a9e
Update docs/src/modules/java/pages/actions.adoc
franciscolopezsancho Oct 5, 2021
997678f
Update samples/java-eventsourced-counter/src/test/java/com/example/ac…
franciscolopezsancho Oct 5, 2021
1fa4764
adding codegen for RPCs streaming, client and server
franciscolopezsancho Oct 5, 2021
fb1ee72
adding comment after imports
franciscolopezsancho Oct 5, 2021
f4bb328
Update docs/src/modules/java/pages/actions.adoc
franciscolopezsancho Oct 6, 2021
c65d83e
Update docs/src/modules/java/pages/actions.adoc
franciscolopezsancho Oct 6, 2021
c0b2e8a
Update docs/src/modules/java/pages/actions.adoc
franciscolopezsancho Oct 6, 2021
10a7894
Update docs/src/modules/java/pages/actions.adoc
franciscolopezsancho Oct 6, 2021
eee315b
adding suggestions
franciscolopezsancho Oct 6, 2021
ba010e0
Update docs/src/modules/java/pages/actions.adoc
franciscolopezsancho Oct 6, 2021
34524db
Update docs/src/modules/java/pages/actions.adoc
franciscolopezsancho Oct 6, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.example.domain;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

import com.akkaserverless.javasdk.action.Action;
import com.akkaserverless.javasdk.action.ActionCreationContext;
import com.akkaserverless.javasdk.testkit.EventSourcedResult;
import com.akkaserverless.javasdk.testkit.ActionResult;
import com.akkaserverless.javasdk.testkit.impl.ActionResultImpl;
import com.akkaserverless.javasdk.impl.action.ActionEffectImpl;
import com.example.actions.CounterJournalToTopicAction;
import com.akkaserverless.javasdk.testkit.impl.StubActionCreationContext;
import com.akkaserverless.javasdk.testkit.impl.StubActionContext;
import com.example.actions.CounterTopicApi;
import java.util.Optional;

/**
* TestKit for unit testing Counter
*/
public final class CounterJournalToTopicActionTestKit {

private Function<ActionCreationContext, CounterJournalToTopicAction> actionFactory;

private CounterJournalToTopicAction createAction() {
CounterJournalToTopicAction action = actionFactory.apply(new StubActionCreationContext());
action._internalSetActionContext(Optional.of(new StubActionContext()));
return action;
};

/**
* Create a testkit instance of Counter with a specific action id.
*/
public static CounterJournalToTopicActionTestKit of(Function<ActionCreationContext, CounterJournalToTopicAction> actionFactory) {
return new CounterJournalToTopicActionTestKit(actionFactory);
}

/** Construction is done through the static CounterTestKit.of-methods */
private CounterJournalToTopicActionTestKit(Function<ActionCreationContext, CounterJournalToTopicAction> actionFactory) {
this.actionFactory = actionFactory;
}

private <E> ActionResult<E> interpretEffects(Action.Effect<E> effect) {
return new ActionResultImpl(effect);
}

public ActionResult<CounterTopicApi.Increased> increase(CounterDomain.ValueIncreased event) {
Action.Effect<CounterTopicApi.Increased> effect = createAction().increase(event);
return interpretEffects(effect);
}

//look at ACtionEffectImpl

public Action.Effect<CounterTopicApi.Decreased> decrease(CounterDomain.ValueDecreased event) {
Action.Effect<CounterTopicApi.Decreased> effect = createAction().decrease(event);
return effect;
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.example.domain;

import com.akkaserverless.javasdk.action.Action;
import com.akkaserverless.javasdk.impl.action.ActionEffectImpl;
import com.akkaserverless.javasdk.testkit.ActionResult;
import com.example.actions.CounterTopicApi;
import com.example.actions.CounterJournalToTopicAction;
import com.google.protobuf.Empty;
import org.junit.Test;

import static org.junit.Assert.*;

public class CounterJournalToTopicActionTest {

@Test
public void increaseTest() {
CounterJournalToTopicActionTestKit testKit = CounterJournalToTopicActionTestKit.of(CounterJournalToTopicAction::new);
int valueToincrease = 1;
ActionResult<CounterTopicApi.Increased> result = testKit.increase(CounterDomain.ValueIncreased.newBuilder().setValue(valueToincrease).build());
assertTrue(result.isReply());
CounterTopicApi.Increased replyMessage = result.getReplyMessage();
assertEquals(replyMessage.getValue(),valueToincrease);
Comment thread
franciscolopezsancho marked this conversation as resolved.
Outdated
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public interface ActionContext extends MetadataContext {
*
* @return The call level metadata.
*/
Metadata metadata();
Metadata metadata(); // TODO this is not necessary
Comment thread
franciscolopezsancho marked this conversation as resolved.
Outdated

/**
* The origin subject of the {@link CloudEvent}. For example, the entity key when the event was
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2021 Lightbend Inc.
*
* 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.
*/

package com.akkaserverless.javasdk.testkit;

import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import com.akkaserverless.javasdk.ServiceCall;
import java.util.concurrent.CompletableFuture;
import com.akkaserverless.javasdk.action.Action;

public interface ActionResult<T> {

/** @return true if the call had an effect with a reply, false if not */
boolean isReply();

T getReplyMessage();
Comment thread
franciscolopezsancho marked this conversation as resolved.
Outdated

/** @return true if the call was forwarded, false if not */
boolean isForward();

ServiceCall getForwardServiceCall();

// TODO rewrite name. Async doesn't seem very descriptive. Are the rest sync?
/** @return true if the call was async, false if not */
boolean isAsync();

CompletableFuture<Action.Effect<T>> getAsyncEffect();
Comment thread
franciscolopezsancho marked this conversation as resolved.
Outdated

/** @return true if the call was an error, false if not */
boolean isError();

String getErrorDescription();

/** @return true if the call had a noReply effect, false if not */
boolean isNoReply();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright 2021 Lightbend Inc.
*
* 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.
*/

package com.akkaserverless.javasdk.testkit.impl

/*
* Copyright 2021 Lightbend Inc.
*
* 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.
*/

import com.akkaserverless.javasdk.testkit.ActionResult
import com.akkaserverless.javasdk.impl.action.ActionEffectImpl
import com.akkaserverless.javasdk.action.Action
import com.akkaserverless.javasdk.ServiceCall
import java.util.concurrent.CompletableFuture;
import scala.concurrent.Future;
import scala.compat.java8.FutureConverters._

final class ActionResultImpl[T](effect: Action.Effect[T]) extends ActionResult[T] {

/** @return true if the call had an effect with a reply, false if not */
def isReply(): Boolean = effect.isInstanceOf[ActionEffectImpl.ReplyEffect[T]]

def getReplyMessage(): T = {
val reply = getEffectOfType(classOf[ActionEffectImpl.ReplyEffect[T]])
reply.msg
}

//TODO add metadata??

/** @return true if the call was forwarded, false if not */
def isForward(): Boolean = effect.isInstanceOf[ActionEffectImpl.ForwardEffect[T]]

def getForwardServiceCall(): ServiceCall = {
val forward = getEffectOfType(classOf[ActionEffectImpl.ForwardEffect[T]])
forward.serviceCall
}

// TODO rewrite
/** @return true if the call was async, false if not */
def isAsync(): Boolean = effect.isInstanceOf[ActionEffectImpl.AsyncEffect[T]]

def getAsyncEffect(): CompletableFuture[Action.Effect[T]] = {
val async = getEffectOfType(classOf[ActionEffectImpl.AsyncEffect[T]])
async.effect.toJava.toCompletableFuture
}

/** @return true if the call was an error, false if not */
def isError(): Boolean = effect.isInstanceOf[ActionEffectImpl.ErrorEffect[T]]

def getErrorDescription(): String = {
val error = getEffectOfType(classOf[ActionEffectImpl.ErrorEffect[T]])
error.description
}

/** @return true if the call had a noReply effect, false if not */
def isNoReply(): Boolean = effect.isInstanceOf[ActionEffectImpl.NoReply[T]]

/**
* Look at the next effect and verify that it is of type E or fail if not or if there is no next effect. If successful
* this consumes the effect, so that the next call to this method looks at the next effect from here.
*
* @return
* The next effect if it is of type E, for additional assertions.
*/
private def getEffectOfType[E](expectedClass: Class[E]): E = {
if (expectedClass.isInstance(effect)) effect.asInstanceOf[E]
else
throw new NoSuchElementException(
"expected effect type [" + expectedClass.getName + "] but found [" + effect.getClass.getName + "]")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2021 Lightbend Inc.
*
* 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.
*/

package com.akkaserverless.javasdk.testkit.impl;

import com.akkaserverless.javasdk.action.ActionContext;
import com.akkaserverless.javasdk.Metadata;
import java.util.Optional;
import com.akkaserverless.javasdk.ServiceCallFactory
import com.akkaserverless.javasdk.valueentity.ValueEntityContext
import com.akkaserverless.javasdk.action.ActionCreationContext
import akka.stream.Materializer

/** Context for action calls. */
final class StubActionContext extends ActionContext {

override def metadata() = Metadata.EMPTY
Comment thread
franciscolopezsancho marked this conversation as resolved.
Outdated

override def eventSubject() = Optional.of("testkitkat")
Comment thread
franciscolopezsancho marked this conversation as resolved.
Outdated

override def serviceCallFactory: ServiceCallFactory = TestKitServiceCallFactory

override def getGrpcClient[T](clientClass: Class[T], service: String): T =
throw new UnsupportedOperationException("Testing logic using a gRPC client is not possible with the testkit")
override def materializer(): Materializer = throw new UnsupportedOperationException(
"Accessing the materializer from testkit not supported yet")

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2021 Lightbend Inc.
*
* 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.
*/

package com.akkaserverless.javasdk.testkit.impl

import com.akkaserverless.javasdk.ServiceCallFactory
import com.akkaserverless.javasdk.valueentity.ValueEntityContext
import com.akkaserverless.javasdk.action.ActionCreationContext
import akka.stream.Materializer

/**
* INTERNAL API Used by the generated testkit
*/
final class StubActionCreationContext extends ActionCreationContext {
override def serviceCallFactory: ServiceCallFactory = TestKitServiceCallFactory
override def getGrpcClient[T](clientClass: Class[T], service: String): T =
throw new UnsupportedOperationException("Testing logic using a gRPC client is not possible with the testkit")
override def materializer(): Materializer = throw new UnsupportedOperationException(
"Accessing the materializer from testkit not supported yet")
}