playframework: -- Database/Test Framework/Cache bug - database

I have fully isolated this problem to a very simple play app
I think it has to do with some DB caching, but I can't figure it out
BasicTest.java
==========
import org.junit.*;
import play.test.*;
import play.Logger;
import models.*;
import play.mvc.Http.*;
public class BasicTest extends FunctionalTest {
#Before public void setUp() {
Fixtures.deleteDatabase();
Fixtures.loadModels("data.yml");
Logger.debug("countFromSetup=%s",User.count());
}
#Test
public void test() {
Response response= GET("/");
Logger.debug("countFromTest=%s",User.count());
assertIsOk(response);
}
}
Uncommented Configs
================
%prod.application.mode=prod
%test.application.mode=dev
%test.db.url=jdbc:h2:mem:play;MODE=MYSQL;LOCK_MODE=0
%test.db=mysql:root:xxx#t_db
%test.jpa.ddl=create
%test.mail.smtp=mock
application.mode=dev
application.name=test
application.secret=jXKw4HabjhaNvosxgzq39to9BJECtOr39EXrEabsQAZKi7YoWAwQWo3B BFUOQnJw
attachments.path=data/attachments
date.format=yyyy-MM-dd
db=mysql:root:xxx#db
mail.smtp=mock
Application.java
============
package controllers;
import play.*;
import play.mvc.*;
import models.*;
public class Application extends Controller {
public static void index() {
Logger.debug("countFromIndex=%s",User.count());
render();
}
}
>play test
Output of log after running the BasicTest http://localhost:9000/#tests
==================================================
11:54:59,008 DEBUG ~ countFromSetup=1
11:54:59,021 DEBUG ~ countFromIndex=0
11:54:59,034 DEBUG ~ countFromTest=1
point to browser=> http://localhost:9000
12:25:59,781 DEBUG ~ countFromIndex=1
What happened to the record during?
Response response= GET("/");
This 'bug' almost makes my test cases useless

It has probably something to do with transactions. I've came across a similar case once with Spring/JUnit couple.
Here is the transactionnal execution of the test (I think) :
Start transaction t1,
Execute setup, result is fetched from cache.
Execute test.
Start transaction t2 for controller execution GET("/")
Result is fetched from database but since t1 hasn't been commmited, it isn't displayed.
Close transaction t2 and commit t1!
Close transaction t1 and commit t2!
By the way, that is not really a Functionnal Test. For functionnal tests, you are not supposed to check such data but only http status. Turn to UnitTests for that. When looking at source code of functionnal tests, you can see all the checks implemented are for response/http checking.

I think its the default behavior of JUnit, #Before annotation makes the method run before every test:
When writing tests, it is common to find that several tests need
similar objects created before they can run. Annotating a public void
method with #Before causes that method to be run before the Test
method. The #Before methods of superclasses will be run before those
of the current class.
From : http://junit.sourceforge.net/javadoc/org/junit/Before.html
IF you want the setup to be run once you can use #BeforeClass Annotation : http://junit.sourceforge.net/javadoc/org/junit/BeforeClass.html

In PlayFramework, there's n+1 threads for prod and 1 thread for test profile or compile profile. So if you have a dual-core CPU, there's 3 threads if you are running in prod, and one thread if you started the application with "test".
Now, one more interesting fact : there'x one Tx per execution. Thus when your application starts, and you launch your very first test, here is what happens :
Play starts with one thread.
The JUnitRunner starts, the first test myTest gets executed. It's an HTTP connection to the application. The reason why you see 0 is because of the Response GET that is executed before the #Before statement.
The #Before gets executed, creates your entries and the result count is accurate in the #Before, because it's done in the same Tx.
So what I suggest is that you either use #BeforeClass, or perform the setup not in a #Before but from a direct call in myTest for the very specific test case with Response.
I assume that if you replace this code
#Test
public void myTest() {
Response response= GET("/test");
}
with this
#Test
public void myTest() {
assertEquals(1,User.count());
}
Correct ?
So the reason why you get this is not a bug. It's simply because of this one thread configuration we have for test environment.
Nicolas

Related

Flink integration test(s) with Testcontainers

