Testing multiple db mappings in MappingIntegrationTests - nhibernate

What's the best approach for testing multiple db's in a s#arparch project?
The current SetUp() code in MappingIntegrationTests tries to test each assembly against the first database.
string[] mappingAssemblies = RepositoryTestsHelper.GetMappingAssemblies();
configuration = NHibernateSession.Init(new SimpleSessionStorage(), mappingAssemblies,
new AutoPersistenceModelGenerator().Generate(),
"../../../../app/Humanities.IBusiness.Web/NHibernate.config");
Has anyone managed to correctly test each mapping against the appropriate database schema?

Hey Alec, thanks for the reply. I've hacked a bit of a solution - it aint pretty but it does smoke test dodgy mappings across multiple db's
In the set up I add the following:
private List<string> sessionKeys;
[SetUp]
public virtual void SetUp()
{
string[] mappingAssemblies = RepositoryTestsHelper.GetMappingAssemblies();
configuration = NHibernateSession.Init(new SimpleSessionStorage(), mappingAssemblies,
new AutoPersistenceModelGenerator().Generate(),
"../../../../app/Humanities.IBusiness.Web/NHibernate.config");
/*NEW CODE */
var configuration2 = NHibernateSession.AddConfiguration(DataGlobals.ROLES_DB_FACTORY_KEY,
mappingAssemblies,
new AutoPersistenceModelGenerator().Generate(),
"../../../../app/Humanities.IBusiness.Web/NHibernateForRolesDb.config",null,null, null);
sessionKeys = new List<string>();
sessionKeys.Add(DataGlobals.DEFAULT_DB_KEY);
sessionKeys.Add(DataGlobals.ROLES_DB_FACTORY_KEY);
Then in the CanConfirmDatabaseMatchesMappings
foreach (var entry in allClassMetadata)
{
bool found = false;
foreach (string key in sessionKeys)
{
ISession session = NHibernateSession.CurrentFor(key);
try
{
session.CreateCriteria(entry.Value.GetMappedClass(EntityMode.Poco))
.SetMaxResults(0).List();
found = true;
}
catch (Exception ex) { }
}
if (found == false)
throw new MappingException("Mapping not found for " + entry.Key.ToString());
}
Not sure if it's a full answer but better than nothing :)
Any thoughts?

Al,
to be honest I do not know the extent that the users are using Multiple Databases. This is something I believe a few very vocal people lobbied for in the beginning of the projects lifecycle. This is something I was going to ask the community about, looks like the time has come for the question to be asked.
What you might need to do is move the set-up code into individual methods. While I am not crazy with breaking the DRY principal, it would seem in this case it is required.
Alec

Related

Register Hibernate 5 Event Listeners

I am working on a legacy non-Spring application, and it is being migrated from Hibernate 3 to Hibernate 5.6.0.Final (latest at this time). I have generally never used Hibernate Event Listeners in my work, so this is quite new to me, and I am studying these in Hibernate 5.
Currently in some test class we have defined the code this way for Hibernate 3:
protected static Configuration createSecuredDatabaseConfig() {
Configuration config = createUnrestrictedDatabaseConfig();
config.setListener("pre-insert", "com.app.server.services.db.eventlisteners.MySecurityHibernateEventListener");
config.setListener("pre-update", "com.app.server.services.db.eventlisteners.MySecurityHibernateEventListener");
config.setListener("pre-delete", "com.app.server.services.db.eventlisteners.MySecurityHibernateEventListener");
config.setListener("pre-load", "com.app.server.services.db.eventlisteners.EkoSecurityHibernateEventListener");
return config;
}
This is obviously no longer valid, and I believe I need to create a Hibernate Integrator, which I have done.
public class MyEventListenerIntegrator implements Integrator {
#Override
public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
EventListenerRegistry eventListenerRegistry = serviceRegistry.getService(EventListenerRegistry.class);
eventListenerRegistry.getEventListenerGroup(EventType.PRE_INSERT).appendListener(new MySecurityHibernateEventListener());
eventListenerRegistry.getEventListenerGroup(EventType.PRE_UPDATE).appendListener(new MySecurityHibernateEventListener());
eventListenerRegistry.getEventListenerGroup(EventType.PRE_DELETE).appendListener(new MySecurityHibernateEventListener());
eventListenerRegistry.getEventListenerGroup(EventType.PRE_LOAD).appendListener(new MySecurityHibernateEventListener());
}
So, now I believe the next step is to add this to the session via the registry builder. I am using this website to help me:
https://www.boraji.com/hibernate-5-event-listener-example
Because we were using older Hibernate 3, we had code to create our session factory as follows:
protected static SessionFactory buildSessionFactory(Database db)
{
if (db == null) {
throw new NullPointerException("Database specifier cannot be null");
}
try {
Configuration config = createSessionFactoryConfiguration(db);
String url = config.getProperty("connection.url");
String user = config.getProperty("connection.username");
String password = config.getProperty("connection.password");
try {
String dbDriver = config.getProperty("hibernate.connection.driver_class");
Class.forName(dbDriver);
Connection conn = DriverManager.getConnection(url, user, password);
}
catch (SQLException error) {
logger.info("Didn't find driver, on QA or production, so it's okay to assume we have DB connection");
error.printStackTrace();
}
SessionFactory sessionFactory = config.buildSessionFactory();
sessionFactoryConfigs.put(sessionFactory, config); // Cannot recover config from factory instance, must be stored.
return sessionFactory;
}
catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
logger.error("Initial SessionFactory creation failed.", ex);
throw new ExceptionInInitializerError(ex);
}
}
The link that I referred to above has a much different way of creating the sessionfactory. So, I'll be testing that out to see if it works in our app.
Without Spring handling our sessions and transactions, in this app it is coded by hand the way it was done before Spring, and I haven't seen that kind of code in years.
I solved this issue with the help from the link I provided above. However, I didn't copy exactly what they did, but some of it helped. My solution is as follows:
protected static SessionFactory createSecuredDatabaseConfig() {
Configuration config = createUnrestrictedDatabaseConfig();
BootstrapServiceRegistry bootstrapRegistry =
new BootstrapServiceRegistryBuilder()
.applyIntegrator(new EkoEventListenerIntegrator())
.build();
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder(bootstrapRegistry).applySettings(config.getProperties()).build();
SessionFactory sessionFactory = config.buildSessionFactory(serviceRegistry);
return sessionFactory;
}
This was it. I tried multiple different ways to register the events without the BootstrapServiceRegistry, but none of those worked. I did have to create the integrator. What I did NOT include was the following:
MetadataSources sources = new MetadataSources(serviceRegistry )
.addPackage("com.myproject.server.model");
Metadata metadata = sources.getMetadataBuilder().build();
// did not create the sessionFactory this way
sessionFactory = metadata.getSessionFactoryBuilder().build();
If I had gone further and use this method to create the sessionFactory, then all of my queries would have been complaining about not being able to find the parameterName, which is something else.
The Hibernate Integrator and this method to create the sessionFactory is all for the unit tests. Without registering these events, one unit test would fail, and now it doesn't. So, this solves my problem for now.

