Appium Parallel Execution + TestNG Framework issue - multithreading

I Just started creating a framework for appium. I am facing challenges when i am trying to create driver.
It starts as follows
Step 1: Based on the thread count and devices i will be creating appium servers at runtime in TestNG's #Beforesuite.
cap.setCapability("noReset", "false");
cap.setCapability(MobileCapabilityType.DEVICE_NAME, "Dev1");
cap.setCapability(MobileCapabilityType.BROWSER_NAME, "Chrome");
cap.setCapability(MobileCapabilityType.UDID, udid);
//Build the Appium service
builder = new AppiumServiceBuilder();
builder.withIPAddress("127.0.0.1");
builder.usingAnyFreePort();
builder.withCapabilities(cap);
builder.withArgument(GeneralServerFlag.SESSION_OVERRIDE);
builder.withArgument(GeneralServerFlag.LOG_LEVEL, "error");
appiumservice = AppiumDriverLocalService.buildService(builder);
appiumservice.start();
Step 2: I will get the appium server url's for all devices connected using
appiumservice.getUrl().toString()
Now i have all server url's and Capabilities.
The question is now in TestNG.xml if i give Parallel and thread-count to 3 how can i set create a AndroidDriver object in #BeforeMethod in such a way each time it should take different appium server url and execute the tests ?
How should my #Beforemethod and #Aftermethod ?
Thanks

Pass port and device from testng :
<suite name="Suite" verbose="1" parallel="tests" thread-count="2">
<parameter name="properties" value="XXX" />
<tests>
<test name="Run on device 1">
<classes>
<parameter name="port" value="4723"/>
<parameter name="device" value="DeviceID1"></parameter>
<class name="com.testScripts.ABC">
<methods>
<include name="test1"/>
</methods>
</class>
</classes>
</test>
<test name="run on device 2">
<classes>
<parameter name="port" value="4724"></parameter>
<parameter name="device" value="DeviceID2"></parameter>
<class name="com.testScripts.ABC">
<methods>
<include name="test1"/>
</methods>
</class>
</classes>
</test>
</tests>
</suite>
Put following annotation in method whrere you are defining your capability ..
#BeforeTest(alwaysRun=true)
#Parameters({"port","device"})
Public void capablities()
{
cap.setCapability("noReset", "false");
cap.setCapability(MobileCapabilityType.DEVICE_NAME, device);
cap.setCapability(MobileCapabilityType.BROWSER_NAME, "Chrome");
cap.setCapability(MobileCapabilityType.UDID, udid);
//Build the Appium service
builder = new AppiumServiceBuilder();
builder.withIPAddress("127.0.0.1");
//use port pass in testng file
// builder.usingAnyFreePort();
builder.withCapabilities(cap);
builder.withArgument(GeneralServerFlag.SESSION_OVERRIDE);
builder.withArgument(GeneralServerFlag.LOG_LEVEL, "error");
appiumservice = AppiumDriverLocalService.buildService(builder);
appiumservice.start();
}

I would suggest initialising the driver in the #BeforeClass method, and as shiv mentioned use TestNG parameters:
driver = new RemoteWebDriver(new URL("http://0.0.0.0:"+ port +"/wd/hub"), capabilities);

Related

MQTT- Spring Integration