I have a simple Apache Flink job that looks very much like this:
public final class Application {
public static void main(final String... args) throws Exception {
final var env = StreamExecutionEnvironment.getExecutionEnvironment();
final var executionConfig = env.getConfig();
final var params = ParameterTool.fromArgs(args);
executionConfig.setGlobalJobParameters(params);
executionConfig.setParallelism(params.getInt("application.parallelism"));
final var source = KafkaSource.<CustomKafkaMessage>builder()
.setBootstrapServers(params.get("application.kafka.bootstrap-servers"))
.setGroupId(config.get("application.kafka.consumer.group-id"))
// .setStartingOffsets(OffsetsInitializer.committedOffsets(OffsetResetStrategy.EARLIEST))
.setStartingOffsets(OffsetsInitializer.earliest())
.setTopics(config.getString("application.kafka.listener.topics"))
.setValueOnlyDeserializer(new MessageDeserializationSchema())
.build();
env.fromSource(source, WatermarkStrategy.noWatermarks(), "custom.kafka-source")
.uid("custom.kafka-source")
.rebalance()
.flatMap(new CustomFlatMapFunction())
.uid("custom.flatmap-function")
.filter(new CustomFilterFunction())
.uid("custom.filter-function")
.addSink(new CustomDiscardSink()) // Will be a Kafka sink in the future
.uid("custom.discard-sink");
env.execute(config.get("application.job-name"));
}
}
Problem is that I would like to provide an integration test for the entire application — sort of like an end-to-end (set of) test(s) for the entire job. I'm using Testcontainers, but I'm not really sure how to move forward with this. For instance, this is how the test looks like (for now):
#Testcontainers
final class ApplicationTest {
private static final DockerImageName DOCKER_IMAGE = DockerImageName.parse("confluentinc/cp-kafka:7.0.1");
#Container
private static final KafkaContainer KAFKA_CONTAINER = new KafkaContainer(DOCKER_IMAGE);
#ClassRule // How come this work in JUnit Jupiter? :/
public static MiniClusterResource cluster;
#BeforeAll
static void init() {
KAFKA_CONTAINER.start();
// ...probably need to wait and create the topic(s) as well
final var config = new MiniClusterResourceConfiguration.Builder().setNumberSlotsPerTaskManager(2)
.setNumberTaskManagers(1)
.build();
cluster = new MiniClusterResource(config);
}
#Test
void main() throws Exception {
// new Application(); // ...what's next?
}
}
I'm not sure how to implement what's required to trigger the job as-is from that point on. Basically, I would like to execute what was defined before, without (almost) any modifications — I've seen plenty of examples that practically build the entire job again, so that's not an option.
Can somebody provide any pointers here?
MessageDeserializationSchema is unbounded, so isEndOfStream returns false. Not sure if that's an impediment.
In order to make the pipeline more testable, I suggest you create a method on your Application class that takes a source and a sink as parameters, and creates and executes the pipeline, using those connectors.
In your tests you can call that method with special sources and sinks that you use for testing. In particular, you will want to use a KafkaSource that uses .setBounded(...) in the tests so that it cleanly handles just the range of data intended for the test(s).
The solutions and tests for the Apache Flink training exercises are organized along these lines; for example, see RideCleansingSolution.java and RideCleansingIntegrationTest.java. These examples don't use kafka or test containers, but hopefully they'll still be helpful.
I would suggest you instrument your application as an opaque-box test by interacting with it through its public API. This can be done either as an out-process test (e.g. by running your application in a container as well, using Testcontainers) are as an in-process test (by creating your Application and calling its main() method).
Now in your comments you explained, that you want to check for the side-effects of interacting with your application (Kafka messages being published). To check this, connect to the KafkaContainer with your own KafkaConsumer from within the test and use a library such as Awaitiliy to wait until the messages have been received.

I want to stop execution of the #Test method if #BeforeMethod is failed. How to achieve This

