/*
* Copyright 2015-2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.hawkular.inventory.api.test;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toSet;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.hawkular.inventory.api.Action.created;
import static org.hawkular.inventory.api.Action.deleted;
import static org.hawkular.inventory.api.Action.syncHashChanged;
import static org.hawkular.inventory.api.Action.updated;
import static org.hawkular.inventory.api.Relationships.Direction.both;
import static org.hawkular.inventory.api.Relationships.Direction.incoming;
import static org.hawkular.inventory.api.Relationships.Direction.outgoing;
import static org.hawkular.inventory.api.Relationships.WellKnown.contains;
import static org.hawkular.inventory.api.Relationships.WellKnown.hasData;
import static org.hawkular.inventory.api.Relationships.WellKnown.incorporates;
import static org.hawkular.inventory.api.Relationships.WellKnown.isParentOf;
import static org.hawkular.inventory.api.filters.Related.asTargetBy;
import static org.hawkular.inventory.api.filters.Related.by;
import static org.hawkular.inventory.api.filters.With.id;
import static org.hawkular.inventory.api.filters.With.path;
import static org.hawkular.inventory.api.filters.With.type;
import static org.hawkular.inventory.paths.DataRole.OperationType.returnType;
import static org.hawkular.inventory.paths.DataRole.Resource.configuration;
import static org.hawkular.inventory.paths.DataRole.Resource.connectionConfiguration;
import static org.hawkular.inventory.paths.DataRole.ResourceType.configurationSchema;
import static org.hawkular.inventory.paths.DataRole.ResourceType.connectionConfigurationSchema;
import java.io.FileInputStream;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.Set;
import java.util.Spliterators;
import java.util.UUID;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.hawkular.inventory.api.Action;
import org.hawkular.inventory.api.Configuration;
import org.hawkular.inventory.api.Data;
import org.hawkular.inventory.api.EntityNotFoundException;
import org.hawkular.inventory.api.Environments;
import org.hawkular.inventory.api.FeedAlreadyRegisteredException;
import org.hawkular.inventory.api.Feeds;
import org.hawkular.inventory.api.Interest;
import org.hawkular.inventory.api.Inventory;
import org.hawkular.inventory.api.Metrics;
import org.hawkular.inventory.api.OperationTypes;
import org.hawkular.inventory.api.Parents;
import org.hawkular.inventory.api.PathFragment;
import org.hawkular.inventory.api.Query;
import org.hawkular.inventory.api.RelationAlreadyExistsException;
import org.hawkular.inventory.api.RelationNotFoundException;
import org.hawkular.inventory.api.Relationships;
import org.hawkular.inventory.api.ResolvableToMany;
import org.hawkular.inventory.api.ResolvableToSingle;
import org.hawkular.inventory.api.ResourceTypes;
import org.hawkular.inventory.api.Resources;
import org.hawkular.inventory.api.Tenants;
import org.hawkular.inventory.api.TransactionFrame;
import org.hawkular.inventory.api.ValidationException;
import org.hawkular.inventory.api.feeds.AcceptWithFallbackFeedIdStrategy;
import org.hawkular.inventory.api.feeds.RandomUUIDFeedIdStrategy;
import org.hawkular.inventory.api.filters.Defined;
import org.hawkular.inventory.api.filters.Filter;
import org.hawkular.inventory.api.filters.RecurseFilter;
import org.hawkular.inventory.api.filters.Related;
import org.hawkular.inventory.api.filters.RelationWith;
import org.hawkular.inventory.api.filters.SwitchElementType;
import org.hawkular.inventory.api.filters.With;
import org.hawkular.inventory.api.model.AbstractElement;
import org.hawkular.inventory.api.model.Blueprint;
import org.hawkular.inventory.api.model.Change;
import org.hawkular.inventory.api.model.DataEntity;
import org.hawkular.inventory.api.model.Entity;
import org.hawkular.inventory.api.model.Environment;
import org.hawkular.inventory.api.model.Feed;
import org.hawkular.inventory.api.model.IdentityHash;
import org.hawkular.inventory.api.model.InventoryStructure;
import org.hawkular.inventory.api.model.MetadataPack;
import org.hawkular.inventory.api.model.Metric;
import org.hawkular.inventory.api.model.MetricDataType;
import org.hawkular.inventory.api.model.MetricType;
import org.hawkular.inventory.api.model.MetricUnit;
import org.hawkular.inventory.api.model.OperationType;
import org.hawkular.inventory.api.model.Relationship;
import org.hawkular.inventory.api.model.Resource;
import org.hawkular.inventory.api.model.ResourceType;
import org.hawkular.inventory.api.model.StructuredData;
import org.hawkular.inventory.api.model.SyncConfiguration;
import org.hawkular.inventory.api.model.SyncHash;
import org.hawkular.inventory.api.model.SyncRequest;
import org.hawkular.inventory.api.model.Tenant;
import org.hawkular.inventory.api.paging.Order;
import org.hawkular.inventory.api.paging.Page;
import org.hawkular.inventory.api.paging.Pager;
import org.hawkular.inventory.base.BaseInventory;
import org.hawkular.inventory.base.spi.Discriminator;
import org.hawkular.inventory.base.spi.InventoryBackend;
import org.hawkular.inventory.paths.CanonicalPath;
import org.hawkular.inventory.paths.DataRole;
import org.hawkular.inventory.paths.Path;
import org.hawkular.inventory.paths.RelativePath;
import org.hawkular.inventory.paths.SegmentType;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import rx.Observable;
import rx.Subscription;
/**
* @author Lukas Krejci
* @since 0.0.6
*/
public abstract class AbstractBaseInventoryTestsuite<E> {
protected BaseInventory<E> inventory;
protected static <E> void setupNewInventory(BaseInventory<E> inventory) throws Exception {
Properties ps = new Properties();
try (FileInputStream f = new FileInputStream(System.getProperty("graph.config"))) {
ps.load(f);
}
Configuration config = Configuration.builder().withFeedIdStrategy(
new AcceptWithFallbackFeedIdStrategy(new RandomUUIDFeedIdStrategy()))
.withConfiguration(ps)
.build();
inventory.initialize(config);
try {
inventory.tenants().delete("com.acme.tenant");
} catch (Exception ignored) {
}
try {
inventory.tenants().delete("com.example.tenant");
} catch (Exception ignored) {
}
try {
inventory.tenants().delete("perf0");
} catch (Exception ignored) {
}
}
protected static <E> void setupData(BaseInventory<E> inventory) throws Exception {
inventory.tenants().getAll().entities().forEach(t -> inventory.inspect(t).delete());
//noinspection AssertWithSideEffects
assert inventory.tenants()
.create(Tenant.Blueprint.builder().withId("com.acme.tenant").withProperty("kachny", "moc").build())
.entity().getId().equals("com.acme.tenant");
assert inventory.tenants().get("com.acme.tenant").environments().create(new Environment.Blueprint("production"))
.entity().getId().equals("production");
assert inventory.tenants().get("com.acme.tenant").resourceTypes()
.create(new ResourceType.Blueprint("URL")).entity().getId().equals("URL");
assert inventory.tenants().get("com.acme.tenant").metricTypes()
.create(new MetricType.Blueprint("ResponseTime",
MetricUnit.MILLISECONDS, MetricDataType.COUNTER, 0L)).entity().getId().equals("ResponseTime");
inventory.tenants().get("com.acme.tenant").resourceTypes().get("URL").metricTypes()
.associate(CanonicalPath.of().tenant("com.acme.tenant").metricType("ResponseTime").get());
assert inventory.tenants().get("com.acme.tenant").environments().get("production").metrics()
.create(new Metric.Blueprint("/ResponseTime", "host1_ping_response")).entity().getId()
.equals("host1_ping_response");
assert inventory.tenants().get("com.acme.tenant").environments().get("production").resources()
.create(new Resource.Blueprint("host1", "/URL")).entity()
.getId().equals("host1");
inventory.tenants().get("com.acme.tenant").environments().get("production").resources()
.get("host1").allMetrics().associate(RelativePath.fromString("../m;host1_ping_response"));
assert inventory.tenants().get("com.acme.tenant").feeds()
.create(new Feed.Blueprint("feed1", null)).entity().getId().equals("feed1");
inventory.tenants().get("com.acme.tenant").environments().get("production").feeds()
.associate(RelativePath.fromString("../f;feed1"));
assert inventory.tenants().get("com.acme.tenant").feeds().get("feed1")
.resources().create(new Resource.Blueprint("feedResource1", "/URL")).entity().getId()
.equals("feedResource1");
assert inventory.tenants().get("com.acme.tenant").feeds().get("feed1")
.resources().create(new Resource.Blueprint("feedResource2", "/URL")).entity().getId()
.equals("feedResource2");
assert inventory.tenants().get("com.acme.tenant").feeds().get("feed1")
.resources().create(new Resource.Blueprint("feedResource3", "/URL")).entity().getId()
.equals("feedResource3");
assert inventory.tenants().get("com.acme.tenant").feeds().get("feed1")
.metrics().create(new Metric.Blueprint("/ResponseTime", "feedMetric1")).entity().getId()
.equals("feedMetric1");
assert inventory.tenants().create(new Tenant.Blueprint("com.example.tenant")).entity().getId()
.equals("com.example.tenant");
assert inventory.tenants().get("com.example.tenant").environments().create(new Environment.Blueprint("test"))
.entity().getId().equals("test");
assert inventory.tenants().get("com.example.tenant").resourceTypes()
.create(new ResourceType.Blueprint("Kachna")).entity().getId().equals("Kachna");
assert inventory.tenants().get("com.example.tenant").resourceTypes()
.create(new ResourceType.Blueprint("Playroom", new HashMap<String, Object>() {{
put("ownedByDepartment", "Facilities");
}})).entity().getId().equals("Playroom");
assert inventory.tenants().get("com.example.tenant").metricTypes()
.create(new MetricType.Blueprint("Size", MetricUnit.BYTES, MetricDataType.COUNTER, 0L))
.entity().getId().equals("Size");
inventory.tenants().get("com.example.tenant").resourceTypes().get("Playroom").metricTypes()
.associate(RelativePath.to().up().metricType("Size").get());
assert inventory.tenants().get("com.example.tenant").environments().get("test").metrics()
.create(new Metric.Blueprint("/Size", "playroom1_size")).entity().getId().equals("playroom1_size");
assert inventory.tenants().get("com.example.tenant").environments().get("test").metrics()
.create(new Metric.Blueprint("/Size", "playroom2_size")).entity().getId().equals("playroom2_size");
assert inventory.tenants().get("com.example.tenant").environments().get("test").resources()
.create(new Resource.Blueprint("playroom1", "/Playroom")).entity().getId()
.equals("playroom1");
assert inventory.tenants().get("com.example.tenant").environments().get("test").resources()
.create(new Resource.Blueprint("playroom2", "/Playroom")).entity().getId()
.equals("playroom2");
inventory.tenants().get("com.example.tenant").environments().get("test").resources()
.get("playroom1").allMetrics().associate(RelativePath.to().up().metric("playroom1_size").get());
inventory.tenants().get("com.example.tenant").environments().get("test").resources()
.get("playroom2").allMetrics().associate(CanonicalPath.of().tenant("com.example.tenant")
.environment("test").metric("playroom2_size").get());
assert inventory.tenants().get("com.example.tenant").environments().get("test").resources()
.get("playroom1").resources()
.create(new Resource.Blueprint("playroom1.1", "/Playroom")).entity().getId()
.equals("playroom1.1");
assert inventory.tenants().get("com.example.tenant").environments().get("test").resources()
.get("playroom1").resources()
.create(new Resource.Blueprint("playroom1.2", "/Playroom")).entity().getId()
.equals("playroom1.2");
inventory.tenants().get("com.example.tenant").environments().get("test").resources()
.get("playroom1").allResources().associate(CanonicalPath.of().tenant("com.example.tenant")
.environment("test").resource("playroom2").get());
assert inventory.tenants().get("com.example.tenant").environments().get("test").resources()
.get("playroom2").resources()
.create(new Resource.Blueprint("playroom2.1", "/Playroom")).entity().getId()
.equals("playroom2.1");
// some ad-hoc relationships
Environment test = inventory.tenants().get("com.example.tenant").environments().get("test").entity();
inventory.tenants().get("com.example.tenant").environments().get("test").resources()
.get("playroom2").allMetrics().get(CanonicalPath.of().tenant("com.example.tenant")
.environment("test").metric("playroom2_size").get()).relationships(outgoing)
.linkWith("yourMom", CanonicalPath.of().tenant("com.example.tenant").environment("test").get(), null);
inventory.tenants().get("com.example.tenant").environments().get("test").resources()
.get("playroom2").allMetrics().get(CanonicalPath.of().tenant("com.example.tenant")
.environment("test").metric("playroom2_size").get()).relationships(incoming)
.linkWith("IamYourFather", CanonicalPath.of().tenant("com.example.tenant").environment("test").get(),
new HashMap<String, Object>() {{
put("adult", true);
}});
// setup configs
StructuredData config = StructuredData.get().map()
.putBool("yes", true)
.putBool("no", false)
.putIntegral("answer", 42L)
.putFloatingPoint("approximateAnswer", 42.0)
.putString("kachna", "moc")
.putUndefined("nothingToSeeHere")
.putList("primitives")
/**/.addBool(true)
/**/.addIntegral(1L)
/**/.addFloatingPoint(2.0)
/**/.addString("str")
/**/.addUndefined()
.closeList()
.putMap("primitiveMap")
/**/.putBool("bool", true)
/**/.putFloatingPoint("float", 1.0)
/**/.putIntegral("int", 2L)
/**/.putString("str", "kachna")
/**/.putUndefined("undef")
.closeMap()
.putList("listOfMaps")
/**/.addMap()
/**//**/.putBool("listOfMaps_bool", true)
/**//**/.putString("listOfMaps_string", "kachny")
/**/.closeMap()
/**/.addMap()
/**//**/.putFloatingPoint("listOfMaps_float", 1.0)
/**/.closeMap()
.closeList()
.putList("listOfLists")
/**/.addList()
/**//**/.addBool(true)
/**//**/.addIntegral(1L)
/**/.closeList()
.closeList()
.putMap("mapOfLists")
/**/.putList("list1")
/**//**/.addString("ducks")
/**//**/.addUndefined()
/**/.closeList()
/**/.putList("list2")
/**//**/.addBool(false)
/**//**/.addFloatingPoint(2.0)
/**/.closeList()
.closeMap()
.putMap("mapOfMaps")
/**/.putMap("map1")
/**//**/.putIntegral("int", 42L)
/**//**/.putString("answer", "probably")
/**/.closeMap()
/**/.putMap("map2")
/**//**/.putFloatingPoint("float", 2.0)
/**/.closeMap()
.closeMap()
.build();
assert inventory.tenants().get("com.example.tenant").environments().get("test")
.resources().get("playroom1").data().create(DataEntity.Blueprint.<DataRole.Resource>builder()
.withRole(configuration).withValue(config).build()).entity().getValue().equals(config);
//create some config definitions...
ResourceTypes.Single personType = inventory.tenants().get("com.acme.tenant").resourceTypes()
.create(ResourceType.Blueprint.builder().withId("Person").build());
personType.data().create(DataEntity.Blueprint
.<DataRole.ResourceType>builder().withRole(configurationSchema).withValue(StructuredData.get().map()
.putString("title", "Person")
.putString("description", "Utterly complete description of a human.")
.putString("type", "object")
.putMap("properties")
/**/.putMap("firstName")
/**//**/.putString("type", "string")
/**/.closeMap()
/**/.putMap("lastName")
/**//**/.putString("type", "string")
/**/.closeMap()
/**/.putMap("age")
/**//**/.putString("description", "Age in years")
/**//**/.putString("type", "integer")
/**//**/.putIntegral("minimum", 0)
/**/.closeMap()
.closeMap()
.putList("required")
/**/.addString("firstName")
/**/.addString("lastName")
.closeList()
.build()).build());
OperationTypes.Single startOp = personType.operationTypes().create(
OperationType.Blueprint.builder().withId
("start").build());
startOp.data().create(DataEntity.Blueprint.<DataRole.OperationType>builder()
.withRole(returnType).withValue(StructuredData.get().map()
.putString("title", "start_returnType")
.putString("description", "start operation result")
.putString("type", "boolean")
.build()).build());
startOp.data().create(DataEntity.Blueprint.<DataRole.OperationType>builder()
.withRole(DataRole.OperationType.parameterTypes).withValue(StructuredData.get().map()
.putString("title", "start_paramTypes")
.putString("description", "start operation parameter types")
.putString("type", "object")
.putMap("properties")
/**/.putMap("quick")
/**//**/.putString("type", "boolean")
/**/.closeMap()
.closeMap()
.build()).build());
//now create some resources with configs
Resources.Single people = inventory.tenants().get("com.acme.tenant").environments().get("production")
.resources()
.create(Resource.Blueprint.builder().withId("people").withResourceTypePath("/Person").build());
people.resources().create(Resource.Blueprint.builder().withId("Alois").withResourceTypePath("/Person")
.build()).data().create(DataEntity.Blueprint.<DataRole.Resource>builder().withRole(configuration)
.withValue(StructuredData.get().map().putString("firstName", "Alois").putString("lastName", "Jirasek")
.build()).build());
people.resources().create(Resource.Blueprint.builder().withId("Hynek").withResourceTypePath("/Person")
.build()).data().create(DataEntity.Blueprint.<DataRole.Resource>builder().withRole(configuration)
.withValue(StructuredData.get().map().putString("firstName", "Hynek").putString("lastName", "Macha")
.build()).build());
people.resources().get("Hynek").resources().create(
Resource.Blueprint.builder().withResourceTypePath("/Person")
.withId("Vilem").build());
people.resources().get("Hynek").resources().create(
Resource.Blueprint.builder().withResourceTypePath("/Person")
.withId("Jarmila").build());
//create a metadata pack
inventory.tenants().get("com.acme.tenant").resourceTypes().create(ResourceType.Blueprint.builder()
.withId("mpRt").withName("Resource Type in a metadata pack").build());
inventory.tenants().get("com.acme.tenant").resourceTypes().get("mpRt").data().create(
DataEntity.Blueprint.<DataRole.ResourceType>builder()
.withRole(DataRole.ResourceType.configurationSchema)
.withValue(StructuredData.get().map().putString("title", "mpRtCs").putString("type",
"string").build()).build());
inventory.tenants().get("com.acme.tenant").resourceTypes().get("mpRt").operationTypes().create(
OperationType.Blueprint.builder().withId("mpRtOt").build());
inventory.tenants().get("com.acme.tenant").resourceTypes().get("mpRt").operationTypes().get("mpRtOt")
.data().create(DataEntity.Blueprint.<DataRole.OperationType>builder().withRole(returnType)
.withValue(StructuredData.get().map().putString("title", "mpRtOtRet")
.putString("type", "string").build()).build());
inventory.tenants().get("com.acme.tenant").metricTypes().create(
MetricType.Blueprint.builder(MetricDataType.GAUGE).withId("mpMt").withUnit(MetricUnit.NONE)
.withInterval(0L).build());
inventory.tenants().get("com.acme.tenant").metadataPacks().create(MetadataPack.Blueprint.builder()
.withMembers(CanonicalPath.fromString("/t;com.acme.tenant/rt;mpRt"),
CanonicalPath.fromString("/t;com.acme.tenant/mt;mpMt")).build());
//resource-owned metrics
assert inventory.tenants().get("com.acme.tenant").feeds().get("feed1")
.resources().get("feedResource3").metrics().create(Metric.Blueprint.builder()
.withId("feedResource3-metric").withMetricTypePath("/ResponseTime").build()).entity().getId()
.equals("feedResource3-metric");
//feed-owned resource types and metric types
assert inventory.tenants().get("com.acme.tenant").feeds().get("feed1").resourceTypes().create(
ResourceType.Blueprint.builder().withId("feed1-resourceType").build()).entity().getId()
.equals("feed1-resourceType");
assert inventory.tenants().get("com.acme.tenant").feeds().get("feed1").metricTypes().create(
MetricType.Blueprint.builder(MetricDataType.GAUGE).withId("feed1-metricType").withUnit(MetricUnit.NONE)
.withInterval(0L).build()).entity().getId().equals("feed1-metricType");
assert inventory.tenants().get("com.acme.tenant").feeds().get("feed1").resources().get("feedResource1")
.resources().create(
Resource.Blueprint.builder().withId("feedChildResource").withResourceTypePath
("/URL").build()).entity().getId().equals("feedChildResource");
}
protected static <E> void teardownData(BaseInventory<E> inventory) throws Exception {
CanonicalPath tenantPath = CanonicalPath.of().tenant("com.example.tenant").get();
CanonicalPath environmentPath = tenantPath.extend(Environment.SEGMENT_TYPE, "test").get();
try {
Tenant t = new Tenant(tenantPath, null);
Environment e = new Environment(environmentPath, null);
MetricType sizeType = new MetricType(tenantPath.extend(MetricType.SEGMENT_TYPE, "Size").get(), null,
null, null);
ResourceType playRoomType = new ResourceType(tenantPath.extend(ResourceType.SEGMENT_TYPE, "Playroom").get(),
null, null, null);
ResourceType kachnaType = new ResourceType(tenantPath.extend(ResourceType.SEGMENT_TYPE, "Kachna").get(),
null, null, null);
Resource playroom1 = new Resource(environmentPath.extend(Resource.SEGMENT_TYPE, "playroom1").get(), null,
null, null, playRoomType);
Resource playroom2 = new Resource(environmentPath.extend(Resource.SEGMENT_TYPE, "playroom2").get(), null,
null, null, playRoomType);
Metric playroom1Size = new Metric(environmentPath.extend(Metric.SEGMENT_TYPE, "playroom1_size").get(), null,
null, null, sizeType);
Metric playroom2Size = new Metric(environmentPath.extend(Metric.SEGMENT_TYPE, "playroom2_size").get(), null,
null, null, sizeType);
//when an association is deleted, it should not be possible to access the target entity through the same
//traversal again
inventory.inspect(playroom2).allMetrics().disassociate(playroom2Size.getPath());
Assert.assertFalse(inventory.inspect(playroom2).allMetrics().get(playroom2Size.getPath()).exists());
Assert.assertFalse(inventory.inspect(playroom2).allMetrics().get(
RelativePath.to().up().metric(playroom2Size.getId()).get()).exists());
inventory.inspect(playroom2Size).delete();
assertDoesNotExist(inventory, playroom2Size);
assertExists(inventory, t, e, sizeType, playRoomType, kachnaType, playroom1, playroom2, playroom1Size);
//disassociation using a relative path should work, too
inventory.inspect(playroom1).allMetrics().disassociate(RelativePath.to().up().metric(playroom1Size.getId())
.get());
Assert.assertFalse(inventory.inspect(playroom1).allMetrics().get(playroom1Size.getPath()).exists());
Assert.assertFalse(inventory.inspect(playroom1).allMetrics().get(
RelativePath.to().up().metric(playroom1Size.getId()).get()).exists());
inventory.inspect(t).resourceTypes().delete(kachnaType.getId());
assertDoesNotExist(inventory, kachnaType);
assertExists(inventory, t, e, sizeType, playRoomType, playroom1, playroom2, playroom1Size);
try {
inventory.inspect(t).metricTypes().delete(sizeType.getId());
Assert.fail("Deleting a metric type which references some metrics should not be possible.");
} catch (IllegalArgumentException ignored) {
//good
}
inventory.inspect(e).metrics().delete(playroom1Size.getId());
assertDoesNotExist(inventory, playroom1Size);
assertExists(inventory, t, e, sizeType, playRoomType, playroom1, playroom2);
inventory.inspect(t).metricTypes().delete(sizeType.getId());
assertDoesNotExist(inventory, sizeType);
assertExists(inventory, t, e, playRoomType, playroom1, playroom2);
try {
inventory.inspect(t).resourceTypes().delete(playRoomType.getId());
Assert.fail("Deleting a resource type which references some resources should not be possible.");
} catch (IllegalArgumentException ignored) {
//good
}
inventory.inspect(e).resources().delete(playroom1.getId());
assertDoesNotExist(inventory, playroom1);
assertExists(inventory, t, e, playRoomType, playroom2);
inventory.tenants().delete(t.getId());
assertDoesNotExist(inventory, t);
assertDoesNotExist(inventory, e);
assertDoesNotExist(inventory, playRoomType);
assertDoesNotExist(inventory, playroom2);
} finally {
Tenants.Single tenant = inventory.inspect(tenantPath, Tenants.Single.class);
if (tenant.exists()) {
tenant.delete();
}
inventory.tenants().delete("com.acme.tenant");
}
}
private static void assertDoesNotExist(BaseInventory<?> inventory, Entity e) {
try {
inventory.inspect(e, ResolvableToSingle.class).entity();
Assert.fail(e + " should have been deleted");
} catch (EntityNotFoundException ignored) {
//good
}
}
@SuppressWarnings("unchecked")
private static void assertExists(BaseInventory<?> inventory, Entity<?, ?> e) {
Assert.assertTrue("Entity should exist: " + e, inventory.inspect(e, ResolvableToSingle.class).exists());
}
private static void assertExists(BaseInventory<?> inventory, Entity... es) {
Stream.of(es).forEach(e -> assertExists(inventory, e));
}
/**
* This needs to return a SINGLETON - i.e. every time this method is called, it needs to return the very same
* instance
*
* @return the inventory instance to run the tests with
*/
protected abstract BaseInventory<E> getInventoryForTest();
protected static Discriminator now() {
return Discriminator.time(Instant.now());
}
@Before
public final void setupData() throws Exception {
inventory = getInventoryForTest();
}
@Test
public void testTenants() throws Exception {
Function<String, Void> test = (id) -> {
Query query = Query.empty().asBuilder()
.with(PathFragment.from(type(Tenant.class), id(id))).build();
InventoryBackend<E> bcknd = inventory.getBackend().startTransaction();
try {
Page<E> results = bcknd.query(now(), query, Pager.unlimited(Order.unspecified()));
Assert.assertTrue(results.hasNext());
E tenant = results.next();
Assert.assertTrue(!results.hasNext());
String eid = inventory.getBackend().extractId(tenant);
Assert.assertEquals(id, eid);
} finally {
bcknd.rollback();
}
return null;
};
test.apply("com.acme.tenant");
test.apply("com.example.tenant");
Query query = Query.empty().asBuilder()
.with(PathFragment.from(type(Tenant.class))).build();
InventoryBackend<E> bcknd = inventory.getBackend().startTransaction();
try {
Page<E> results = bcknd.query(now(), query, Pager.unlimited(Order.unspecified()));
Assert.assertTrue(results.hasNext());
results.next();
Assert.assertTrue(results.hasNext());
results.next();
Assert.assertTrue(!results.hasNext());
} finally {
bcknd.rollback();
}
}
@Test
public void testEntitiesByRelationships() throws Exception {
Function<Function<InventoryBackend<E>, Page<E>>, Page<E>> inTx = (f) -> {
InventoryBackend<E> backend = inventory.getBackend().startTransaction();
Page<E> ret = f.apply(backend);
inventory.getBackend().rollback();
return ret;
};
Function<Integer, Function<Class<? extends Entity<?, ?>>, Function<String, Function<Integer,
Function<Class<? extends Entity<?, ?>>, Function<ResolvableToMany<?>,
Consumer<ResolvableToMany<?>>>>>>>>
testHelper = (numberOfParents -> parentType -> edgeLabel -> numberOfKids -> childType ->
multipleParents -> multipleChildren -> {
Page<E> parents = inTx.apply(b -> b.query(now(), Query.path().with(type(parentType)).get(),
Pager.unlimited(Order.unspecified())));
List<E> parentsList = parents.toList();
Page<E> children = inTx.apply(b -> b.query(now(), Query.path().with(type(parentType),
by(edgeLabel), type(childType)).get(), Pager.unlimited(Order.unspecified())));
List<E> childrenList = children.toList();
Assert.assertEquals(
"There must be exactly " + numberOfParents + " " + parentType + "s " + "that " +
"have outgoing edge labeled with " + edgeLabel +
". Backend query returned only " +
parentsList.size(), (int) numberOfParents, parentsList.size());
Assert.assertEquals("There must be exactly " +
numberOfParents + " " + parentType + "s that have outgoing edge labeled with " +
edgeLabel +
". Tested API returned only " + multipleParents.entities().size(),
(int) numberOfParents,
multipleParents.entities().size());
Assert.assertEquals("There must be exactly " + numberOfKids + " " + childType +
"s that are directly under " + parentType + " connected with " + edgeLabel +
". Gremlin query returned only " + childrenList.size(), (int) numberOfKids,
childrenList.size());
Assert.assertEquals((int) numberOfKids, multipleChildren.entities().size());
});
ResolvableToMany parents = inventory.tenants().getAll(by("contains"));
ResolvableToMany kids = inventory.tenants().getAll().environments().getAll(asTargetBy("contains"));
testHelper.apply(2).apply(Tenant.class).apply("contains").apply(2).apply(Environment.class).apply(parents)
.accept(kids);
kids = inventory.tenants().getAll().resourceTypes().getAll(asTargetBy("contains"));
testHelper.apply(2).apply(Tenant.class).apply("contains").apply(5).apply(
ResourceType.class).apply(parents)
.accept(kids);
kids = inventory.tenants().getAll().metricTypes().getAll(asTargetBy("contains"));
testHelper.apply(2).apply(Tenant.class).apply("contains").apply(3).apply(MetricType.class).apply(parents)
.accept(kids);
parents = inventory.tenants().getAll().environments().getAll(by("contains"));
kids = inventory.tenants().getAll().environments().getAll().metrics().getAll(
asTargetBy("contains"));
testHelper.apply(2).apply(Environment.class).apply("contains").apply(3).apply(Metric.class).apply(parents).
accept(kids);
kids = inventory.tenants().getAll().environments().getAll().resources().getAll(
asTargetBy("contains"));
testHelper.apply(2).apply(Environment.class).apply("contains").apply(4).apply(
Resource.class).apply(parents)
.accept(kids);
parents = inventory.tenants().getAll().metricTypesUnder(Parents.any()).getAll();
kids = inventory.tenants().getAll().environments().getAll().metricsUnder(Parents.any()).getAll();
testHelper.apply(4).apply(MetricType.class).apply("defines").apply(5).apply(Metric.class).apply(parents)
.accept(kids);
}
@Test
public void testRelationshipServiceNamed1() throws Exception {
Set<Relationship> contains = inventory.tenants().getAll().relationships().named("contains").entities();
assert contains.stream().anyMatch(rel -> "com.acme.tenant".equals(rel.getSource().getSegment().getElementId())
&& "URL".equals(rel.getTarget().getSegment().getElementId()))
: "Tenant 'com.acme.tenant' must contain ResourceType 'URL'.";
assert contains.stream().anyMatch(rel -> "com.acme.tenant".equals(rel.getSource().getSegment().getElementId())
&& "production".equals(rel.getTarget().getSegment().getElementId()))
: "Tenant 'com.acme.tenant' must contain Environment 'production'.";
assert contains.stream().anyMatch(rel -> "com.example.tenant".equals(rel.getSource().getSegment()
.getElementId()) && "Size".equals(rel.getTarget().getSegment().getElementId()))
: "Tenant 'com.example.tenant' must contain MetricType 'Size'.";
contains.forEach((r) -> {
assert r.getId() != null;
});
}
@Test
public void testRelationshipServiceNamed2() throws Exception {
Set<Relationship> contains = inventory.tenants().get("com.example.tenant").environments().get("test")
.relationships().named("contains").entities();
assert contains.stream().anyMatch(rel -> "playroom1".equals(rel.getTarget().getSegment().getElementId()))
: "Environment 'test' must contain 'playroom1'.";
assert contains.stream().anyMatch(rel -> "playroom2".equals(rel.getTarget().getSegment().getElementId()))
: "Environment 'test' must contain 'playroom2'.";
assert contains.stream().anyMatch(rel -> "playroom2_size".equals(rel.getTarget().getSegment().getElementId()))
: "Environment 'test' must contain 'playroom2_size'.";
assert contains.stream().anyMatch(rel -> "playroom1_size".equals(rel.getTarget().getSegment().getElementId()))
: "Environment 'test' must contain 'playroom1_size'.";
assert contains.stream().allMatch(rel -> !"production".equals(rel.getSource().getSegment().getElementId()))
: "Environment 'production' cant be the source of these relationships.";
contains.forEach((r) -> {
assert r.getId() != null;
});
}
@Test
public void testRelationshipServiceLinkedWith() throws Exception {
Set<Relationship> rels = inventory.tenants().get("com.example.tenant").environments().get("test")
.metrics().get("playroom2_size").relationships(outgoing).named("yourMom").entities();
assert rels != null && rels.size() == 1 : "There should be 1 relationship conforming the filters";
assert "test".equals(rels.iterator().next().getTarget().getSegment().getElementId())
: "Target of relationship 'yourMom' should be the 'test' environment";
rels = inventory.tenants().get("com.example.tenant").environments().get("test").metrics()
.get("playroom2_size").relationships(both).named("IamYourFather").entities();
assert rels != null && rels.size() == 1 : "There should be 1 relationship conforming the filters";
assert "test".equals(rels.iterator().next().getSource().getSegment().getElementId())
: "Source of relationship 'IamYourFather' should be the 'test' environment";
}
@Test
public void testRelationshipServiceLinkedWithAndDelete() throws Exception {
Relationship link = inventory.tenants().get("com.acme.tenant").environments().get("production")
.resources().get("host1").relationships(incoming)
.linkWith("crossTenantLink", CanonicalPath.of().tenant("com.example.tenant").get(), null).entity();
assert inventory.tenants().get("com.example.tenant").relationships(outgoing)
.named("crossTenantLink").entities().size() == 1 : "Relation 'crossTenantLink' was not found.";
// delete the relationship
inventory.tenants().get("com.example.tenant").relationships(/*defaults to outgoing*/).delete(link.getId());
assert inventory.tenants().get("com.example.tenant").relationships()
.named("crossTenantLink").entities().size() == 0 : "Relation 'crossTenantLink' was found.";
// try deleting again
try {
inventory.tenants().get("com.example.tenant").relationships(/*defaults to outgoing*/).delete(link.getId());
assert false : "It shouldn't be possible to delete the same relationship twice";
} catch (RelationNotFoundException e) {
// good
}
}
@Test
public void testRelationshipServiceUpdateRelationship1() throws Exception {
final String someKey = "k3y";
final String someValue = "v4lu3";
Relationship rel1 = inventory.tenants().get("com.example.tenant").environments().get("test").metrics()
.get("playroom2_size").relationships(outgoing).named("yourMom").entities().iterator().next();
assert null == rel1.getProperties().get(someKey) : "There should not be any property with key 'k3y'";
Relationship rel2 = inventory.tenants().get("com.example.tenant").environments().get("test").metrics()
.get("playroom2_size").relationships(outgoing).named("yourMom").entities().iterator().next();
assert rel1.getId().equals(rel2.getId()) && null == rel2.getProperties().get(someKey) : "There should not be" +
" any property with key 'k3y'";
// persist the change
inventory.tenants().get("com.example.tenant").environments().get("test").metrics().get("playroom2_size")
.relationships(outgoing).update(rel1.getId(), Relationship.Update.builder()
.withProperty(someKey, someValue).build());
Relationship rel3 = inventory.tenants().get("com.example.tenant").environments().get("test").metrics()
.get("playroom2_size").relationships(outgoing).named("yourMom").entities().iterator().next();
assert rel1.getId().equals(rel3.getId()) && someValue.equals(rel3.getProperties().get(someKey))
: "There should be the property with key 'k3y' and value 'v4lu3'";
}
@Test
public void testRelationshipServiceGetAllFilters() throws Exception {
Set<Relationship> rels = inventory.tenants().get("com.example.tenant").environments().get("test")
.relationships(outgoing).getAll(RelationWith.name("contains")).entities();
assert rels != null && rels.size() == 4 : "There should be 4 relationships conforming the filters";
assert rels.stream().anyMatch(rel -> "playroom2_size".equals(rel.getTarget().getSegment().getElementId()));
assert rels.stream().anyMatch(rel -> "playroom1".equals(rel.getTarget().getSegment().getElementId()));
rels = inventory.tenants().get("com.example.tenant").environments().get("test")
.relationships(outgoing).getAll(RelationWith.name("contains"), RelationWith
.targetOfType(Metric.class)).entities();
assert rels != null && rels.size() == 2 : "There should be 2 relationships conforming the filters";
assert rels.stream().allMatch(rel ->
SegmentType.m.equals(rel.getTarget().getSegment().getElementType())) : "The type of all the " +
"targets should be the 'Metric'";
rels = inventory.tenants().get("com.example.tenant").environments().get("test")
.relationships(incoming).getAll(RelationWith.name("contains")).entities();
assert rels != null && rels.size() == 1 : "There should be just 1 relationship conforming the filters";
assert "com.example.tenant".equals(rels.iterator().next().getSource().getSegment().getElementId())
: "Tenant 'com.example.tenant' was not found";
rels = inventory.tenants().getAll().relationships().named
(contains).environments().getAll().relationships().getAll(RelationWith
.propertyValues("label", "contains"), RelationWith.targetsOfTypes(
Resource.class, Metric.class))
.entities();
assert rels != null && rels.size() == 7 : "There should be 6 relationships conforming the filters";
assert rels.stream().allMatch(rel -> "test".equals(rel.getSource().getSegment().getElementId())
|| "production".equals(rel.getSource().getSegment().getElementId()))
: "Source should be either 'test' or 'production'";
assert rels.stream().allMatch(rel -> SegmentType.r.equals(rel.getTarget().getSegment().getElementType()) ||
SegmentType.m.equals(rel.getTarget().getSegment().getElementType()))
: "Target should be either a metric or a resource";
}
@Test
public void testRelationshipServiceGetAllFiltersWithSubsequentCalls() throws Exception {
Metric metric = inventory.tenants().getAll().relationships().named
(contains).environments().getAll().relationships().getAll(RelationWith
.propertyValues("label", "contains"), RelationWith.targetsOfTypes(
Resource.class, Metric.class))
.metrics().getAll(id("playroom1_size")).entities().iterator().next();
assert "playroom1_size".equals(metric.getId()) : "Metric playroom1_size was not found using various relation " +
"filters";
try {
inventory.tenants().getAll().relationships().named
(contains).environments().getAll().relationships().getAll(RelationWith
.propertyValues("label", "contains"), RelationWith.targetsOfTypes(
Resource.class))
.metrics().getAll(id("playroom1_size")).entities().iterator().next();
assert false : "this code should not be reachable. There should be no metric reachable under " +
"'RelationWith.targetsOfTypes(Resource.class))' filter";
} catch (NoSuchElementException e) {
// good
}
}
@Test
public void testRelationshipServiceCallChaining() throws Exception {
MetricType metricType = inventory.tenants().get("com.example.tenant").resourceTypes().get("Playroom")
.relationships().named("incorporates").metricTypes().get(
CanonicalPath.of().tenant("com.example.tenant").metricType("Size").get()).entity();// not empty
assert "Size".equals(metricType.getId()) : "ResourceType[Playroom] -incorporates-> MetricType[Size] was not " +
"found";
try {
inventory.tenants().get("com.example.tenant").resourceTypes().get("Playroom").relationships()
.named("contains").metricTypes().getAll(id("Size")).entities().iterator().next();
assert false : "There is no such an entity satisfying the query, this code shouldn't be reachable";
} catch (NoSuchElementException e) {
// good
}
Set<Resource> resources = inventory.tenants().get("com.example.tenant").resourceTypes().get("Playroom")
.relationships().named
("defines").resources().getAll().entities();
assert resources.stream().allMatch(res -> Arrays.asList("playroom1", "playroom2", "playroom1.1", "playroom1.2",
"playroom2.1").contains(res.getId())) : "ResourceType[Playroom] -defines-> resources called playroom*";
resources = inventory.tenants().get("com.example.tenant").resourceTypes().get("Playroom")
.relationships().named("incorporates").resources().getAll().entities(); // empty
assert resources.isEmpty()
: "No resources should be found under the relationship called incorporates from resource type";
}
@Test
public void testEnvironments() throws Exception {
BiFunction<String, String, Void> test = (tenantId, id) -> {
Query q = Query.empty().asBuilder()
.with(PathFragment.from(type(Tenant.class), id(tenantId), by(contains),
type(Environment.class), id(id))).build();
//query, we should get the same results
Environment env = inventory.tenants().get(tenantId).environments().get(id).entity();
Assert.assertEquals(id, env.getId());
InventoryBackend<E> bcknd = inventory.getBackend().startTransaction();
try {
Page<E> envs = bcknd.query(now(), q, Pager.unlimited(Order.unspecified()));
Assert.assertTrue(envs.hasNext());
env = bcknd.convert(now(), envs.next(), Environment.class);
Assert.assertTrue(!envs.hasNext());
Assert.assertEquals(id, env.getId());
} finally {
bcknd.rollback();
}
return null;
};
test.apply("com.acme.tenant", "production");
test.apply("com.example.tenant", "test");
Query q = Query.empty().asBuilder()
.with(PathFragment.from(type(Environment.class))).build();
InventoryBackend<E> bcknd = inventory.getBackend().startTransaction();
try {
Assert.assertEquals(2, bcknd.query(now(), q, Pager.unlimited(Order.unspecified())).toList().size());
} finally {
bcknd.rollback();
}
}
@Test
public void testResourceTypes() throws Exception {
BiFunction<String, String, Void> test = (tenantId, id) -> {
Query query = Query.path().with(type(Tenant.class), id(tenantId),
by(contains), type(ResourceType.class), id(id)).get();
InventoryBackend<E> bcknd = inventory.getBackend().startTransaction();
try {
Page<?> results = bcknd.query(now(), query, Pager.unlimited(Order.unspecified()));
Assert.assertTrue(results.hasNext());
} finally {
bcknd.rollback();
}
ResourceType
rt = inventory.tenants().get(tenantId).resourceTypes().get(id).entity();
assert rt.getId().equals(id);
return null;
};
test.apply("com.acme.tenant", "URL");
test.apply("com.example.tenant", "Kachna");
test.apply("com.example.tenant", "Playroom");
Query query = Query.path().with(type(ResourceType.class)).get();
InventoryBackend<E> bcknd = inventory.getBackend().startTransaction();
try {
Assert.assertEquals(6, bcknd.query(now(), query, Pager.unlimited(Order.unspecified())).toList()
.size());
} finally {
bcknd.rollback();
}
}
@Test
public void testMetricDefinitions() throws Exception {
BiFunction<String, String, Void> test = (tenantId, id) -> {
Query query = Query.path().with(type(Tenant.class), id(tenantId),
by(contains), type(MetricType.class), id(id)).get();
InventoryBackend<E> bcknd = inventory.getBackend().startTransaction();
try {
assert bcknd.query(now(), query, Pager.unlimited(Order.unspecified())).hasNext();
} finally {
bcknd.rollback();
}
MetricType md = inventory.tenants().get(tenantId).metricTypes().get(id).entity();
assert md.getId().equals(id);
return null;
};
test.apply("com.acme.tenant", "ResponseTime");
test.apply("com.example.tenant", "Size");
Query query = Query.path().with(type(MetricType.class)).get();
InventoryBackend<E> bcknd = inventory.getBackend().startTransaction();
try {
Assert.assertEquals(4, bcknd.query(now(), query, Pager.unlimited(Order.unspecified())).toList()
.size());
} finally {
bcknd.rollback();
}
}
@Test
public void testMetricTypesLinkedToResourceTypes() throws Exception {
TetraFunction<String, String, String, CanonicalPath, Void> test = (tenantId, resourceTypeId, id, path) -> {
Query q = Query.path().with(type(Tenant.class), id(tenantId),
by(contains), type(ResourceType.class), id(resourceTypeId), by(incorporates),
type(MetricType.class), id(id)).get();
InventoryBackend<E> bcknd = inventory.getBackend().startTransaction();
try {
assert bcknd.query(now(), q, Pager.unlimited(Order.unspecified())).hasNext();
} finally {
bcknd.rollback();
}
MetricType md = inventory.tenants().get(tenantId).resourceTypes().get(resourceTypeId)
.metricTypes().get(path).entity();
assert md.getId().equals(id);
return null;
};
test.apply("com.acme.tenant", "URL", "ResponseTime", CanonicalPath.of().tenant("com.acme.tenant")
.metricType("ResponseTime").get());
test.apply("com.example.tenant", "Playroom", "Size", CanonicalPath.of().tenant("com.example.tenant")
.metricType("Size").get());
}
@Test
public void testMetrics() throws Exception {
TetraFunction<String, String, String, String, Void> test = (tenantId, environmentId, metricDefId, id) -> {
Metric m = inventory.tenants().get(tenantId).environments().get(environmentId).metrics()
.getAll(new Filter[][]{
{Defined.by(CanonicalPath.of().tenant(tenantId).metricType(metricDefId)
.get())},
{id(id)}})
.entities().iterator().next();
assert m.getId().equals(id);
return null;
};
test.apply("com.acme.tenant", "production", "ResponseTime", "host1_ping_response");
test.apply("com.example.tenant", "test", "Size", "playroom1_size");
test.apply("com.example.tenant", "test", "Size", "playroom2_size");
InventoryBackend<E> bcknd = inventory.getBackend().startTransaction();
try {
Assert.assertEquals(5, bcknd.query(now(), Query.path().with(type(Metric.class)).get(),
Pager.unlimited(Order.unspecified())).toList().size());
} finally {
bcknd.rollback();
}
}
@Test
public void testResources() throws Exception {
TetraFunction<String, String, String, String, Void> test = (tenantId, environmentId, resourceTypeId, id) -> {
Resource
r = inventory.tenants().get(tenantId).environments().get(environmentId).resources()
.getAll(new Filter[][]{
{Defined.by(CanonicalPath.of().tenant(tenantId).resourceType(resourceTypeId).get())},
{id(id)}})
.entities().iterator().next();
assert r.getId().equals(id);
return null;
};
test.apply("com.acme.tenant", "production", "URL", "host1");
test.apply("com.example.tenant", "test", "Playroom", "playroom1");
test.apply("com.example.tenant", "test", "Playroom", "playroom2");
InventoryBackend<E> bcknd = inventory.getBackend().startTransaction();
try {
Assert.assertEquals(15, inventory.getBackend().query(now(), Query.path().with(type(
Resource.class)).get(),
Pager.unlimited(Order.unspecified())).toList().size());
} finally {
bcknd.rollback();
}
}
@Test
public void testResourcesFilteredByTypeProperty() throws Exception {
Set<Resource> resources = inventory.tenants().get("com.example.tenant").environments().get("test")
.resources().getAll(new Filter[][]{
{Defined.by(CanonicalPath.of().tenant("com.example.tenant").resourceType("Playroom").get()),
With.propertyValue("ownedByDepartment", "Facilities")},
}).entities();
Assert.assertEquals(2, resources.size());
Assert.assertEquals(new HashSet<>(asList("playroom1", "playroom2")),
resources.stream().map(AbstractElement::getId).collect(toSet()));
resources = inventory.tenants().get("com.example.tenant").environments().get("test")
.resources().getAll(new Filter[][]{
{Defined.by(CanonicalPath.of().tenant("com.example.tenant").resourceType("Playroom").get()),
With.propertyValue("ownedByDepartment", "kachny")},
}).entities();
Assert.assertTrue(resources.isEmpty());
resources = inventory.tenants().get("com.example.tenant").environments().get("test")
.resources().getAll(new Filter[][]{
{Defined.by(CanonicalPath.of().tenant("com.example.tenant").resourceType("Playroom").get()),
With.propertyValue("ownedByDepartment", "Facilities")},
{With.id("playroom1")}
}).entities();
Assert.assertEquals(1, resources.size());
Assert.assertEquals("playroom1", resources.iterator().next().getId());
resources = inventory.tenants().get("com.example.tenant").environments().get("test")
.resources().getAll(
Defined.by(CanonicalPath.of().tenant("com.example.tenant").resourceType("Playroom").get()),
With.id("playroom1")).entities();
Assert.assertEquals(1, resources.size());
Assert.assertEquals("playroom1", resources.iterator().next().getId());
}
@Test
public void testAssociateMetricWithResource() throws Exception {
TetraFunction<String, String, String, String, Void> test = (tenantId, environmentId, resourceId, metricId) -> {
Metric m = inventory.tenants().get(tenantId).environments().get(environmentId).resources()
.get(resourceId).allMetrics().getAll(id(metricId)).entities().iterator().next();
assert metricId.equals(m.getId());
return null;
};
test.apply("com.acme.tenant", "production", "host1", "host1_ping_response");
test.apply("com.example.tenant", "test", "playroom1", "playroom1_size");
test.apply("com.example.tenant", "test", "playroom2", "playroom2_size");
}
@Test
public void testOperationTypes() throws Exception {
OperationTypes.Single ots = inventory.tenants().get("com.acme.tenant").resourceTypes()
.get("Person").operationTypes().get("start");
Assert.assertNotNull(ots.entity());
//also test the inspect path
ots = inventory.inspect(CanonicalPath.of().tenant("com.acme.tenant").resourceType("Person").operationType
("start").get(), OperationTypes.Single.class);
Assert.assertEquals("start", ots.entity().getId());
StructuredData returnTypeSchema = ots.data().get(returnType).entity().getValue();
StructuredData parametersSchema = ots.data().get(DataRole.OperationType.parameterTypes).entity().getValue();
Assert.assertEquals("start_returnType", returnTypeSchema.map().get("title").string());
Assert.assertEquals("boolean", returnTypeSchema.map().get("type").string());
Assert.assertEquals("start_paramTypes", parametersSchema.map().get("title").string());
}
@Test
public void queryMultipleTenants() throws Exception {
Set<Tenant> tenants = inventory.tenants().getAll().entities();
Assert.assertEquals(2, tenants.size());
}
@Test
public void queryMultipleEnvironments() throws Exception {
Set<Environment> environments = inventory.tenants().getAll().environments().getAll().entities();
assert environments.size() == 2;
}
@Test
public void queryMultipleResourceTypes() throws Exception {
Set<ResourceType> types = inventory.tenants().getAll().resourceTypes().getAll().entities();
Assert.assertEquals(5, types.size());
}
@Test
public void queryMultipleMetricDefs() throws Exception {
Set<MetricType> types = inventory.tenants().getAll().metricTypes().getAll().entities();
Assert.assertEquals(3, types.size());
}
@Test
public void queryMultipleResources() throws Exception {
Set<Resource> rs = inventory.tenants().getAll().environments().getAll().resources().getAll().entities();
assert rs.size() == 4;
}
@Test
public void queryMultipleMetrics() throws Exception {
Set<Metric> ms = inventory.tenants().getAll().environments().getAll().metrics().getAll().entities();
assert ms.size() == 3;
}
@Test
public void testNoTwoFeedsWithSameID() throws Exception {
Feed f1 = null;
Feed f2 = null;
try {
Feeds.ReadWrite feeds = inventory.tenants().get("com.acme.tenant").feeds();
f1 = feeds.create(new Feed.Blueprint("feed", null)).entity();
try {
f2 = feeds.create(new Feed.Blueprint("feed", null)).entity();
} catch (FeedAlreadyRegisteredException fare) {
//good
}
f2 = feeds.create(new Feed.Blueprint(null, null)).entity();
assert f1.getId().equals("feed");
assert !f1.getId().equals(f2.getId());
} finally {
if (f1 != null) {
inventory.inspect(f1).delete();
}
if (f2 != null) {
inventory.inspect(f2).delete();
}
}
}
@Test
public void testNoTwoEquivalentEntitiesOnTheSamePath() throws Exception {
try {
inventory.tenants().create(new Tenant.Blueprint("com.acme.tenant"));
Assert.fail("Creating tenant with existing ID should fail");
} catch (Exception e) {
//good
}
try {
inventory.tenants().get("com.acme.tenant").environments().create(new Environment.Blueprint("production"));
Assert.fail("Creating environment with existing ID should fail");
} catch (Exception e) {
//good
}
try {
inventory.tenants().get("com.acme.tenant").environments().get("production").resources()
.create(new Resource.Blueprint("host1", "URL"));
Assert.fail("Creating resource with existing ID should fail");
} catch (Exception e) {
//good
}
}
@Test
public void testContainsLoopsImpossible() throws Exception {
try {
inventory.tenants().get("com.example.tenant").relationships(outgoing)
.linkWith("contains", CanonicalPath.of().tenant("com.example.tenant").get(), null);
Assert.fail("Self-loops in contains should be disallowed");
} catch (IllegalArgumentException e) {
//expected
}
try {
inventory.tenants().get("com.example.tenant").relationships(incoming)
.linkWith("contains", CanonicalPath.of().tenant("com.example.tenant").get(), null);
Assert.fail("Self-loops in contains should be disallowed");
} catch (IllegalArgumentException e) {
//expected
}
try {
inventory.tenants().get("com.example.tenant").environments().get("test")
.relationships(outgoing)
.linkWith("contains", CanonicalPath.of().tenant("com.example.tenant").get(), null);
Assert.fail("Loops in contains should be disallowed");
} catch (IllegalArgumentException e) {
//expected
}
try {
inventory.tenants().get("com.example.tenant").relationships(incoming)
.linkWith("contains", CanonicalPath.of().tenant("com.example.tenant")
.environment("test").get(), null);
Assert.fail("Loops in contains should be disallowed");
} catch (IllegalArgumentException e) {
//expected
}
}
@Test
public void testContainsDiamondsImpossible() throws Exception {
try {
inventory.tenants().get("com.example.tenant").relationships(outgoing)
.linkWith("contains", CanonicalPath.of().tenant("com.acme.tenant").resourceType("URL").get(), null);
Assert.fail("Entity cannot be contained in 2 or more others");
} catch (IllegalArgumentException e) {
//expected
}
try {
inventory.tenants().get("com.acme.tenant").resourceTypes().get("URL")
.relationships(incoming)
.linkWith("contains", CanonicalPath.of().tenant("com.example.tenant").get(), null);
Assert.fail("Entity cannot be contained in 2 or more others");
} catch (IllegalArgumentException e) {
//expected
}
}
@Test
public void testPropertiesCreated() throws Exception {
Tenant t = inventory.tenants().get("com.acme.tenant").entity();
Assert.assertEquals(1, t.getProperties().size());
Assert.assertEquals("moc", t.getProperties().get("kachny"));
}
@Test
public void testPropertiesUpdatedOnEntities() throws Exception {
inventory.tenants().update("com.acme.tenant", Tenant.Update.builder().withProperty("ducks", "many")
.withProperty("hammer", "nails").build());
Tenant t = inventory.tenants().get("com.acme.tenant").entity();
Assert.assertEquals(2, t.getProperties().size());
Assert.assertEquals("many", t.getProperties().get("ducks"));
Assert.assertEquals("nails", t.getProperties().get("hammer"));
//reset the change we made back...
inventory.tenants().get("com.acme.tenant").update(Tenant.Update.builder().withProperty("kachny", "moc")
.build());
testPropertiesCreated();
}
@Test
public void testPropertiesUpdatedOnRelationships() throws Exception {
Relationship r = inventory.tenants().get("com.acme.tenant").relationships()
.getAll(RelationWith.name("contains")).entities().iterator().next();
inventory.tenants().get("com.acme.tenant").relationships().update(r.getId(),
Relationship.Update.builder().withProperty("ducks", "many").withProperty("hammer", "nails").build());
r = inventory.tenants().get("com.acme.tenant").relationships().get(r.getId()).entity();
Assert.assertEquals(2, r.getProperties().size());
Assert.assertEquals("many", r.getProperties().get("ducks"));
Assert.assertEquals("nails", r.getProperties().get("hammer"));
//reset the change we made back...
inventory.tenants().get("com.acme.tenant").relationships().update(r.getId(), new Relationship.Update(null));
r = inventory.tenants().get("com.acme.tenant").relationships().get(r.getId()).entity();
Assert.assertEquals(2, r.getProperties().size());
}
@Test
public void testPropertiesUpdateOnRelationshipsToEmpty() throws Exception {
final String tenantName = "com.acme.tenant";
Relationship r = inventory.tenants().get(tenantName).relationships()
.getAll(RelationWith.name("contains")).entities().iterator().next();
inventory.tenants().get(tenantName).relationships().update(r.getId(),
Relationship.Update.builder().withProperty("ducks", "many").withProperty("hammer", "nails").build());
r = inventory.tenants().get(tenantName).relationships().get(r.getId()).entity();
Assert.assertEquals(2, r.getProperties().size());
Assert.assertEquals("many", r.getProperties().get("ducks"));
Assert.assertEquals("nails", r.getProperties().get("hammer"));
//reset the change we made back...
inventory.tenants().get(tenantName).relationships().update(r.getId(),
new Relationship.Update(new HashMap<>()));
r = inventory.tenants().get(tenantName).relationships().get(r.getId()).entity();
Assert.assertEquals(0, r.getProperties().size());
}
@Test
public void testCreationMetricTypeWithProperties() {
HashMap<String, Object> properties = new HashMap<>();
properties.put("p1", "1");
properties.put("p2", "2");
inventory.tenants().create(Tenant.Blueprint.builder().withId("testCreationMetricTypeWithProperties").build())
.metricTypes().create(
new MetricType.Blueprint("test", MetricUnit.BYTES, MetricDataType.COUNTER, properties, 0L));
Assert.assertThat(inventory.tenants().get("testCreationMetricTypeWithProperties").metricTypes().get("test")
.entity().getProperties().size(), equalTo(properties.size()));
inventory.tenants().delete("testCreationMetricTypeWithProperties");
}
@Test
public void testPaging() throws Exception {
//the page is not modifiable but we'll need to modify this later on in the tests
List<Metric> allResults = inventory.tenants().getAll().environments().getAll().metrics()
.getAll().entities(Pager.unlimited(Order.by("id", Order.Direction.DESCENDING))).toList();
assert allResults.size() == 3;
Pager firstPage = new Pager(0, 1, Order.by("id", Order.Direction.DESCENDING));
Metrics.Multiple metrics = inventory.tenants().getAll().environments().getAll().metrics().getAll();
Page<Metric> ms = metrics.entities(firstPage);
List<Metric> msList = ms.toList();
assert msList.size() == 1;
assert ms.getTotalSize() == 3;
assert msList.get(0).equals(allResults.get(0));
ms = metrics.entities(firstPage.nextPage());
msList = ms.toList();
assert msList.size() == 1;
assert ms.getTotalSize() == 3;
assert msList.get(0).equals(allResults.get(1));
ms = metrics.entities(firstPage.nextPage().nextPage());
msList = ms.toList();
assert msList.size() == 1;
assert ms.getTotalSize() == 3;
assert msList.get(0).equals(allResults.get(2));
ms = metrics.entities(firstPage.nextPage().nextPage().nextPage());
msList = ms.toList();
assert ms.getTotalSize() == 3;
assert msList.size() == 0;
//try the same with an unspecified order
//the reason for checking this explicitly is that the order pipe implicitly loads
//all elements before sending them on in the pipeline to the range filter.
//If the order is not present, the elements might not be all loaded before the range
//is overflown. The total still needs to match even in that case.
firstPage = new Pager(0, 1, Order.unspecified());
ms = metrics.entities(firstPage);
msList = ms.toList();
assert msList.size() == 1;
assert ms.getTotalSize() == 3;
assert allResults
.remove(msList.get(0)); //i.e. we check that the result is in all results and remove it from there
//so that subsequent checks for the same thing cannot get confused by the
//existence of this metric in all the results.
ms = metrics.entities(firstPage.nextPage());
msList = ms.toList();
assert msList.size() == 1;
assert ms.getTotalSize() == 3;
assert allResults.remove(msList.get(0));
ms = metrics.entities(firstPage.nextPage().nextPage());
msList = ms.toList();
assert msList.size() == 1;
assert ms.getTotalSize() == 3;
assert allResults.remove(msList.get(0));
ms = metrics.entities(firstPage.nextPage().nextPage().nextPage());
msList = ms.toList();
assert ms.getTotalSize() == 3;
assert msList.size() == 0;
}
@Test
public void testGettingResourcesFromFeedsUsingEnvironments() throws Exception {
Set<Resource> rs = inventory.tenants().get("com.acme.tenant").environments().get("production")
.resourcesUnder(Environments.ResourceParents.FEED).getAll().entities();
Assert.assertEquals(3, rs.size());
Assert.assertTrue(rs.stream().anyMatch((r) -> "feedResource1".equals(r.getId())));
Assert.assertTrue(rs.stream().anyMatch((r) -> "feedResource2".equals(r.getId())));
Assert.assertTrue(rs.stream().anyMatch((r) -> "feedResource3".equals(r.getId())));
}
@Test
public void testGettingMetricsFromFeedsUsingEnvironments() throws Exception {
Set<Metric> rs = inventory.tenants().get("com.acme.tenant").environments().get("production")
.metricsUnder(Parents.any()).getAll().entities();
Assert.assertTrue(rs.stream().anyMatch((r) -> "host1_ping_response".equals(r.getId())));
Assert.assertTrue(rs.stream().anyMatch((r) -> "feedMetric1".equals(r.getId())));
}
@Test
public void testFilterByPropertyValues() throws Exception {
Assert.assertTrue(inventory.tenants().getAll(With.property("kachny")).anyExists());
Assert.assertFalse(inventory.tenants().getAll(With.property("v-kachna")).anyExists());
Assert.assertTrue(inventory.tenants().getAll(With.propertyValue("kachny", "moc")).anyExists());
Assert.assertFalse(inventory.tenants().getAll(With.propertyValue("kachny", "malo")).anyExists());
Assert.assertTrue(inventory.tenants().getAll(With.propertyValues("kachny", "moc", "malo")).anyExists());
Assert.assertFalse(inventory.tenants().getAll(With.propertyValues("kachny", "hodne", "malo")).anyExists());
Assert.assertTrue(inventory.tenants().get("com.example.tenant").environments().get("test").relationships()
.getAll(RelationWith.property("adult")).anyExists());
Assert.assertFalse(inventory.tenants().get("com.example.tenant").environments().get("test").relationships()
.getAll(RelationWith.property("infant")).anyExists());
Assert.assertTrue(inventory.tenants().get("com.example.tenant").environments().get("test").relationships()
.getAll(RelationWith.propertyValue("adult", true)).anyExists());
Assert.assertFalse(inventory.tenants().get("com.example.tenant").environments().get("test").relationships()
.getAll(RelationWith.propertyValue("adult", false)).anyExists());
Assert.assertTrue(inventory.tenants().get("com.example.tenant").environments().get("test").relationships()
.getAll(RelationWith.propertyValues("adult", false, true)).anyExists());
}
@Test
public void testResourceHierarchy() throws Exception {
Resources.Single res = inventory.tenants().get("com.example.tenant").environments().get("test")
.resources().get("playroom1");
Pager pager = Pager.unlimited(Order.unspecified());
Page<Resource> children = res.resources().getAll().entities(pager);
Assert.assertEquals(2, children.toList().size());
children = res.allResources().getAll().entities(pager);
Assert.assertEquals(3, children.toList().size());
children = res.allResources().getAll(Related.asTargetWith(res.entity().getPath(), isParentOf)).entities(pager);
Assert.assertEquals(3, children.toList().size());
}
@Test
public void testResourceHierarchyNoLoopsPossible() throws Exception {
//first, let's try a self-loop using generic relationships
CanonicalPath t = CanonicalPath.of().tenant("com.example.tenant").get();
try {
inventory.inspect(t, Tenants.Single.class).relationships(outgoing).linkWith(isParentOf, t, null);
Assert.fail("Should not be able to create self-loop in isParentOf using generic relationships");
} catch (IllegalArgumentException e) {
//good
}
//now let's try self-loop using association interface
Resource
r = inventory.inspect(t, Tenants.Single.class).environments().get("test").resources()
.get("playroom1").entity();
try {
inventory.inspect(r).allResources().associate(r.getPath());
Assert.fail("Should not be able to create self-loop in isParentOf using resource association interface.");
} catch (IllegalArgumentException e) {
//good
}
//playroom1 -isParentOf> playroom2 exists. Let's try creating a loop
Resource
r2 = inventory.inspect(t, Tenants.Single.class).environments().get("test").resources()
.get("playroom2").entity();
try {
inventory.inspect(r2).relationships(outgoing).linkWith(isParentOf, r.getPath(), null);
Assert.fail("Should not be possible to create loops in isParentOf using generic relationships.");
} catch (IllegalArgumentException e) {
//good
}
try {
inventory.inspect(r2).allResources().associate(r.getPath());
Assert.fail("Should not be possible to create loops in isParentOf using association interface.");
} catch (IllegalArgumentException e) {
//good
}
}
@Test
public void testImpossibleToDeleteContainsRelationship() throws Exception {
try {
Set<Relationship> rels = inventory.tenants().get("com.example.tenant").relationships().named(contains)
.entities();
inventory.tenants().get("com.example.tenant").relationships().delete(rels.iterator().next().getId());
Assert.fail("Should not be able to delete contains relationship explicitly.");
} catch (IllegalArgumentException e) {
//good
}
}
@Test
public void testImpossibleToDeleteIsParentOfWhenTheresContainsToo() throws Exception {
Set<Relationship> rels = inventory.tenants().get("com.example.tenant").environments().get("test")
.resources().get("playroom1").relationships().named(isParentOf).entities();
for (Relationship r : rels) {
if (r.getTarget().getSegment().getElementId().equals("playroom1.1")) {
try {
inventory.tenants().get("com.example.tenant").environments().get("test")
.resources().get("playroom1").relationships().delete(r.getId());
Assert.fail("Should not be possible to delete isParentOf when there's contains relationship in" +
" the same direction, too.");
} catch (IllegalArgumentException e) {
//good
}
break;
}
}
}
@Test
public void testRelativePathHandlingDuringDisassociationWhenThereAreMultipleRels() throws Exception {
CanonicalPath envPath = CanonicalPath.fromString("/t;com.example.tenant/e;test");
Environments.Single env = inventory.inspect(envPath, Environments.Single.class);
Tenants.Single tenant = inventory.inspect(envPath.up(), Tenants.Single.class);
Feed f = null;
Resource r = null;
Metric m1 = null;
Metric m2 = null;
try {
r = env.resources().create(Resource.Blueprint.builder().withId("assocR1")
.withResourceTypePath("/rt;Playroom").build()).entity();
//notice that m1 and m2 have the same ID, only a different path
m1 = env.metrics().create(Metric.Blueprint.builder().withId("assocMetric")
.withMetricTypePath("/mt;Size").build()).entity();
f = tenant.feeds().create(Feed.Blueprint.builder().withId("assocF").build()).entity();
m2 = tenant.feeds().get("assocF").metrics().create(Metric.Blueprint.builder().withId("assocMetric")
.withMetricTypePath("/mt;Size").build()).entity();
inventory.inspect(r).allMetrics().associate(m1.getPath());
inventory.inspect(r).allMetrics().associate(m2.getPath());
Assert.assertEquals(new HashSet<>(Arrays.asList(m1, m2)),
inventory.inspect(r).allMetrics().getAll().entities());
inventory.inspect(r).allMetrics().disassociate(Path.fromString("../m;assocMetric"));
Assert.assertEquals(Collections.singleton(m2), inventory.inspect(r).allMetrics().getAll().entities());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (r != null) {
inventory.inspect(r).delete();
}
if (m1 != null) {
inventory.inspect(m1).delete();
}
if (m2 != null) {
inventory.inspect(m2).delete();
}
if (f != null) {
inventory.inspect(f).delete();
}
}
}
@Test
public void testCannotCreateOrDeleteHasDataRelationship() throws Exception {
Relationships.Multiple rels = inventory.relationships()
.getAll(RelationWith.sourceOfType(DataEntity.class),
RelationWith.name(Relationships.WellKnown.hasData.name()));
try {
Relationship rel = rels.entities().iterator().next();
//we actually shouldn't be able to get here, because hasData relationship's target is a structured data
//which is not a legal target for a relationship.
inventory.relationships().get(rel.getId()).delete();
Assert.fail("Explicitly deleting hasData relationship shouldn't be possible.");
} catch (IllegalArgumentException e) {
// good
}
try {
inventory.tenants().get("com.example.tenant").relationships()
.linkWith(hasData, CanonicalPath.of().tenant("com.example.tenant").resourceType("Playroom").get(),
null);
Assert.fail("Explicitly creating hasData relationship shouldn't be possible.");
} catch (IllegalArgumentException e) {
//good
}
}
@Test
public void testInspectChildResource() throws Exception {
Resources.Single access = inventory.inspect(CanonicalPath.of().tenant("com.example.tenant").environment("test")
.resource("playroom1").resource("playroom1.1").get(), Resources.Single.class);
Assert.assertEquals("playroom1.1", access.entity().getId());
}
@Test
public void testDescendChildResource() throws Exception {
Resources.Single r = inventory.tenants().get("com.example.tenant").environments().get("test")
.resources().descend("playroom1", RelativePath.fromString("../r;playroom2"))
.allResources().get(RelativePath.fromString("r;playroom2.1"));
Assert.assertEquals("playroom2.1", r.entity().getId());
}
@Test
public void testAssociateEnvironmentWithFeeds() throws Exception {
Assert.assertTrue(inventory.tenants().get("com.acme.tenant").environments().get("production").feeds().get(
RelativePath.to().up().feed("feed1").get()).exists());
inventory.tenants().get("com.acme.tenant").environments().create(
Environment.Blueprint.builder().withId("staging").build());
try {
inventory.tenants().get("com.acme.tenant").environments().get("staging").feeds()
.associate(RelativePath.to().up().feed("feed1").get());
Assert.fail("It should not be possible to associate a feed with more than 1 environment.");
} catch (IllegalArgumentException e) {
//good
} finally {
inventory.tenants().get("com.acme.tenant").environments().delete("staging");
}
}
@Test
public void testCreationUnderNonExistentParentThrowsEntityNotFoundException() throws Exception {
try {
inventory.tenants().get("com.acme.tenant").feeds().get("no-feed")
.resources().create(Resource.Blueprint.builder().withId("blah").withResourceTypePath("../../URL")
.build());
Assert.fail("Should not be able to traverse over non-existent entity.");
} catch (EntityNotFoundException e) {
//good
}
}
@Test
public void testNamePersisted() throws Exception {
Tenant t = null;
try {
t = inventory.tenants().create(Tenant.Blueprint.builder().withId("named-tenant").withName("tenant")
.build()).entity();
Assert.assertEquals("tenant", t.getName());
Environment e =
inventory.inspect(t).environments().create(Environment.Blueprint.builder().withId("named-env")
.withName("env").build()).entity();
Assert.assertEquals("env", e.getName());
Feed f = inventory.inspect(t).feeds().create(Feed.Blueprint.builder().withId("named-feed").withName("feed")
.build()).entity();
Assert.assertEquals("feed", f.getName());
ResourceType
rt = inventory.inspect(t).resourceTypes().create(ResourceType.Blueprint.builder()
.withId("named-resourceType").withName("resourceType").build()).entity();
Assert.assertEquals("resourceType", rt.getName());
MetricType mt = inventory.inspect(t).metricTypes().create(MetricType.Blueprint
.builder(MetricDataType.GAUGE).withId("named-metricType").withUnit(MetricUnit.BITS)
.withName("metricType").withInterval(0L).build()).entity();
Assert.assertEquals("metricType", mt.getName());
OperationType
ot = inventory.inspect(rt).operationTypes().create(OperationType.Blueprint.builder()
.withId("named-operationType").withName("operationType").build()).entity();
Assert.assertEquals("operationType", ot.getName());
Resource r = inventory.inspect(f).resources().create(
Resource.Blueprint.builder().withId("named-resource")
.withName("resource").withResourceTypePath(rt.getPath().toString()).build()).entity();
Assert.assertEquals("resource", r.getName());
Metric m = inventory.inspect(f).metrics().create(Metric.Blueprint.builder().withId("named-metric")
.withName("metric").withMetricTypePath(mt.getPath().toString()).build()).entity();
Assert.assertEquals("metric", m.getName());
try {
inventory.inspect(t).environments().create(Environment.Blueprint.builder().withId("failing-env")
.withProperty("name", "invalid-property").build());
Assert.fail("Should not be possible to create an entity with a property called \"name\".");
} catch (IllegalArgumentException ex) {
//ok
}
} finally {
if (t != null) {
inventory.inspect(t).delete();
}
}
}
@Test
public void testNameUpdatable() throws Exception {
Tenant t = null;
try {
t = inventory.tenants().create(Tenant.Blueprint.builder().withId("named-tenant").withName("tenant")
.build()).entity();
testUpdate(t, Tenant.Update.builder());
Environment e = inventory.inspect(t).environments().create(Environment.Blueprint.builder()
.withId("named-env").withName("env").build()).entity();
testUpdate(e, Environment.Update.builder());
Feed f = inventory.inspect(t).feeds().create(Feed.Blueprint.builder().withId("named-feed").withName("feed")
.build()).entity();
testUpdate(f, Feed.Update.builder());
ResourceType
rt = inventory.inspect(t).resourceTypes().create(ResourceType.Blueprint.builder()
.withId("named-resourceType").withName("resourceType").build()).entity();
testUpdate(rt, ResourceType.Update.builder());
MetricType mt = inventory.inspect(t).metricTypes().create(MetricType.Blueprint
.builder(MetricDataType.GAUGE).withId("named-metricType").withUnit(MetricUnit.BITS)
.withName("metricType").withInterval(0L).build()).entity();
testUpdate(mt, MetricType.Update.builder());
OperationType
ot = inventory.inspect(rt).operationTypes().create(OperationType.Blueprint.builder()
.withId("named-operationType").withName("operationType").build()).entity();
testUpdate(ot, OperationType.Update.builder());
Resource r = inventory.inspect(f).resources().create(
Resource.Blueprint.builder().withId("named-resource")
.withName("resource").withResourceTypePath(rt.getPath().toString()).build()).entity();
testUpdate(r, Resource.Update.builder());
Metric m = inventory.inspect(f).metrics().create(Metric.Blueprint.builder().withId("named-metric")
.withName("metric").withMetricTypePath(mt.getPath().toString()).build()).entity();
testUpdate(m, Metric.Update.builder());
try {
inventory.inspect(m).update(Metric.Update.builder().withProperty("name", "disallowed").build());
Assert.fail("A property called \"name\" should not be allowed in updates.");
} catch (IllegalArgumentException ex) {
//ok
}
} finally {
if (t != null) {
inventory.inspect(t).delete();
}
}
}
@Test
public void testMetadataPackMembershipNonUpdatable() throws Exception {
CanonicalPath tenantPath = CanonicalPath.of().tenant("com.acme.tenant").get();
CanonicalPath rtPath = tenantPath.extend(ResourceType.SEGMENT_TYPE, "Person").get();
MetadataPack pack = inventory.inspect(tenantPath, Tenants.Single.class).metadataPacks().getAll().entities()
.iterator().next();
try {
inventory.inspect(pack).relationships().linkWith(incorporates, rtPath, null);
Assert.fail("Adding a resource type to a metadatapack should not be possible after the pack has been " +
"created.");
} catch (IllegalArgumentException e) {
//good
}
try {
inventory.inspect(rtPath, ResourceTypes.Single.class).relationships(incoming).linkWith(incorporates,
pack.getPath(), null);
Assert.fail("Adding a resource type to a metadatapack should not be possible after the pack has been " +
"created.");
} catch (IllegalArgumentException e) {
//good
}
}
@Test
public void testModificationsOfEntitiesInMetadataPacksImpossible() throws Exception {
Tenant t = inventory.tenants().get("com.acme.tenant").entity();
MetricType mt = inventory.inspect(t).metricTypes().get("mpMt").entity();
ResourceType rt = inventory.inspect(t).resourceTypes().get("mpRt").entity();
try {
inventory.inspect(mt).update(MetricType.Update.builder().withUnit(MetricUnit.PER_DAY).build());
Assert.fail("Updating a metric type that is a part of metadata pack should not be possible.");
} catch (IllegalArgumentException e) {
//good
}
try {
inventory.inspect(rt).operationTypes().create(
OperationType.Blueprint.builder().withId("asfd").build());
Assert.fail("It should not be possible to add an operation type to a resource type in metadata pack.");
} catch (IllegalArgumentException e) {
//good
}
try {
inventory.inspect(rt).operationTypes().delete("mpRtOt");
Assert.fail("It should not be possible to delete an operation type from a resource type in metadata pack.");
} catch (IllegalArgumentException e) {
//good
}
try {
inventory.inspect(rt).operationTypes().get("mpRtOt").delete();
Assert.fail("It should not be possible to delete an operation type from a resource type in metadata pack.");
} catch (IllegalArgumentException e) {
//good
}
try {
inventory.inspect(rt).operationTypes().get("mpRtOt").data()
.create(DataEntity.Blueprint.<DataRole.OperationType>builder()
.withRole(DataRole.OperationType.parameterTypes).withValue(
StructuredData.get().undefined()).build());
Assert.fail("It should not be possible to add data to operation type from a resource type in metadata " +
"pack.");
} catch (IllegalArgumentException e) {
//good
}
try {
inventory.inspect(rt).operationTypes().get("mpRtOt").data().update(returnType, DataEntity.Update.builder
().withValue(StructuredData.get().bool(true)).build());
Assert.fail("It should not be possible to modify data of operation type from a resource type in metadata " +
"pack.");
} catch (IllegalArgumentException e) {
//good
}
try {
inventory.inspect(rt).operationTypes().get("mpRtOt").data().delete(returnType);
Assert.fail("It should not be possible to delete data of operation type from a resource type in metadata " +
"pack.");
} catch (IllegalArgumentException e) {
//good
}
try {
inventory.inspect(rt).data().create(
DataEntity.Blueprint.<DataRole.ResourceType>builder().withRole(connectionConfigurationSchema)
.withValue(StructuredData.get().bool(true)).build());
Assert.fail("It should not be possible to add an data to a resource type in metadata pack.");
} catch (IllegalArgumentException e) {
//good
}
try {
inventory.inspect(rt).data().get(configurationSchema).delete();
Assert.fail("It should not be possible to remove data from a resource type in metadata pack.");
} catch (IllegalArgumentException e) {
//good
}
try {
inventory.inspect(rt).data().get(configurationSchema).update(DataEntity.Update.builder().withValue
(StructuredData.get().undefined()).build());
Assert.fail("It should not be possible to modify data of a resource type in metadata pack.");
} catch (IllegalArgumentException e) {
//good
}
}
@Test
public void testMetadataPackIdEqualToContentHash() throws Exception {
MetricType mt = inventory.tenants().get("com.acme.tenant").metricTypes().get("mpMt").entity();
ResourceType
rt = inventory.tenants().get("com.acme.tenant").resourceTypes().get("mpRt").entity();
OperationType ot = inventory.inspect(rt).operationTypes().get("mpRtOt").entity();
StructuredData configSchema = inventory.inspect(rt).data().get(configurationSchema).entity().getValue();
StructuredData retType = inventory.inspect(ot).data().get(returnType).entity().getValue();
String expectedContentHash = IdentityHash.of(MetadataPack.Members.builder()
.with(MetricType.Blueprint
.builder(mt.getMetricDataType())
.withUnit(mt.getUnit())
.withInterval(0L)
.withId(mt.getId()).build())
.with(ResourceType.Blueprint.builder().withId(rt.getId()).build())
.with(DataEntity.Blueprint.<DataRole.ResourceType>builder()
.withRole(configurationSchema).withValue(configSchema).build())
.with(OperationType.Blueprint.builder().withId(ot.getId()).build())
.with(DataEntity.Blueprint.<DataRole.OperationType>builder()
.withRole(returnType).withValue(retType).build())
.done()
.done()
.build());
MetadataPack mp = inventory.tenants().get("com.acme.tenant").metadataPacks().get(expectedContentHash).entity();
Assert.assertEquals(expectedContentHash, mp.getId());
}
private <T extends Entity<B, U>, B extends Blueprint, U extends Entity.Update>
void testUpdate(T entity, Entity.Update.Builder<T, U, ?> update) {
@SuppressWarnings("unchecked")
Class<ResolvableToSingle<T, U>> cls = (Class<ResolvableToSingle<T, U>>) (Class) ResolvableToSingle.class;
inventory.inspect(entity, cls).update(update.withName("updated").build());
entity = inventory.inspect(entity, cls).entity();
Assert.assertEquals("updated", entity.getName());
}
@Test
public void testIdenticalResourceTypesFound() throws Exception {
Tenant t = inventory.tenants().create(Tenant.Blueprint.builder().withId(UUID.randomUUID().toString()).build())
.entity();
try {
Feed f1 = inventory.inspect(t).feeds().create(Feed.Blueprint.builder().withId("f1").build()).entity();
Feed f2 = inventory.inspect(t).feeds().create(Feed.Blueprint.builder().withId("f2").build()).entity();
ResourceType rt1 = inventory.inspect(f1).resourceTypes().create(
ResourceType.Blueprint.builder().withId
("rt").build()).entity();
ResourceType rt2 = inventory.inspect(f2).resourceTypes().create(
ResourceType.Blueprint.builder().withId
("rt").build()).entity();
Set<ResourceType> identicals = inventory.inspect(rt1).identical().getAll().entities();
Assert.assertEquals(2, identicals.size());
Assert.assertTrue(identicals.contains(rt1));
Assert.assertTrue(identicals.contains(rt2));
String hash = inventory.inspect(rt1).entity().getIdentityHash();
Assert.assertEquals(hash, inventory.inspect(rt2).entity().getIdentityHash());
DataEntity.Blueprint<DataRole.ResourceType> bl = DataEntity.Blueprint.<DataRole.ResourceType>builder()
.withRole(DataRole.ResourceType.configurationSchema).withValue(StructuredData.get().map()
.putString("title", "blah")
.putString("type", "string").build()).build();
inventory.inspect(rt1).data().create(bl);
Assert.assertNotEquals(hash, inventory.inspect(rt1).entity().getIdentityHash());
identicals = inventory.inspect(rt1).identical().getAll().entities();
Assert.assertEquals(1, identicals.size());
Assert.assertTrue(identicals.contains(rt1));
inventory.inspect(rt2).data().create(bl);
identicals = inventory.inspect(rt1).identical().getAll().entities();
Assert.assertEquals(2, identicals.size());
Assert.assertTrue(identicals.contains(rt1));
Assert.assertTrue(identicals.contains(rt2));
} finally {
inventory.tenants().delete(t.getId());
}
}
@Test
public void testIdenticalMetricTypesFound() throws Exception {
Tenant t = inventory.tenants().create(Tenant.Blueprint.builder().withId(UUID.randomUUID().toString()).build())
.entity();
try {
Feed f1 = inventory.inspect(t).feeds().create(Feed.Blueprint.builder().withId("f1").build()).entity();
Feed f2 = inventory.inspect(t).feeds().create(Feed.Blueprint.builder().withId("f2").build()).entity();
MetricType mt1 = inventory.inspect(f1).metricTypes().create(MetricType.Blueprint.builder(MetricDataType
.GAUGE).withId("mt").withInterval(0L).withUnit(MetricUnit.NONE).build()).entity();
MetricType mt2 = inventory.inspect(f2).metricTypes().create(MetricType.Blueprint.builder(MetricDataType
.GAUGE).withId("mt").withInterval(0L).withUnit(MetricUnit.NONE).build()).entity();
Set<MetricType> identicals = inventory.inspect(mt1).identical().getAll().entities();
Assert.assertEquals(2, identicals.size());
Assert.assertTrue(identicals.contains(mt1));
Assert.assertTrue(identicals.contains(mt2));
String hash = inventory.inspect(mt1).entity().getIdentityHash();
Assert.assertEquals(hash, inventory.inspect(mt2).entity().getIdentityHash());
inventory.inspect(mt1).update(MetricType.Update.builder().withUnit(MetricUnit.MILLISECONDS).build());
Assert.assertNotEquals(hash, inventory.inspect(mt1).entity().getIdentityHash());
identicals = inventory.inspect(mt1).identical().getAll().entities();
Assert.assertEquals(1, identicals.size());
Assert.assertTrue(identicals.contains(mt1));
inventory.inspect(mt2).update(MetricType.Update.builder().withUnit(MetricUnit.MILLISECONDS).build());
identicals = inventory.inspect(mt1).identical().getAll().entities();
Assert.assertEquals(2, identicals.size());
Assert.assertTrue(identicals.contains(mt1));
Assert.assertTrue(identicals.contains(mt2));
} finally {
inventory.tenants().delete(t.getId());
}
}
@Test
public void testParentIdentityHashUpdatedWhenChildCreated() throws Exception {
String tenantId = "testParentIdentityHashUpdatedWhenChildCreated";
try {
Feeds.Single f = inventory.tenants().create(Tenant.Blueprint.builder().withId(tenantId).build())
.feeds().create(Feed.Blueprint.builder().withId("feed").build());
f.resourceTypes().create(ResourceType.Blueprint.builder().withId("resourceType").build());
Resources.Single r = f.resources()
.create(Resource.Blueprint.builder().withId("res").withResourceTypePath("resourceType").build());
String fHash = IdentityHash.of(f.entity(), inventory);
Assert.assertEquals(fHash, f.entity().getIdentityHash());
r.data().create(DataEntity.Blueprint.<DataRole.Resource>builder().withRole(configuration).withValue
(StructuredData.get().integral(42L)).build());
Assert.assertNotEquals(fHash, f.entity().getIdentityHash());
} finally {
if (inventory.tenants().get(tenantId).exists()) {
inventory.tenants().get(tenantId).delete();
}
}
}
@Test
public void testParentIdentityHashUpdatedWhenChildUpdated() throws Exception {
String tenantId = "testParentIdentityHashUpdatedWhenChildUpdated";
try {
Feeds.Single f = inventory.tenants().create(Tenant.Blueprint.builder().withId(tenantId).build())
.feeds().create(Feed.Blueprint.builder().withId("feed").build());
f.metricTypes().create(MetricType.Blueprint.builder(MetricDataType.GAUGE).withId("metricType").withUnit
(MetricUnit.BITS).withInterval(0L).build());
String fHash = IdentityHash.of(f.entity(), inventory);
Assert.assertEquals(fHash, f.entity().getIdentityHash());
f.metricTypes().get("metricType").update(MetricType.Update.builder().withUnit(MetricUnit.BYTES).build());
Assert.assertNotEquals(fHash, f.entity().getIdentityHash());
} finally {
if (inventory.tenants().get(tenantId).exists()) {
inventory.tenants().get(tenantId).delete();
}
}
}
@Test
public void testParentIdentityHashUpdatedWhenChildDeleted() throws Exception {
String tenantId = "testParentIdentityHashUpdatedWhenChildDeleted";
try {
Feeds.Single f = inventory.tenants().create(Tenant.Blueprint.builder().withId(tenantId).build())
.feeds().create(Feed.Blueprint.builder().withId("feed").build());
f.resourceTypes().create(ResourceType.Blueprint.builder().withId("resourceType").build());
f.resources().create(Resource.Blueprint.builder().withId("resource").withResourceTypePath("resourceType")
.build());
f.resources().get("resource").resources().create(Resource.Blueprint.builder().withId("childRersource")
.withResourceTypePath("../resourceType").build());
String fHash = IdentityHash.of(f.entity(), inventory);
Assert.assertEquals(fHash, f.entity().getIdentityHash());
f.resources().delete("resource");
Assert.assertNotEquals(fHash, f.entity().getIdentityHash());
} finally {
if (inventory.tenants().get(tenantId).exists()) {
inventory.tenants().get(tenantId).delete();
}
}
}
@Test
public void testTreeHash() throws Exception {
String tenantId = "testTreeHash";
try {
Feeds.Single f = inventory.tenants().create(Tenant.Blueprint.builder().withId(tenantId).build())
.feeds().create(Feed.Blueprint.builder().withId("feed").build(), false);
ResourceType rt = f.resourceTypes().create(ResourceType.Blueprint.builder().withId("resourceType")
.build()).entity();
MetricType mt = f.metricTypes()
.create(MetricType.Blueprint.builder(MetricDataType.GAUGE).withId("metricType").withInterval(0L)
.withUnit(MetricUnit.NONE).build())
.entity();
//get the resource only after all its children are created so that we obtain the right hash
f.resources()
.create(Resource.Blueprint.builder().withId("resource").withResourceTypePath("resourceType")
.build())
.entity();
f.resources().get("resource").resources()
.create(Resource.Blueprint.builder().withId("childResource").withResourceTypePath("../resourceType")
.build())
.entity();
Metric resourceMetric = f.resources().get("resource").metrics()
.create(Metric.Blueprint.builder().withId("metric").withMetricTypePath("../metricType").build())
.entity();
Metric feedMetric = f.metrics()
.create(Metric.Blueprint.builder().withId("metric").withMetricTypePath("metricType").build())
.entity();
//just create an association so that we can check that the association doesn't affect the tree hash
f.resources().descendContained(RelativePath.to().resource("resource").resource("childResource").get())
.allMetrics().associate(RelativePath.to().up().metric("metric").get());
Resource resource = f.resources().get("resource").entity();
Resource childResource = f.resources().get("resource").resources().get("childResource").entity();
SyncHash.Tree feedTreeHash = f.treeHash();
Assert.assertEquals(4, feedTreeHash.getChildren().size());
Assert.assertEquals(f.entity().getSyncHash(), feedTreeHash.getHash());
Assert.assertEquals(rt.getSyncHash(),
feedTreeHash.getChild(Path.Segment.from("rt;resourceType")).getHash());
Assert.assertEquals(mt.getSyncHash(),
feedTreeHash.getChild(Path.Segment.from("mt;metricType")).getHash());
Assert.assertEquals(resource.getSyncHash(),
feedTreeHash.getChild(Path.Segment.from("r;resource")).getHash());
Assert.assertEquals(feedMetric.getSyncHash(),
feedTreeHash.getChild(Path.Segment.from("m;metric")).getHash());
Assert.assertTrue(feedTreeHash.getChild(Path.Segment.from("rt;resourceType")).getChildren().isEmpty());
Assert.assertTrue(feedTreeHash.getChild(Path.Segment.from("mt;metricType")).getChildren().isEmpty());
Assert.assertTrue(feedTreeHash.getChild(Path.Segment.from("m;metric")).getChildren().isEmpty());
SyncHash.Tree resourceTreeHash = feedTreeHash.getChild(Path.Segment.from("r;resource"));
Assert.assertEquals(2, resourceTreeHash.getChildren().size());
Assert.assertEquals(resourceMetric.getSyncHash(),
resourceTreeHash.getChild(Path.Segment.from("m;metric")).getHash());
Assert.assertEquals(childResource.getSyncHash(),
resourceTreeHash.getChild(Path.Segment.from("r;childResource")).getHash());
Assert.assertTrue(resourceTreeHash.getChild(Path.Segment.from("m;metric")).getChildren().isEmpty());
Assert.assertTrue(resourceTreeHash.getChild(Path.Segment.from("r;childResource")).getChildren().isEmpty());
} finally {
if (inventory.tenants().get(tenantId).exists()) {
inventory.tenants().get(tenantId).delete();
}
}
}
@Test
public void testSynchronizeNew() throws Exception {
String tenantId = "testSynchronizeNew";
try {
Feeds.Single f = inventory.tenants().create(Tenant.Blueprint.builder().withId(tenantId).build())
.feeds().create(Feed.Blueprint.builder().withId("feed").build(), false);
InventoryStructure<Feed.Blueprint> structure = InventoryStructure.Offline
.of(Feed.Blueprint.builder().withId("feed").build())
.addChild(ResourceType.Blueprint.builder().withId("resourceType").build())
.addChild(MetricType.Blueprint.builder(MetricDataType.GAUGE)
.withId("metricType").withInterval(0L).withUnit(MetricUnit.NONE).build())
.startChild(Resource.Blueprint.builder().withId("resource").withResourceTypePath("resourceType")
.build())
/**/.addChild(Resource.Blueprint.builder().withId("childResource")
/**/.withResourceTypePath("../resourceType").withProperty("a", "b").build())
/**/.addChild(Metric.Blueprint.builder().withId("metric").withInterval(0L)
/**/.withMetricTypePath("../metricType").build())
.end()
.addChild(Metric.Blueprint.builder().withId("metric").withMetricTypePath("metricType")
.withInterval(0L).build())
.build();
f.synchronize(SyncRequest.syncEverything(structure));
SyncHash.Tree feedTreeHash = f.treeHash();
ResourceType rt = f.resourceTypes().get("resourceType").entity();
MetricType mt = f.metricTypes().get("metricType").entity();
Resource resource = f.resources().get("resource").entity();
Metric feedMetric = f.metrics().get("metric").entity();
Metric resourceMetric = f.resources().get("resource").metrics().get("metric").entity();
Resource childResource = f.resources().get("resource").resources().get("childResource").entity();
Assert.assertEquals(4, feedTreeHash.getChildren().size());
Assert.assertEquals(f.entity().getSyncHash(), feedTreeHash.getHash());
Assert.assertEquals(rt.getSyncHash(),
feedTreeHash.getChild(Path.Segment.from("rt;resourceType")).getHash());
Assert.assertEquals(mt.getSyncHash(),
feedTreeHash.getChild(Path.Segment.from("mt;metricType")).getHash());
Assert.assertEquals(resource.getSyncHash(),
feedTreeHash.getChild(Path.Segment.from("r;resource")).getHash());
Assert.assertEquals(feedMetric.getSyncHash(),
feedTreeHash.getChild(Path.Segment.from("m;metric")).getHash());
Assert.assertTrue(feedTreeHash.getChild(Path.Segment.from("rt;resourceType")).getChildren().isEmpty());
Assert.assertTrue(feedTreeHash.getChild(Path.Segment.from("mt;metricType")).getChildren().isEmpty());
Assert.assertTrue(feedTreeHash.getChild(Path.Segment.from("m;metric")).getChildren().isEmpty());
SyncHash.Tree resourceTreeHash = feedTreeHash.getChild(Path.Segment.from("r;resource"));
Assert.assertEquals(2, resourceTreeHash.getChildren().size());
Assert.assertEquals(resourceMetric.getSyncHash(),
resourceTreeHash.getChild(Path.Segment.from("m;metric")).getHash());
Assert.assertEquals(childResource.getSyncHash(),
resourceTreeHash.getChild(Path.Segment.from("r;childResource")).getHash());
Assert.assertEquals("b", childResource.getProperties().get("a"));
Assert.assertTrue(resourceTreeHash.getChild(Path.Segment.from("m;metric")).getChildren().isEmpty());
Assert.assertTrue(resourceTreeHash.getChild(Path.Segment.from("r;childResource")).getChildren().isEmpty());
} catch (Throwable t) {
t.printStackTrace();
throw t;
} finally {
if (inventory.tenants().get(tenantId).exists()) {
inventory.tenants().get(tenantId).delete();
}
}
}
@Test
public void testSynchronizeNonExistent() throws Exception {
String tenantId = "testSynchronizeNonExistent";
try {
InventoryStructure<Feed.Blueprint> structure = InventoryStructure.Offline
.of(Feed.Blueprint.builder().withId("feed").build())
.addChild(ResourceType.Blueprint.builder().withId("resourceType").build())
.build();
Feeds.Single f = inventory.tenants().create(Tenant.Blueprint.builder().withId(tenantId).build())
.feeds().get("feed");
f.synchronize(SyncRequest.syncEverything(structure));
SyncHash.Tree feedTreeHash = f.treeHash();
ResourceType rt = f.resourceTypes().get("resourceType").entity();
Assert.assertEquals(1, feedTreeHash.getChildren().size());
Assert.assertEquals(f.entity().getSyncHash(), feedTreeHash.getHash());
Assert.assertEquals(rt.getSyncHash(),
feedTreeHash.getChild(Path.Segment.from("rt;resourceType")).getHash());
Assert.assertTrue(feedTreeHash.getChild(Path.Segment.from("rt;resourceType")).getChildren().isEmpty());
} catch (Throwable t) {
t.printStackTrace();
throw t;
} finally {
if (inventory.tenants().get(tenantId).exists()) {
inventory.tenants().get(tenantId).delete();
}
}
}
@Test
public void testSyncNonExistentData() throws Exception {
//this is a special case, because we need to do some internal magic for this to work, so an extra test is
//worth it.
String tenantId = "testSyncNonExistentData";
try {
InventoryStructure<DataEntity.Blueprint<DataRole>> structure = InventoryStructure.Offline
.of(DataEntity.Blueprint.builder().withRole(configurationSchema).build())
.build();
ResourceTypes.Single rt = inventory.tenants().create(Tenant.Blueprint.builder().withId(tenantId).build())
.resourceTypes().create(ResourceType.Blueprint.builder().withId("resourceType").build());
Data.Single d = rt.data().get(configurationSchema);
d.synchronize(SyncRequest.syncEverything((InventoryStructure) structure));
SyncHash.Tree dataTreeHash = d.treeHash();
DataEntity de = d.entity();
Assert.assertEquals(de.getSyncHash(), dataTreeHash.getHash());
} catch (Throwable t) {
t.printStackTrace();
throw t;
} finally {
if (inventory.tenants().get(tenantId).exists()) {
inventory.tenants().get(tenantId).delete();
}
}
}
@Test
public void testSynchronizeUpdate() throws Exception {
String tenantId = "testSynchronizeUpdate";
try {
Feeds.Single f = inventory.tenants().create(Tenant.Blueprint.builder().withId(tenantId).build())
.feeds().create(Feed.Blueprint.builder().withId("feed").build());
f.resourceTypes().create(ResourceType.Blueprint.builder().withId("resourceType")
.build()).entity();
f.metricTypes()
.create(MetricType.Blueprint.builder(MetricDataType.GAUGE).withId("metricType").withInterval(0L)
.withUnit(MetricUnit.NONE).build())
.entity();
//get the resource only after all its children are created so that we obtain the right hash
f.resources()
.create(Resource.Blueprint.builder().withId("resource").withResourceTypePath("resourceType")
.build())
.entity();
f.resources().get("resource").resources()
.create(Resource.Blueprint.builder().withId("childResource").withResourceTypePath("../resourceType")
.build())
.entity();
f.resources().get("resource").metrics()
.create(Metric.Blueprint.builder().withId("metric").withMetricTypePath("../metricType").build())
.entity();
f.metrics()
.create(Metric.Blueprint.builder().withId("metric").withMetricTypePath("metricType")
.withProperty("a", "b").withProperty("b", "c").withName("Metric Name").build())
.entity();
//just create an association so that we can check that the association doesn't affect the tree hash
f.resources().descendContained(RelativePath.to().resource("resource").resource("childResource").get())
.allMetrics().associate(RelativePath.to().up().metric("metric").get());
f.resources().get("resource").entity();
f.resources().get("resource").resources().get("childResource").entity();
InventoryStructure.Offline.Builder<Feed.Blueprint> structureBuiler = InventoryStructure.Offline
.copy(InventoryStructure.of(f.entity(), inventory)).asBuilder();
structureBuiler.getChild(Path.Segment.from("mt;metricType")).replace(MetricType.Blueprint.builder(
MetricDataType.GAUGE).withId("metricType").withInterval(0L).withUnit(MetricUnit.BYTES).build());
structureBuiler.getChild(Path.Segment.from("m;metric")).replace(Metric.Blueprint.builder().withId("metric")
.withMetricTypePath("metricType").withProperty("a", "c").withProperty("c", "d")
.withName("Name Of Metric").build());
structureBuiler.getChild(Path.Segment.from("r;resource")).remove();
InventoryStructure<Feed.Blueprint> structure = structureBuiler.build();
f.synchronize(SyncRequest.syncEverything(structure));
Assert.assertTrue(f.metricTypes().get("metricType").exists());
Assert.assertEquals("c", f.metrics().get("metric").entity().getProperties().get("a"));
Assert.assertEquals("d", f.metrics().get("metric").entity().getProperties().get("c"));
Assert.assertEquals("Name Of Metric", f.metrics().get("metric").entity().getName());
Assert.assertFalse(f.metrics().get("metric").entity().getProperties().containsKey("b"));
Assert.assertFalse(f.resources().get("resource").exists());
Assert.assertFalse(f.resources().get("resource").resources().get("childResource").exists());
Assert.assertFalse(f.resources().get("resource").metrics().get("metrics").exists());
} finally {
if (inventory.tenants().get(tenantId).exists()) {
inventory.tenants().get(tenantId).delete();
}
}
}
private static InventoryStructure<Feed.Blueprint> getSyncConfigStructure() {
return InventoryStructure
.of(Feed.Blueprint.builder().withId("feed").build())
.addChild(ResourceType.Blueprint.builder().withId("resourceType").build())
.addChild(MetricType.Blueprint.builder(MetricDataType.GAUGE).withId("metricType").withInterval(0L)
.withUnit(MetricUnit.NONE).build())
.startChild(Resource.Blueprint.builder().withResourceTypePath("resourceType").withId("resource1")
.build())
/**/.addChild(Metric.Blueprint.builder().withMetricTypePath("../metricType").withId("metric1")
.withInterval(0L).build())
/**/.addChild(Metric.Blueprint.builder().withMetricTypePath("../metricType").withId("metric2")
.withInterval(0L).build())
.end()
.startChild(Resource.Blueprint.builder().withResourceTypePath("resourceType").withId("resource2")
.build())
/**/.addChild(Metric.Blueprint.builder().withMetricTypePath("../metricType").withId("metric3")
.withInterval(0L).build())
/**/.addChild(Metric.Blueprint.builder().withMetricTypePath("../metricType").withId("metric4")
.withInterval(0L).build())
/**/.addChild(Resource.Blueprint.builder().withId("resource3")
.withResourceTypePath("../resourceType").build())
.end()
.addChild(Metric.Blueprint.builder().withMetricTypePath("metricType").withId("metric5")
.withInterval(0L).build())
.addChild(Metric.Blueprint.builder().withMetricTypePath("metricType").withId("metric6")
.withInterval(0L).build())
.build();
}
@Test
public void testSyncConfig_limitTypes_shallow() throws Exception {
String tenantId = "testSyncConfig_limitTypes_shallow";
try {
Feeds.Single f = inventory.tenants().create(Tenant.Blueprint.builder().withId(tenantId).build())
.feeds().create(Feed.Blueprint.builder().withId("feed").build());
InventoryStructure<Feed.Blueprint> fullStructure = getSyncConfigStructure();
f.synchronize(SyncRequest.syncEverything(fullStructure));
//k, now let's just update metrics... resource3 gets created, too, because of metric8
InventoryStructure<Feed.Blueprint> updateStructure = InventoryStructure
.of(Feed.Blueprint.builder().withId("feed").build())
.addChild(Metric.Blueprint.builder().withMetricTypePath("metricType").withId("metric6")
.withInterval(0L).build())
.addChild(Metric.Blueprint.builder().withMetricTypePath("metricType").withId("metric7")
.withInterval(0L).build())
.startChild(Resource.Blueprint.builder().withResourceTypePath("resourceType").withId("resource4")
.build())
/**/.addChild(Metric.Blueprint.builder().withMetricTypePath("../metricType").withId("metric8")
.withInterval(0L).build())
.end()
.build();
f.synchronize(new SyncRequest<>(SyncConfiguration.builder().withType(SegmentType.m).build(),
updateStructure));
//check the new stuff got added
Assert.assertTrue(f.resources().get("resource4").exists());
Assert.assertTrue(f.resources().get("resource4").metrics().get("metric8").exists());
Assert.assertTrue(f.metrics().get("metric7").exists());
//check that stuff that should not be there isn't
Assert.assertFalse(f.metrics().get("metric5").exists());
//check that the rest of the inventory is still there
Assert.assertTrue(f.resourceTypes().get("resourceType").exists());
Assert.assertTrue(f.metricTypes().get("metricType").exists());
Assert.assertTrue(f.resources().get("resource1").exists());
Assert.assertTrue(f.resources().get("resource2").exists());
Assert.assertTrue(f.resources().get("resource1").metrics().get("metric1").exists());
Assert.assertTrue(f.resources().get("resource1").metrics().get("metric2").exists());
Assert.assertTrue(f.resources().get("resource2").metrics().get("metric3").exists());
Assert.assertTrue(f.resources().get("resource2").metrics().get("metric4").exists());
Assert.assertTrue(f.resources().get("resource2").resources().get("resource3").exists());
} catch (Exception t) {
t.printStackTrace();
throw t;
} finally {
if (inventory.tenants().get(tenantId).exists()) {
inventory.tenants().delete(tenantId);
}
}
}
@Test
public void testSyncConfig_limitTypes_deep() throws Exception {
String tenantId = "testSyncConfig_limitTypes_deep";
try {
Feeds.Single f = inventory.tenants().create(Tenant.Blueprint.builder().withId(tenantId).build())
.feeds().create(Feed.Blueprint.builder().withId("feed").build());
InventoryStructure<Feed.Blueprint> fullStructure = getSyncConfigStructure();
f.synchronize(SyncRequest.syncEverything(fullStructure));
//and now try to remove all metrics from everywhere using a deep search
InventoryStructure<Feed.Blueprint> deleteMetricsStructure = InventoryStructure
.of(Feed.Blueprint.builder().withId("feed").build()).build();
f.synchronize(
new SyncRequest<>(SyncConfiguration.builder().withType(SegmentType.m).withDeepSearch(true).build(),
deleteMetricsStructure));
//check that everything but the metrics exists
Assert.assertFalse(f.metrics().get("metric5").exists());
Assert.assertFalse(f.metrics().get("metric6").exists());
Assert.assertTrue(f.resourceTypes().get("resourceType").exists());
Assert.assertTrue(f.metricTypes().get("metricType").exists());
Assert.assertTrue(f.resources().get("resource1").exists());
Assert.assertTrue(f.resources().get("resource2").exists());
Assert.assertFalse(f.resources().get("resource1").metrics().get("metric1").exists());
Assert.assertFalse(f.resources().get("resource1").metrics().get("metric2").exists());
Assert.assertFalse(f.resources().get("resource2").metrics().get("metric3").exists());
Assert.assertFalse(f.resources().get("resource2").metrics().get("metric4").exists());
Assert.assertTrue(f.resources().get("resource2").resources().get("resource3").exists());
} catch (Exception t) {
t.printStackTrace();
throw t;
} finally {
if (inventory.tenants().get(tenantId).exists()) {
inventory.tenants().delete(tenantId);
}
}
}
@Test
public void testObserveTenants() throws Exception {
String tid = "testObserveTenants";
runObserverTest(Tenant.class, 0, 0, () -> {
inventory.tenants().create(new Tenant.Blueprint(tid));
inventory.tenants().update(tid, Tenant.Update.builder().build());
inventory.tenants().delete(tid);
});
}
@Test
public void testObserveEnvironments() throws Exception {
String tid = "testObserveEnvironments";
String eid = "env";
runObserverTest(Environment.class, 1, 1, () -> {
inventory.tenants().create(Tenant.Blueprint.builder().withId(tid).build());
inventory.tenants().get(tid).environments().create(Environment.Blueprint.builder().withId(eid).build());
inventory.tenants().get(tid).environments().update(eid, Environment.Update.builder().build());
inventory.tenants().get(tid).environments().delete(eid);
inventory.tenants().delete(tid);
});
}
@Test
public void testObserveResourceTypes() throws Exception {
String tid = "testObserveResourceTypes";
String rtid = "rtype";
String mtid = "mtype";
runObserverTest(ResourceType.class, 3, 3, () -> {
inventory.tenants().create(Tenant.Blueprint.builder().withId(tid).build());
inventory.tenants().get(tid).resourceTypes().create(new ResourceType.Blueprint(rtid));
inventory.tenants().get(tid).resourceTypes().update(rtid, new ResourceType.Update(null));
MetricType mt = inventory.tenants().get(tid).metricTypes()
.create(MetricType.Blueprint.builder(MetricDataType.COUNTER)
.withId(mtid).withUnit(MetricUnit.BYTES).withInterval(0L).build()).entity();
List<Relationship> createdRelationships = new ArrayList<>();
inventory.observable(Interest.in(Relationship.class).being(created())).subscribe(createdRelationships::add);
inventory.tenants().get(tid).resourceTypes().get(rtid).metricTypes().associate(mt.getPath());
inventory.tenants().get(tid).metricTypes().delete(mtid);
Assert.assertEquals(1, createdRelationships.size());
inventory.tenants().get(tid).resourceTypes().delete(rtid);
inventory.tenants().delete(tid);
});
}
@Test
public void testObserveMetricTypes() throws Exception {
String tid = "testObserveMetricTypes";
String mtid = "mtype";
try {
runObserverTest(MetricType.class, 1, 1, () -> {
inventory.tenants().create(Tenant.Blueprint.builder().withId(tid).build());
inventory.tenants().get(tid).metricTypes()
.create(new MetricType.Blueprint(mtid, MetricUnit.BYTES, MetricDataType.COUNTER, 0L));
inventory.tenants().get(tid).metricTypes().update(mtid, MetricType.Update.builder()
.withUnit(MetricUnit.MILLISECONDS).build());
inventory.tenants().get(tid).metricTypes().delete(mtid);
});
} finally {
inventory.tenants().delete(tid);
}
}
@Test
public void testObserveMetrics() throws Exception {
String tid = "testObserveMetrics";
String eid = "env";
String mtid = "mtype";
String mid = "met";
try {
runObserverTest(Metric.class, 4, 2, () -> {
inventory.tenants().create(Tenant.Blueprint.builder().withId(tid).build());
inventory.tenants().get(tid).environments().create(Environment.Blueprint.builder().withId(eid).build());
inventory.tenants().get(tid).metricTypes()
.create(new MetricType.Blueprint(mtid, MetricUnit.BYTES, MetricDataType.COUNTER, 0L));
inventory.tenants().get(tid).environments().get(eid).metrics()
.create(new Metric.Blueprint("/" + mtid, mid));
inventory.tenants().get(tid).environments().get(eid).metrics().update(mid,
Metric.Update.builder().build());
inventory.tenants().get(tid).environments().get(eid).metrics().delete(mid);
});
} finally {
inventory.tenants().delete(tid);
}
}
@Test
public void testObserveResources() throws Exception {
String tid = "testObserveResources";
String eid = "env";
String rtid = "rtype";
String mtid = "mtype";
String mid = "met";
String rid = "res";
try {
runObserverTest(Resource.class, 8, 3, () -> {
inventory.tenants().create(Tenant.Blueprint.builder().withId(tid).build());
inventory.tenants().get(tid).environments().create(Environment.Blueprint.builder().withId(eid).build());
inventory.tenants().get(tid).resourceTypes().create(ResourceType.Blueprint.builder().withId(rtid)
.build());
inventory.tenants().get(tid).metricTypes()
.create(MetricType.Blueprint.builder(MetricDataType.COUNTER).withId(mtid)
.withUnit(MetricUnit.BYTES).withInterval(0L).build());
inventory.tenants().get(tid).environments().get(eid).resources()
.create(new Resource.Blueprint(rid, "/" + rtid));
inventory.tenants().get(tid).environments().get(eid).resources().update(rid,
Resource.Update.builder().build());
Metric m = inventory.tenants().get(tid).environments().get(eid).metrics()
.create(Metric.Blueprint.builder().withId(mid).withMetricTypePath("/" + mtid).build()).entity();
List<Relationship> createdRelationships = new ArrayList<>();
inventory.observable(Interest.in(Relationship.class).being(created()))
.subscribe(createdRelationships::add);
inventory.tenants().get(tid).environments().get(eid).resources().get(rid).allMetrics().associate(
m.getPath());
Assert.assertEquals(1, createdRelationships.size());
inventory.tenants().get(tid).environments().get(eid).resources().delete(rid);
});
} finally {
inventory.tenants().delete(tid);
}
}
@Test
public void testObserveDataEntities() throws Exception {
String tid = "testObserveDataEntities";
String eid = "env";
String rtid = "rtype";
String rid = "res";
try {
runObserverTest(DataEntity.class, 5, 1, () -> {
inventory.tenants().create(Tenant.Blueprint.builder().withId(tid).build());
inventory.tenants().get(tid).environments().create(Environment.Blueprint.builder().withId(eid).build());
inventory.tenants().get(tid).resourceTypes().create(ResourceType.Blueprint.builder().withId(rtid)
.build());
inventory.tenants().get(tid).environments().get(eid).resources()
.create(new Resource.Blueprint(rid, "/" + rtid));
Data.ReadWrite<DataRole.Resource> dataAccess = inventory.tenants().get(tid).environments().get(eid)
.resources().get(rid).data();
dataAccess.create(DataEntity.Blueprint.<DataRole.Resource>builder()
.withRole(configuration).build());
dataAccess.update(configuration, DataEntity.Update.builder().build());
dataAccess.delete(configuration);
});
} finally {
inventory.tenants().delete(tid);
}
}
@Test
public void testObserveIdentityHashChangedOnParentOfChangedEntity() throws Exception {
String tenantId = "testObserveIdentityHashChangedOnParentOfChangedEntity";
testSyncHashObservation(tenantId, updateCounts -> {
//now update the unit of the metric type
inventory.tenants().get(tenantId).feeds().get("feed").metricTypes().get("metricType").update(MetricType
.Update.builder().withUnit(MetricUnit.BYTES).build());
//and check that identity hashes changed and we were informed about it
Assert.assertEquals(1, updateCounts.remove(MetricType.class).intValue());
Assert.assertEquals(1, updateCounts.remove(Feed.class).intValue());
Assert.assertTrue(updateCounts.isEmpty());
});
}
@Test
public void testObserveSyncHashChangedOnParentOfCreatedEntity() throws Exception {
String tenantId = "testObserveSyncHashChangedOnParentOfCreatedEntity";
testSyncHashObservation(tenantId, updateCounts -> {
//now create some new grandchild of the feed, let's say new sub-resource
inventory.tenants().get(tenantId).feeds().get("feed").resources().get("resource").resources()
.create(Resource.Blueprint.builder().withId("childResource").withResourceTypePath
("../resourceType").build());
//and check that identity hashes changed and we were informed about it
Assert.assertEquals(1, updateCounts.remove(Resource.class).intValue()); //the hash of parent resource
Assert.assertEquals(1, updateCounts.remove(Feed.class).intValue());
Assert.assertTrue(updateCounts.isEmpty());
});
}
@Test
public void testObserveIdentityHashChangedOnParentOfDeletedEntity() throws Exception {
String tenantId = "testObserveIdentityHashChangedOnParentOfDeletedEntity";
testSyncHashObservation(tenantId, updateCounts -> {
//now delete the return type of the operation type
inventory.tenants().get(tenantId).feeds().get("feed").resourceTypes().get("resourceType")
.operationTypes().get("operationType").data().delete(returnType);
//and check that identity hashes changed and we were informed about it
Assert.assertEquals(1, updateCounts.remove(OperationType.class).intValue());
Assert.assertEquals(1, updateCounts.remove(ResourceType.class).intValue());
Assert.assertEquals(1, updateCounts.remove(Feed.class).intValue());
Assert.assertTrue(updateCounts.isEmpty());
});
}
private void testSyncHashObservation(String tenantId, Consumer<Map<Class<?>, Integer>> test) throws Exception {
Subscription subs = null;
try {
createInventoryForSyncHashChangeObservations(tenantId);
Map<Class<?>, Integer> updateCounts = new HashMap<>();
subs = Observable.merge(
inventory.observable(Interest.in(Feed.class).having(syncHashChanged())),
inventory.observable(Interest.in(ResourceType.class).having(syncHashChanged())),
inventory.observable(Interest.in(MetricType.class).having(syncHashChanged())),
inventory.observable(Interest.in(OperationType.class).having(syncHashChanged())),
inventory.observable(Interest.in(Resource.class).having(syncHashChanged())),
inventory.observable(Interest.in(Metric.class).having(syncHashChanged())),
inventory.observable(Interest.in(DataEntity.class).having(syncHashChanged()))
).subscribe(e ->
updateCounts.put(e.getClass(), updateCounts.getOrDefault(e.getClass(), 0) + 1));
test.accept(updateCounts);
} finally {
if (inventory.tenants().get(tenantId).exists()) {
inventory.tenants().delete(tenantId);
}
if (subs != null) {
subs.unsubscribe();
}
}
}
private void createInventoryForSyncHashChangeObservations(String tenantId) throws Exception {
Feeds.Single f = inventory.tenants().create(Tenant.Blueprint.builder().withId(tenantId).build())
.feeds().create(Feed.Blueprint.builder().withId("feed").build());
f.metricTypes().create(MetricType.Blueprint.builder(MetricDataType.GAUGE).withId("metricType").withUnit
(MetricUnit.BITS).withInterval(0L).build());
ResourceTypes.Single rt = f.resourceTypes().create(ResourceType.Blueprint.builder().withId("resourceType")
.build());
OperationTypes.Single ot = rt.operationTypes().create(OperationType.Blueprint.builder().withId("operationType")
.build());
ot.data().create(DataEntity.Blueprint.<DataRole.OperationType>builder().withRole(returnType)
.withValue(StructuredData.get().map().putString("type", "string").build()).build());
Resources.Single r = f.resources()
.create(Resource.Blueprint.builder().withId("resource").withResourceTypePath("resourceType").build());
r.data().create(DataEntity.Blueprint.<DataRole.Resource>builder().withRole(configuration).withValue
(StructuredData.get().integral(42L)).build());
}
@Test
public void testBackendFind() throws Exception {
InventoryBackend<E> backend = inventory.getBackend().startTransaction();
try {
CanonicalPath tenantPath = CanonicalPath.of().tenant("com.acme.tenant").get();
E entity = backend.find(now(), tenantPath);
Tenant tenant = backend.convert(now(), entity, Tenant.class);
Assert.assertEquals("com.acme.tenant", tenant.getId());
CanonicalPath envPath = tenantPath.extend(Environment.SEGMENT_TYPE, "production").get();
entity = backend.find(now(), envPath);
Environment env = backend.convert(now(), entity, Environment.class);
Assert.assertEquals("com.acme.tenant", env.getPath().ids().getTenantId());
Assert.assertEquals("production", env.getId());
entity = backend.find(now(), envPath.extend(Resource.SEGMENT_TYPE, "host1").get());
Resource r = backend.convert(now(), entity, Resource.class);
Assert.assertEquals("com.acme.tenant", r.getPath().ids().getTenantId());
Assert.assertEquals("production", r.getPath().ids().getEnvironmentId());
Assert.assertNull(r.getPath().ids().getFeedId());
Assert.assertEquals("host1", r.getId());
entity = backend.find(now(), envPath.extend(Metric.SEGMENT_TYPE, "host1_ping_response").get());
Metric m = backend.convert(now(), entity, Metric.class);
Assert.assertEquals("com.acme.tenant", m.getPath().ids().getTenantId());
Assert.assertEquals("production", m.getPath().ids().getEnvironmentId());
Assert.assertNull(m.getPath().ids().getFeedId());
Assert.assertEquals("host1_ping_response", m.getId());
CanonicalPath feedPath = tenantPath.extend(Feed.SEGMENT_TYPE, "feed1").get();
entity = backend.find(now(), feedPath);
Feed f = backend.convert(now(), entity, Feed.class);
Assert.assertEquals("com.acme.tenant", f.getPath().ids().getTenantId());
Assert.assertEquals("feed1", f.getId());
entity = backend.find(now(), feedPath.extend(Resource.SEGMENT_TYPE, "feedResource1").get());
r = backend.convert(now(), entity, Resource.class);
Assert.assertEquals("com.acme.tenant", r.getPath().ids().getTenantId());
Assert.assertEquals("feed1", r.getPath().ids().getFeedId());
Assert.assertEquals("feedResource1", r.getId());
entity = backend.find(now(), feedPath.extend(Metric.SEGMENT_TYPE, "feedMetric1").get());
m = backend.convert(now(), entity, Metric.class);
Assert.assertEquals("com.acme.tenant", m.getPath().ids().getTenantId());
Assert.assertEquals("feed1", m.getPath().ids().getFeedId());
Assert.assertEquals("feedMetric1", m.getId());
entity = backend.find(now(), tenantPath.extend(ResourceType.SEGMENT_TYPE, "URL").get());
ResourceType
rt = backend.convert(now(), entity, ResourceType.class);
Assert.assertEquals("com.acme.tenant", rt.getPath().ids().getTenantId());
Assert.assertEquals("URL", rt.getId());
entity = backend.find(now(), tenantPath.extend(MetricType.SEGMENT_TYPE, "ResponseTime").get());
MetricType mt = backend.convert(now(), entity, MetricType.class);
Assert.assertEquals("com.acme.tenant", mt.getPath().ids().getTenantId());
Assert.assertEquals("ResponseTime", mt.getId());
} finally {
backend.rollback();
}
}
@Test
public void testBackendGetRelationship() throws Exception {
InventoryBackend<E> backend = inventory.getBackend().startTransaction();
try {
E tenant = backend.find(now(), CanonicalPath.of().tenant("com.acme.tenant").get());
E environment = backend.find(now(), CanonicalPath.of().tenant("com.acme.tenant").environment("production").get());
E r = backend.getRelationship(now(), tenant, environment, contains.name());
Relationship rel = backend.convert(now(), r, Relationship.class);
Assert.assertEquals("com.acme.tenant", rel.getSource().getSegment().getElementId());
Assert.assertEquals("production", rel.getTarget().getSegment().getElementId());
Assert.assertEquals("contains", rel.getName());
} finally {
backend.rollback();
}
}
@Test
public void testBackendGetRelationships() throws Exception {
InventoryBackend<E> backend = inventory.getBackend().startTransaction();
try {
E entity = backend.find(now(), CanonicalPath.of().tenant("com.acme.tenant").get());
Assert.assertEquals("com.acme.tenant", backend.extractId(entity));
Set<E> rels = backend.getRelationships(now(), entity, both);
Assert.assertEquals(8, rels.size());
Function<Set<E>, Stream<Relationship>> checks = (es) -> es.stream().map((e) -> backend.convert(now(), e,
Relationship.class));
Assert.assertTrue(checks.apply(rels).anyMatch((r) -> contains.name().equals(r.getName()) &&
"com.acme.tenant".equals(r.getSource().getSegment().getElementId()) &&
"production".equals(r.getTarget().getSegment().getElementId())));
Assert.assertTrue(checks.apply(rels).anyMatch((r) -> contains.name().equals(r.getName()) &&
"com.acme.tenant".equals(r.getSource().getSegment().getElementId()) &&
"URL".equals(r.getTarget().getSegment().getElementId())));
Assert.assertTrue(checks.apply(rels).anyMatch((r) -> contains.name().equals(r.getName()) &&
"com.acme.tenant".equals(r.getSource().getSegment().getElementId()) &&
"Person".equals(r.getTarget().getSegment().getElementId())));
Assert.assertTrue(checks.apply(rels).anyMatch((r) -> contains.name().equals(r.getName()) &&
"com.acme.tenant".equals(r.getSource().getSegment().getElementId()) &&
"ResponseTime".equals(r.getTarget().getSegment().getElementId())));
Assert.assertTrue(checks.apply(rels).anyMatch((r) -> contains.name().equals(r.getName()) &&
"com.acme.tenant".equals(r.getSource().getSegment().getElementId()) &&
"feed1".equals(r.getTarget().getSegment().getElementId())));
rels = backend.getRelationships(now(), entity, incoming);
Assert.assertTrue(rels.isEmpty());
rels = backend.getRelationships(now(), entity, outgoing);
Assert.assertTrue(checks.apply(rels).anyMatch((r) -> contains.name().equals(r.getName()) &&
"com.acme.tenant".equals(r.getSource().getSegment().getElementId()) &&
"production".equals(r.getTarget().getSegment().getElementId())));
Assert.assertTrue(checks.apply(rels).anyMatch((r) -> contains.name().equals(r.getName()) &&
"com.acme.tenant".equals(r.getSource().getSegment().getElementId()) &&
"URL".equals(r.getTarget().getSegment().getElementId())));
Assert.assertTrue(checks.apply(rels).anyMatch((r) -> contains.name().equals(r.getName()) &&
"com.acme.tenant".equals(r.getSource().getSegment().getElementId()) &&
"ResponseTime".equals(r.getTarget().getSegment().getElementId())));
entity = backend.find(now(), CanonicalPath.of().tenant("com.example.tenant").environment("test").get());
Assert.assertEquals("test", backend.extractId(entity));
rels = backend.getRelationships(now(), entity, incoming);
Assert.assertEquals(2, rels.size());
Assert.assertTrue(checks.apply(rels).anyMatch((r) -> "contains".equals(r.getName()) &&
"com.example.tenant".equals(r.getSource().getSegment().getElementId())));
Assert.assertTrue(checks.apply(rels).anyMatch((r) -> "yourMom".equals(r.getName()) &&
"playroom2_size".equals(r.getSource().getSegment().getElementId())));
rels = backend.getRelationships(now(), entity, outgoing, "IamYourFather");
Assert.assertEquals(1, rels.size());
Assert.assertTrue(checks.apply(rels).anyMatch((r) -> "IamYourFather".equals(r.getName()) &&
"playroom2_size".equals(r.getTarget().getSegment().getElementId())));
} finally {
backend.rollback();
}
}
@Test
public void testBackendGetTransitiveClosure() throws Exception {
InventoryBackend<E> backend = inventory.getBackend().startTransaction();
try {
TriFunction<E, Relationships.Direction, String[], Stream<? extends Entity<?, ?>>> test =
(start, direction, name) -> {
Iterator<E> transitiveClosure = backend.getTransitiveClosureOver(now(), start, direction, name);
return StreamSupport.stream(Spliterators.spliterator(transitiveClosure, Integer.MAX_VALUE, 0),
false).map((e) -> (Entity<?, ?>) backend.convert(now(), e, backend.extractType(e)));
};
E env = backend.find(now(), CanonicalPath.of().tenant("com.acme.tenant").environment("production").get());
E feed = backend.find(now(), CanonicalPath.of().tenant("com.acme.tenant").feed("feed1").get());
Assert.assertEquals(8, test.apply(feed, outgoing, new String[]{"contains"}).count());
Assert.assertFalse(test.apply(feed, outgoing, new String[]{"contains"}).anyMatch((e) -> e instanceof Feed &&
"feed1".equals(e.getId())));
Assert.assertTrue(test.apply(env, outgoing, new String[]{"contains", "incorporates"}).anyMatch((e) -> e
instanceof Resource && "feedResource1".equals(e.getId())));
Assert.assertTrue(test.apply(env, outgoing, new String[]{"contains", "incorporates"}).anyMatch((e) -> e
instanceof Resource && "feedResource2".equals(e.getId())));
Assert.assertTrue(test.apply(env, outgoing, new String[]{"contains", "incorporates"}).anyMatch((e) -> e
instanceof Resource && "feedResource3".equals(e.getId())));
Assert.assertTrue(test.apply(env, outgoing, new String[]{"contains", "incorporates"}).anyMatch((e) -> e
instanceof Metric && "feedMetric1".equals(e.getId())));
Assert.assertTrue(test.apply(feed, outgoing, new String[]{"contains"}).anyMatch((e) -> e
instanceof ResourceType && "feed1-resourceType".equals(e.getId())));
Assert.assertTrue(test.apply(feed, outgoing, new String[]{"contains"}).anyMatch((e) -> e
instanceof MetricType && "feed1-metricType".equals(e.getId())));
Assert.assertEquals(1, test.apply(env, incoming, new String[]{"contains"}).count());
Assert.assertTrue(test.apply(env, incoming, new String[]{"contains"}).anyMatch((e) -> e instanceof Tenant &&
"com.acme.tenant".equals(e.getId())));
} finally {
backend.rollback();
}
}
@Test
public void testRecurseFilter() throws Exception {
Query q = Query.path()
.with(With.path(CanonicalPath.of().tenant("com.acme.tenant").feed("feed1").get()))
.with(RecurseFilter.builder().addChain(Related.by(contains)).build())
.with(With.type(Metric.class))
.get();
try (Page<Metric> results = inventory.execute(q, Metric.class, Pager.none())) {
Assert.assertEquals(2, results.getTotalSize());
}
}
@Test
public void testBackendHasRelationship() throws Exception {
InventoryBackend<E> backend = inventory.getBackend().startTransaction();
try {
E tenant = backend.find(now(), CanonicalPath.of().tenant("com.example.tenant").get());
Assert.assertTrue(backend.hasRelationship(now(), tenant, outgoing, "contains"));
Assert.assertFalse(backend.hasRelationship(now(), tenant, incoming, "contains"));
Assert.assertTrue(backend.hasRelationship(now(), tenant, both, "contains"));
E env = backend.find(now(), CanonicalPath.of().tenant("com.example.tenant").environment("test").get());
Assert.assertTrue(backend.hasRelationship(now(), tenant, env, "contains"));
Assert.assertFalse(backend.hasRelationship(now(), tenant, env, "e-kachny"));
} finally {
backend.rollback();
}
}
@Test
public void testBackendExtractId() throws Exception {
InventoryBackend<E> backend = inventory.getBackend().startTransaction();
try {
E tenant = backend.find(now(), CanonicalPath.of().tenant("com.example.tenant").get());
Assert.assertEquals("com.example.tenant", backend.extractId(tenant));
} finally {
backend.rollback();
}
}
@Test
public void testBackendExtractType() throws Exception {
InventoryBackend<E> backend = inventory.getBackend().startTransaction();
try {
CanonicalPath tenantPath = CanonicalPath.of().tenant("com.acme.tenant").get();
E entity = backend.find(now(), tenantPath);
Assert.assertEquals(Tenant.class, backend.extractType(entity));
CanonicalPath envPath = tenantPath.extend(Environment.SEGMENT_TYPE, "production").get();
entity = backend.find(now(), envPath);
Assert.assertEquals(Environment.class, backend.extractType(entity));
entity = backend.find(now(), envPath.extend(Resource.SEGMENT_TYPE, "host1").get());
Assert.assertEquals(Resource.class, backend.extractType(entity));
entity = backend.find(now(), envPath.extend(Metric.SEGMENT_TYPE, "host1_ping_response").get());
Assert.assertEquals(Metric.class, backend.extractType(entity));
CanonicalPath feedPath = tenantPath.extend(Feed.SEGMENT_TYPE, "feed1").get();
entity = backend.find(now(), feedPath);
Assert.assertEquals(Feed.class, backend.extractType(entity));
entity = backend.find(now(), feedPath.extend(Resource.SEGMENT_TYPE, "feedResource1").get());
Assert.assertEquals(Resource.class, backend.extractType(entity));
entity = backend.find(now(), feedPath.extend(Metric.SEGMENT_TYPE, "feedMetric1").get());
Assert.assertEquals(Metric.class, backend.extractType(entity));
entity = backend.find(now(), tenantPath.extend(ResourceType.SEGMENT_TYPE, "URL").get());
Assert.assertEquals(ResourceType.class, backend.extractType(entity));
entity = backend.find(now(), tenantPath.extend(MetricType.SEGMENT_TYPE, "ResponseTime").get());
Assert.assertEquals(MetricType.class, backend.extractType(entity));
} finally {
backend.rollback();
}
}
@Test
public void testBackendQuery() throws Exception {
InventoryBackend<E> backend = inventory.getBackend().startTransaction();
try {
Pager unlimited = Pager.unlimited(Order.unspecified());
Query q = Query.path().with(type(Tenant.class), id("com.acme.tenant")).get();
Page<E> results = backend.query(now(), q, unlimited);
Assert.assertTrue(results.hasNext());
Assert.assertEquals("com.acme.tenant", backend.extractId(results.next()));
Assert.assertTrue(!results.hasNext());
q = Query.path().with(type(Tenant.class), id("com.acme.tenant"), Related.by("contains"),
type(Environment.class), id("production")).get();
results = backend.query(now(), q, unlimited);
Assert.assertTrue(results.hasNext());
Assert.assertEquals("production", backend.extractId(results.next()));
Assert.assertTrue(!results.hasNext());
// equivalent to inventory.tenants().getAll(Related.by("contains"), type(ResourceType.class, id("URL"))
// .environments().getAll().entities();
q = Query.path().with(type(Tenant.class)).filter().with(Related.by("contains"), type(
ResourceType.class),
id("URL")).path().with(Related.by("contains"), type(Environment.class)).get();
results = backend.query(now(), q, unlimited);
Assert.assertTrue(results.hasNext());
Assert.assertEquals("production", backend.extractId(results.next()));
Assert.assertTrue(!results.hasNext());
} finally {
backend.rollback();
}
}
@Test
public void testCreateConfiguration() throws Exception {
Resources.Single res = inventory.tenants().get("com.example.tenant").environments().get("test")
.resources().get("playroom2");
StructuredData orig = StructuredData.get().map().putBool("yes", true).putBool("no", false).build();
res.data().create(DataEntity.Blueprint.<DataRole.Resource>builder().withRole(connectionConfiguration)
.withValue(orig).build());
StructuredData retrieved = res.data().get(connectionConfiguration).entity().getValue();
Assert.assertEquals(orig, retrieved);
Assert.assertFalse(res.data().get(configuration).exists());
res.data().delete(connectionConfiguration);
Assert.assertFalse(res.data().get(connectionConfiguration).exists());
}
@Test
public void testUpdateStructuredDataSimpleValue() throws Exception {
Data.Single dataAccess = inventory.inspect(
CanonicalPath.fromString("/t;com.example.tenant/e;test/r;playroom1/d;configuration"),
Data.Single.class);
StructuredData origData = dataAccess.entity().getValue();
Assert.assertNotNull(origData);
StructuredData modified = origData.update().toMap().putBool("answer", true).build();
dataAccess.update(DataEntity.Update.builder().withValue(modified).build());
StructuredData persisted = dataAccess.entity().getValue();
Assert.assertEquals(modified, persisted);
modified = modified.update().toMap().updateList("primitives").setBool(0, false).closeList().build();
dataAccess.update(DataEntity.Update.builder().withValue(modified).build());
persisted = dataAccess.entity().getValue();
Assert.assertEquals(modified, persisted);
modified = modified.update().toMap().remove("answer").build();
dataAccess.update(DataEntity.Update.builder().withValue(modified).build());
persisted = dataAccess.entity().getValue();
Assert.assertEquals(modified, persisted);
// restore the original value
dataAccess.update(DataEntity.Update.builder().withValue(origData).build());
}
@Test
public void testFilteringByData() throws Exception {
Data.Read<DataRole.Resource> configs = inventory.tenants().getAll().environments().getAll().resources()
.getAll().data();
Assert.assertEquals(1, configs.getAll(With.dataAt(RelativePath.to().structuredData().key("primitives").index(0)
.get())).entities().size());
Assert.assertEquals(0, configs.getAll(new Filter[][]{{
With.dataAt(RelativePath.to().structuredData().key("primitives").index(0).get()),
With.dataValue(false)}}).entities().size());
Assert.assertEquals(1, configs.getAll(new Filter[][]{{
With.dataAt(RelativePath.to().structuredData().key("primitives").index(0).get()),
With.dataValue(true)}}).entities().size());
Assert.assertEquals(1, configs.getAll(new Filter[][]{{
With.dataAt(RelativePath.to().structuredData().key("primitives").get()),
With.dataOfTypes(StructuredData.Type.list)}}).entities().size());
Assert.assertEquals(1, configs.getAll(new Filter[][]{{
With.dataAt(RelativePath.to().structuredData().key("primitives").index(0).get()),
With.dataOfTypes(StructuredData.Type.bool)}}).entities().size());
Assert.assertEquals(0, configs.getAll(new Filter[][]{{
With.dataAt(RelativePath.to().structuredData().key("primitives").get()),
With.dataOfTypes(StructuredData.Type.map)}}).entities().size());
Assert.assertEquals(0, configs.getAll(new Filter[][]{{
With.dataAt(RelativePath.to().structuredData().key("primitives").index(0).get()),
With.dataOfTypes(StructuredData.Type.integral)}}).entities().size());
}
@Test
public void testRetrievingDataPortions() throws Exception {
Data.Single config = inventory.inspect(
CanonicalPath.fromString("/t;com.example.tenant/e;test/r;playroom1/d;configuration"),
Data.Single.class);
StructuredData allData = config.entity().getValue();
StructuredData portion = config.data(RelativePath.to().structuredData().key("primitives").index(0).get());
Assert.assertEquals(allData.map().get("primitives").list().get(0), portion);
portion = config.data(RelativePath.empty().get());
Assert.assertEquals(allData, portion);
portion = config.flatData(RelativePath.to().structuredData().key("primitives").index(0).get());
Assert.assertEquals(allData.map().get("primitives").list().get(0), portion);
portion = config.flatData(RelativePath.empty().get());
//noinspection AssertEqualsBetweenInconvertibleTypes
Assert.assertEquals(Collections.emptyMap(), portion.getValue());
portion = config.flatData(RelativePath.to().structuredData().key("primitives").get());
//noinspection AssertEqualsBetweenInconvertibleTypes
Assert.assertEquals(Collections.emptyList(), portion.getValue());
}
@Test
public void testCreateInvalidConfiguration() throws Exception {
Resources.Single res = inventory.inspect(CanonicalPath.fromString("/t;com.acme.tenant/e;production/r;people"),
Resources.Single.class);
try {
res.data().create(DataEntity.Blueprint.<DataRole.Resource>builder()
.withRole(configuration).withValue(StructuredData.get().map()
.putBool("firstName", false).build()).build());
Assert.fail("Creating a config that doesn't conform to the schema shouldn't be possible.");
} catch (ValidationException e) {
//good, we should get 2 errors - missing last name and invalid value type on the firstName
Assert.assertEquals(2, e.getMessages().size());
Assert.assertEquals(CanonicalPath.fromString("/t;com.acme.tenant/e;production/r;people/d;configuration"),
e.getDataPath());
Assert.assertEquals("ERROR", e.getMessages().get(0).getSeverity());
Assert.assertEquals("ERROR", e.getMessages().get(1).getSeverity());
}
}
@Test
public void testUpdateWithInvalidConfiguration() throws Exception {
Resources.Single res = inventory.inspect(
CanonicalPath.fromString("/t;com.acme.tenant/e;production/r;people/r;Alois"), Resources.Single.class);
try {
res.data().get(configuration).update(DataEntity.Update.builder().withValue(StructuredData.get().map()
.putBool("firstName", false).build()).build());
Assert.fail("Updating a config that doesn't conform to the schema shouldn't be possible.");
} catch (ValidationException e) {
//good, we should get 2 errors - missing last name and invalid value type on the firstName
Assert.assertEquals(2, e.getMessages().size());
Assert.assertEquals(CanonicalPath
.fromString("/t;com.acme.tenant/e;production/r;people/r;Alois/d;configuration"),
e.getDataPath());
Assert.assertEquals("ERROR", e.getMessages().get(0).getSeverity());
Assert.assertEquals("ERROR", e.getMessages().get(1).getSeverity());
}
}
@Test
public void testCreateWithRelationships() throws Exception {
try {
inventory.tenants().get("com.acme.tenant").environments().create(Environment.Blueprint.builder()
.withId("env-with-rel")
.addOutgoingRelationship("kachna", CanonicalPath.of().tenant("com.acme.tenant").get())
.addIncomingRelationship("duck", CanonicalPath.of().tenant("com.acme.tenant").get())
.build());
Assert.assertTrue(inventory.tenants().get("com.acme.tenant").relationships(incoming).named("kachna")
.anyExists());
Assert.assertTrue(inventory.tenants().get("com.acme.tenant").relationships(outgoing).named("duck")
.anyExists());
} finally {
//clean up
Environments.Single env = inventory.tenants().get("com.acme.tenant").environments().get("env-with-rel");
if (env.exists()) {
env.delete();
}
}
}
@Test
public void testResourceOwnedMetrics() throws Exception {
inventory.tenants().get("com.acme.tenant").feeds().get("feed1")
.resources().get("feedResource3").metrics().get("feedResource3-metric").exists();
inventory.tenants().get("com.acme.tenant").feeds().get("feed1")
.resources().get("feedResource3").allMetrics().get(RelativePath.to().metric("feedResource3-metric")
.get()).exists();
}
@Test
public void testGettingResourceTypesFromTenants() throws Exception {
Set<ResourceType> rts = inventory.tenants().get("com.acme.tenant").resourceTypes().getAll().entities();
Assert.assertEquals(3, rts.size());
Assert.assertTrue(rts.stream().anyMatch(rt -> rt.getId().equals("URL")));
Assert.assertTrue(rts.stream().anyMatch(rt -> rt.getId().equals("Person")));
Assert.assertTrue(rts.stream().anyMatch(rt -> rt.getId().equals("mpRt")));
rts = inventory.tenants().get("com.acme.tenant").resourceTypesUnder(Parents.any()).getAll()
.entities();
Assert.assertEquals(4, rts.size());
Assert.assertTrue(rts.stream().anyMatch(rt -> rt.getId().equals("URL")));
Assert.assertTrue(rts.stream().anyMatch(rt -> rt.getId().equals("Person")));
Assert.assertTrue(rts.stream().anyMatch(rt -> rt.getId().equals("mpRt")));
Assert.assertTrue(rts.stream().anyMatch(rt -> rt.getId().equals("feed1-resourceType")));
rts = inventory.tenants().get("com.acme.tenant").resourceTypesUnder().getAll().entities();
Assert.assertEquals(3, rts.size());
Assert.assertTrue(rts.stream().anyMatch(rt -> rt.getId().equals("URL")));
Assert.assertTrue(rts.stream().anyMatch(rt -> rt.getId().equals("Person")));
Assert.assertTrue(rts.stream().anyMatch(rt -> rt.getId().equals("mpRt")));
rts = inventory.tenants().get("com.acme.tenant").resourceTypesUnder(Tenants.ResourceTypeParents.TENANT).getAll()
.entities();
Assert.assertEquals(3, rts.size());
Assert.assertTrue(rts.stream().anyMatch(rt -> rt.getId().equals("URL")));
Assert.assertTrue(rts.stream().anyMatch(rt -> rt.getId().equals("Person")));
Assert.assertTrue(rts.stream().anyMatch(rt -> rt.getId().equals("mpRt")));
rts = inventory.tenants().get("com.acme.tenant").resourceTypesUnder(Tenants.ResourceTypeParents.FEED).getAll()
.entities();
Assert.assertEquals(1, rts.size());
Assert.assertTrue(rts.stream().anyMatch(rt -> rt.getId().equals("feed1-resourceType")));
}
@Test
public void testGettingMetricTypesFromTenants() throws Exception {
Set<MetricType> mts = inventory.tenants().get("com.acme.tenant").metricTypes().getAll().entities();
Assert.assertEquals(2, mts.size());
Assert.assertTrue(mts.stream().anyMatch(rt -> rt.getId().equals("ResponseTime")));
Assert.assertTrue(mts.stream().anyMatch(rt -> rt.getId().equals("mpMt")));
mts = inventory.tenants().get("com.acme.tenant").metricTypesUnder().getAll().entities();
Assert.assertEquals(2, mts.size());
Assert.assertTrue(mts.stream().anyMatch(rt -> rt.getId().equals("ResponseTime")));
Assert.assertTrue(mts.stream().anyMatch(rt -> rt.getId().equals("mpMt")));
mts = inventory.tenants().get("com.acme.tenant").metricTypesUnder(Parents.any()).getAll().entities();
Assert.assertEquals(3, mts.size());
Assert.assertTrue(mts.stream().anyMatch(rt -> rt.getId().equals("ResponseTime")));
Assert.assertTrue(mts.stream().anyMatch(rt -> rt.getId().equals("mpMt")));
Assert.assertTrue(mts.stream().anyMatch(rt -> rt.getId().equals("feed1-metricType")));
mts = inventory.tenants().get("com.acme.tenant").metricTypesUnder(Tenants.MetricTypeParents.TENANT).getAll()
.entities();
Assert.assertEquals(2, mts.size());
Assert.assertTrue(mts.stream().anyMatch(rt -> rt.getId().equals("ResponseTime")));
Assert.assertTrue(mts.stream().anyMatch(rt -> rt.getId().equals("mpMt")));
mts = inventory.tenants().get("com.acme.tenant").metricTypesUnder(Tenants.MetricTypeParents.FEED).getAll()
.entities();
Assert.assertEquals(1, mts.size());
Assert.assertTrue(mts.stream().anyMatch(rt -> rt.getId().equals("feed1-metricType")));
}
@Test
public void testGettingResourcesFromFeeds() throws Exception {
Set<Resource> rs = inventory.tenants().get("com.acme.tenant").feeds().get("feed1").resources().getAll()
.entities();
Assert.assertEquals(3, rs.size());
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedResource1")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedResource2")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedResource3")));
rs = inventory.tenants().get("com.acme.tenant").feeds().get("feed1").resourcesUnder(Parents.any()).getAll()
.entities();
Assert.assertEquals(4, rs.size());
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedResource1")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedResource2")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedResource3")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedChildResource")));
rs = inventory.tenants().get("com.acme.tenant").feeds().get("feed1").resourcesUnder(Feeds.ResourceParents.FEED)
.getAll().entities();
Assert.assertEquals(3, rs.size());
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedResource1")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedResource2")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedResource3")));
rs = inventory.tenants().get("com.acme.tenant").feeds().get("feed1")
.resourcesUnder(Feeds.ResourceParents.RESOURCE).getAll().entities();
Assert.assertEquals(1, rs.size());
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedChildResource")));
}
@Test
public void testGettingMetricsFromFeeds() throws Exception {
Set<Metric> ms = inventory.tenants().get("com.acme.tenant").feeds().get("feed1").metrics().getAll().entities();
Assert.assertEquals(1, ms.size());
Assert.assertTrue(ms.stream().anyMatch(m -> m.getId().equals("feedMetric1")));
ms = inventory.tenants().get("com.acme.tenant").feeds().get("feed1").metricsUnder(Feeds.MetricParents.FEED)
.getAll().entities();
Assert.assertEquals(1, ms.size());
Assert.assertTrue(ms.stream().anyMatch(m -> m.getId().equals("feedMetric1")));
ms = inventory.tenants().get("com.acme.tenant").feeds().get("feed1").metricsUnder(Feeds.MetricParents.FEED,
Feeds.MetricParents.RESOURCE).getAll().entities();
Assert.assertEquals(2, ms.size());
Assert.assertTrue(ms.stream().anyMatch(m -> m.getId().equals("feedMetric1")));
Assert.assertTrue(ms.stream().anyMatch(m -> m.getId().equals("feedResource3-metric")));
ms = inventory.tenants().get("com.acme.tenant").feeds().get("feed1").metricsUnder(Parents.any()).getAll()
.entities();
Assert.assertEquals(2, ms.size());
Assert.assertTrue(ms.stream().anyMatch(m -> m.getId().equals("feedMetric1")));
Assert.assertTrue(ms.stream().anyMatch(m -> m.getId().equals("feedResource3-metric")));
ms = inventory.tenants().get("com.acme.tenant").feeds().get("feed1").metricsUnder(Feeds.MetricParents.RESOURCE)
.getAll().entities();
Assert.assertEquals(1, ms.size());
Assert.assertTrue(ms.stream().anyMatch(m -> m.getId().equals("feedResource3-metric")));
}
@Test
public void testGettingResourcesFromEnvironments() throws Exception {
Set<Resource> rs = inventory.tenants().get("com.acme.tenant").environments().get("production").resources()
.getAll().entities();
Assert.assertEquals(2, rs.size());
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("host1")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("people")));
rs = inventory.tenants().get("com.acme.tenant").environments().get("production").resourcesUnder(Parents.any())
.getAll().entities();
Assert.assertEquals(10, rs.size());
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("host1")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedResource1")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedResource2")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedResource3")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedChildResource")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("people")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Hynek")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Alois")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Vilem")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Jarmila")));
rs = inventory.tenants().get("com.acme.tenant").environments().get("production")
.resourcesUnder(Environments.ResourceParents.ENVIRONMENT).getAll().entities();
Assert.assertEquals(2, rs.size());
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("host1")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("people")));
rs = inventory.tenants().get("com.acme.tenant").environments().get("production")
.resourcesUnder(Environments.ResourceParents.FEED).getAll().entities();
Assert.assertEquals(3, rs.size());
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedResource1")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedResource2")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedResource3")));
rs = inventory.tenants().get("com.acme.tenant").environments().get("production")
.resourcesUnder(Environments.ResourceParents.RESOURCE).getAll().entities();
Assert.assertEquals(5, rs.size());
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Hynek")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Alois")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Vilem")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Jarmila")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedChildResource")));
rs = inventory.tenants().get("com.acme.tenant").environments().get("production")
.resourcesUnder(Environments.ResourceParents.ENVIRONMENT, Environments.ResourceParents.RESOURCE)
.getAll().entities();
Assert.assertEquals(7, rs.size());
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("host1")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("people")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Hynek")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Alois")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Vilem")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Jarmila")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("feedChildResource")));
}
@Test
public void testGettingMetricsFromEnvironments() throws Exception {
Set<Metric> ms = inventory.tenants().get("com.acme.tenant").environments().get("production").metrics().getAll()
.entities();
Assert.assertEquals(1, ms.size());
Assert.assertTrue(ms.stream().anyMatch(m -> m.getId().equals("host1_ping_response")));
ms = inventory.tenants().get("com.acme.tenant").environments().get("production")
.metricsUnder(Environments.MetricParents.ENVIRONMENT).getAll().entities();
Assert.assertEquals(1, ms.size());
Assert.assertTrue(ms.stream().anyMatch(m -> m.getId().equals("host1_ping_response")));
ms = inventory.tenants().get("com.acme.tenant").environments().get("production")
.metricsUnder(Environments.MetricParents.FEED).getAll().entities();
Assert.assertEquals(1, ms.size());
Assert.assertTrue(ms.stream().anyMatch(m -> m.getId().equals("feedMetric1")));
ms = inventory.tenants().get("com.acme.tenant").environments().get("production")
.metricsUnder(Environments.MetricParents.RESOURCE).getAll().entities();
Assert.assertEquals(1, ms.size());
Assert.assertTrue(ms.stream().anyMatch(m -> m.getId().equals("feedResource3-metric")));
ms = inventory.tenants().get("com.acme.tenant").environments().get("production")
.metricsUnder(Environments.MetricParents.FEED, Environments.MetricParents.ENVIRONMENT).getAll()
.entities();
Assert.assertEquals(2, ms.size());
Assert.assertTrue(ms.stream().anyMatch(m -> m.getId().equals("feedMetric1")));
Assert.assertTrue(ms.stream().anyMatch(m -> m.getId().equals("host1_ping_response")));
ms = inventory.tenants().get("com.acme.tenant").environments().get("production")
.metricsUnder(Parents.any()).getAll().entities();
Assert.assertEquals(3, ms.size());
Assert.assertTrue(ms.stream().anyMatch(m -> m.getId().equals("feedMetric1")));
Assert.assertTrue(ms.stream().anyMatch(m -> m.getId().equals("host1_ping_response")));
Assert.assertTrue(ms.stream().anyMatch(m -> m.getId().equals("feedResource3-metric")));
}
@Test
public void testGettingResourcesFromResources() throws Exception {
Set<Resource> rs = inventory.tenants().get("com.acme.tenant").environments().get("production").resources()
.get("people").resources().getAll().entities();
Assert.assertEquals(2, rs.size());
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Alois")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Hynek")));
rs = inventory.tenants().get("com.acme.tenant").environments().get("production").resources()
.get("people").recursiveResources().getAll().entities();
Assert.assertEquals(4, rs.size());
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Alois")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Hynek")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Vilem")));
Assert.assertTrue(rs.stream().anyMatch(r -> r.getId().equals("Jarmila")));
}
@Test
public void testAssociationsNotDuplicated() throws Exception {
Tenant t = inventory.tenants().create(Tenant.Blueprint.builder().withId("testAssociationsNotDuplicated")
.build()).entity();
ResourceType rt = inventory.inspect(t).resourceTypes()
.create(ResourceType.Blueprint.builder().withId("rtype").build()).entity();
MetricType mt = inventory.inspect(t).metricTypes()
.create(MetricType.Blueprint.builder(MetricDataType.GAUGE).withId("mtype").withUnit(MetricUnit.NONE)
.withInterval(0L).build()).entity();
Environment env = inventory.inspect(t).environments().create(Environment.Blueprint.builder().withId("env")
.build())
.entity();
Resource r = inventory.inspect(env).resources().create(
Resource.Blueprint.builder().withId("res")
.withResourceTypePath(rt.getPath().toString()).build()).entity();
Metric m = inventory.inspect(env).metrics().create(Metric.Blueprint.builder().withId("met")
.withMetricTypePath(mt.getPath().toString()).build()).entity();
try {
Relationship rel = inventory.inspect(r).allMetrics().associate(m.getPath());
Assert.assertNotNull(rel);
try {
Relationship rel2 = inventory.inspect(r).allMetrics().associate(m.getPath());
Assert.fail("Should not be possible to create an association twice.");
} catch (RelationAlreadyExistsException e) {
//expected
}
//also check that the duplicates are not possible using an explicit relationship creation call
try {
Relationship rel2 = inventory.inspect(r).relationships().linkWith(incorporates, m.getPath(), null)
.entity();
Assert.fail("Should not be possible to create an association twice.");
} catch (RelationAlreadyExistsException e) {
//expected
}
} finally {
inventory.inspect(t).delete();
}
}
@Test
public void testNotificationsInTransactionFrame() throws Exception {
Tenant tenant = null;
TransactionFrame frame = inventory.newTransactionFrame();
try {
Inventory inv = frame.boundInventory();
Integer[] observedCreations = new Integer[]{0};
Observable<Feed> obs = inv.observable(Interest.in(Feed.class).being(created()));
obs.subscribe((t) -> observedCreations[0]++);
tenant = inv.tenants()
.create(Tenant.Blueprint.builder().withId("testNotificationsInTransactionFrame").build())
.entity();
inv.inspect(tenant).feeds().create(Feed.Blueprint.builder().withId("feed").build()).entity();
Feed f = inv.inspect(tenant).feeds().get("feed").entity();
Assert.assertEquals(0, (int) observedCreations[0]);
//this must be computed at the time of the actual commit below
Assert.assertNull(f.getIdentityHash());
frame.commit();
Assert.assertEquals(1, (int) observedCreations[0]);
f = inventory.inspect(tenant).feeds().get("feed").entity();
Assert.assertNotNull(f.getIdentityHash());
} catch (Exception e) {
frame.rollback();
throw e;
} finally {
if (tenant != null) {
inventory.inspect(tenant).delete();
}
}
}
@Test
@SuppressWarnings("unchecked")
public void testExecuteQuery() throws Exception {
Query normalQuery = Query.path().with(type(Tenant.class)).get();
Query elementTypeSwitchingQuery =
Query.path().with(type(Tenant.class), SwitchElementType.outgoingRelationships()).get();
Query elementTypeSwitchingQuery2 = Query.path().with(
path(CanonicalPath.of().tenant("com.acme.tenant").environment("production").resource("host1").get()),
SwitchElementType.outgoingRelationships(),
RelationWith.name("incorporates"),
SwitchElementType.targetEntities(),
type(Metric.class)).get();
Page<AbstractElement<?, ?>> res = inventory.execute(normalQuery, (Class) AbstractElement.class, Pager.none());
List<?> result = res.toList();
Assert.assertEquals(2, result.size());
Page<Relationship> res2 = inventory.execute(elementTypeSwitchingQuery, Relationship.class, Pager.none());
result = res2.toList();
Assert.assertEquals(12, result.size());
res = inventory.execute(elementTypeSwitchingQuery2, (Class) AbstractElement.class, Pager.none());
result = res.toList();
Assert.assertEquals(1, result.size());
}
@Test
public void testEradicate() throws Exception {
String tenantId = "testEradicate";
try {
Instant beforeCreate = Instant.now();
Thread.sleep(10); //make sure before and after timestamps differ even if create was done in
//under a millisecond...
Tenants.Single ts = inventory.tenants()
.create(Tenant.Blueprint.builder().withId(tenantId).withProperty("key", "value").build());
Instant afterCreate = Instant.now();
Thread.sleep(10); //make sure before and after eradicate timestamps differ even if eradicate was done in
//under a millisecond...
ts.eradicate();
Instant afterDelete = Instant.now();
//check that at no point in time can we find our tenant... eradicate will just delete all reference
//to it...
Assert.assertFalse(inventory.at(beforeCreate).tenants().get(tenantId).exists());
Assert.assertFalse(inventory.at(afterCreate).tenants().get(tenantId).exists());
Assert.assertFalse(inventory.at(afterDelete).tenants().get(tenantId).exists());
} finally {
if (inventory.tenants().get(tenantId).exists()) {
inventory.tenants().delete(tenantId);
}
}
}
@Test
public void testHistory() throws Exception {
String tenantId = "testHistory";
try {
Tenants.Single ts = inventory.tenants()
.create(Tenant.Blueprint.builder().withId(tenantId).withProperty("key", "value").build());
Tenant beforeDelete = ts.entity();
ts.delete();
Thread.sleep(10);
inventory.tenants()
.create(Tenant.Blueprint.builder().withId(tenantId).withProperty("key", "value").build());
Thread.sleep(10);
Tenant.Update update = Tenant.Update.builder().withProperty("key", "value2").withName("kachny").build();
ts.update(update);
Tenant beforeFinalDelete = beforeDelete.update().with(update);
Thread.sleep(10);
ts.delete();
//getting history of an entity that no longer exists should work
List<Change<Tenant>> cs = ts.history();
Assert.assertEquals(5, cs.size());
Assert.assertEquals(Action.created(), cs.get(0).getAction());
Assert.assertEquals(beforeDelete, cs.get(0).getElement());
Assert.assertEquals(Action.deleted(), cs.get(1).getAction());
Assert.assertEquals(beforeDelete, cs.get(1).getElement());
Assert.assertEquals(Action.created(), cs.get(2).getAction());
Assert.assertEquals(beforeDelete, cs.get(2).getElement());
Assert.assertEquals(Action.updated().asEnum(), cs.get(3).getAction().asEnum());
Assert.assertEquals(beforeDelete, cs.get(3).getElement());
Tenant.Update historyUpdate = ((Action.Update<Tenant, Tenant.Update>) cs.get(3).getActionContext())
.getUpdate();
Assert.assertEquals(update.getName(), historyUpdate.getName());
Assert.assertEquals(update.getProperties(), historyUpdate.getProperties());
Assert.assertEquals(Action.deleted(), cs.get(4).getAction());
Assert.assertEquals(beforeFinalDelete, cs.get(4).getElement());
//getting history of an entity that never existed should throw
try {
inventory.tenants().get(UUID.randomUUID().toString()).history(null, null);
Assert.fail("It should not be possible to get history of entity that never existed.");
} catch (EntityNotFoundException e) {
//good
}
} finally {
if (inventory.tenants().get(tenantId).exists()) {
inventory.tenants().get(tenantId).delete();
}
}
}
@Test
public void testHistory_constrained() throws Exception {
String tenantId = "testHistory_constrained";
try {
Tenants.Single ts = inventory.tenants()
.create(Tenant.Blueprint.builder().withId(tenantId).build());
Thread.sleep(10);
Tenant afterCreateTenant = ts.entity();
Instant afterCreate = Instant.now();
Tenant.Update update = Tenant.Update.builder().withName("kachny").build();
ts.update(update);
Thread.sleep(10);
Tenant beforeDeleteTenant = afterCreateTenant.update().with(update);
Instant beforeDelete = Instant.now();
ts.delete();
Thread.sleep(10);
Instant past = Instant.ofEpochMilli(0);
List<Change<Tenant>> cs = ts.history(past, afterCreate);
Assert.assertEquals(1, cs.size());
Assert.assertEquals(Action.created().asEnum(), cs.get(0).getAction().asEnum());
Assert.assertEquals(afterCreateTenant, cs.get(0).getElement());
cs = ts.history(past, beforeDelete);
Assert.assertEquals(2, cs.size());
Assert.assertEquals(Action.created().asEnum(), cs.get(0).getAction().asEnum());
Assert.assertEquals(afterCreateTenant, cs.get(0).getElement());
Assert.assertEquals(Action.updated().asEnum(), cs.get(1).getAction().asEnum());
Assert.assertEquals(beforeDeleteTenant, cs.get(1).getElement());
cs = ts.history(past, Instant.now());
Assert.assertEquals(3, cs.size());
Assert.assertEquals(Action.created().asEnum(), cs.get(0).getAction().asEnum());
Assert.assertEquals(afterCreateTenant, cs.get(0).getElement());
Assert.assertEquals(Action.updated().asEnum(), cs.get(1).getAction().asEnum());
Assert.assertEquals(beforeDeleteTenant, cs.get(1).getElement());
Assert.assertEquals(Action.deleted().asEnum(), cs.get(2).getAction().asEnum());
Assert.assertEquals(beforeDeleteTenant, cs.get(2).getElement());
cs = ts.history(beforeDelete, Instant.now());
Assert.assertEquals(1, cs.size());
Assert.assertEquals(Action.deleted().asEnum(), cs.get(0).getAction().asEnum());
Assert.assertEquals(beforeDeleteTenant, cs.get(0).getElement());
cs = ts.history(afterCreate, Instant.now());
Assert.assertEquals(2, cs.size());
Assert.assertEquals(Action.updated().asEnum(), cs.get(0).getAction().asEnum());
Assert.assertEquals(beforeDeleteTenant, cs.get(0).getElement());
Assert.assertEquals(Action.deleted().asEnum(), cs.get(1).getAction().asEnum());
Assert.assertEquals(beforeDeleteTenant, cs.get(1).getElement());
} finally {
if (inventory.tenants().get(tenantId).exists()) {
inventory.tenants().get(tenantId).delete();
}
}
}
@Test
public void testTimeSnapshots_API() throws Exception {
String tenantId = "testTimeSnapshots_API";
try {
Instant beforeCreate = Instant.now();
Thread.sleep(10);
Feeds.Single fs = inventory.tenants().create(Tenant.Blueprint.builder().withId(tenantId).build())
.feeds().create(Feed.Blueprint.builder().withId("feed").build());
fs.resourceTypes()
.create(ResourceType.Blueprint.builder().withId("resourceType").build()).entity();
Instant beforeR1 = Instant.now();
Thread.sleep(10);
fs.resources()
.create(Resource.Blueprint.builder().withId("r1").withResourceTypePath("resourceType").build());
Instant beforeR2 = Instant.now();
Thread.sleep(10);
fs.resources()
.create(Resource.Blueprint.builder().withId("r2").withResourceTypePath("resourceType").build());
Instant beforeR3 = Instant.now();
Thread.sleep(10);
fs.resources()
.create(Resource.Blueprint.builder().withId("r3").withResourceTypePath("resourceType").build());
Instant afterR3 = Instant.now();
Set<Resource> beforeCreateResources = inventory.at(beforeCreate).tenants().get(tenantId).feeds().get("feed")
.resources().getAll().entities();
Set<Resource> beforeR1Resources = inventory.at(beforeR1).tenants().get(tenantId).feeds().get("feed")
.resources().getAll().entities();
Set<Resource> beforeR2Resources = inventory.at(beforeR2).tenants().get(tenantId).feeds().get("feed")
.resources().getAll().entities();
Set<Resource> beforeR3Resources = inventory.at(beforeR3).tenants().get(tenantId).feeds().get("feed")
.resources().getAll().entities();
Set<Resource> afterR3Resources = inventory.at(afterR3).tenants().get(tenantId).feeds().get("feed")
.resources().getAll().entities();
Assert.assertTrue(beforeCreateResources.isEmpty());
Assert.assertTrue(beforeR1Resources.isEmpty());
Assert.assertEquals(1, beforeR2Resources.size());
Assert.assertEquals(2, beforeR3Resources.size());
Assert.assertEquals(3, afterR3Resources.size());
} finally {
if (inventory.tenants().get(tenantId).exists()) {
inventory.tenants().delete(tenantId);
}
}
}
@Test
public void testTimeSnapshots_Query() throws Exception {
String tenantId = "testTimeSnapshots_Query";
try {
Instant beforeCreate = Instant.now();
Thread.sleep(10);
Feeds.Single fs = inventory.tenants().create(Tenant.Blueprint.builder().withId(tenantId).build())
.feeds().create(Feed.Blueprint.builder().withId("feed").build());
fs.resourceTypes()
.create(ResourceType.Blueprint.builder().withId("resourceType").build()).entity();
Instant beforeR1 = Instant.now();
Thread.sleep(10);
fs.resources()
.create(Resource.Blueprint.builder().withId("r1").withResourceTypePath("resourceType").build());
Instant beforeR2 = Instant.now();
Thread.sleep(10);
fs.resources()
.create(Resource.Blueprint.builder().withId("r2").withResourceTypePath("resourceType").build());
Instant beforeR3 = Instant.now();
Thread.sleep(10);
fs.resources()
.create(Resource.Blueprint.builder().withId("r3").withResourceTypePath("resourceType").build());
Instant afterR3 = Instant.now();
Query q = Query.path().with(With.path(CanonicalPath.of().tenant(tenantId).feed("feed").get()))
.with(Related.by(contains))
.with(With.type(Resource.class)).get();
try (Page<Resource> beforeCreateResources = inventory.at(beforeCreate).execute(q, Resource.class,
Pager.none())) {
Assert.assertEquals(0, beforeCreateResources.getTotalSize());
}
try (Page<Resource> beforeR1Resources = inventory.at(beforeR1).execute(q, Resource.class, Pager.none())) {
Assert.assertEquals(0, beforeR1Resources.getTotalSize());
}
try (Page<Resource> beforeR2Resources = inventory.at(beforeR2).execute(q, Resource.class, Pager.none())) {
Assert.assertEquals(1, beforeR2Resources.getTotalSize());
}
try (Page<Resource> beforeR3Resources = inventory.at(beforeR3).execute(q, Resource.class, Pager.none())) {
Assert.assertEquals(2, beforeR3Resources.getTotalSize());
}
try (Page<Resource> afterR3Resources = inventory.at(afterR3).execute(q, Resource.class, Pager.none())) {
Assert.assertEquals(3, afterR3Resources.getTotalSize());
}
//k, now something more radical - all resources everywhere
try (Page<Resource> allResources = inventory.at(Instant.ofEpochMilli(0))
.execute(Query.filter().with(With.type(Resource.class)).get(), Resource.class, Pager.none())) {
Assert.assertEquals(0, allResources.getTotalSize());
}
try (Page<Resource> allResources = inventory.at(beforeCreate)
.execute(Query.filter().with(With.type(Resource.class)).get(), Resource.class, Pager.none())) {
Assert.assertEquals(15, allResources.getTotalSize());
}
} finally {
if (inventory.tenants().get(tenantId).exists()) {
inventory.tenants().delete(tenantId);
}
}
}
@Test
public void testDeleteAtPointInTime() throws Exception {
String tenantId = "testDeleteAtPointInTime";
try {
Tenants.Single t = inventory.tenants().create(Tenant.Blueprint.builder().withId(tenantId).build());
Instant afterCreate = Instant.now();
Thread.sleep(10);
t.update(Tenant.Update.builder().withName("kachny").build());
//now try to delete at afterCreate time
try {
inventory.at(afterCreate).tenants().delete(tenantId);
Assert.fail("Delete before an update should fail.");
} catch (IllegalArgumentException e) {
//good
}
//a delete at "now" should work fine
t.delete();
//eradicate only works if the entity exists
inventory.at(afterCreate).tenants().eradicate(tenantId);
} finally {
if (inventory.tenants().get(tenantId).exists()) {
inventory.tenants().delete(tenantId);
}
}
}
private <T extends AbstractElement<?, U>, U extends AbstractElement.Update>
void runObserverTest(Class<T> entityClass, int nofCreatedRelationships, int nofDeletedRelationships,
Runnable payload) {
List<T> createdEntities = new ArrayList<>();
List<Action.Update<T, U>> updatedEntities = new ArrayList<>();
List<T> deletedEntities = new ArrayList<>();
List<Relationship> createdRelationships = new ArrayList<>();
List<Relationship> deletedRelationships = new ArrayList<>();
Subscription s1 = inventory.observable(Interest.in(entityClass).being(created()))
.subscribe(createdEntities::add);
Subscription s2 = inventory.observable(Interest.in(entityClass).being(updated()))
.subscribe(updatedEntities::add);
Subscription s3 = inventory.observable(Interest.in(entityClass).being(deleted()))
.subscribe(deletedEntities::add);
inventory.observable(Interest.in(Relationship.class).being(created())).subscribe(createdRelationships::add);
inventory.observable(Interest.in(Relationship.class).being(deleted())).subscribe(deletedRelationships::add);
//dummy observer just to check that unsubscription works
inventory.observable(Interest.in(entityClass).being(created())).subscribe((t) -> {
});
payload.run();
Assert.assertEquals(1, createdEntities.size());
Assert.assertEquals(1, updatedEntities.size());
Assert.assertEquals(1, deletedEntities.size());
Assert.assertEquals(nofCreatedRelationships, createdRelationships.size());
Assert.assertEquals(nofDeletedRelationships, deletedRelationships.size());
s1.unsubscribe();
s2.unsubscribe();
s3.unsubscribe();
Assert.assertTrue(inventory.hasObservers(Interest.in(entityClass).being(created())));
Assert.assertFalse(inventory.hasObservers(Interest.in(entityClass).being(updated())));
Assert.assertFalse(inventory.hasObservers(Interest.in(entityClass).being(deleted())));
}
private interface TriFunction<T, U, V, R> {
R apply(T t, U u, V v);
}
private interface TetraFunction<T, U, V, W, R> {
R apply(T t, U u, V v, W w);
}
}