/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright © 2011-2013 ForgeRock AS. All rights reserved.
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* http://forgerock.org/license/CDDLv1.0.html
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at http://forgerock.org/license/CDDLv1.0.html
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*/
package org.forgerock.openidm.repo.orientdb.impl;
import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
import com.orientechnologies.orient.core.metadata.schema.OType;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.server.OServer;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.forgerock.json.resource.ConflictException;
import org.testng.annotations.*;
import static org.testng.Assert.*;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.fest.assertions.api.Assertions.entry;
public class DocumentUtilTest {
String dbURL = "plocal:./target/docutiltestdb";
ODatabaseDocumentTx db = null;
String orientDocClass = "Sample";
OServer server;
@BeforeClass
public void init() throws Exception {
db = new ODatabaseDocumentTx(dbURL);
if (!db.exists()) {
db.create();
} else {
db.open("admin", "admin");
}
}
@AfterClass
public void cleanup() {
if (db != null) {
db.close();
}
}
@Test
public void docToMapNullTest() {
assertNull(DocumentUtil.toMap(null));
}
@Test
public void flatDocToMap() {
ODocument doc = new ODocument();
doc.field(DocumentUtil.ORIENTDB_PRIMARY_KEY, "client-assigned-id");
doc.field("firstname", "Sam");
doc.field("lastname", "Iam");
doc.field("telephone", "(555) 123-4567");
doc.field("age", 20);
doc.field("longnumber", Long.MAX_VALUE);
doc.field("amount", Float.valueOf(12345678.89f));
doc.field("present", Boolean.FALSE);
doc.field("somedate", new Date());
Map result = DocumentUtil.toMap(doc);
assertThat(result).contains(
entry(DocumentUtil.TAG_ID, "client-assigned-id"), //"-1:-1"), // ID when doc not yet stored
entry(DocumentUtil.TAG_REV, "0"), // Doc version starts at 0
entry("firstname", "Sam"),
entry("lastname", "Iam"),
entry("telephone", "(555) 123-4567"),
entry("age", 20),
entry("longnumber", Long.MAX_VALUE),
entry("amount", 12345678.89f),
entry("present", false));
Object somedate = result.get("somedate");
assertNotNull(somedate, "somedate entry null");
assertThat(somedate).isInstanceOf(Date.class);
// The ID should appear in map not as the key we use for OrientDB internal
assertFalse(result.containsKey(DocumentUtil.ORIENTDB_PRIMARY_KEY), "DB layer internal key " + DocumentUtil.ORIENTDB_PRIMARY_KEY
+ " should not appear in map, but did.");
}
@Test
public void embeddedDocToMap() {
ODocument doc = new ODocument();
doc.field(DocumentUtil.ORIENTDB_PRIMARY_KEY, "client-assigned-id");
doc.field("firstname", "John");
doc.field("lastname", "Doe");
doc.field("city", new ODocument().field("name","Paris").field("country", "France"));
doc.field("phonenumbers", new ODocument().field("home","555-666-7777").field("mobile", "555-111-2222"), OType.EMBEDDED);
Map result = DocumentUtil.toMap(doc);
assertThat(result).contains(
entry(DocumentUtil.TAG_ID, "client-assigned-id"), //"-1:-1"), // ID when doc not yet stored
entry(DocumentUtil.TAG_REV, "0"), // Doc version starts at 0
entry("firstname", "John"),
entry("lastname", "Doe"));
Object city = result.get("city");
assertNotNull(city, "city map entry null");
assertThat(city).isInstanceOf(Map.class);
assertThat((Map)city)
.hasSize(2)
.contains(entry("name", "Paris"), entry("country", "France"));
Object phonenumbers = result.get("phonenumbers");
assertNotNull(phonenumbers, "phonenumbers map entry null");
assertThat(phonenumbers).isInstanceOf(Map.class);
assertThat((Map)phonenumbers)
.hasSize(2)
.contains(entry("home", "555-666-7777"), entry("mobile", "555-111-2222"));
}
@Test
public void embeddedListToMap() {
ODocument doc = new ODocument();
doc.field(DocumentUtil.ORIENTDB_PRIMARY_KEY, "client-assigned-id");
doc.field("firstname", "John");
doc.field("lastname", "Doe");
doc.field("city", new ODocument().field("name","Paris").field("country", "France"));
List<ODocument> addresses = new ArrayList<ODocument>();
addresses.add(new ODocument().field("type", "home").field("street", "Main st.").field("city", "San Franciso") );
addresses.add(new ODocument().field("type", "business").field("street", "Wall st.").field("city", "New York") );
doc.field("addresses", addresses, OType.EMBEDDED);
Map result = DocumentUtil.toMap(doc);
assertThat(result).contains(
entry(DocumentUtil.TAG_ID, "client-assigned-id"), //"-1:-1"), // ID when doc not yet stored
entry(DocumentUtil.TAG_REV, "0"), // Doc version starts at 0
entry("firstname", "John"),
entry("lastname", "Doe"));
Object addrResult = result.get("addresses");
assertNotNull(addrResult, "addresses map entry null");
assertThat(addrResult).isInstanceOf(List.class);
List addr = (List)addrResult;
assertThat(addr)
.hasSize(2);
assertThat(addr.get(0)).isInstanceOf(Map.class);
Map firstEntry = (Map) addr.get(0);
assertThat(firstEntry).contains(
entry("type", "home"),
entry("street", "Main st."),
entry("city", "San Franciso"));
Map secondEntry = (Map) addr.get(1);
assertThat(secondEntry).contains(
entry("type", "business"),
entry("street", "Wall st."),
entry("city", "New York"));
}
@Test
public void deepNestingToMap() {
ODocument doc = new ODocument();
doc.field(DocumentUtil.ORIENTDB_PRIMARY_KEY, "client-assigned-id");
List<ODocument> detail = new ArrayList<ODocument>();
List<ODocument> addresses = new ArrayList<ODocument>();
ODocument status1 = new ODocument("inventory", 10);
ODocument status2 = new ODocument("inventory", 20);
addresses.add(new ODocument().field("street", "Main st.").field("city", "San Franciso").field("status", status1, OType.EMBEDDED));
addresses.add(new ODocument().field("street", "Wall st.").field("city", "New York").field("status", status2, OType.EMBEDDED));
detail.add(new ODocument().field("locations", addresses, OType.EMBEDDED));
doc.field("widget", new ODocument().field("name","widget-a").field("detail", detail), OType.EMBEDDED);
Map result = DocumentUtil.toMap(doc);
assertThat(result).contains(
entry(DocumentUtil.TAG_ID, "client-assigned-id"),
entry(DocumentUtil.TAG_REV, "0"));
Map resultWidgets = (Map) result;
Map resultWidget = (Map) resultWidgets.get("widget");
List resultDetails = (List) resultWidget.get("detail");
Map resultDetail1 = (Map) resultDetails.get(0);
List resultLocations = (List) resultDetail1.get("locations");
Map resultAddress2 = (Map) resultLocations.get(1);
System.out.println(resultAddress2);
Map resultStatus = (Map) resultAddress2.get("status");
Integer resultInventory = (Integer) resultStatus.get("inventory");
assertEquals(resultInventory.intValue(), 20);
}
@Test
public void deepNestingWithSetToMap() {
ODocument doc = new ODocument();
doc.field(DocumentUtil.ORIENTDB_PRIMARY_KEY, "client-assigned-id");
Set<ODocument> detail = new HashSet<ODocument>();
Set<ODocument> addresses = new HashSet<ODocument>();
ODocument status1 = new ODocument("inventory", 10);
ODocument status2 = new ODocument("inventory", 20);
addresses.add(new ODocument().field("street", "Main st.").field("city", "San Franciso").field("status", status1, OType.EMBEDDED));
detail.add(new ODocument().field("locations", addresses, OType.EMBEDDED));
doc.field("widget", new ODocument().field("name","widget-a").field("detail", detail), OType.EMBEDDED);
Map result = DocumentUtil.toMap(doc);
assertThat(result).contains(
entry(DocumentUtil.TAG_ID, "client-assigned-id"),
entry(DocumentUtil.TAG_REV, "0"));
Map resultWidgets = (Map) result;
Map resultWidget = (Map) resultWidgets.get("widget");
List resultDetails = (List) resultWidget.get("detail");
Map resultDetail1 = (Map) resultDetails.get(0);
List resultLocations = (List) resultDetail1.get("locations");
Map resultAddress1 = (Map) resultLocations.get(0);
System.out.println(resultAddress1);
Map resultStatus = (Map) resultAddress1.get("status");
Integer resultInventory = (Integer) resultStatus.get("inventory");
assertEquals(resultInventory.intValue(), 10);
}
@Test
public void deepNestingMixedODocAndMapToMap() {
ODocument doc = new ODocument();
doc.field(DocumentUtil.ORIENTDB_PRIMARY_KEY, "client-assigned-id");
List<Map<String, Object>> detail = new ArrayList<Map<String, Object>>();
List<ODocument> addresses = new ArrayList<ODocument>();
ODocument status1 = new ODocument("inventory", 10);
ODocument status2 = new ODocument("inventory", 20);
addresses.add(new ODocument().field("street", "Main st.").field("city", "San Franciso").field("status", status1, OType.EMBEDDED));
addresses.add(new ODocument().field("street", "Wall st.").field("city", "New York").field("status", status2, OType.EMBEDDED));
Map<String, Object> locationsMap = new HashMap<String, Object>();
locationsMap.put("locations", addresses);
detail.add(locationsMap);
doc.field("widget", new ODocument().field("name","widget-a").field("detail", detail), OType.EMBEDDED);
Map result = DocumentUtil.toMap(doc);
assertThat(result).contains(
entry(DocumentUtil.TAG_ID, "client-assigned-id"),
entry(DocumentUtil.TAG_REV, "0"));
Map resultWidgets = (Map) result;
Map resultWidget = (Map) resultWidgets.get("widget");
List resultDetails = (List) resultWidget.get("detail");
Map resultDetail1 = (Map) resultDetails.get(0);
List resultLocations = (List) resultDetail1.get("locations");
Map resultAddress2 = (Map) resultLocations.get(1);
System.out.println(resultAddress2);
Map resultStatus = (Map) resultAddress2.get("status");
Integer resultInventory = (Integer) resultStatus.get("inventory");
assertEquals(resultInventory.intValue(), 20);
}
@Test
public void mapToDocNullTest() throws ConflictException {
assertNull(DocumentUtil.toDocument(null, null, db, orientDocClass, false, true));
}
@Test
public void mapToNewFlatDoc() throws ConflictException{
Map<String, Object> map = new HashMap<String, Object>();
map.put(DocumentUtil.TAG_ID, "client-assigned-id");
map.put(DocumentUtil.TAG_REV, "1");
map.put("firstname", "Sam");
map.put("lastname", "Iam");
map.put("telephone", "(555) 123-4567");
map.put("age", 20);
map.put("longnumber", Long.MAX_VALUE);
map.put("amount", Float.valueOf(12345678.89f));
map.put("present", Boolean.FALSE);
map.put("somedate", new Date());
ODocument result = DocumentUtil.toDocument(map, null, db, orientDocClass);
assertEquals(result.field(DocumentUtil.ORIENTDB_PRIMARY_KEY), "client-assigned-id", "unexpected ID");
assertEquals(result.field("firstname"), "Sam", "unexpected firstname");
assertEquals(result.field("lastname"), "Iam", "unexpected lastname");
assertEquals(result.field("telephone"), "(555) 123-4567", "unexpected telephone");
assertEquals(result.field("age"), 20, "unexpected age");
assertEquals(result.field("longnumber"), Long.MAX_VALUE, "unexpected longnumber");
assertEquals(result.field("amount"), 12345678.89f, "unexpected amount");
assertEquals(result.field("present"), false, "unexpected present boolean");
assertEquals(result.getVersion(), 1, "Version not as expected");
Object somedate = result.field("somedate");
assertNotNull(somedate, "somedate entry null");
assertTrue((somedate instanceof Date), "Date not of expected type.");
}
@Test
public void mapToExistingFlatDoc() throws ConflictException {
Map<String, Object> map = new HashMap<String, Object>();
map.put(DocumentUtil.TAG_ID, "client-assigned-id");
map.put(DocumentUtil.TAG_REV, "1");
map.put("firstname", "Sam");
map.put("lastname", "Iam");
map.put("telephone", "(555) 123-4567");
map.put("age", 20);
map.put("longnumber", Long.MAX_VALUE);
map.put("amount", Float.valueOf(12345678.89f));
map.put("present", Boolean.FALSE);
map.put("somedate", new Date());
// An existing document to get updated from the map
ODocument existingDoc = db.newInstance(orientDocClass);
existingDoc.field(DocumentUtil.ORIENTDB_PRIMARY_KEY, "client-assigned-id");
// firstname and lastname deliberately not in the existing doc
existingDoc.field("fieldtoberemoved", "ABC");
existingDoc.field("telephone", "(999) 999-9999");
existingDoc.field("age", 20);
existingDoc.field("longnumber", 0);
existingDoc.field("amount", Float.valueOf(12345678.89f));
existingDoc.field("present", Boolean.FALSE);
existingDoc.field("somedate", new Date());
existingDoc.field("AnotherFieldToBeRemoved", new Date());
ODocument result = DocumentUtil.toDocument(map, existingDoc, db, orientDocClass);
assertEquals(result.field(DocumentUtil.ORIENTDB_PRIMARY_KEY), "client-assigned-id", "unexpected ID");
assertEquals(result.field("firstname"), "Sam", "unexpected firstname");
assertEquals(result.field("lastname"), "Iam", "unexpected lastname");
assertEquals(result.field("telephone"), "(555) 123-4567", "unexpected telephone");
assertEquals(result.field("age"), 20, "unexpected age");
assertEquals(result.field("longnumber"), Long.MAX_VALUE, "unexpected longnumber");
assertEquals(result.field("amount"), 12345678.89f, "unexpected amount");
assertEquals(result.field("present"), false, "unexpected present boolean");
assertFalse(result.containsField("fieldtoberemoved"), "Field 'fieldtoberemoved' not removed as expected");
assertFalse(result.containsField("AnotherFieldToBeRemoved"), "Field 'AnotherFieldToBeRemoved' not removed as expected");
assertEquals(result.getVersion(), 1, "Version not as expected");
Object somedate = result.field("somedate");
assertNotNull(somedate, "somedate entry null");
assertTrue((somedate instanceof Date), "Date not of expected type.");
}
@Test
public void mapToNewDocExistingRevision() throws ConflictException {
Map<String, Object> map = new HashMap<String, Object>();
map.put(DocumentUtil.TAG_ID, "client-assigned-id");
map.put(DocumentUtil.TAG_REV, "100");
map.put("firstname", "John");
ODocument result = DocumentUtil.toDocument(map, null, db, orientDocClass);
assertEquals(result.field(DocumentUtil.ORIENTDB_PRIMARY_KEY), "client-assigned-id", "unexpected ID");
assertEquals(result.field("firstname"), "John", "unexpected firstname");
assertEquals(result.getVersion(), 100, "Version not as expected");
}
@Test
public void mapToNewEmbeddedDoc() throws ConflictException {
Map<String, Object> map = new HashMap<String, Object>();
map.put(DocumentUtil.TAG_ID, "client-assigned-id");
map.put("firstname", "John");
map.put("lastname", "Doe");
Map<String, Object> city = new HashMap<String, Object>();
city.put("name","Paris");
city.put("country", "France");
map.put("city", city);
Map<String, Object> phone = new HashMap<String, Object>();
phone.put("home","555-666-7777");
phone.put("mobile", "555-111-2222");
map.put("phonenumbers", phone);
ODocument result = DocumentUtil.toDocument(map, null, db, orientDocClass);
assertEquals(result.field(DocumentUtil.ORIENTDB_PRIMARY_KEY), "client-assigned-id", "unexpected ID");
assertEquals(result.field("firstname"), "John", "unexpected firstname");
assertEquals(result.field("lastname"), "Doe", "unexpected lastname");
assertEquals(result.getVersion(), 0, "Version not as expected");
ODocument phonenumbers = (ODocument)result.field("phonenumbers");
assertNotNull(phonenumbers, "phonenumbers map entry null");
assertEquals(phonenumbers.field("home"), "555-666-7777", "unexpected home phone");
assertEquals(phonenumbers.field("mobile"), "555-111-2222", "unexpected mobile phone");
assertThat((ODocument)phonenumbers)
.hasSize(2);
}
@Test
public void mapToExistingEmbeddedDoc() throws ConflictException {
Map<String, Object> map = new HashMap<String, Object>();
map.put(DocumentUtil.TAG_ID, "client-assigned-id");
// deliberately remove the firstname
map.put("lastname", "Doe");
// deliberately remove the city
Map<String, Object> phone = new HashMap<String, Object>();
//remove the home number, change the mobile, add a work number
phone.put("mobile", "555-111-2229");
phone.put("work","666-777-8888");
map.put("phonenumbers", phone);
ODocument existingDoc = new ODocument();
existingDoc.field(DocumentUtil.ORIENTDB_PRIMARY_KEY, "client-assigned-id");
existingDoc.field("firstname", "Johnathan");
// lastname deliberately not in existing doc
existingDoc.field("city", new ODocument().field("name","Paris").field("country", "France"));
existingDoc.field("phonenumbers", new ODocument().field("home","555-666-7777").field("mobile", "555-111-2222"), OType.EMBEDDED);
ODocument result = DocumentUtil.toDocument(map, null, db, orientDocClass);
assertEquals(result.field(DocumentUtil.ORIENTDB_PRIMARY_KEY), "client-assigned-id", "unexpected ID");
assertFalse(result.containsField("firstname"), "Firstname should have been removed but is present");
assertEquals(result.field("lastname"), "Doe", "unexpected lastname");
assertEquals(result.getVersion(), 0, "Version not as expected");
assertFalse(result.containsField("city"), "City map should have been removed but is present.");
ODocument phonenumbers = (ODocument)result.field("phonenumbers");
assertNotNull(phonenumbers, "phonenumbers map entry null");
assertEquals(phonenumbers.field("work"), "666-777-8888", "unexpected work phone");
assertEquals(phonenumbers.field("mobile"), "555-111-2229", "unexpected mobile phone");
assertFalse(phonenumbers.containsField("home"), "Home phone should have been removed but is present.");
assertThat((ODocument)phonenumbers)
.hasSize(2);
}
@Test
public void listToEmbeddedList() throws ConflictException {
Map<String, Object> map = new HashMap<String, Object>();
map.put(DocumentUtil.TAG_ID, "client-assigned-id");
map.put("firstname", "John");
map.put("lastname", "Doe");
List<Object> cities = new ArrayList<Object>();
cities.add("Paris");
cities.add("St. Louis");
map.put("cities", cities);
Map<String, Object> phone = new HashMap<String, Object>();
phone.put("home","555-666-7777");
phone.put("mobile", "555-111-2222");
map.put("phonenumbers", phone);
ODocument result = DocumentUtil.toDocument(map, null, db, orientDocClass);
assertEquals(result.field(DocumentUtil.ORIENTDB_PRIMARY_KEY), "client-assigned-id", "unexpected ID");
assertEquals(result.field("firstname"), "John", "unexpected firstname");
assertEquals(result.field("lastname"), "Doe", "unexpected lastname");
assertEquals(result.getVersion(), 0, "Version not as expected");
Object resultCities = result.field("cities");
assertThat(resultCities).isInstanceOf(List.class);
assertThat((List)resultCities).containsOnly("Paris", "St. Louis");
ODocument phonenumbers = (ODocument)result.field("phonenumbers");
assertNotNull(phonenumbers, "phonenumbers map entry null");
assertEquals(phonenumbers.field("home"), "555-666-7777", "unexpected home phone");
assertEquals(phonenumbers.field("mobile"), "555-111-2222", "unexpected mobile phone");
assertThat((ODocument)phonenumbers)
.hasSize(2);
}
@Test(expectedExceptions = ConflictException.class)
public void mapToDocInvalidRevision() throws ConflictException {
// Check ConflictException is thrown for invalid versions
Map<String, Object> map = new HashMap<String, Object>();
map.put(DocumentUtil.TAG_ID, "client-assigned-id");
map.put(DocumentUtil.TAG_REV, "invalid-version"); // OrientDB revisions are ints
map.put("firstname", "John");
ODocument result = DocumentUtil.toDocument(map, null, db, orientDocClass);
assertTrue(false, "Invalid Revision must trigger failure");
}
@Test
public void mapToDocToMap() throws ConflictException {
Map<String, Object> map = new HashMap<String, Object>();
map.put(DocumentUtil.TAG_ID, "client-assigned-id");
map.put(DocumentUtil.TAG_REV, "2");
map.put("firstname", "John");
map.put("lastname", "Doe");
Map<String, Object> city = new HashMap<String, Object>();
city.put("name","Paris");
city.put("country", "France");
map.put("city", city);
Map<String, Object> phone = new HashMap<String, Object>();
phone.put("home","555-666-7777");
phone.put("mobile", "555-111-2222");
map.put("phonenumbers", phone);
ODocument intermediateResult = DocumentUtil.toDocument(map, null, db, orientDocClass);
Map result = DocumentUtil.toMap(intermediateResult);
assertThat(result).contains(
entry(DocumentUtil.TAG_ID, "client-assigned-id"),
entry(DocumentUtil.TAG_REV, "2"),
entry("firstname", "John"),
entry("lastname", "Doe"));
Object checkCity = result.get("city");
assertNotNull(checkCity, "city map entry null");
assertThat(checkCity).isInstanceOf(Map.class);
assertThat((Map)checkCity)
.hasSize(2)
.contains(entry("name", "Paris"), entry("country", "France"));
Object phonenumbers = result.get("phonenumbers");
assertNotNull(phonenumbers, "phonenumbers map entry null");
assertThat(phonenumbers).isInstanceOf(Map.class);
assertThat((Map)phonenumbers)
.hasSize(2)
.contains(entry("home", "555-666-7777"), entry("mobile", "555-111-2222"));
}
@Test
public void parseValidRevision() throws ConflictException {
int ver = DocumentUtil.parseVersion("98765");
assertEquals(ver, 98765);
}
@Test(expectedExceptions = ConflictException.class)
public void parseInvalidRevision() throws ConflictException {
int ver = DocumentUtil.parseVersion("some-text-98765");
assertTrue(false, "Parsing of invalid revision must fail, but did not.");
}
}