I go with a general example. I have login code in the #Before method:
#BeforeTest
public void setUp(){
///somelogin logic
}
#Test
public void Testdashboard() throws Exception{
//Some Dashboard validation logic
}
So here if login fails in the #BeforeMethod I want to stop the execution of #Test method how to do this?
I don't think the test method will run if beforemethod fails. The #test method should get skipped automatically.
You can use dependsOnMethods attribute in #Test annotation as below:
#Test(dependsOnMethods={"setUp"})
public void Testdashboard() {
//Some Dashboard validation logic
}
I guess it would not be possible as method annotated with #BeforeMethod is not a test method. It is used to perform any setup prior to execution of test method.
If you want test method to depend on other method then you need to use dependsOnMethods attribute whose value is some other method annotated with #Test.
You can do this by using below option:
-configfailurepolicy- Its value can be skip|continue.
This determines whether TestNG should continue to execute the remaining tests in the suite or skip them if an #Before* method fails. Default behaviour is skip.
Refer to link:
http://testng.org/doc/documentation-main.html

Apache camel how to test a rollback scenario

I have a generic message router that has its routes created at run time by various route builders based on some configuration.
The configuration is stored as XML and when loaded in memory it gets converted into a RouteConfig domain object exposing via its getters how the route should be build. Such a RouteConfig will have a getFromUri(), getDestinations(), getDeadLetterUri(), isTransacted(), etc methods defined.
An example such a route builder would look like below:
public class NonTransactedRouteBuilder extends AbstractRouteBuilder {
#Override
protected void buildRoute(String endPoint, RouteConfig routeConfig) {
RouteBean routeBean = getRouteBean(routeConfig.getBean());
final String[] destinations = routeConfig.getDestinations();
from(endPoint).routeId(createRouteId())
.autoStartup(false)
.threads(routeConfig.getThreads())
.filter(body().isNotNull())
.process((Processor) routeBean)
.filter(body().isNotNull())
.choice()
.when(header("dead.letter").isNotNull())
.to(getDeadLetterUri())
.otherwise()
.loadBalance().random()
.to(destinations)
.endChoice();
}
}
The above is just an example to give you an idea about what kind of routes we build. The only one relevant thing is that the route is not transacted. Now to unit test it works as expected we extend the TestNG flavor of CamelTestSupport and pass a mocked RouteConfig instance that will result in a route being configured to move messages between a direct:test and two mock:test1 and mock:test2 end points. The route bean has a bit of logic in it and depending of the message content help us with all testing scenarios:
#Test
public void shouldDiscardNullMessages() throws Exception {
...
}
#Test
public void shouldDiscardScamMessages() throws Exception {
...
}
#Test
public void shouldRouteMessageToDeadLetterQueue() throws Exception {
...
}
#Test(timeOut = 1000)
public void shouldRouteMessagesInALoadBalancedWay()
...
}
Everything works fine and we are very happy we can make code changes and test them immediately. However most of our routes builders will build transacted routes. From our integration and end to end tests we know the transacted functionality works fine but would be so much better to be able to test this at your code changing point with an unit test.
So my question is:
Having the same route as above with just an autoStartup(false).transacted() change on it would it be a way to getting the message back in the sender direct:test end point so we can cover this part of the functionality as well. We would be happy with any work around suggestion just to prove this aspect works.
Thank you in advance for your inputs.
UPDATE 1:
One of the things I tried was to configure my test camel context with a TransactionErrorHandler that had a mock jta transaction manager injected. Something like bleow:
#Test
public void shouldBeAbleToRollback() throws Exception {
TransactionErrorHandlerBuilder errorHandlerBuilder = new TransactionErrorHandlerBuilder();
errorHandlerBuilder.setTransactionManager(jtaTransactionManagerMock);
context().setErrorHandlerBuilder(errorHandlerBuilder);
template.sendBody(FROM_1, "rollback message");
...
}
Then I hoped that I will be able to capture a jtaTransactionManagerMock.rollback() but this did not happen. Wat would be the reason not to work.
UPDATE 2:
Unable to achieve the above I stepped back and started integrating ActiveMQ as a transactional resource in my unit tests and everything worked fine. In reality our routes include also file and database end points but for the purpose of unit testing a generic queue builder using just a JMS resource is enough. I did not realized how easy would be when you deal all day long with Webshere MQ manager where you need to have MQ manager created and configured and you have to have the queues already there and all the heavy infrastructure that you have to build for this. ActiveMQ just did a very good job.
However I will still be interested in whether there would be an way to mock this transnational behavior.