I am trying to run the Sample MQTT-SPring integration project . How ever I have modified some the configuration details to fetch from property file . And trying connect to message broker from the runMQTT.java file.
Code snippet are as follow
MQTT-Context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:int-mqtt="http://www.springframework.org/schema/integration/mqtt"
xsi:schemaLocation="
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-4.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/integration/mqtt http://www.springframework.org/schema/integration/mqtt/spring-integration-mqtt-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<bean id="clientFactory"
class="org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory">
<property name="userName" value="username" />
<property name="password" value="password" />
<property name="serverURIs" value="${serveruri}"></property>
</bean>
<!-- intercept and log every message -->
<int:logging-channel-adapter id="logger"
level="ERROR" />
<int:wire-tap channel="logger" />
<!-- Mark the auto-startup="true" for starting MqttPahoMessageDrivenChannelAdapter from configuration -->
<int-mqtt:message-driven-channel-adapter
id="startCaseAdapter" client-id="clientId" url="${mqttbrokerurl}"
topics="topic" channel="startCase" auto-startup="true" />
<int:channel id="startCase" />
<int:service-activator id="startCaseService"
input-channel="startCase" ref="mqttCaseService" method="startCase" />
<bean id="mqttCaseService" class="com.XXX.integration.ieg.mqtt.MqttCaseService" />
</beans>
The properties(mqttbrokerurl, serveruri) are loaded from root context
RunMQTT
package com.XXX.integration.ieg.mqtt;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
public class RunMqtt {
public void test() throws MqttException{
ApplicationContext ac = new ClassPathXmlApplicationContext("/META-INF/spring/integration/mqtt/mqtt-context.xml");
System.out.println(ac);
MqttPahoMessageDrivenChannelAdapter startCaseAdapter = (MqttPahoMessageDrivenChannelAdapter)ac.getBean("startCaseAdapter");
//Uncomment to stop the adapter manually from program
//startCaseAdapter.start();
//DefaultMqttPahoClientFactory mqttClient = (DefaultMqttPahoClientFactory)ac.getBean("clientFactory");
DefaultMqttPahoClientFactory mqttClient = new DefaultMqttPahoClientFactory();
MqttClient mclient = mqttClient.getClientInstance("tcp://localhost:1883", "JavaSample");
String data = "This is what I am sending in 2nd attempt";
MqttMessage mm = new MqttMessage(data.getBytes());
mm.setQos(1);
mclient.connect();
mclient.publish("topic",mm);
mclient.disconnect();
//Uncomment to stop the adapter manually from program
//startCaseAdapter.stop();
}
public static void main(String[] args) throws MqttException {
new RunMqtt().test();
}
/*public static void main1(String[] args) {
String topic = "MQTT Examples";
String content = "Message from MqttPublishSample";
int qos = 2;
String broker = "tcp://localhost:1883";
String clientId = "JavaSample";
MemoryPersistence persistence = new MemoryPersistence();
try {
MqttClient sampleClient = new MqttClient(broker, clientId, persistence);
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
System.out.println("Connecting to broker: "+broker);
sampleClient.connect(connOpts);
System.out.println("Connected");
System.out.println("Publishing message: "+content);
MqttMessage message = new MqttMessage(content.getBytes());
message.setQos(qos);
sampleClient.publish(topic, message);
System.out.println("Message published");
sampleClient.disconnect();
System.out.println("Disconnected");
System.exit(0);
} catch(MqttException me) {
System.out.println("reason "+me.getReasonCode());
System.out.println("msg "+me.getMessage());
System.out.println("loc "+me.getLocalizedMessage());
System.out.println("cause "+me.getCause());
System.out.println("excep "+me);
me.printStackTrace();
}
}*/
}
The root context
The root context is as follow
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- This file will be the root context file for web app. All other context will be imported here -->
<!-- Security context . Now the spring security with basic authentication implemented. OAuth2 will be implemented -->
<import resource="security-config.xml" />
<!-- rest service call context -->
<import resource="classpath:META-INF/spring/integration/rest/applicationContext-http-int.xml"/>
<!-- Sftp context-->
<import resource="classpath:META-INF/spring/integration/sftp/SftpInboundReceive-context.xml"/>
<import resource="classpath:META-INF/spring/integration/sftp/SftpOutboundTransfer-context.xml"/>
<import resource="classpath:META-INF/spring/integration/sftp/SftpOutboundTransfer-poll.xml"/>
<!-- mqtt context-->
<import resource="classpath:META-INF/spring/integration/mqtt/mqtt-context.xml"/>
<!--Component scan base package -->
<context:component-scan base-package="com.XXX.integration.ieg"/>
<!-- All the property configuration moved to parent context file to solve the propert not found exception -->
<context:property-placeholder order="1"
location="classpath:/sftpuser.properties, classpath:/sftpfile.properties,classpath:/resthttp.properties, classpath:/mqtt.properties" ignore-unresolvable="true"/>
</beans>
In this case either mqtt or sftp or resthttp property loading is failing. Please help to resolve
stacktrace
java.lang.IllegalArgumentException: ${mqttbrokerurl}
at org.eclipse.paho.client.mqttv3.MqttConnectOptions.validateURI(MqttConnectOptions.java:448)
at org.eclipse.paho.client.mqttv3.MqttAsyncClient.<init>(MqttAsyncClient.java:260)
at org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory.getAsyncClientInstance(DefaultMqttPahoClientFactory.java:119)
at org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter.connectAndSubscribe(MqttPahoMessageDrivenChannelAdapter.java:189)
at org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter.doStart(MqttPahoMessageDrivenChannelAdapter.java:110)
at org.springframework.integration.endpoint.AbstractEndpoint.start(AbstractEndpoint.java:94)
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:173)
at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:51)
at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:346)
at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:149)
at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:112)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:770)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:483)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.XXX.integration.ieg.mqtt.RunMqtt.test(RunMqtt.java:18)
at com.XXX.integration.ieg.mqtt.RunMqtt.main(RunMqtt.java:39)
The properties file
mqtt.properties
mqttbrokerurl=tcp://172.18.128.150:1883
See this answer. When running in a web app, the classpath is relative to the web context.
According to StackTrace your property-placeholders aren't resolved and that's just because you don't have <context:property-placeholder> for your properties file.
Even if you say that it is:
The properties(mqttbrokerurl, serveruri) are loaded from root context
I don't see that stuff in your code:
You show only MQTT-Context.xml
Your RunMqtt starts only that context:
new ClassPathXmlApplicationContext("/META-INF/spring/integration/mqtt/mqtt-context.xml");
So, fix, please, those issues and come back to us with further progress.

