| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.rya.indexing.entity.storage.mongo; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| |
| import java.util.HashSet; |
| import java.util.Optional; |
| import java.util.Set; |
| |
| import org.apache.rya.api.domain.RyaType; |
| import org.apache.rya.api.domain.RyaURI; |
| import org.apache.rya.indexing.entity.model.Entity; |
| import org.apache.rya.indexing.entity.model.Property; |
| import org.apache.rya.indexing.entity.model.Type; |
| import org.apache.rya.indexing.entity.model.TypedEntity; |
| import org.apache.rya.indexing.entity.storage.EntityStorage; |
| import org.apache.rya.indexing.entity.storage.EntityStorage.EntityAlreadyExistsException; |
| import org.apache.rya.indexing.entity.storage.EntityStorage.EntityStorageException; |
| import org.apache.rya.indexing.entity.storage.EntityStorage.StaleUpdateException; |
| import org.apache.rya.mongodb.MongoITBase; |
| import org.eclipse.rdf4j.model.vocabulary.XMLSchema; |
| import org.junit.Test; |
| |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Sets; |
| |
| /** |
| * Integration tests the methods of {@link MongoEntityStorage}. |
| */ |
| public class MongoEntityStorageIT extends MongoITBase { |
| |
| private static final String RYA_INSTANCE_NAME = "testInstance"; |
| |
| @Test |
| public void create_and_get() throws Exception { |
| // An Entity that will be stored. |
| final Entity entity = Entity.builder() |
| .setSubject(new RyaURI("urn:GTIN-14/00012345600012")) |
| .setExplicitType(new RyaURI("urn:icecream")) |
| .setProperty(new RyaURI("urn:icecream"), new Property(new RyaURI("urn:brand"), new RyaType(XMLSchema.STRING, "Awesome Icecream"))) |
| .setProperty(new RyaURI("urn:icecream"), new Property(new RyaURI("urn:flavor"), new RyaType(XMLSchema.STRING, "Chocolate"))) |
| .build(); |
| |
| // Create it. |
| final EntityStorage storage = new MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME); |
| storage.create(entity); |
| |
| // Get it. |
| final Optional<Entity> storedEntity = storage.get(new RyaURI("urn:GTIN-14/00012345600012")); |
| |
| // Verify the correct value was returned. |
| assertEquals(entity, storedEntity.get()); |
| } |
| |
| @Test |
| public void can_not_create_with_same_subject() throws Exception { |
| // A Type that will be stored. |
| final Entity entity = Entity.builder() |
| .setSubject(new RyaURI("urn:GTIN-14/00012345600012")) |
| .setExplicitType(new RyaURI("urn:icecream")) |
| .setProperty(new RyaURI("urn:icecream"), new Property(new RyaURI("urn:brand"), new RyaType(XMLSchema.STRING, "Awesome Icecream"))) |
| .setProperty(new RyaURI("urn:icecream"), new Property(new RyaURI("urn:flavor"), new RyaType(XMLSchema.STRING, "Chocolate"))) |
| .build(); |
| |
| // Create it. |
| final EntityStorage storage = new MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME); |
| storage.create(entity); |
| |
| // Try to create it again. This will fail. |
| boolean failed = false; |
| try { |
| storage.create(entity); |
| } catch(final EntityAlreadyExistsException e) { |
| failed = true; |
| } |
| assertTrue(failed); |
| } |
| |
| @Test |
| public void get_noneExisting() throws Exception { |
| // Get a Type that hasn't been created. |
| final EntityStorage storage = new MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME); |
| final Optional<Entity> storedEntity = storage.get(new RyaURI("urn:GTIN-14/00012345600012")); |
| |
| // Verify nothing was returned. |
| assertFalse(storedEntity.isPresent()); |
| } |
| |
| @Test |
| public void delete() throws Exception { |
| // An Entity that will be stored. |
| final Entity entity = Entity.builder() |
| .setSubject(new RyaURI("urn:GTIN-14/00012345600012")) |
| .setExplicitType(new RyaURI("urn:icecream")) |
| .setProperty(new RyaURI("urn:icecream"), new Property(new RyaURI("urn:brand"), new RyaType(XMLSchema.STRING, "Awesome Icecream"))) |
| .setProperty(new RyaURI("urn:icecream"), new Property(new RyaURI("urn:flavor"), new RyaType(XMLSchema.STRING, "Chocolate"))) |
| .build(); |
| |
| // Create it. |
| final EntityStorage storage = new MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME); |
| storage.create(entity); |
| |
| // Delete it. |
| final boolean deleted = storage.delete( new RyaURI("urn:GTIN-14/00012345600012") ); |
| |
| // Verify a document was deleted. |
| assertTrue( deleted ); |
| } |
| |
| @Test |
| public void delete_nonExisting() throws Exception { |
| // Delete an Entity that has not been created. |
| final EntityStorage storage = new MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME); |
| final boolean deleted = storage.delete( new RyaURI("urn:GTIN-14/00012345600012") ); |
| |
| // Verify no document was deleted. |
| assertFalse( deleted ); |
| } |
| |
| @Test |
| public void search_byDataType() throws Exception { |
| final EntityStorage storage = new MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME); |
| |
| // The Type we will search by. |
| final Type icecreamType = new Type(new RyaURI("urn:icecream"), |
| ImmutableSet.<RyaURI>builder() |
| .add(new RyaURI("urn:brand")) |
| .add(new RyaURI("urn:flavor")) |
| .add(new RyaURI("urn:cost")) |
| .build()); |
| |
| // Some Person typed entities. |
| final Entity alice = Entity.builder() |
| .setSubject( new RyaURI("urn:SSN/111-11-1111") ) |
| .setExplicitType(new RyaURI("urn:person")) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Alice"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue"))) |
| .build(); |
| |
| final Entity bob = Entity.builder() |
| .setSubject( new RyaURI("urn:SSN/222-22-2222") ) |
| .setExplicitType(new RyaURI("urn:person")) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Bob"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:age"), new RyaType(XMLSchema.INT, "57"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue"))) |
| .build(); |
| |
| // Some Icecream typed objects. |
| final Entity chocolateIcecream = Entity.builder() |
| .setSubject(new RyaURI("urn:GTIN-14/00012345600012")) |
| .setExplicitType(new RyaURI("urn:icecream")) |
| .setProperty(new RyaURI("urn:icecream"), new Property(new RyaURI("urn:brand"), new RyaType(XMLSchema.STRING, "Awesome Icecream"))) |
| .setProperty(new RyaURI("urn:icecream"), new Property(new RyaURI("urn:flavor"), new RyaType(XMLSchema.STRING, "Chocolate"))) |
| .build(); |
| |
| final Entity vanillaIcecream = Entity.builder() |
| .setSubject( new RyaURI("urn:GTIN-14/22356325213432") ) |
| .setExplicitType(new RyaURI("urn:icecream")) |
| .setProperty(new RyaURI("urn:icecream"), new Property(new RyaURI("urn:brand"), new RyaType(XMLSchema.STRING, "Awesome Icecream"))) |
| .setProperty(new RyaURI("urn:icecream"), new Property(new RyaURI("urn:flavor"), new RyaType(XMLSchema.STRING, "Vanilla"))) |
| .build(); |
| |
| |
| final Entity strawberryIcecream = Entity.builder() |
| .setSubject( new RyaURI("urn:GTIN-14/77544325436721") ) |
| .setProperty(new RyaURI("urn:icecream"), new Property(new RyaURI("urn:brand"), new RyaType(XMLSchema.STRING, "Awesome Icecream"))) |
| .setProperty(new RyaURI("urn:icecream"), new Property(new RyaURI("urn:flavor"), new RyaType(XMLSchema.STRING, "Strawberry"))) |
| .build(); |
| |
| // Create the objects in the storage. |
| storage.create(alice); |
| storage.create(bob); |
| storage.create(chocolateIcecream); |
| storage.create(vanillaIcecream); |
| storage.create(strawberryIcecream); |
| |
| // Search for all icecreams. |
| final Set<TypedEntity> objects = new HashSet<>(); |
| try(final ConvertingCursor<TypedEntity> it = storage.search(Optional.empty(), icecreamType, new HashSet<>())) { |
| while(it.hasNext()) { |
| objects.add(it.next()); |
| } |
| } |
| |
| // Verify the expected results were returned. |
| final Set<TypedEntity> expected = Sets.newHashSet( |
| chocolateIcecream.makeTypedEntity(new RyaURI("urn:icecream")).get(), |
| vanillaIcecream.makeTypedEntity(new RyaURI("urn:icecream")).get()); |
| assertEquals(expected, objects); |
| } |
| |
| @Test |
| public void search_byFields() throws Exception { |
| final EntityStorage storage = new MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME); |
| |
| // A Type that defines a Person. |
| final Type personType = new Type(new RyaURI("urn:person"), |
| ImmutableSet.<RyaURI>builder() |
| .add(new RyaURI("urn:name")) |
| .add(new RyaURI("urn:age")) |
| .add(new RyaURI("urn:eye")) |
| .build()); |
| |
| // Some Person typed objects. |
| final Entity alice = Entity.builder() |
| .setSubject( new RyaURI("urn:SSN/111-11-1111") ) |
| .setExplicitType(new RyaURI("urn:person")) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Alice"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue"))) |
| .build(); |
| |
| final Entity bob = Entity.builder() |
| .setSubject( new RyaURI("urn:SSN/222-22-2222") ) |
| .setExplicitType(new RyaURI("urn:person")) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Bob"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:age"), new RyaType(XMLSchema.INT, "57"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue"))) |
| .build(); |
| |
| |
| final Entity charlie = Entity.builder() |
| .setSubject( new RyaURI("urn:SSN/333-33-3333") ) |
| .setExplicitType( new RyaURI("urn:person") ) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Charlie"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue"))) |
| .build(); |
| |
| final Entity david = Entity.builder() |
| .setSubject( new RyaURI("urn:SSN/444-44-4444") ) |
| .setExplicitType( new RyaURI("urn:person") ) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "David"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "brown"))) |
| .build(); |
| |
| final Entity eve = Entity.builder() |
| .setSubject( new RyaURI("urn:SSN/555-55-5555") ) |
| .setExplicitType( new RyaURI("urn:person") ) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Eve"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30"))) |
| .build(); |
| |
| final Entity frank = Entity.builder() |
| .setSubject( new RyaURI("urn:SSN/666-66-6666") ) |
| .setExplicitType( new RyaURI("urn:person") ) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Frank"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue"))) |
| .setProperty(new RyaURI("urn:someOtherType"), new Property(new RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30"))) |
| .build(); |
| |
| final Entity george = Entity.builder() |
| .setSubject( new RyaURI("urn:SSN/777-77-7777") ) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "George"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue"))) |
| .build(); |
| |
| // Create the objects in the storage. |
| storage.create(alice); |
| storage.create(bob); |
| storage.create(charlie); |
| storage.create(david); |
| storage.create(eve); |
| storage.create(frank); |
| storage.create(george); |
| |
| // Search for all people who are 30 and have blue eyes. |
| final Set<TypedEntity> objects = new HashSet<>(); |
| |
| final Set<Property> searchValues = Sets.newHashSet( |
| new Property(new RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue")), |
| new Property(new RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30"))); |
| |
| try(final ConvertingCursor<TypedEntity> it = storage.search(Optional.empty(), personType, searchValues)) { |
| while(it.hasNext()) { |
| objects.add(it.next()); |
| } |
| } |
| |
| // Verify the expected results were returned. |
| assertEquals(2, objects.size()); |
| assertTrue(objects.contains(alice.makeTypedEntity(new RyaURI("urn:person")).get())); |
| assertTrue(objects.contains(charlie.makeTypedEntity(new RyaURI("urn:person")).get())); |
| } |
| |
| @Test |
| public void update() throws Exception { |
| final EntityStorage storage = new MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME); |
| |
| // Store Alice in the repository. |
| final Entity alice = Entity.builder() |
| .setSubject( new RyaURI("urn:SSN/111-11-1111") ) |
| .setExplicitType(new RyaURI("urn:person")) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Alice"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue"))) |
| .build(); |
| |
| storage.create(alice); |
| |
| // Show Alice was stored. |
| Optional<Entity> latest = storage.get(new RyaURI("urn:SSN/111-11-1111")); |
| assertEquals(alice, latest.get()); |
| |
| // Change Alice's eye color to brown. |
| final Entity updated = Entity.builder(alice) |
| .setVersion(latest.get().getVersion() + 1) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "brown"))) |
| .build(); |
| |
| storage.update(alice, updated); |
| |
| // Fetch the Alice object and ensure it has the new value. |
| latest = storage.get(new RyaURI("urn:SSN/111-11-1111")); |
| |
| assertEquals(updated, latest.get()); |
| } |
| |
| @Test(expected = StaleUpdateException.class) |
| public void update_stale() throws Exception { |
| final EntityStorage storage = new MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME); |
| |
| // Store Alice in the repository. |
| final Entity alice = Entity.builder() |
| .setSubject( new RyaURI("urn:SSN/111-11-1111") ) |
| .setExplicitType(new RyaURI("urn:person")) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:name"), new RyaType(XMLSchema.STRING, "Alice"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:age"), new RyaType(XMLSchema.INT, "30"))) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "blue"))) |
| .build(); |
| |
| storage.create(alice); |
| |
| // Show Alice was stored. |
| final Optional<Entity> latest = storage.get(new RyaURI("urn:SSN/111-11-1111")); |
| assertEquals(alice, latest.get()); |
| |
| // Create the wrong old state and try to change Alice's eye color to brown. |
| final Entity wrongOld = Entity.builder(alice) |
| .setVersion(500) |
| .build(); |
| |
| final Entity updated = Entity.builder(alice) |
| .setVersion(501) |
| .setProperty(new RyaURI("urn:person"), new Property(new RyaURI("urn:eye"), new RyaType(XMLSchema.STRING, "brown"))) |
| .build(); |
| |
| storage.update(wrongOld, updated); |
| } |
| |
| @Test(expected = EntityStorageException.class) |
| public void update_differentSubjects() throws Exception { |
| // Two objects that do not have the same Subjects. |
| final Entity old = Entity.builder() |
| .setSubject( new RyaURI("urn:SSN/111-11-1111") ) |
| .setExplicitType( new RyaURI("urn:person") ) |
| .build(); |
| |
| final Entity updated = Entity.builder() |
| .setSubject( new RyaURI("urn:SSN/222-22-2222") ) |
| .setExplicitType( new RyaURI("urn:person") ) |
| .build(); |
| |
| // The update will fail. |
| final EntityStorage storage = new MongoEntityStorage(super.getMongoClient(), RYA_INSTANCE_NAME); |
| storage.update(old, updated); |
| } |
| } |