Why I'm getting all history revisions when querying for Iterations or Releases?

I'm working with Rally REST API for Java
I want get the list of actual Iterations and Releases
here is the snippet
JsonObject projects = new JsonObject();
QueryRequest queryProjects = new QueryRequest("release");
queryProjects.setPageSize(1);
queryProjects.setLimit(1000);
queryProjects.setFetch(new Fetch("_refObjectName","Name"));
QueryResponse queryResponse;
try {
queryResponse = restApi.query(queryProjects);
} catch (IOException e) {
// TODO Auto-generated catch block
throw new ServiceException(e);
}
In result I'm getting the list with a lot of duplicates. After closer inspection it seems I'm getting all versions of object - for the same Iteration/Release I have multiple versions - I can see different "_objectVersion" attribute for such duplicates.
Why is it so?
Can you please help me with the query which will retrieve distinct list of Iterations / Releases - I'm interested in just latest versions.
I can filter it out in Java but have a feeling there is more 'proper' way of doing this. Also getting the list with whole object history is not the best for code performance.
Thanks for any help!
When Releases and Iterations are created in Rally in a top project there is an option to propagate them throughout the project hierarchy. For example, if you have top project P1 with child project P2 and grandchild projects P21 and P22, you may create 4 releases with the same name and the same start and release dates. They are not identical releases: they have ObjectID and _ref unique to them. Please verify if this applies to your scenario.
To limit release query to a specific project set request project. Here is an example that returns only three releases that I have in a top project: R1,R2, and R3. Note
String projectRef = "/project/12352608219";
that is used later in the code:
releaseRequest.setProject(projectRef);
Note also the commented out
//String workspaceRef = "/workspace/12352608129";
and
// releaseRequest.setWorkspace(workspaceRef);
If I switch the comments: comment out project reference and uncomment workspace reference I will get what you called duplicates: multiple R1, R2 and R3 releases.
public class FindReleases {
public static void main(String[] args) throws URISyntaxException, IOException {
String host = "https://rally1.rallydev.com";
String username = "user#co.com";
String password = "secret";
String projectRef = "/project/12352608219";
//String workspaceRef = "/workspace/12352608129";
String applicationName = "RESTExampleFindReleasesByProject";
RallyRestApi restApi = null;
try {
restApi = new RallyRestApi(
new URI(host),
username,
password);
restApi.setApplicationName(applicationName);
System.out.println(restApi.getWsapiVersion()); //v.2.0 by default when using 2.0.2 jar and up
QueryRequest releaseRequest = new QueryRequest("Release");
releaseRequest.setFetch(new Fetch("Name"));
releaseRequest.setLimit(1000);
releaseRequest.setScopedDown(false);
releaseRequest.setScopedUp(false);
// releaseRequest.setWorkspace(workspaceRef);
releaseRequest.setProject(projectRef);
QueryResponse releaseQueryResponse = restApi.query(releaseRequest);
int numberOfReleasesInProject = releaseQueryResponse.getTotalResultCount();
System.out.println(numberOfReleasesInProject);
if(numberOfReleasesInProject >0){
for (int i=0;i<numberOfReleasesInProject;i++){
JsonObject releaseJsonObject = releaseQueryResponse.getResults().get(i).getAsJsonObject();
System.out.println(releaseJsonObject.get("Name"));
}
}
}
finally{
if (restApi != null) {
restApi.close();
}
}
}
}