NServiceBus 4 with Azure Storage getting NullReferenceException in TimeoutPersister

I am trying to use NServiceBus (version 4.6.0.0) with an ASP.NET MVC application hosted in a Windows Azure Website and Azure Storage for persistence but am having problems with the TimeoutManager.
Before trying to use Azure I got my app working with NServiceBus using the default MSMQ and RavenDB settings and then changed over to using Azure Storage. With that setup however I am getting multiple NullReferenceException errors right after startup in NServiceBus.Azure.TimoutManagerPersister.TryGetLastSuccessfulRead().
I have tried running this local using the Storage Emulator and with everything deployed to Azure and have the same error on both.
Here is how I have NServiceBus setup in my app:
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
public static IBus Bus { get; private set; }
protected void Application_Start()
{
...
Configure.ScaleOut(s => s.UseSingleBrokerQueue());
Feature.Enable<Sagas>();
IStartableBus startableBus = Configure.With()
.DefaultBuilder()
.DefineEndpointName("MyApp.Web")
.AzureConfigurationSource()
.UseTransport<AzureStorageQueue>()
.AzureMessageQueue()
.AzureSubscriptionStorage()
.UseAzureTimeoutPersister()
.AzureSagaPersister()
.PurgeOnStartup(false)
.UnicastBus()
.LoadMessageHandlers()
.RunHandlersUnderIncomingPrincipal(false)
.Log4Net(new DebugAppender { Threshold = Level.Warn })
.RijndaelEncryptionService()
.CreateBus();
Configure.Instance.ForInstallationOn<Windows>().Install();
Bus = startableBus.Start();
}
}
Web.config
<configSections>
<section name="MessageForwardingInCaseOfFaultConfig" type="NServiceBus.Config.MessageForwardingInCaseOfFaultConfig, NServiceBus.Core" />
<section name="UnicastBusConfig" type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core" />
<section name="AuditConfig" type="NServiceBus.Config.AuditConfig, NServiceBus.Core" />
<section name="AzureProfileConfig" type="NServiceBus.Config.AzureProfileConfig, NServiceBus.Hosting.Azure" />
<section name="AzureSubscriptionStorageConfig" type="NServiceBus.Config.AzureSubscriptionStorageConfig, NServiceBus.Azure" />
<section name="AzureSagaPersisterConfig" type="NServiceBus.Config.AzureSagaPersisterConfig, NserviceBus.Azure" />
<section name="AzureTimeoutPersisterConfig" type="NServiceBus.Config.AzureTimeoutPersisterConfig, NserviceBus.Azure" />
</configSections>
<connectionStrings>
<add name="NServiceBus/Transport" connectionString="DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=mykey" />
</connectionStrings>
<AzureSagaPersisterConfig ConnectionString="DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=mykey" CreateSchema="true" />
<AzureTimeoutPersisterConfig ConnectionString="DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=mykey" TimeoutManagerDataTableName="TimeoutManagerData" TimeoutDataTableName="TimeoutData" />
<AzureSubscriptionStorageConfig ConnectionString="DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=mykey" />
And here is the exception I am getting:
System.NullReferenceException was unhandled by user code
HResult=-2147467261
Message=Object reference not set to an instance of an object.
Source=Microsoft.Data.Services.Client
StackTrace:
at System.Data.Services.Client.UriWriter.VisitResourceSetExpression(ResourceSetExpression rse)
at System.Data.Services.Client.DataServiceALinqExpressionVisitor.Visit(Expression exp)
at System.Data.Services.Client.UriWriter.Translate(DataServiceContext context, Boolean addTrailingParens, Expression e, Uri& uri, Version& version)
at System.Data.Services.Client.DataServiceQueryProvider.Translate(Expression e)
at System.Data.Services.Client.DataServiceQuery`1.Translate()
at System.Data.Services.Client.DataServiceQuery`1.Execute()
at System.Data.Services.Client.DataServiceQuery`1.GetEnumerator()
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
at NServiceBus.Azure.SafeLinqExtensions.SafeFirstOrDefault[TSource](IEnumerable`1 source) in y:\BuildAgent\work\ba77a0c29cee2af1\src\NServiceBus.Azure\SafeLinqExtensions.cs:line 13
at NServiceBus.Azure.TimeoutPersister.TryGetLastSuccessfulRead(ServiceContext context, TimeoutManagerDataEntity& lastSuccessfulReadEntity) in
y:\BuildAgent\work\ba77a0c29cee2af1\src\NServiceBus.Azure\Timeout\TimeoutLogic\TimeoutPersister.cs:line 338
at NServiceBus.Azure.TimeoutPersister.GetNextChunk(DateTime startSlice, DateTime& nextTimeToRunQuery) in y:\BuildAgent\work\ba77a0c29cee2af1\src\NServiceBus.Azure\Timeout\TimeoutLogic\TimeoutPersister.cs:line 27
at NServiceBus.Timeout.Hosting.Windows.TimeoutPersisterReceiver.Poll(Object obj) in y:\BuildAgent\work\31f8c64a6e8a2d7c\src\NServiceBus.Core\Timeout\Hosting\Windows\TimeoutPersisterReceiver.cs:line 80
at System.Threading.Tasks.Task.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
Even with the error messages are getting added to the Azure queue and are being processed but only for a couple of minutes than the TimeoutManager stops processing and messages are not dequeued.
Sounds like something is wrong in the storage sdk that you are using, which version are you on?

