/*
* Copyright 2013 Gordon Burgett and individual contributors
*
* 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 org.xflatdb.xflat.db;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.hamcrest.Matchers;
import org.jdom2.Element;
import org.jdom2.xpath.XPathFactory;
import org.junit.After;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import static org.mockito.Mockito.*;
import org.xflatdb.xflat.Cursor;
import org.xflatdb.xflat.XFlatConstants;
import org.xflatdb.xflat.convert.ConversionService;
import org.xflatdb.xflat.convert.DefaultConversionService;
import org.xflatdb.xflat.convert.converters.JDOMConverters;
import org.xflatdb.xflat.convert.converters.StringConverters;
import org.xflatdb.xflat.query.XPathQuery;
import org.xflatdb.xflat.query.XPathUpdate;
import org.xflatdb.xflat.transaction.TransactionManager;
import org.xflatdb.xflat.transaction.TransactionOptions;
import org.xflatdb.xflat.transaction.TransactionScope;
import test.Bar;
import test.Foo;
/**
*
* @author gordon
*/
public class ConvertingKeyValueTableTest {
public ConvertingKeyValueTableTest() {
}
ConversionService conversionService;
Engine engine;
private XPathFactory xpath;
ConvertingKeyValueTable getInstance(){
conversionService.addConverter(Foo.class, Element.class, new Foo.ToElementConverter());
conversionService.addConverter(Element.class, Foo.class, new Foo.FromElementConverter());
conversionService.addConverter(Bar.class, Element.class, new Bar.ToElementConverter());
conversionService.addConverter(Element.class, Bar.class, new Bar.FromElementConverter());
ConvertingKeyValueTable fooInstance = new ConvertingKeyValueTable("foo");
fooInstance.setConversionService(conversionService);
fooInstance.setEngineProvider(new EngineProvider() {
@Override
public Engine provideEngine() {
return engine;
}
});
return fooInstance;
};
@Before
public void setUp() {
conversionService = new DefaultConversionService();
StringConverters.registerTo(conversionService);
JDOMConverters.registerTo(conversionService);
engine = mock(Engine.class);
xpath = XPathFactory.instance();
}
@After
public void tearDown() {
}
private String getId(Element data){
return data.getAttributeValue("id", XFlatConstants.xFlatNs);
}
private void setId(Element e, String id){
e.setAttribute("id", id, XFlatConstants.xFlatNs);
}
@Test
public void testAdd_Foo_FooIsAdded() throws Exception {
System.out.println("testAdd_Foo_FooIsAdded");
Foo foo = new Foo();
foo.fooInt = 17;
//ACT
getInstance().add("foo", foo);
//ASSERT
ArgumentCaptor<Element> dataCaptor = ArgumentCaptor.forClass(Element.class);
verify(engine).insertRow(argThat(Matchers.equalTo("foo")), dataCaptor.capture());
Element data = dataCaptor.getValue();
assertEquals("Data should be a foo", "foo", data.getName());
assertEquals("Should have stored foo in element", "17", data.getChild("fooInt").getValue());
}
@Test
public void testSet_Foo_FooIsSet() throws Exception {
System.out.println("testSet_Foo_FooIsSet");
Foo foo = new Foo();
foo.fooInt = 17;
//ACT
getInstance().set("foo", foo);
//ASSERT
ArgumentCaptor<Element> dataCaptor = ArgumentCaptor.forClass(Element.class);
verify(engine).upsertRow(argThat(Matchers.equalTo("foo")), dataCaptor.capture());
Element data = dataCaptor.getValue();
assertEquals("Data should be a foo", "foo", data.getName());
assertEquals("Should have stored foo in element", "17", data.getChild("fooInt").getValue());
}
@Test
public void testPut_Foo_RowDoesNotExist_RowIsInserted() throws Exception {
System.out.println("testPut_Foo_RowDoesNotExist_RowIsInserted");
Foo foo = new Foo();
foo.fooInt = 17;
//ACT
Foo old = getInstance().put("foo", foo);
//ASSERT
assertNull(old);
ArgumentCaptor<Element> dataCaptor = ArgumentCaptor.forClass(Element.class);
verify(engine).insertRow(argThat(Matchers.equalTo("foo")), dataCaptor.capture());
Element data = dataCaptor.getValue();
assertEquals("Data should be a foo", "foo", data.getName());
assertEquals("Should have stored foo in element", "17", data.getChild("fooInt").getValue());
}
@Test
public void testPut_Foo_RowExists_OldRowIsReturned() throws Exception {
System.out.println("testPut_Foo_RowExists_OldRowIsReturned");
Foo foo = new Foo();
foo.fooInt = 17;
Element inEngine = new Element("Foo").setContent( new Element("fooInt").setText("16"));
when(engine.readRow("foo"))
.thenReturn(inEngine);
when(engine.replaceRow(eq("foo"), any(Element.class)))
.thenReturn(inEngine);
//ACT
Foo old = getInstance().put("foo", foo);
//ASSERT
assertNotNull(old);
assertEquals(16, old.fooInt);
ArgumentCaptor<Element> dataCaptor = ArgumentCaptor.forClass(Element.class);
verify(engine).replaceRow(argThat(Matchers.equalTo("foo")), dataCaptor.capture());
Element data = dataCaptor.getValue();
assertEquals("Data should be a foo", "foo", data.getName());
assertEquals("Should have stored foo in element", "17", data.getChild("fooInt").getValue());
}
@Test
public void testGet_NoDataInDb_NothingReturned() throws Exception {
System.out.println("testGet_NoDataInDb_NothingReturned");
//act
Foo inDb = getInstance().get("foo", Foo.class);
//assert
assertNull(inDb);
}
@Test
public void testGet_DataInDb_GetsData() throws Exception {
System.out.println("testGet_DataInDb_GetsData");
when(engine.readRow("foo"))
.thenReturn(new Element("Foo").setContent( new Element("fooInt").setText("16")));
//act
Foo inDb = getInstance().get("foo", Foo.class);
//assert
assertNotNull(inDb);
assertEquals(16, inDb.fooInt);
}
@Test
public void testFindOne_Foo_DeserializesAndClosesCursor() throws Exception {
System.out.println("testFindOne_Foo_DeserializesAndClosesCursor");
Element inDb = new Element("foo");
inDb.addContent(new Element("fooInt").setText("32"));
XPathQuery query = XPathQuery.eq(xpath.compile("foo/fooInt"), 32);
Cursor<Element> mockCursor = getMockCursor(inDb);
when(engine.queryTable(query))
.thenReturn(mockCursor);
//ACT
Foo found = getInstance().findOne(query, Foo.class);
//ASSERT
assertNotNull("Should have found one", found);
assertEquals("Should have deserialized", 32, found.fooInt);
verify(mockCursor).close();
}//end testFindOne_Foo_DeserializesAndClosesCursor
@Test
public void testFind_Foo_ReturnsConvertingCursor() throws Exception {
System.out.println("testFind_Foo_ReturnsConvertingCursor");
Element inDb1 = new Element("foo")
.addContent(new Element("fooInt").setText("32"));
Element inDb2 = new Element("foo")
.addContent(new Element("fooInt").setText("33"));
XPathQuery query = XPathQuery.gte(xpath.compile("foo/fooInt"), 32);
Cursor<Element> mockCursor = getMockCursor(inDb1, inDb2);
when(engine.queryTable(query))
.thenReturn(mockCursor);
//ACT
Cursor<Foo> fooCursor = getInstance().find(query, Foo.class);
//ASSERT
Iterator<Foo> i = fooCursor.iterator();
Foo found1 = i.next();
Foo found2 = i.next();
assertEquals("Should have gotten correct values", 32, found1.fooInt);
assertEquals("Should have gotten correct values", 33, found2.fooInt);
//verify engine cursor is closed when we close returned cursor
verify(mockCursor, never()).close();
fooCursor.close();
verify(mockCursor).close();
}//end testFind_Foo_ReturnsConvertingCursor
@Test
public void testFindAll_Foo_ConvertsAllToList() throws Exception {
System.out.println("testFindAll_Foo_ConvertsAllToList");
Element inDb1 = new Element("foo")
.addContent(new Element("fooInt").setText("32"));
Element inDb2 = new Element("foo")
.addContent(new Element("fooInt").setText("33"));
XPathQuery query = XPathQuery.gte(xpath.compile("foo/fooInt"), 32);
Cursor<Element> mockCursor = getMockCursor(inDb1, inDb2);
when(engine.queryTable(query))
.thenReturn(mockCursor);
//ACT
List<Foo> fooList = getInstance().findAll(query, Foo.class);
//ASSERT
Foo found1 = fooList.get(0);
Foo found2 = fooList.get(1);
assertEquals("Should have gotten correct values", 32, found1.fooInt);
assertEquals("Should have gotten correct values", 33, found2.fooInt);
}//end testFindAll_Foo_ConvertsAllToList
@Test
public void testReplace_Foo_ReplacesRowWithSameId() throws Exception {
System.out.println("testReplace_Foo_ReplacesRowWithSameId");
Foo replacement = new Foo();
replacement.fooInt = 17;
replacement.setId("test id");
//act
this.getInstance().replace("test id", replacement);
//assert
ArgumentCaptor<Element> captor = ArgumentCaptor.forClass(Element.class);
verify(engine).replaceRow(eq("test id"), captor.capture());
assertEquals("Should have replaced with serialized data", "17",
captor.getValue().getChild("fooInt").getText());
}//end testReplace_Foo_ReplacesRowWithSameId
@Test
public void testUpdate_SendsThroughToEngine() throws Exception {
System.out.println("testUpdate_SendsThroughToEngine");
XPathUpdate update = XPathUpdate.set(xpath.compile("fooInt"), 32);
when(engine.update("test", update))
.thenReturn(Boolean.TRUE);
//ACT
boolean didUpdate = this.getInstance().update("test", update);
//ASSERT
assertTrue("Should have invoked update to get true result", didUpdate);
verify(engine).update("test", update);
}//end testUpdate_Id_ConvertsId
@Test
public void testDelete_SendsThroughToEngine() throws Exception {
System.out.println("testDelete_SendsThroughToEngine");
//ACT
this.getInstance().delete("test");
//ASSERT
verify(engine).deleteRow("test");
}//end testDelete_Id_ConvertsId
@Test
public void testDeleteAll_Passthrough() throws Exception {
System.out.println("testDeleteAll_Passthrough");
XPathQuery query = XPathQuery.eq(xpath.compile("foo/fooInt"), 17);
//ACT
this.getInstance().deleteAll(query);
//ASSERT
verify(engine).deleteAll(query);
}//end testDeleteAll_Passthrough
private Cursor<Element> getMockCursor(Element... elements){
return getMockCursor(Arrays.asList(elements));
}
private Cursor<Element> getMockCursor(final Iterable<Element> elements){
Cursor<Element> ret = mock(Cursor.class);
when(ret.iterator())
.thenReturn(elements.iterator());
return ret;
}
}