Rss20FeedFormatter Ignores TextSyndicationContent type for SyndicationItem.Summary

While using the Rss20FeedFormatter class in a WCF project, I was trying to wrap the content of my description elements with a <![CDATA[ ]]> section. I found that no matter what I did, the HTML content of the description elements was always encoded and the CDATA section was never added. After peering into the source code of Rss20FeedFormatter, I found that when building the Summary node, it basically creates a new TextSyndicationContent instance which wipes out whatever settings were previously specified (I think).
My Code
public class CDataSyndicationContent : TextSyndicationContent
{
public CDataSyndicationContent(TextSyndicationContent content)
: base(content)
{
}
protected override void WriteContentsTo(System.Xml.XmlWriter writer)
{
writer.WriteCData(Text);
}
}
... (The following code should wrap the Summary with a CDATA section)
SyndicationItem item = new SyndicationItem();
item.Title = new TextSyndicationContent(name);
item.Summary = new CDataSyndicationContent(
new TextSyndicationContent(
"<div>This is a test</div>",
TextSyndicationContentKind.Html));
Rss20FeedFormatter Code
(AFAIK, the above code does not work because of this logic)
...
else if (reader.IsStartElement("description", ""))
result.Summary = new TextSyndicationContent(reader.ReadElementString());
...
As a workaround, I've resorted to using the RSS20FeedFormatter to build the RSS, and then patch the RSS manually. For example:
StringBuilder buffer = new StringBuilder();
XmlTextWriter writer = new XmlTextWriter(new StringWriter(buffer));
feedFormatter.WriteTo(writer ); // feedFormatter = RSS20FeedFormatter
PostProcessOutputBuffer(buffer);
WebOperationContext.Current.OutgoingResponse.ContentType =
"application/xml; charset=utf-8";
return new MemoryStream(Encoding.UTF8.GetBytes(buffer.ToString()));
...
public void PostProcessOutputBuffer(StringBuilder buffer)
{
var xmlDoc = XDocument.Parse(buffer.ToString());
foreach (var element in xmlDoc.Descendants("channel").First()
.Descendants("item")
.Descendants("description"))
{
VerifyCdataHtmlEncoding(buffer, element);
}
foreach (var element in xmlDoc.Descendants("channel").First()
.Descendants("description"))
{
VerifyCdataHtmlEncoding(buffer, element);
}
buffer.Replace(" xmlns:a10=\"http://www.w3.org/2005/Atom\"",
" xmlns:atom=\"http://www.w3.org/2005/Atom\"");
buffer.Replace("a10:", "atom:");
}
private static void VerifyCdataHtmlEncoding(StringBuilder buffer,
XElement element)
{
if (!element.Value.Contains("<") || !element.Value.Contains(">"))
{
return;
}
var cdataValue = string.Format("<{0}><![CDATA[{1}]]></{2}>",
element.Name,
element.Value,
element.Name);
buffer.Replace(element.ToString(), cdataValue);
}
The idea for this workaround came from the following location, I just adapted it to work with WCF instead of MVC. http://localhost:8732/Design_Time_Addresses/SyndicationServiceLibrary1/Feed1/
I'm just wondering if this is simply a bug in Rss20FeedFormatter or is it by design? Also, if anyone has a better solution, I'd love to hear it!
Well #Page Brooks, I see this more as a solution then as a question :). Thanks!!! And to answer your question ( ;) ), yes, I definitely think this is a bug in the Rss20FeedFormatter (though I did not chase it as far), because had encountered precisely the same issue that you described.
You have a 'localhost:8732' referral in your post, but it wasn't available on my localhost ;). I think you meant to credit the 'PostProcessOutputBuffer' workaround to this post:
http://damieng.com/blog/2010/04/26/creating-rss-feeds-in-asp-net-mvc
Or actually it is not in this post, but in a comment to it by David Whitney, which he later put in a seperate gist here:
https://gist.github.com/davidwhitney/1027181
Thank you for providing the adaption of this workaround more to my needs, because I had found the workaround too, but was still struggling to do the adaptation from MVC. Now I only needed to tweak your solution to put the RSS feed to the current Http request in the .ashx handler that I was using it in.
Basically I'm guessing that the fix you mentioned using the CDataSyndicationContent, is from feb 2011, assuming you got it from this post (at least I did):
SyndicationFeed: Content as CDATA?
This fix stopped working in some newer ASP.NET version or something, due to the code of the Rss20FeedFormatter changing to what you put in your post. This code change might as well have been an improvement for other stuff that IS in the MVC framework, but for those using the CDataSyndicationContent fix it definitely causes a bug!
string stylesheet = #"<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""><xsl:output cdata-section-elements=""description"" method=""xml"" indent=""yes""/></xsl:stylesheet>";
XmlReader reader = XmlReader.Create(new StringReader(stylesheet));
XslCompiledTransform t = new XslCompiledTransform(true);
t.Load(reader);
using (MemoryStream ms = new MemoryStream())
{
XmlWriter writer = XmlWriter.Create(ms, t.OutputSettings);
rssFeed.WriteTo(writer); // rssFeed is Rss20FeedFormatter
writer.Flush();
ms.Position = 0;
string niko = Encoding.UTF8.GetString(ms.ToArray());
}
I'm sure someone pointed this out already but this a stupid workaround I used.
t.OutputSettings is of type XmlWriterSettings with cdataSections being populated with a single XmlQualifiedName "description".
Hope it helps someone else.
I found the code for Cdata elsewhere
public class CDataSyndicationContent : TextSyndicationContent
{
public CDataSyndicationContent(TextSyndicationContent content)
: base(content)
{
}
protected override void WriteContentsTo(System.Xml.XmlWriter writer)
{
writer.WriteCData(Text);
}
}
Code to call it something along the lines:
item.Content = new Helpers.CDataSyndicationContent(new TextSyndicationContent("<span>TEST2</span>", TextSyndicationContentKind.Html));
However the "WriteContentsTo" function wasn't being called.
Instead of Rss20FeedFormatter I tried Atom10FeedFormatter - and it worked!
Obviously this gives Atom feed rather than traditional RSS - but worth mentioning.
Output code is:
//var formatter = new Rss20FeedFormatter(feed);
Atom10FeedFormatter formatter = new Atom10FeedFormatter(feed);
using (var writer = XmlWriter.Create(response.Output, new XmlWriterSettings { Indent = true }))
{
formatter.WriteTo(writer);
}