WCF MaxItemsInObjectGraph setting not working

I have been getting the following error trying to access my WCF service.
'Maximum number of items that can be serialized or deserialized in an object graph is '65536'. Change the object graph or increase the MaxItemsInObjectGraph quota
Doing some research, it looks like all I need to do is update this setting to be a higher value. This is what I am trying to do, but the setting does not seem to be getting read from the configuration. I keep getting the same exception with the 65536 value in it.
I followed the instructions found at this Link, but am having no luck.
Here is what I have configured on the WCF Service's Web.Config.
<behaviors>
<serviceBehaviors>
<behavior name="metadataBehavior">
<serviceMetadata httpGetEnabled="true" httpGetUrl="" />
<serviceDebug includeExceptionDetailInFaults="false" />
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
</behavior>
</serviceBehaviors>
</behaviors>
This is what is in the Client's app.config:
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" />
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior >
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
</behavior>
</endpointBehaviors>
</behaviors>
And lastly, I have the following attribute on the WCF service itself:
[ServiceBehavior(MaxItemsInObjectGraph = 2147483646, IncludeExceptionDetailInFaults = true)]
Despite the configurations above, I still get an Exception complaining about the 65536 value. Why aren't any of these settings being used by the applications? Is there something else that needs to be set somewhere?
You were on the right track!
All you had to do was add a name to the behavior
<behavior name="MyBehavior">
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
</behavior>
And then on the end point add
<endpoint .... behaviorConfiguration="MyBehavior"/>
Had to go nuclear and update that machine.config;
Directions Here
The gist of it is to add the following to the "system.serviceModel" section.
<commonBehaviors>
<endpointBehaviors>
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</endpointBehaviors>
<serviceBehaviors>
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</serviceBehaviors>
</commonBehaviors>
I wrote a program to modify the machine configs for this, because support. It works for me, but I haven't done tons of testing.
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace FixMachineConfigBehavior
{
class Program
{
public static XElement IfNotExistsAdd(XDocument xd, XElement rootElement, string childName, XElement newChild)
{
if (rootElement.Elements(childName).Count() == 0)
{
Console.WriteLine(" adding " + childName + " node...");
rootElement.Add(newChild);
}
return rootElement.Element(childName);
}
static void Main(string[] args)
{
foreach (var file in Directory.EnumerateFiles(Environment.GetEnvironmentVariable("windir") + #"\Microsoft.NET\","machine.config",SearchOption.AllDirectories))
{
Console.WriteLine("fixing: " + file);
TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
double ms = t.TotalMilliseconds;
File.Copy(file, file + "." + ms + ".bak", true);
var xd = XDocument.Load(file);
XElement i = xd.Root;
i = IfNotExistsAdd(xd, i, "system.serviceModel", new XElement("system.serviceModel"));
i = IfNotExistsAdd(xd, i, "commonBehaviors", new XElement("commonBehaviors"));
i = IfNotExistsAdd(xd, i, "endpointBehaviors", new XElement("endpointBehaviors"));
i = IfNotExistsAdd(xd, i, "dataContractSerializer", new XElement("dataContractSerializer", new XAttribute("maxItemsInObjectGraph", Int32.MaxValue)));
xd.Save(file);
}
Console.ReadLine();
}
}
}
I had the same problem and tried several options but I found the solution here:
https://msdn.microsoft.com/en-us/library/ms732038.aspx
In "Controlling the serialization process".
Adding ...
[ServiceBehavior(MaxItemsInObjectGraph=100000)]
class My Service ...
good luck
I had the same issue , There was some enums in returning class. What found out they cannot be null. Check whether you have any Enums that are to be returned.

Threading issues with Hibernate

I'm experiencing a strange behaviour with Hibernate. I've been banging my head against the wall for a while now, and will award any answer which leads to a solution with a +100 bounty.
I have a JAX-RS (Jersey) REST server, with a filter that associates one Hibernate-session per request.
In one request a client POSTs some data which is stored in the database using one session (and one transaction). In a subsequent call, the client tries to GET this entity, but Hibernate can't find it.
Some observations:
I can only reproduce this if I run multiple simultaneous clients. I've never managed to reproduce it by running one client at a time.)
I can see the entity ID in the database, and if I restart the server, the entity is found by Hibernate as it should.
The error does not occur if I use a thread pool of size 1 (regardless of how many clients I run simultaneously).
Here's the code, with some logging:
chargeables.setId(new SecureRandom().nextLong());
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"session.beginTransaction()");
session.beginTransaction();
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"session.save(id = "+chargeables.getId()+")");
session.save(chargeables);
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"session.getTransaction().commit()");
session.getTransaction().commit();
The code for getting the entity:
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"session.get("+id+")");
Chargeables entity = (Chargeables) session.get(Chargeables.class, id);
if (entity == null)
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"ENTITY NOT FOUND!");
Now here is an excerpt of the resulting log (with some additional open/close session output):
Thread[Grizzly(5),5,main], session: 2041842357 [factory.openSession()]
Thread[Grizzly(5),5,main], session: 2041842357 [session.beginTransaction()]
Thread[Grizzly(5),5,main], session: 2041842357 [session.save(id = 7939229356942262438)]
Thread[Grizzly(5),5,main], session: 2041842357 [session.getTransaction().commit()]
Thread[Grizzly(5),5,main], session: 2041842357 [session.close()]
[...]
Thread[Grizzly(7),5,main], session: 1717445911 [factory.openSession()]
Thread[Grizzly(7),5,main], session: 1717445911 [session.get(7939229356942262438)]
Thread[Grizzly(7),5,main], session: 1717445911 [ENTITY NOT FOUND!]
Thread[Grizzly(7),5,main], session: 1717445911 [session.close()]
Why on earth do I reach ENTITY NOT FOUND!?
Hibernate version: 4.1.9.Final
MySQL verison: 14.14 Distrib 5.5.29
Mapping file for Chargeables:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping
default-cascade="all"
package="se.package.common.chargeables"
default-lazy="false">
<class name="Chargeables">
<id name="id" type="long">
<generator class="assigned"/>
</id>
<property name="startTimeStamp" />
<property name="endTimeStamp" />
<list name="chargeables">
<key column="chargeableId" />
<list-index column="pos" />
<many-to-many class="Chargeable"/>
</list>
</class>
<class name="Chargeable">
<id column="id" type="long">
<generator class="native"/>
</id>
<discriminator />
<property name="timestamp" />
</class>
<subclass name="DataTransfer" extends="Chargeable">
<property name="bytesSent" />
<property name="bytesReceived" />
</subclass>
<subclass name="TelephonyChargeable" extends="Chargeable">
<many-to-one name="num" />
</subclass>
<subclass name="Call" extends="TelephonyChargeable">
<property name="duration" />
</subclass>
<subclass name="OutgoingCall" extends="Call" />
<subclass name="IncomingCall" extends="Call" />
<subclass name="Message" extends="TelephonyChargeable" />
<subclass name="Sms" extends="Message" />
<subclass name="IncomingSms" extends="Sms" />
<subclass name="OutgoingSms" extends="Sms" />
<subclass name="Mms" extends="Message" />
<subclass name="IncomingMms" extends="Mms" />
<subclass name="OutgoingMms" extends="Mms" />
</hibernate-mapping>
IMHO it's an isolation problem. Your second session start before the transaction of the 1st one is commited. As default hibernate isolation level is read_commited, the 2nd session can't so retrieve the entity. How are you passing id between the 2 threads ?
If you can see the commit in the database, it cannot be an isolation issue at the MySQL level: console operations are also client operations, you don't get special powers when running them, so they conform to the isolation policy you selected.
Looking out for solution, I discovered that Hibernate provide some facilities to cache DB results: there are actually 2 levels of cache implemented there. Perhaps your hibernate installation comes bundled with a cache mechanism?
The first level works on a per session basis, which is consistent with the behaviour you observe when running the code on one thread, and seemingly happens to be activated by default. I am not Hibernate proficient, I can't say that for sure, but my opinion is that your setup has this first level of cache set in read-only mode, while you would like it to be in read-write mode.

