/*******************************************************************************
* Copyright (c) 2015 IBM Corp.
*
* 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 com.ibm.ws.lars.rest;
import static com.ibm.ws.lars.rest.SortOptions.SortOrder.ASCENDING;
import static com.ibm.ws.lars.rest.SortOptions.SortOrder.DESCENDING;
import static com.ibm.ws.lars.rest.matchers.ServerAssetByIdMatcher.assetsWithIds;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.ibm.ws.lars.rest.Condition.Operation;
import com.ibm.ws.lars.rest.exceptions.InvalidJsonAssetException;
import com.ibm.ws.lars.rest.exceptions.NonExistentArtefactException;
import com.ibm.ws.lars.rest.model.Asset;
import com.ibm.ws.lars.rest.model.AssetCursor;
import com.ibm.ws.lars.rest.model.Attachment;
import com.ibm.ws.lars.rest.model.AttachmentContentMetadata;
import com.ibm.ws.lars.rest.mongo.PersistenceBean;
import com.ibm.ws.lars.testutils.BasicChecks;
import com.ibm.ws.lars.testutils.FatUtils;
import com.mongodb.DB;
import com.mongodb.MongoClient;
import com.mongodb.WriteConcern;
import mockit.Mocked;
public class PersistenceBeanTest {
// TODO Should the db name be configurable?
private static final String DB_NAME = "testdb";
private static final WriteConcern WRITE_CONCERN = WriteConcern.JOURNAL_SAFE;
private MongoClient mongoClient;
private PersistenceBean persistenceBean;
private DB db;
// We needed to mock the logger here because something about running other jmockit tests
// which mock it meant that the Logger class wasn't getting initialized properly and would
// null pointer unexpectedly. Probably a bug in jmockit but the easiest thing is just to
// always mock the logger.
@Mocked
Logger logger;
@Before
public void setUp() throws Exception {
// Inject a MongoDB connection into our persistence bean to test it
//
// At present, we use a real live MongoDB but maybe in the future
// we should mock it.
//
// Also we currently don't bother with Mongo security but clearly we
// might like to think about that at some point
mongoClient = new MongoClient("localhost:" + FatUtils.DB_PORT);
mongoClient.setWriteConcern(WRITE_CONCERN);
db = mongoClient.getDB(DB_NAME);
persistenceBean = new PersistenceBean();
// @Inject the DB
Field dbField = PersistenceBean.class.getDeclaredField("db");
dbField.setAccessible(true);
dbField.set(persistenceBean, db);
// This is a @PostConstruct method so must call it
persistenceBean.createGridFS();
// Ensure we start the test with nothing in the DB
db.dropDatabase();
// Mainly to make sure there is text index for the search tests.
persistenceBean.initialize();
}
@After
public void tearDown() throws Exception {
db.dropDatabase();
mongoClient.close();
}
private void assertEmpty() throws IOException {
AssetCursor allAssets = persistenceBean.retrieveAllAssets();
assertTrue(allAssets.size() == 0);
}
/**
* Simple test that does create. retrieve, update and delete on one object.
*
* @throws IOException
* @throws InvalidJsonAssetException
* @throws NonExistentArtefactException
*/
@Test
public void testCRUD() throws IOException, InvalidJsonAssetException, NonExistentArtefactException {
// Verify that an empty collection is indeed empty
assertEmpty();
// Create
Asset asset = new Asset();
String[] keys = new String[] { "name", "wibble", "abyte", "ashort", "anint", "along", "achar" };
Object[] values = new Object[] { "this is my name", "wibble", (byte) 23, (short) -1, 65536, 12345678901L, 'a' };
putAll(asset.getProperties(), keys, values);
// Retrieve
Asset returnedAsset = persistenceBean.createAsset(asset);
String id = returnedAsset.get_id();
assertNotNull("id should not be null", id);
// verify that the objects are equal in every way apart from their ids
asset.set_id(returnedAsset.get_id());
// This fails, as the id needs to go in at the front
// (LinkedHashMap checks the order)
// assertEquals(asset, returnedMap);
// Update
returnedAsset.put("anint", 24);
persistenceBean.updateAsset(id, returnedAsset);
Asset returnedAssetAfterPut = persistenceBean.retrieveAsset(id);
assertEquals(returnedAsset, returnedAssetAfterPut);
// Delete
persistenceBean.deleteAsset(id);
assertEmpty();
}
/**
* Tests that attachment (JSON) metadata can be stored in and retrieved from the
* PersistenceBean.
*/
@Test
public void testStoreAndRetrieveAttachmentMetadata() throws NonExistentArtefactException {
HashMap<String, Object> properties = new HashMap<>();
properties.put("AnInt", 12);
properties.put("AString", "This is a string");
Attachment attachment = Attachment.createAttachmentFromMap(properties);
Attachment createdAttachment = persistenceBean.createAttachmentMetadata(attachment);
Attachment returnedAttachment = persistenceBean.retrieveAttachmentMetadata(createdAttachment.get_id());
assertNotNull(returnedAttachment.get_id());
returnedAttachment.getProperties().remove(Attachment._ID);
assertEquals(attachment, returnedAttachment);
}
/**
* Tests that attachment content (ie arbitrary binary data) can be stored in and retrieved from
* the PersistenceBean.
*/
@Test
public void testStoreAndRetrieveAttachmentContent() throws IOException, NonExistentArtefactException {
byte[] content = "This is a very small amount of content".getBytes();
AttachmentContentMetadata contentMetadata = persistenceBean.createAttachmentContent("MrAttachment.txt",
"test/plain",
new ByteArrayInputStream(content));
assertNotNull(contentMetadata.filename);
assertEquals(content.length, contentMetadata.length);
try (InputStream contentStream = persistenceBean.retrieveAttachmentContent(contentMetadata.filename).getContentStream()) {
byte[] returnedContent = BasicChecks.slurp(contentStream);
assertTrue(Arrays.equals(content, returnedContent));
}
}
/**
* Verifies that an exception is thrown when we attempt to retrieve a non-existent asset.
*/
@Test(expected = NonExistentArtefactException.class)
public void testRetrieveNonExistentAsset() throws NonExistentArtefactException {
persistenceBean.retrieveAsset("123456789012345678901234");
}
/**
* Verifies that an exception is thrown when we attempt to retrieve the metadata for a
* non-existent attachment.
*/
@Test(expected = NonExistentArtefactException.class)
public void testRetrieveNonExistentAttachmentMetadata() throws NonExistentArtefactException {
persistenceBean.retrieveAttachmentMetadata("123456789012345678901234");
}
/**
* Verifies that an exception is thrown when we attempt to retrieve the content for a
* non-existent attachment
*/
@Test(expected = NonExistentArtefactException.class)
public void testRetrieveNonExistentAttachmentContent() throws NonExistentArtefactException {
persistenceBean.retrieveAttachmentContent("123456789012345678901234");
}
@Test
public void testRetrieveAllFiltered() throws Exception {
Asset asset1 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"new name1\", \"layer1\":{\"layer1field\":\"layer1value\",\"layer2\":{\"layer2field\":\"layer2value\",\"layer3\":{\"layer3field\":\"layer3value\"}}}}"));
Asset asset2 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"new name2\", \"layer1\":{\"layer1field\":\"layer1value\",\"layer2\":{\"layer2field\":\"layer2value\",\"layer3\":{\"layer3field\":\"layer3value\"}}}}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"new name3\", \"layer1\":{\"layer1field\":\"layer1value3\",\"layer2\":\"layer2value\"}}"));
List<AssetFilter> filters = new ArrayList<>();
filters.add(new AssetFilter("name", Arrays.asList(eq("new name1"))));
List<Asset> assets = readAll(persistenceBean.retrieveAllAssets(filters, null, null, null));
assertEquals("Should only have got 1 asset back", 1, assets.size());
assertEquals("Got the wrong asset back", asset1.get_id(), assets.get(0).get_id());
List<AssetFilter> filters2 = new ArrayList<>();
filters2.add(new AssetFilter("layer1.layer1field", Arrays.asList(eq("layer1value"))));
List<Asset> assets2 = readAll(persistenceBean.retrieveAllAssets(filters2, null, null, null));
assertEquals("Should have got 2 asset back", 2, assets2.size());
for (Asset retrievedAsset : assets2) {
if (!retrievedAsset.get_id().equals(asset1.get_id()) && !retrievedAsset.get_id().equals(asset2.get_id())) {
fail("The wrong asset was retrieved. Asset id " + retrievedAsset.get_id() + " was retrieved. Expected " + asset1.get_id() + " or " + asset2.get_id());
}
}
List<AssetFilter> filters3 = new ArrayList<>();
filters3.add(new AssetFilter("name", Arrays.asList(eq("new name1"), eq("new name2"))));
List<Asset> assets3 = readAll(persistenceBean.retrieveAllAssets(filters3, null, null, null));
assertEquals("Should have got 2 asset back", 2, assets3.size());
for (Asset retrievedAsset : assets3) {
if (!retrievedAsset.get_id().equals(asset1.get_id()) && !retrievedAsset.get_id().equals(asset2.get_id())) {
fail("The wrong asset was retrieved. Asset id " + retrievedAsset.get_id() + " was retrieved. Expected " + asset1.get_id() + " or " + asset2.get_id());
}
}
// With a search term as well
List<AssetFilter> filters4 = new ArrayList<>();
filters4.add(new AssetFilter("name", Arrays.asList(eq("new name1"), eq("new name2"))));
List<Asset> assets4 = readAll(persistenceBean.retrieveAllAssets(filters4, "name1", null, null));
assertEquals("Wrong number of assets retrieved", 1, assets4.size());
Asset retrieved = assets4.get(0);
assertEquals("Got the wrong asset back", asset1.get_id(), retrieved.get_id());
// Checking that the sorting score isn't left in the asset
assertEquals("The asset has been modified", asset1, retrieved);
}
@Test
public void testRetrieveAllFiltered2() throws Exception {
Asset asset1 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"new name1\", \"layer1\":{\"layer1field\":\"layer1value\",\"layer2\":{\"layer2field\":\"layer2value\",\"layer3\":{\"layer3field\":\"layer3value\"}}}}"));
Asset asset2 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"new name1\", \"layer1\":{\"layer1field\":\"layer1value\",\"layer2\":{\"layer2field\":\"layer2value\",\"layer3\":{\"layer3field\":\"layer3value\"}}}}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"new name2\", \"layer1\":{\"layer1field\":\"layer1value\",\"layer2\":{\"layer2field\":\"layer2value\",\"layer3\":{\"layer3field\":\"layer3value\"}}}}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"new name3\", \"layer1\":{\"layer1field\":\"layer1value3\",\"layer2\":\"layer2value\"}}"));
// Test with an empty set of filters
List<AssetFilter> emptyFilters = Collections.emptyList();
List<Asset> assets = readAll(persistenceBean.retrieveAllAssets(emptyFilters, null, null, null));
assertEquals("An empty filter should get all assets", 4, assets.size());
List<AssetFilter> filters = new ArrayList<>();
// test which retrieves no assets
filters.add(new AssetFilter("blurgh", Arrays.asList(eq("new name1"))));
List<Asset> assets2 = readAll(persistenceBean.retrieveAllAssets(filters, null, null, null));
assertEquals("Should not have got any assets back", 0, assets2.size());
// test which uses multiple entries in the map
filters.clear();
filters.add(new AssetFilter("name", Arrays.asList(eq("new name1"))));
filters.add(new AssetFilter("layer1.layer1field", Arrays.asList(eq("layer1value"))));
List<Asset> assets3 = readAll(persistenceBean.retrieveAllAssets(filters, null, null, null));
assertEquals("Wrong number of assets retrieved", 2, assets3.size());
String id1 = asset1.get_id();
String id2 = asset2.get_id();
for (Asset retrievedAsset : assets3) {
String id = retrievedAsset.get_id();
if (!id.equals(id1) && !id.equals(id2)) {
fail("The wrong asset was retrieved. Expected id " + id1 + " or " + id2 + " but got " + id);
}
}
}
@SuppressWarnings("unused")
@Test
public void testRetrieveAllAssetsNotFiltered() throws InvalidJsonAssetException {
Asset asset1 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"new name1\", \"layer1\":{\"layer1field\":\"layer1value\",\"layer2\":{\"layer2field\":\"layer2value\",\"layer3\":{\"layer3field\":\"layer3value\"}}}}"));
Asset asset2 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"new name1\", \"layer1\":{\"layer1field\":\"layer1value\",\"layer2\":{\"layer2field\":\"layer2value\",\"layer3\":{\"layer3field\":\"layer3value\"}}}}"));
Asset asset3 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"new name2\", \"layer1\":{\"layer1field\":\"layer1value\",\"layer2\":{\"layer2field\":\"layer2value\",\"layer3\":{\"layer3field\":\"layer3value\"}}}}"));
// Empty filters should get everything
List<AssetFilter> emptyFilters = Collections.emptyList();
List<Asset> allAssets = readAll(persistenceBean.retrieveAllAssets(emptyFilters, null, null, null));
assertEquals("Unexpected number of assets returned", 3, allAssets.size());
List<AssetFilter> filters;
// query that should return nothing
filters = new ArrayList<>();
filters.add(new AssetFilter("layer1.layer1field", Arrays.asList(neq("layer1value"))));
List<Asset> emptyAssets = readAll(persistenceBean.retrieveAllAssets(filters, null, null, null));
assertEquals("Unexpected number of assets returned", 0, emptyAssets.size());
filters.clear();
// basic not filter
filters = new ArrayList<>();
filters.add(new AssetFilter("name", Arrays.asList(neq("new name1"))));
List<Asset> assets1 = readAll(persistenceBean.retrieveAllAssets(filters, null, null, null));
assertEquals("Unexpected number of assets returned", 1, assets1.size());
assertEquals("The wrong asset id was retrieved", asset3.get_id(), assets1.get(0).get_id());
// not filter and a normal filter
Asset asset4 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"new name2\", \"layer1\":{\"layer1field\":\"layer1value2\",\"layer2\":{\"layer2field\":\"layer2value\",\"layer3\":{\"layer3field\":\"layer3value\"}}}}"));
filters = new ArrayList<>();
filters.add(new AssetFilter("name", Arrays.asList(neq("new name1"))));
filters.add(new AssetFilter("layer1.layer1field", Arrays.asList(eq("layer1value2"))));
List<Asset> assets2 = readAll(persistenceBean.retrieveAllAssets(filters, null, null, null));
assertEquals("Unexpected number of assets returned", 1, assets2.size());
assertEquals("The wrong asset id was retrieved", asset4.get_id(), assets2.get(0).get_id());
// not filter and a normal filter and a search term
filters = new ArrayList<>();
filters.add(new AssetFilter("name", Arrays.asList(neq("new name1"))));
filters.add(new AssetFilter("layer1.layer1field", Arrays.asList(eq("layer1value2"))));
List<Asset> assets3 = readAll(persistenceBean.retrieveAllAssets(filters, "\"new name2\"", null, null));
assertEquals("Unexpected number of assets returned", 1, assets3.size());
assertEquals("The wrong asset id was retrieved", asset4.get_id(), assets3.get(0).get_id());
}
@Test
public void testRetrieveAllAssetsOrFiltered() throws InvalidJsonAssetException {
Asset asset1 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"hot\", \"ground\":\"flat\", \"name\":\"a long name\"}"));
Asset asset2 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"hot\", \"ground\":\"hilly\", \"name\":\"a long name\"}"));
Asset asset3 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"hot\", \"ground\":\"mountainous\"}"));
Asset asset4 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"cold\", \"ground\":\"flat\"}"));
Asset asset5 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"cold\", \"ground\":\"hilly\"}"));
Asset asset6 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"cold\", \"ground\":\"mountainous\"}"));
Asset asset7 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"warm\", \"ground\":\"flat\", \"name\":\"a long name\"}"));
Asset asset8 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"warm\", \"ground\":\"hilly\"}"));
Asset asset9 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"warm\", \"ground\":\"mountainous\"}"));
// Empty filters should get everything
List<AssetFilter> emptyFilters = Collections.emptyList();
List<Asset> allAssets = readAll(persistenceBean.retrieveAllAssets(emptyFilters, null, null, null));
assertEquals("Unexpected number of assets returned", 9, allAssets.size());
assertThat(allAssets, containsInAnyOrder(assetsWithIds(asset1, asset2, asset3, asset4, asset5, asset6, asset7, asset8, asset9)));
List<AssetFilter> filters;
// Simple OR filter
filters = new ArrayList<>();
filters.add(new AssetFilter("weather", Arrays.asList(eq("hot"), eq("warm"))));
List<Asset> result1 = readAll(persistenceBean.retrieveAllAssets(filters, null, null, null));
assertThat(result1, containsInAnyOrder(assetsWithIds(asset1, asset2, asset3, asset7, asset8, asset9)));
// OR with NOT
filters = new ArrayList<>();
filters.add(new AssetFilter("weather", Arrays.asList(eq("hot"), eq("warm"))));
filters.add(new AssetFilter("ground", Arrays.asList(neq("mountainous"))));
List<Asset> result2 = readAll(persistenceBean.retrieveAllAssets(filters, null, null, null));
assertThat(result2, containsInAnyOrder(assetsWithIds(asset1, asset2, asset7, asset8)));
// Two ORs
filters = new ArrayList<>();
filters.add(new AssetFilter("weather", Arrays.asList(eq("hot"), eq("warm"))));
filters.add(new AssetFilter("ground", Arrays.asList(eq("hilly"), eq("mountainous"))));
List<Asset> result3 = readAll(persistenceBean.retrieveAllAssets(filters, null, null, null));
assertThat(result3, containsInAnyOrder(assetsWithIds(asset2, asset3, asset8, asset9)));
// OR with NOT and searchTerm
filters = new ArrayList<>();
filters.add(new AssetFilter("weather", Arrays.asList(eq("hot"), eq("warm"))));
filters.add(new AssetFilter("ground", Arrays.asList(neq("mountainous"))));
List<Asset> result4 = readAll(persistenceBean.retrieveAllAssets(filters, "long", null, null));
assertThat(result4, containsInAnyOrder(assetsWithIds(asset1, asset2, asset7)));
}
@Test
public void testGetDistinctValues() throws InvalidJsonAssetException {
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"hot\", \"ground\":\"flat\", \"name\":\"hot and flat\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"hot\", \"ground\":\"hilly\", \"name\":\"hot and hilly\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"hot\", \"ground\":\"mountainous\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"cold\", \"ground\":\"flat\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"cold\", \"ground\":\"hilly\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"cold\", \"ground\":\"mountainous\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"warm\", \"ground\":\"flat\", \"name\":\"warm and flat\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"warm\", \"ground\":\"hilly\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"warm\", \"ground\":\"mountainous\"}"));
List<AssetFilter> filters;
filters = Collections.emptyList();
List<Object> weathers = persistenceBean.getDistinctValues("weather", filters, null);
assertThat("Wrong list of possible weathers", weathers, containsInAnyOrder((Object) "hot", "warm", "cold"));
List<Object> names = persistenceBean.getDistinctValues("name", filters, null);
assertThat("Wrong list of possible names", names, containsInAnyOrder((Object) "hot and flat", "hot and hilly", "warm and flat"));
filters = new ArrayList<>();
filters.add(new AssetFilter("weather", Arrays.asList(eq("hot"))));
List<Object> hotNames = persistenceBean.getDistinctValues("name", filters, null);
assertThat("Wrong list of possible names with weather=hot", hotNames, containsInAnyOrder((Object) "hot and flat", "hot and hilly"));
filters = Collections.emptyList();
List<Object> searchNames = persistenceBean.getDistinctValues("name", filters, "hot");
assertThat("Wrong list of possible names with searchTerm=hot", searchNames, containsInAnyOrder((Object) "hot and flat", "hot and hilly"));
}
@Test
public void testPagination() throws Exception {
Asset asset1 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"asset1\"}"));
Asset asset2 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"asset2\"}"));
Asset asset3 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"asset3\"}"));
Asset asset4 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"asset4\"}"));
List<AssetFilter> emptyFilter = Collections.emptyList();
// Test 2 per page
List<Asset> page1 = readAll(persistenceBean.retrieveAllAssets(emptyFilter, null, new PaginationOptions(0, 2), null));
assertEquals("Wrong number of assets on page 1", 2, page1.size());
List<Asset> page2 = readAll(persistenceBean.retrieveAllAssets(emptyFilter, null, new PaginationOptions(2, 2), null));
assertEquals("Wrong number of assets on page 2", 2, page2.size());
List<Asset> page3 = readAll(persistenceBean.retrieveAllAssets(emptyFilter, null, new PaginationOptions(4, 2), null));
assertEquals("Wrong number of assets on page 3", 0, page3.size());
assertThat(collatePages(page1, page2, page3), containsInAnyOrder(asset1, asset2, asset3, asset4));
// Test 3 per page
page1 = readAll(persistenceBean.retrieveAllAssets(emptyFilter, null, new PaginationOptions(0, 3), null));
assertEquals("Wrong number of assets on page 1", 3, page1.size());
page2 = readAll(persistenceBean.retrieveAllAssets(emptyFilter, null, new PaginationOptions(3, 3), null));
assertEquals("Wrong number of assets on page 2", 1, page2.size());
page3 = readAll(persistenceBean.retrieveAllAssets(emptyFilter, null, new PaginationOptions(6, 3), null));
assertEquals("Wrong number of assets on page 3", 0, page3.size());
assertThat(collatePages(page1, page2, page3), containsInAnyOrder(asset1, asset2, asset3, asset4));
// Test with filter
List<AssetFilter> conditions = new ArrayList<>();
conditions.add(new AssetFilter("name", Arrays.asList(eq("asset2"), eq("asset3"), eq("asset4"))));
page1 = readAll(persistenceBean.retrieveAllAssets(conditions, null, new PaginationOptions(0, 2), null));
assertEquals("Wrong number of assets on page 1", 2, page1.size());
page2 = readAll(persistenceBean.retrieveAllAssets(conditions, null, new PaginationOptions(2, 2), null));
assertEquals("Wrong number of assets on page 2", 1, page2.size());
assertThat(collatePages(page1, page2), containsInAnyOrder(asset2, asset3, asset4));
}
@Test
public void testSortOptions() throws Exception {
Asset asset1 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"asset1\"}"));
Asset asset2 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"asset2\", \"score\":3}"));
Asset asset3 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"asset3\", \"score\":2}"));
Asset asset4 = persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"name\":\"asset4\", \"score\":1}"));
List<AssetFilter> emptyFilter = Collections.emptyList();
List<Asset> result = readAll(persistenceBean.retrieveAllAssets(emptyFilter, null, null, new SortOptions("name", ASCENDING)));
assertThat(result, contains(asset1, asset2, asset3, asset4));
result = readAll(persistenceBean.retrieveAllAssets(emptyFilter, null, null, new SortOptions("name", DESCENDING)));
assertThat(result, contains(asset4, asset3, asset2, asset1));
// Missing values should be the "lowest"
result = readAll(persistenceBean.retrieveAllAssets(emptyFilter, null, null, new SortOptions("score", ASCENDING)));
assertThat(result, contains(asset1, asset4, asset3, asset2));
result = readAll(persistenceBean.retrieveAllAssets(emptyFilter, null, null, new SortOptions("score", DESCENDING)));
assertThat(result, contains(asset2, asset3, asset4, asset1));
// Sort by something non-existent, the order is undefined but it should return all assets
result = readAll(persistenceBean.retrieveAllAssets(emptyFilter, null, null, new SortOptions("wibble", ASCENDING)));
assertThat(result, containsInAnyOrder(asset1, asset2, asset3, asset4));
// Test sorting with pagination
List<Asset> page1 = readAll(persistenceBean.retrieveAllAssets(emptyFilter, null, new PaginationOptions(0, 2), new SortOptions("name", ASCENDING)));
List<Asset> page2 = readAll(persistenceBean.retrieveAllAssets(emptyFilter, null, new PaginationOptions(2, 2), new SortOptions("name", ASCENDING)));
assertThat(collatePages(page1, page2), contains(asset1, asset2, asset3, asset4));
}
@Test
public void testCountAllAssets() throws Exception {
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"hot\", \"ground\":\"flat\", \"name\":\"hot and flat\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"hot\", \"ground\":\"hilly\", \"name\":\"hot and hilly\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"hot\", \"ground\":\"mountainous\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"cold\", \"ground\":\"flat\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"cold\", \"ground\":\"hilly\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"cold\", \"ground\":\"mountainous\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"warm\", \"ground\":\"flat\", \"name\":\"warm and flat\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"warm\", \"ground\":\"hilly\"}"));
persistenceBean.createAsset(Asset.deserializeAssetFromJson("{\"weather\":\"warm\", \"ground\":\"mountainous\"}"));
List<AssetFilter> emptyFilter = Collections.emptyList();
// Test counting all assets
int result = persistenceBean.countAllAssets(emptyFilter, null);
assertEquals(9, result);
// Test counting assets with a filter
List<AssetFilter> filter = new ArrayList<>();
filter.add(new AssetFilter("weather", Arrays.asList(eq("hot"))));
result = persistenceBean.countAllAssets(filter, null);
assertEquals(3, result);
// Test counting assets with a search
result = persistenceBean.countAllAssets(emptyFilter, "flat");
assertEquals(2, result);
// Test counting assets with a filter and a search
filter.clear();
filter.add(new AssetFilter("weather", Arrays.asList(eq("hot"))));
result = persistenceBean.countAllAssets(filter, "flat");
assertEquals(1, result);
}
/**
* Collate the contents of several AssetLists into one List.
* <p>
* The asset lists are processed in order, each asset in each list is appended to the result
* list.
*
* @param lists the AssetLists
* @return the collated list
*/
private static List<Asset> collatePages(List<?>... lists) {
List<Asset> result = new ArrayList<Asset>();
for (Object list : lists) {
for (Object asset : (Iterable<?>) list) {
result.add((Asset) asset);
}
}
return result;
}
static void putAll(Map<String, Object> map, String[] keys, Object[] values) {
for (int i = 0; i < keys.length; i++) {
map.put(keys[i], values[i]);
}
}
/**
* Convenience method to create a condition checking for equality with the given value
*
* @param value the value
* @return condition of equality with the given value
*/
private static Condition eq(String value) {
return new Condition(Operation.EQUALS, value);
}
/**
* Convenience method to create a condition checking for non-equality with the given value
*
* @param value the value
* @return condition of non-equality with the given value
*/
private static Condition neq(String value) {
return new Condition(Operation.NOT_EQUALS, value);
}
private static List<Asset> readAll(AssetCursor cursor) {
List<Asset> result = new ArrayList<>();
while (cursor.hasNext()) {
result.add(cursor.next());
}
return result;
}
}