RhinoMocks AAA Syntax

I've spent a good part of the day trying to figure out why a simple RhinoMocks test doesn't return the value I'm setting in the return. I'm sure that I'm just missing something really simple but I can't figure it out. Here's my test:
[TestMethod]
public void CopyvRAFiles_ShouldCallCopyvRAFiles_ShouldReturnTrue2()
{
FileInfo fi = new FileInfo(#"c:\Myprogram.txt");
FileInfo[] myFileInfo = new FileInfo[2];
myFileInfo[0] = fi;
myFileInfo[1] = fi;
var mockSystemIO = MockRepository.GenerateMock<ISystemIO>();
mockSystemIO.Stub(x => x.GetFilesForCopy("c:")).Return(myFileInfo);
mockSystemIO.Expect(y => y.FileCopyDateCheck(#"c:\Myprogram.txt", #"c:\Myprogram.txt")).Return("Test");
CopyFiles copy = new CopyFiles(mockSystemIO);
List<string> retValue = copy.CopyvRAFiles("c:", "c:", new AdminWindowViewModel(vRASharedData));
mockSystemIO.VerifyAllExpectations();
}
I have an interface for my SystemIO class I'm passing in a mock for that to my CopyFiles class. I'm setting an expectation on my FileCopyDatCheck method and saying that it should Return("Test"). When I step through the code, it returns a null insteaed. Any ideas what I'm missing here?
Here's my CopyFiles class Method:
public List<string> CopyvRAFiles(string currentDirectoryPath, string destPath, AdminWindowViewModel adminWindowViewModel)
{
string fileCopied;
List<string> filesCopied = new List<string>();
try
{
sysIO.CreateDirectoryIfNotExist(destPath);
FileInfo[] files = sysIO.GetFilesForCopy(currentDirectoryPath);
if (files != null)
{
foreach (FileInfo file in files)
{
fileCopied = sysIO.FileCopyDateCheck(file.FullName, destPath + file.Name);
filesCopied.Add(fileCopied);
}
}
//adminWindowViewModel.CheckFilesThatRequireSystemUpdate(filesCopied);
return filesCopied;
}
catch (Exception ex)
{
ExceptionPolicy.HandleException(ex, "vRAClientPolicy");
Console.WriteLine("{0} Exception caught.", ex);
ShowErrorMessageDialog(ex);
return null;
}
}
I would think that "fileCopied" would have the Return value set by the Expect. The GetFilesForCopy returns the two files in myFileInfo. Please Help. :)
thanks in advance!
A mock will not start returning recorded answers until it is switched to replay mode with Replay(). Stubs and mocks do no work in the same way. I have written a blog post about the difference.
Also note that you are mixing the old record-replay-verify syntax with the new arrange-act-assert syntax. With AAA, you should not use mocks and Expect. Instead, use stubs and AssertWasCalled like this:
[TestMethod]
public void CopyvRAFiles_ShouldCallCopyvRAFiles_ShouldReturnTrue2()
{
// arrange
FileInfo fi = new FileInfo(#"c:\Myprogram.txt");
FileInfo[] myFileInfo = new FileInfo[2];
myFileInfo[0] = fi;
myFileInfo[1] = fi;
var stubSystemIO = MockRepository.GenerateStub<ISystemIO>();
stubSystemIO.Stub(
x => x.GetFilesForCopy(Arg<string>.Is.Anything)).Return(myFileInfo);
stubSystemIO.Stub(
y => y.FileCopyDateCheck(
Arg<string>.Is.Anything, Arg<string>.Is.Anything)).Return("Test");
CopyFiles copy = new CopyFiles(mockSystemIO);
// act
List<string> retValue = copy.CopyvRAFiles(
"c:", "c:", new AdminWindowViewModel(vRASharedData));
// make assertions here about return values, state of objects, stub usage
stubSystemIO.AssertWasCalled(
y => y.FileCopyDateCheck(#"c:\Myprogram.txt", #"c:\Myprogram.txt"));
}
Note how setting up the behavior of stubs at the start is separate from the assertions at the end. Stub does not set any expectations.
The advantage of seperating behavior and assertions is that you can make less assertions per test, making it easier to diagnose why a test failed.
Does the method FileCopyDateCheck really get called with the exact strings #"c:\Myprogram.txt" and #"c:\Myprogram.txt" as arguments?
I am not sure if FileInfo is doing something with c:\. Maybe it is modified to upper case C:\, which would make your expectation not working.
Maybe try an expectation which does not check for the exact argument values
mockSystemIO.Expect(y => y.FileCopyDateCheck(Arg<string>.Is.Anything, Arg<string>.Is.Anything)).Return("Test");
For more details about argument constraints see: Rhino Mocks 3.5, Argument Constraints
I am pretty sure that there are also possibilities to make the expectation case insensitive.
I think it's because your CopyvRAFiles() method isn't virtual.

Serialize an Activity to xaml

I have Googled a bit, and cannot seem to find any examples of Xaml-fying Activities - good, bad, or otherwise!
public static string ToXaml (this Activity activity)
{
// i would use ActivityXamlServices to go from Xaml
// to activity, but how to go other way? documentation
// is slim, and cannot infer proper usage of
// ActivityXamlServices from Xml remarks :S
string xaml = string.Empty;
return xaml;
}
Hints, tips, pointers would be welcome :)
NOTE: so found this. Will work through and update once working. Anyone wanna beat me to the punch, by all means. Better yet, if you can find a way to be rid of WorkflowDesigner, seems odd it is required.
Alright, so worked through this forum posting.
You may Xaml-fy [ie transform an instance to declarative Xaml] a well-known Activity via
public static string ToXaml (this Activity activity)
{
StringBuilder xaml = new StringBuilder ();
using (XmlWriter xmlWriter = XmlWriter.Create (
xaml,
new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true, }))
using (XamlWriter xamlWriter = new XamlXmlWriter (
xmlWriter,
new XamlSchemaContext ()))
using (XamlWriter xamlServicesWriter =
ActivityXamlServices.CreateBuilderWriter (xamlWriter))
{
ActivityBuilder activityBuilder = new ActivityBuilder
{
Implementation = activity
};
XamlServices.Save (xamlServicesWriter, activityBuilder);
}
return xaml.ToString ();
}
Your Xaml may contain certain artifacts, such as references to System.Activities.Presentation namespace appearing as xmlns:sap="...". If this presents an issue in your solution, read the source link above - there is a means to inject directives to ignore unrecognized namespaces.
Will leave this open for a while. If anyone can find a better solution, or improve upon this, please by all means :)
How about XamlServices.Save(filename, activity)?
Based on the other solution (for VS2010B2) and some Reflectoring, I found a solution for VS2010RC. Since XamlWriter is abstract in the RC, the new way to serialize an activity tree is this:
public static string ToXaml (this Activity activity)
{
var xamlBuilder = new StringBuilder();
var xmlWriter = XmlWriter.Create(xamlBuilder,
new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true });
using (xmlWriter)
{
var xamlXmlWriter =
new XamlXmlWriter(xmlWriter, new XamlSchemaContext());
using (xamlXmlWriter)
{
XamlWriter xamlWriter =
ActivityXamlServices.CreateBuilderWriter(xamlXmlWriter);
using (xamlWriter)
{
var activityBuilder =
new ActivityBuilder { Implementation = sequence };
XamlServices.Save(xamlWriter, activityBuilder);
}
}
}
return xamlBuilder.ToString();
}