log4net MemoryAppender not working

I'm using log4net to log in my app. My FileAppender is working fine, but I'm having problems with MemoryAppender.
Here is my config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="LogFileAppender" type="log4net.Appender.FileAppender">
<param name="File" value="Envision.log" />
<param name="AppendToFile" value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="Header" value="" />
<param name="Footer" value="" />
<param name="ConversionPattern" value="%d [%t] %-5p %m%n" />
</layout>
</appender>
<appender name="MemoryAppender" type="log4net.Appender.MemoryAppender">
</appender>
<root>
<level value="ALL" />
<appender-ref ref="LogFileAppender" />
<appender-ref ref="MemoryAppender" />
</root>
</log4net>
</configuration>
I use this code to setup the config file.
FileInfo file = new FileInfo(configPath);
log4net.Config.XmlConfigurator.Configure(file);
file = null;
Like I said, the FileAppender works great. But I can't seem to get any events.
I've tried using something like this to get the MemoryAppender.
Hierarchy hierarchy = LogManager.GetRepository() as Hierarchy;
MemoryAppender mappender = hierarchy.Root.GetAppender("MemoryAppender") as MemoryAppender;
I've tried using:
var events = mappender.GetEvents()
after logging something, and events is always empty. I've tried setting up the FileAppender and MemoryAppender in code instead of using the config file, and I get the same, the FileAppender works fine, but can't seem to get any events from MemoryAppender. Curious if I'm understanding MemoryAppender right? I also tried setting up a thread that loops checking for the GetEvents to not be empty, and while logging away it always comes back empty. I've tried setting the Threshold to Core.Level.All on the MemoryAppender but that did not change anything.
Thanks for any direction. I've looked around, and from the sites I've seen, I can't tell what I'm doing different.
Even something as simple as this does not work. events length is always zero;
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
MemoryAppender appender = new MemoryAppender();
ILog logger = LogManager.GetLogger("foo");
BasicConfigurator.Configure(appender);
logger.Error("Should work");
var events = appender.GetEvents();
}
}
For those that need it, here's how to do it programmatically in C#:
var memoryAppender = new MemoryAppender();
var repository = (log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository();
repository.Root.AddAppender(memoryAppender);
var events = memoryAppender.GetEvents();
I used Ralph's code above in my unit testing:
using log4net;
using log4net.Appender;
// ...
internal static MemoryAppender GetMemoLog<T>() where T: class
{
var memoLog = new MemoryAppender();
ILog appendableLog = LogManager.GetLogger(typeof(T).Assembly, typeof(T));
var repository = (log4net.Repository.Hierarchy.Hierarchy)appendableLog.Logger.Repository;
repository.Root.AddAppender(memoLog);
var logField = typeof(T).GetField("Log", BindingFlags.Static | BindingFlags.NonPublic);
if (logField != null) logField.SetValue(null, appendableLog);
return memoLog;
}
This assumes you have a private static Log field on your class:
private static readonly ILog Log = LogManager.GetLogger(typeof(MyClass));
So, in the test, it's just:
var memoLog = GetMemoLog<MyClass>();
// followed by test logic, and then...
var events = memoLog.GetEvents();
The simple sample code you posted works fine for me using log4net 1.2.10.0.
I would recommend downloading the source and stepping through it in a debugger. It may seem a little daunting at first, but you get used to their code pretty quickly and it's not hard to follow. I've done this many times when I had problems with custom constraints and appenders. It really helps solve problems quickly and gives you a much better understanding of how log4net works.
I figured it out. I was using the Compact Framework .dll by mistake. Once I realized that I switched to the .net 2.0 version, which caused a problem with log4net namespace not being found, so I did a search on that and realized I needed to change my .net Framework 4 client Profile to .net Framework 4. I'm now getting the events as expected.
I adapted CZahrobsky's answer. Had to tweak slightly, since my class cannot have static logger by design.
Class under test has the log field declared like:
private ILog Logger = Log4netFactory.GetLogger(typeof(MyClass));
In the GetMemLog logic I have to first create an instance of MyClass and change the logField look up to getField by name 'Logger' and BindingFlags.Instance instead of BindingFlags.Static
//create an instance of the class
var myObject = new MyClass(context);
var memoryLog = new MemoryAppender();
ILog appendableLog = LogManager.GetLogger(typeof(JobQueue).Assembly, typeof(MyClass));
var repository = (log4net.Repository.Hierarchy.Hierarchy)appendableLog.Logger.Repository;
repository.Root.AddAppender(memoryLog);
var logField = typeof(MyClass).GetField("Logger", BindingFlags.NonPublic | BindingFlags.Instance);
if (logField != null)
{
//set logfield property value for the instance
logField.SetValue(myObject, appendableLog);
}
Examples on SetValue() for PropertyInfo is here

Resources