/*
* 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 org.hawkular.inventory.paths.DataRole.OperationType.parameterTypes;
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.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.hawkular.inventory.api.model.DataEntity;
import org.hawkular.inventory.api.model.IdentityHash;
import org.hawkular.inventory.api.model.InventoryStructure;
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.Resource;
import org.hawkular.inventory.api.model.ResourceType;
import org.hawkular.inventory.api.model.StructuredData;
import org.hawkular.inventory.paths.DataRole;
import org.hawkular.inventory.paths.RelativePath;
import org.junit.Assert;
import org.junit.Test;
/**
* @author Lukas Krejci
* @since 0.7.0
*/
public class IdentityHashTest {
@Test
public void testMetricTypeHash() throws Exception {
MetricType.Blueprint mtb =
MetricType.Blueprint.builder(MetricDataType.GAUGE).withId("mt").withUnit(MetricUnit.NONE).build();
InventoryStructure<MetricType.Blueprint> structure = InventoryStructure.of(mtb).build();
String blueprintHash = IdentityHash.of(structure);
String expectedHash = digest(mtb.getId() + mtb.getMetricDataType() + mtb.getUnit());
Assert.assertEquals(expectedHash, blueprintHash);
}
@Test
public void testResourceTypeHashWithNoAppendages() throws Exception {
ResourceType.Blueprint rtb = ResourceType.Blueprint.builder().withId("rt").build();
InventoryStructure<ResourceType.Blueprint> members = InventoryStructure.of(rtb).build();
String blueprintHash = IdentityHash.of(members);
String configSchemaHash = digest(configurationSchema + "null");
String connSchemaHash = digest(connectionConfigurationSchema + "null");
//nullnull is for the undefined config and conn schemas
String expectedHash = digest(configSchemaHash + connSchemaHash + rtb.getId());
Assert.assertEquals(expectedHash, blueprintHash);
}
@SuppressWarnings("Duplicates")
@Test
public void testResourceTypeHashWithAppendages() throws Exception {
DataEntity.Blueprint<DataRole.ResourceType> configSchema = DataEntity.Blueprint
.<DataRole.ResourceType>builder()
.withRole(configurationSchema).withValue(StructuredData.get().integral(5L)).build();
DataEntity.Blueprint<DataRole.ResourceType> connSchema = DataEntity.Blueprint.<DataRole.ResourceType>builder()
.withRole(connectionConfigurationSchema)
.withValue(StructuredData.get().list().addBool(true).addUndefined().build())
.build();
OperationType.Blueprint otb = OperationType.Blueprint.builder().withId("op").build();
DataEntity.Blueprint<DataRole.OperationType> retType = DataEntity.Blueprint
.<DataRole.OperationType>builder()
.withRole(returnType)
.withValue(StructuredData.get().integral(42L)).build();
DataEntity.Blueprint<DataRole.OperationType> paramTypes = DataEntity.Blueprint
.<DataRole.OperationType>builder()
.withRole(parameterTypes)
.withValue(StructuredData.get().string("answer")).build();
ResourceType.Blueprint rtb = ResourceType.Blueprint.builder().withId("rt").build();
InventoryStructure<ResourceType.Blueprint> structure = InventoryStructure.of(rtb).addChild(configSchema)
.addChild(connSchema).startChild(otb).addChild(retType).addChild(paramTypes).end().build();
String configSchemaHash = digest("" + configurationSchema + configSchema.getValue().toJSON());
String connSchemaHash = digest("" + connectionConfigurationSchema + connSchema.getValue().toJSON());
String returnTypeHash = digest("" + returnType + retType.getValue().toJSON());
String parameterTypesHash = digest("" + parameterTypes + paramTypes.getValue()
.toJSON());
String operationTypeHash = digest(returnTypeHash + parameterTypesHash + otb.getId());
String expectedHash = digest(configSchemaHash + connSchemaHash + operationTypeHash + rtb.getId());
String blueprintHash = IdentityHash.of(structure);
Assert.assertEquals(expectedHash, blueprintHash);
}
@SuppressWarnings("Duplicates")
@Test
public void testIdentityHashTree_ResourceTypes() throws Exception {
DataEntity.Blueprint<DataRole.ResourceType> configSchema = DataEntity.Blueprint
.<DataRole.ResourceType>builder()
.withRole(configurationSchema).withValue(StructuredData.get().integral(5L)).build();
DataEntity.Blueprint<DataRole.ResourceType> connSchema = DataEntity.Blueprint.<DataRole.ResourceType>builder()
.withRole(connectionConfigurationSchema)
.withValue(StructuredData.get().list().addBool(true).addUndefined().build())
.build();
OperationType.Blueprint otb = OperationType.Blueprint.builder().withId("op").build();
DataEntity.Blueprint<DataRole.OperationType> retType = DataEntity.Blueprint
.<DataRole.OperationType>builder()
.withRole(returnType)
.withValue(StructuredData.get().integral(42L)).build();
DataEntity.Blueprint<DataRole.OperationType> paramTypes = DataEntity.Blueprint
.<DataRole.OperationType>builder()
.withRole(parameterTypes)
.withValue(StructuredData.get().string("answer")).build();
ResourceType.Blueprint rtb = ResourceType.Blueprint.builder().withId("rt").build();
InventoryStructure<ResourceType.Blueprint> structure = InventoryStructure.of(rtb).addChild(configSchema)
.addChild(connSchema).startChild(otb).addChild(retType).addChild(paramTypes).end().build();
String configSchemaHash = digest("" + configurationSchema + configSchema.getValue().toJSON());
String connSchemaHash = digest("" + connectionConfigurationSchema + connSchema.getValue().toJSON());
String returnTypeHash = digest("" + returnType + retType.getValue().toJSON());
String parameterTypesHash = digest("" + parameterTypes + paramTypes.getValue()
.toJSON());
String operationTypeHash = digest(returnTypeHash + parameterTypesHash + otb.getId());
String resourceTypeHash = digest(configSchemaHash + connSchemaHash + operationTypeHash + rtb.getId());
IdentityHash.Tree treeHash = IdentityHash.treeOf(structure);
Assert.assertEquals(resourceTypeHash, treeHash.getHash());
Assert.assertEquals(RelativePath.empty().get(), treeHash.getPath());
Assert.assertEquals(3, treeHash.getChildren().size());
Assert.assertTrue(treeHash.getChildren().stream()
.filter(c -> RelativePath.to().operationType("op").get().equals(c.getPath()))
.filter(c -> operationTypeHash.equals(c.getHash()))
.findFirst().isPresent());
Assert.assertTrue(treeHash.getChildren().stream()
.filter(c -> RelativePath.to().dataEntity(configurationSchema).get().equals(c.getPath()))
.filter(c -> configSchemaHash.equals(c.getHash()))
.findFirst().isPresent());
Assert.assertTrue(treeHash.getChildren().stream()
.filter(c -> RelativePath.to().dataEntity(connectionConfigurationSchema).get().equals(c.getPath()))
.filter(c -> connSchemaHash.equals(c.getHash()))
.findFirst().isPresent());
Assert.assertTrue(treeHash.getChildren().stream()
.filter(c -> RelativePath.to().operationType("op").get().equals(c.getPath()))
.flatMap(t -> t.getChildren().stream())
.filter(c -> RelativePath.to().operationType("op").data(returnType).get().equals(c.getPath()))
.filter(c -> returnTypeHash.equals(c.getHash()))
.findFirst().isPresent());
Assert.assertTrue(treeHash.getChildren().stream()
.filter(c -> RelativePath.to().operationType("op").get().equals(c.getPath()))
.flatMap(t -> t.getChildren().stream())
.filter(c -> RelativePath.to().operationType("op").data(parameterTypes).get().equals(c.getPath()))
.filter(c -> parameterTypesHash.equals(c.getHash()))
.findFirst().isPresent());
}
@SuppressWarnings("Duplicates")
@Test
public void testIdentityHashTree_Resources() throws Exception {
Resource.Blueprint rb = Resource.Blueprint.builder().withId("res").withResourceTypePath("../rt;RT").build();
Resource.Blueprint crb =
Resource.Blueprint.builder().withId("childRes").withResourceTypePath("../../rt;RT").build();
DataEntity.Blueprint conf = DataEntity.Blueprint.builder().withRole(configuration)
.withValue(StructuredData.get().integral(42L)).build();
InventoryStructure<Resource.Blueprint> structure = InventoryStructure.of(rb).addChild(conf).addChild(crb)
.build();
String confHash = digest("" + configuration + conf.getValue().toJSON());
String dummyConnConfHash = digest("" + connectionConfiguration +
dummyDataBlueprint(connectionConfiguration).getValue().toJSON());
String dummyconfHash = digest("" + configuration + dummyDataBlueprint(configuration).getValue().toJSON());
String childHash = digest(dummyconfHash + dummyConnConfHash + crb.getId());
String resourceHash = digest(confHash + dummyConnConfHash + childHash + rb.getId());
IdentityHash.Tree treeHash = IdentityHash.treeOf(structure);
Assert.assertEquals(resourceHash, treeHash.getHash());
Assert.assertEquals(RelativePath.empty().get(), treeHash.getPath());
//we get a "dummy" hash for non-existant configurations
Assert.assertEquals(3, treeHash.getChildren().size());
Assert.assertTrue(treeHash.getChildren().stream()
.filter(c -> RelativePath.to().resource("childRes").get().equals(c.getPath()))
.filter(c -> childHash.equals(c.getHash()))
.findFirst().isPresent());
Assert.assertTrue(treeHash.getChildren().stream()
.filter(c -> RelativePath.to().dataEntity(configuration).get().equals(c.getPath()))
.filter(c -> confHash.equals(c.getHash()))
.findFirst().isPresent());
}
private String digest(String content) throws NoSuchAlgorithmException {
byte[] digest = MessageDigest.getInstance("SHA-1").digest(content.getBytes(Charset.forName("UTF-8")));
StringBuilder bld = new StringBuilder();
for (byte b : digest) {
bld.append(Integer.toHexString(Byte.toUnsignedInt(b)));
}
return bld.toString();
}
private static <R extends DataRole> DataEntity.Blueprint<R> dummyDataBlueprint(R role) {
return DataEntity.Blueprint.<R>builder().withRole(role).withValue(StructuredData.get().undefined()).build();
}
}