How to get code cover for Enum class in APEX

I have a Enum class as:
global class Util {
global enum Session {
Winter,
Summer,
Rain
}
}
and a test class as :
public static testmethod void callTestData(){
test.starttest();
Util.Session se = Util.Session.Winter;
test.stoptest();
}
But still my code coverage is 0%?? Why.
Also I tried many ways to cover it but not able to can any one help!!
This seems like it should give you 100% coverage.
Sometimes Salesforce needs a bit of encouragement to give you the correct code coverage results.
Try:
Clearing all previous test case results
Setup > App Setup > Develop > Apex Text Execution > View Test History > Clear Test Results
Running the test case from the force.com IDE
That the class and the test method class are using the same API version in the metadata file. E.g. both 29.0.
Running the test case from an external tool, such as MavensMate in Sublime Text or the FuseIT SFDC Explorer that has both synchronous and asynchronous testing options.

Android Unit Tests Requiring Context

I am writing my first Android database backend and I'm struggling to unit test the creation of my database.
Currently the problem I am encountering is obtaining a valid Context object to pass to my implementation of SQLiteOpenHelper. Is there a way to get a Context object in a class extending TestCase? The solution I have thought of is to instantiate an Activity in the setup method of my TestCase and then assigning the Context of that Activity to a field variable which my test methods can access...but it seems like there should be an easier way.
You can use InstrumentationRegistry methods to get a Context:
InstrumentationRegistry.getTargetContext() - provides the application Context of the target application.
InstrumentationRegistry.getContext() - provides the Context of this Instrumentation’s package.
For AndroidX use InstrumentationRegistry.getInstrumentation().getTargetContext() or InstrumentationRegistry.getInstrumentation().getContext().
New API for AndroidX:
ApplicationProvider.getApplicationContext()
You might try switching to AndroidTestCase. From looking at the docs, it seems like it should be able to provide you with a valid Context to pass to SQLiteOpenHelper.
Edit:
Keep in mind that you probably have to have your tests setup in an "Android Test Project" in Eclipse, since the tests will try to execute on the emulator (or real device).
Your test is not a Unit test!!!
When you need
Context
Read or Write on storage
Access Network
Or change any config to test your function
You are not writing a unit test.
You need to write your test in androidTest package
Using the AndroidTestCase:getContext() method only gives a stub Context in my experience. For my tests, I'm using an empty activity in my main app and getting the Context via that. Am also extending the test suite class with the ActivityInstrumentationTestCase2 class. Seems to work for me.
public class DatabaseTest extends ActivityInstrumentationTestCase2<EmptyActivity>
EmptyActivity activity;
Context mContext = null;
...
#Before
public void setUp() {
activity = getActivity();
mContext = activity;
}
... //tests to follow
}
What does everyone else do?
You can derive from MockContext and return for example a MockResources on getResources(), a valid ContentResolver on getContentResolver(), etc. That allows, with some pain, some unit tests.
The alternative is to run for example Robolectric which simulates a whole Android OS. Those would be for system tests: It's a lot slower to run.
You should use ApplicationTestCase or ServiceTestCase.
Extending AndroidTestCase and calling AndroidTestCase:getContext() has worked fine for me to get Context for and use it with an SQLiteDatabase.
The only niggle is that the database it creates and/or uses will be the same as the one used by the production application so you will probably want to use a different filename for both
eg.
public static final String NOTES_DB = "notestore.db";
public static final String DEBUG_NOTES_DB = "DEBUG_notestore.db";
First Create Test Class under (androidTest).
Now use following code:
public class YourDBTest extends InstrumentationTestCase {
private DBContracts.DatabaseHelper db;
private RenamingDelegatingContext context;
#Override
public void setUp() throws Exception {
super.setUp();
context = new RenamingDelegatingContext(getInstrumentation().getTargetContext(), "test_");
db = new DBContracts.DatabaseHelper(context);
}
#Override
public void tearDown() throws Exception {
db.close();
super.tearDown();
}
#Test
public void test1() throws Exception {
// here is your context
context = context;
}}
Initialize context like this in your Test File
private val context = mock(Context::class.java)

Resources