I am trying to extend test case for camunda and JUnit5.
I am getting the following error - Illegal call of execute(job = 'null') - must not be null!
java.lang.IllegalArgumentException: Illegal call of execute(job = 'null') - must not be null!
#ExtendWith(ProcessEngineExtension.class)
public class SimpleTestCase {
#Deployment(resources = {"testProcess.bpmn"})
#Test
public void shouldExecuteProcess() {
// Given we create a new process instance
ProcessInstance processInstance = runtimeService().startProcessInstanceByKey("testProcess");
// Then it should be active
assertThat(processInstance).isActive();
// And it should be the only instance
assertThat(processInstanceQuery().count()).isEqualTo(1);
// And there should exist just a single task within that process instance
assertThat(task(processInstance)).isNotNull();
ProcessEngineTests.execute(ProcessEngineTests.job());
BpmnAwareTests.execute(BpmnAwareTests.job());
// When we complete that task
complete(task(processInstance));
// Then the process instance should be ended
assertThat(processInstance).isEnded();
//then
//Checking the run queue
assertThat(processInstance).hasPassedInOrder(new String[] { "UserTask_1","UserTask_2"});
}
ProcessInstance processInstance =
runtimeService().startProcessInstanceByKey("testProcess");
// Then it should be active
assertThat(processInstance).isActive();
// And it should be the only instance
assertThat(processInstanceQuery().count()).isEqualTo(1);
// And there should exist just a single task within that process instance
assertThat(task(processInstance)).isNotNull();
assertThat(processInstance).isWaitingAt("UserTask_1");
// When we complete that task
complete(task(processInstance));
assertThat(processInstance).isWaitingAt("UserTask_2");
complete(task(processInstance));
// Then the process instance should be ended
assertThat(processInstance).isEnded();
assertThat(processInstance).hasPassedInOrder("UserTask_1","UserTask_2");
Related
i need to test 'tableInfo' method of Service class
Here is my junit test script:
class JUnitTest extends Specification {
Service service
Table table = GroovyMock(Table)
def spy = Spy(Service){
getTable() >> table
}
def setup() {
service = new Service(
table: table
)
}
def "when table contains information"() {
given:
spy.internalMethod(*_) >> [Bean.BEAN_SUCCESS]
table.getUnits(*_) >> {}
Response response = new Response()
when:
spy.tableInfo(.....)
then:
response.status == 0
response.error == []
}
Question: I am getting null pointer exception in table.getUnits as below
"java.lang.NullPointerException: Cannot invoke method getUnits() on
null object"
Please help me out of this
If you want to call the method every time. But need aware of exception means, simply check the condition before calling table.getUnits() method like below.
if(table.getUnits!=null)
table.getUnits();
SEVERE: Exception occurred during processing request: There is a cycle in the hierarchy!
net.sf.json.JSONException: There is a cycle in the hierarchy!
I have added the setcycleDetectionStrategy in the in the method:
public HttpHeaders show() {
System.out.println("In show.");
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setIgnoreDefaultExcludes(false);
//jsonConfig.setExcludes(new String[]{"requests"});
jsonConfig.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);
model = service.get(Long.parseLong(id));
return new DefaultHttpHeaders("show");
}
But it still does not work.
Usually, it happens with having a instance reference cycle. Some object has an instance variable pointing to another object, which has an instance variable pointing back at the first object. Make sure to avoid the above scenario in your code.
I have got the following code:
Collection<String> errors = ...;
try (InputStream stream = My.class.getResourceAsStream(resource)) {
// do stuff
}
catch(IOException ex) {
errors.add("Fail");
}
I'm trying with Byteman Junit Runner to trigger an IOException when the (valid) input stream I give is supposedly closed:
#RunWith(BMUnitRunner.class)
public class MyTest {
private My my = new My();
#BMRule(
name = "force_read_error",
targetClass = "java.io.InputStream",
targetMethod = "close()",
action = "throw new IOException(\"bazinga\")"
)
#Test
public void catches_read_error() throws IOException {
Collection<String> errors = my.foo("/valid-resource-in-classpath");
assertThat(errors).containsExactly("Fail");
}
}
My test fails: errors is always empty, which means the Byteman rule obviously isn't executed (it's well loaded by the agent, so I don't understand what's going on).
How can I trigger an IOException on close method called via try-with-resources?
Your rule ist not firing, because the class of the stream object received when calling
InputStream stream = My.class.getResourceAsStream(resource)
is not a "java.io.InputStream" class. It is a class extending "java.io.InputStream", most likely a "BufferedInputStream".
To tell byteman to "trigger rule for any class extending java.io.InputStream", you need to put a '^' before the class name:
targetClass = "^java.io.InputStream"
This change might have the unwanted side effect, that the rule gets triggered also when other objects extending "java.io.InputStream" get closed. To prevent this from happening, a condition should be added to the rule to only get triggered, when the caller matches the "foo" method of the "My" class. Byteman has a helper method for that called "callerMatches" (Please see also the advanced tutorial)
A working condition for your case would be:
condition = "callerMatches(\".+My.foo\",true,true)"
The complete Byteman rule definition as BMRule annotation should look like:
#BMRule(
name = "force_read_error",
targetClass = "^java.io.InputStream",
targetMethod = "close()",
condition = "callerMatches(\".+My.foo\",true,true)",
action = "throw new java.io.IOException(\"bazinga\")"
)
In order to avoid duplicates in my redis channel I'm checking if the message is already there by keeping an index in Redis set. Following is my implementation. However, it is giving an exception.
redis.clients.jedis.exceptions.JedisDataException: Please close pipeline or multi block before calling this method.
at redis.clients.jedis.Response.get(Response.java:23)
Here is the implementation.
Jedis jedis = pool.getResource();
String id = message.getId();
Transaction transaction = jedis.multi();
redis.clients.jedis.Response<java.lang.Boolean> response = transaction.sismember(ID_SET_REDIS_KEY, id);
if (response != null && !response.get().booleanValue()) {
//add it to the
transaction.sadd(ID_SET_REDIS_KEY, id);
transaction.publish(redisChannelName, message);
}
transaction.exec();
pool.returnResource(jedis);
I need to do the get inside the transaction because there are multiple publishers who may publish the exact same message.
You can't have the result of your get before you end the transaction.
If you are using Redis > 2.6.X, what you can do is use a Lua Script to create a function with you logic. See Redis Lua
This is exactly what I did to guarantee concurrency in my project.
Edit: Including a more complete example
You should create something like a PUBLISHNX script (not tested):
local shouldPublish = redis.call('SISMEMBER', KEYS[1], ARGV[1])
if shouldPublish == 0
redis.call('SADD', KEYS[1], ARGV[1])
redis.call('PUBLISH', ARGV[2], ARGV[3])
end
And you pass all the arguments necessary, channel, messageId, message, controlKey.
PS. Wei Li is right, you could accomplish the same result using WATCH and a loop for retrying in case of concurrency, but I still prefer using a Lua script.
Based on #Axexandre's comment above I used the following piece of code to do perform the operation.
import redis.clients.jedis.Jedis;
public class RedisLuaDemo {
public static void main(String args[])
{
Jedis jedis = new Jedis("localhost");
jedis.sadd("a", "b");
int numberOfKeys = 1 //we are using only one Redis set 'setvar'
jedis.eval("if redis.call('sismember', KEYS[1], ARGV[1]) == 1 then return ARGV[2] else redis.call('sadd', KEYS[1], ARGV[1]); redis.call('publish', 'channel.mychannel', ARGV[2]) end", numberOfKeys, "setvar", "joe", "message from joe!");
}
}
Here is some more information about the script. It took some time to understand the syntax.
if redis.call('sismember', KEYS[1], ARGV[1]) == 1 eqavalent to SISMEMBER setvar joe
redis.call('sadd', KEYS[1], ARGV[1]);
For some reason if I don't have this jedis.sadd("a", "b"); line I get an exception (see below).
Exception in thread "main" java.lang.NullPointerException
at redis.clients.jedis.Connection.setTimeoutInfinite(Connection.java:41)
at redis.clients.jedis.Jedis.eval(Jedis.java:2763)
at redis.RedisLuaDemo.main(RedisLuaDemo.java:13)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
The scenarios:
3 tables I have which form a Many-to-many relationship:
Agent (AgentID (PK), AgentName)
AgentChannel (AgentID (PK), ChannelID (PK))
Channel (ChannelID (PK), ChannelName)
I do not want to add/delete any record in Agent and Channel tables, but only modify the AgentChannel table.
I am using EF 4.1, POCO and Self-Tracking Entity. All codes that deal with database are include in WCF layer which I calls them server side code, and I only able to control the add/remove of records in client side code.
For example:
I has one Agent record, with multiple Channel records. I able to link existing channel to agent in this way:
var channel = new Channel { ChannelID = 1 };
channel.MarkAsUnchanged();
agent.Channels.Add(channel);
// This will add new entry to AgentChannel table, but no change on Agent and Channel tables
Also I can remove the linkage of a channel to agent in this way:
var tempChannels = agent.Channels.ToList();
var channelToDelete = tempChannels.FirstOrDefault(c => c.ChannelID == 3);
agent.Channels.Remove(channelToDelete);
// This will remove the entry in AgentChannel, but no change on Agent and Channel tables.
My problem:
If I removed a channel, and add back a new channel which has the same ChannelID with the previously removed channel into agent.Channels collection , I will get this error:
AcceptChanges cannot continue because the object’s key values conflict with another object in the ObjectStateManager.
Sample code to demostrates:
//
// I not able to call ObjectContext here because it was reside in server side.
//
//
// This is client side code
//
var tempChannels = agent.Channels.ToList();
var channelToDelete = tempChannels.FirstOrDefault(c => c.ChannelID == 3);
// remove channel 3
agent.Channels.Remove(channelToDelete);
var channel = new Channel { ChannelID = 3 };
channel.MarkAsUnchanged();
// Add back channel 3
agent.Channels.Add(channel);
//
// This is server side code (WCF layer)
//
try
{
using (var ctx = new testEntities())
{
ctx.ApplyChanges("Agents", agent); // <-- ERROR happen here
ctx.SaveChanges();
}
}
catch (Exception)
{
throw;
}
then I got thie exception message:
System.InvalidOperationException was unhandled
Message=AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.
Source=System.Data.Entity
StackTrace:
at System.Data.Objects.ObjectStateManager.FixupKey(EntityEntry entry)
at System.Data.Objects.EntityEntry.AcceptChanges()
at System.Data.Objects.EntityEntry.ChangeObjectState(EntityState requestedState)
at System.Data.Objects.ObjectStateManager.ChangeObjectState(Object entity, EntityState entityState)
at TestManyToMany.SelfTrackingEntitiesContextExtensions.ChangeEntityStateBasedOnObjectState(ObjectContext context, IObjectWithChangeTracker entity) in F:\MyFile\Development\Temp\TestManyToMany\TestManyToMany\Model1.Context.Extensions.cs:line 728
at TestManyToMany.SelfTrackingEntitiesContextExtensions.HandleEntity(ObjectContext context, EntityIndex entityIndex, RelationshipSet allRelationships, IObjectWithChangeTracker entity) in F:\MyFile\Development\Temp\TestManyToMany\TestManyToMany\Model1.Context.Extensions.cs:line 596
at TestManyToMany.SelfTrackingEntitiesContextExtensions.ApplyChanges[TEntity](ObjectContext context, String entitySetName, TEntity entity) in F:\MyFile\Development\Temp\TestManyToMany\TestManyToMany\Model1.Context.Extensions.cs:line 84
at TestManyToMany.Program.Main(String[] args) in F:\MyFile\Development\Temp\TestManyToMany\TestManyToMany\Program.cs:line 53
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
I hope I make myself clear. This is the only problem I facing now and I run out of idea.
Many thanks.
-
-
Update - Answer
I got the answer after done the testing according to comment from Ladislav Mrnka.
Basically you need to add back to the same entity which removed previously, no other entity because that will gave you the same error above.
Here is the sample code on client side, no changes required in server side:
int channelId = 1;
var tempChannels = agent.Channels.ToList();
var channelToDelete = tempChannels.FirstOrDefault(c => c.ChannelID == channelId);
// remove channel 1
agent.Channels.Remove(channelToDelete);
//var channel = _allChannels.First(c => c.ChannelID == channelId);
//agent.Channels.Add(channel); <-- This line will give you ERROR because the channel entity is from _allChannels, but not from agent.Channels
// Add back channel 1
agent.Channels.Add(channelToDelete); // <-- This is CORRECT
That is not allowed operation. If you removed channel and you want to add it again you mustn't create a new instance. You must use the old one and only change its state. The main rule is that each entity with unique key must be declared only once. Your code results in two instances with the same key = error.