/**
* Copyright (C) 2010-2017 Structr GmbH
*
* This file is part of Structr <http://structr.org>.
*
* Structr is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Structr is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Structr. If not, see <http://www.gnu.org/licenses/>.
*/
package org.structr.schema;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.structr.common.StructrTest;
import org.structr.common.error.ErrorToken;
import org.structr.common.error.FrameworkException;
import org.structr.core.GraphObject;
import org.structr.core.app.StructrApp;
import org.structr.core.entity.AbstractNode;
import org.structr.core.entity.Group;
import org.structr.core.entity.SchemaNode;
import org.structr.core.entity.SchemaRelationshipNode;
import org.structr.core.entity.TestOne;
import org.structr.core.entity.TestTwelve;
import org.structr.core.graph.NodeAttribute;
import org.structr.core.graph.NodeInterface;
import org.structr.core.graph.Tx;
import org.structr.core.property.EnumProperty;
import org.structr.core.property.PropertyKey;
import org.structr.core.property.StringProperty;
/**
*
*
*/
public class ValidationTest extends StructrTest {
private static final Logger logger = LoggerFactory.getLogger(ValidationTest.class.getName());
@Test
public void testUUIDValidation() {
try (final Tx tx = app.tx()) {
// test 31 characters
app.create(TestOne.class, new NodeAttribute<>(GraphObject.id, "1234567890123456789012345678901"));
tx.success();
fail("UUID format constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid UUID uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid UUID uniqueness validation result", "id", token.getProperty());
assertEquals("Invalid UUID uniqueness validation result", "TestOne", token.getType());
assertEquals("Invalid UUID uniqueness validation result", "must_match", token.getToken());
}
try (final Tx tx = app.tx()) {
// test 33 characters
app.create(TestOne.class, new NodeAttribute<>(GraphObject.id, "123456789012345678901234567890123"));
tx.success();
fail("UUID format constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid UUID uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid UUID uniqueness validation result", "id", token.getProperty());
assertEquals("Invalid UUID uniqueness validation result", "TestOne", token.getType());
assertEquals("Invalid UUID uniqueness validation result", "must_match", token.getToken());
}
try (final Tx tx = app.tx()) {
// test 40 characters
app.create(TestOne.class, new NodeAttribute<>(GraphObject.id, "1234567890123456789012345678901234567890"));
tx.success();
fail("UUID format constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid UUID uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid UUID uniqueness validation result", "id", token.getProperty());
assertEquals("Invalid UUID uniqueness validation result", "TestOne", token.getType());
assertEquals("Invalid UUID uniqueness validation result", "must_match", token.getToken());
}
try (final Tx tx = app.tx()) {
// test wrong characters
app.create(TestOne.class, new NodeAttribute<>(GraphObject.id, "123456789012345678g0123456789012"));
tx.success();
fail("UUID format constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid UUID uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid UUID uniqueness validation result", "id", token.getProperty());
assertEquals("Invalid UUID uniqueness validation result", "TestOne", token.getType());
assertEquals("Invalid UUID uniqueness validation result", "must_match", token.getToken());
}
try (final Tx tx = app.tx()) {
// test wrong characters
app.create(TestOne.class, new NodeAttribute<>(GraphObject.id, "!bcdefabcdefabcdefabcdefabcdefab"));
tx.success();
fail("UUID format constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid UUID uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid UUID uniqueness validation result", "id", token.getProperty());
assertEquals("Invalid UUID uniqueness validation result", "TestOne", token.getType());
assertEquals("Invalid UUID uniqueness validation result", "must_match", token.getToken());
}
try (final Tx tx = app.tx()) {
// test wrong characters
app.create(TestOne.class, new NodeAttribute<>(GraphObject.id, "sdfkgjh34t"));
tx.success();
fail("UUID format constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid UUID uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid UUID uniqueness validation result", "id", token.getProperty());
assertEquals("Invalid UUID uniqueness validation result", "TestOne", token.getType());
assertEquals("Invalid UUID uniqueness validation result", "must_match", token.getToken());
}
try (final Tx tx = app.tx()) {
// test all allowed characters
app.create(TestOne.class, new NodeAttribute<>(GraphObject.id, "abcdef1234567890ABCDEF1234567890"));
tx.success();
} catch (FrameworkException fex) {
fail("UUID validation failed for valid result.");
}
try (final Tx tx = app.tx()) {
app.create(TestOne.class, new NodeAttribute<>(GraphObject.id, "xy-"));
tx.success();
fail("UUID format constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid UUID uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid UUID uniqueness validation result", "id", token.getProperty());
assertEquals("Invalid UUID uniqueness validation result", "TestOne", token.getType());
assertEquals("Invalid UUID uniqueness validation result", "must_match", token.getToken());
}
try (final Tx tx = app.tx()) {
app.create(TestOne.class, new NodeAttribute<>(GraphObject.id, ""));
tx.success();
fail("UUID not empty constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token1 = tokens.get(0);
final ErrorToken token2 = tokens.get(1);
assertEquals("Invalid uniqueness validation result", 2, tokens.size());
assertEquals("Invalid UUID uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid UUID uniqueness validation result", "id", token1.getProperty());
assertEquals("Invalid UUID uniqueness validation result", "TestOne", token1.getType());
assertEquals("Invalid UUID uniqueness validation result", "must_not_be_empty", token1.getToken());
assertEquals("Invalid UUID uniqueness validation result", "id", token2.getProperty());
assertEquals("Invalid UUID uniqueness validation result", "TestOne", token2.getType());
assertEquals("Invalid UUID uniqueness validation result", "must_match", token2.getToken());
}
}
@Test
public void testSchemaNodeNameValidation() {
try (final Tx tx = app.tx()) {
app.create(SchemaNode.class, "lowercase");
tx.success();
fail("SchemaNode name constraint violation!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid constraint violation error token", 422, fex.getStatus());
assertEquals("Invalid constraint violation error token", "name", token.getProperty());
assertEquals("Invalid constraint violation error token", "SchemaNode", token.getType());
assertEquals("Invalid constraint violation error token", "must_match", token.getToken());
}
try (final Tx tx = app.tx()) {
app.create(SchemaNode.class, "7NumberAsFirstChar");
tx.success();
fail("SchemaNode name constraint violation!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid constraint violation error token", 422, fex.getStatus());
assertEquals("Invalid constraint violation error token", "name", token.getProperty());
assertEquals("Invalid constraint violation error token", "SchemaNode", token.getType());
assertEquals("Invalid constraint violation error token", "must_match", token.getToken());
}
try (final Tx tx = app.tx()) {
app.create(SchemaNode.class, "7Number");
tx.success();
fail("SchemaNode name constraint violation!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid constraint violation error token", 422, fex.getStatus());
assertEquals("Invalid constraint violation error token", "name", token.getProperty());
assertEquals("Invalid constraint violation error token", "SchemaNode", token.getType());
assertEquals("Invalid constraint violation error token", "must_match", token.getToken());
}
try (final Tx tx = app.tx()) {
app.create(SchemaNode.class, "7Number");
tx.success();
fail("SchemaNode name constraint violation!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid constraint violation error token", 422, fex.getStatus());
assertEquals("Invalid constraint violation error token", "name", token.getProperty());
assertEquals("Invalid constraint violation error token", "SchemaNode", token.getType());
assertEquals("Invalid constraint violation error token", "must_match", token.getToken());
}
try (final Tx tx = app.tx()) {
app.create(SchemaNode.class, "Valid");
app.create(SchemaNode.class, "Valid");
tx.success();
fail("SchemaNode uniqueness constraint violation!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid constraint violation error token", 422, fex.getStatus());
assertEquals("Invalid constraint violation error token", "name", token.getProperty());
assertEquals("Invalid constraint violation error token", "SchemaNode", token.getType());
assertEquals("Invalid constraint violation error token", "already_taken", token.getToken());
}
}
@Test
public void testGlobalUniqueness() {
try (final Tx tx = app.tx()) {
app.create(SchemaNode.class, new NodeAttribute<>(AbstractNode.name, "Test"));
tx.success();
} catch (FrameworkException fex) {
fail("Unexpected exception.");
}
final Class testType = StructrApp.getConfiguration().getNodeEntityClass("Test");
if (testType != null) {
String uuid = null;
try (final Tx tx = app.tx()) {
uuid = app.create(testType, new NodeAttribute<>(GraphObject.id, "00000000000000000000000000000000")).getUuid();
tx.success();
} catch (FrameworkException fex) {
fail("Unexpected exception.");
}
for (int i=0; i<5; i++) {
try (final Tx tx = app.tx()) {
app.create(testType, new NodeAttribute<>(GraphObject.id, "00000000000000000000000000000000"));
tx.success();
fail("UUID uniqueness constraint violated!");
} catch (FrameworkException fex) {
final ErrorToken token = fex.getErrorBuffer().getErrorTokens().get(0);
assertEquals("Invalid UUID uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid UUID uniqueness validation result", "id", token.getProperty());
assertEquals("Invalid UUID uniqueness validation result", "Test", token.getType());
assertEquals("Invalid UUID uniqueness validation result", "already_taken", token.getToken());
assertEquals("Invalid UUID uniqueness validation result", uuid, token.getDetail());
}
}
}
}
@Test
public void testConcurrentValidation() {
final int count = 100;
try (final Tx tx = app.tx()) {
app.create(SchemaNode.class,
new NodeAttribute(SchemaNode.name, "Item"),
new NodeAttribute(new StringProperty("_name"), "+String!")
);
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
fail("Unexpected exception.");
}
final Class type = StructrApp.getConfiguration().getNodeEntityClass("Item");
assertNotNull(type);
final PropertyKey name = StructrApp.getConfiguration().getPropertyKeyForJSONName(type, "name", false);
assertNotNull(name);
final Runnable tester = new Runnable() {
@Override
public void run() {
for (int i=0; i<count; i++) {
// testing must be done in an isolated transaction
try (final Tx tx = app.tx()) {
app.create(type, "Item" + i);
tx.success();
} catch (FrameworkException ignore) {}
}
}
};
// submit three test instances
final ExecutorService executor = Executors.newCachedThreadPool();
final Future f1 = executor.submit(tester);
final Future f2 = executor.submit(tester);
final Future f3 = executor.submit(tester);
try {
f1.get();
f2.get();
f3.get();
} catch (Throwable ex) {}
List<GraphObject> result = null;
try (final Tx tx = app.tx()) {
result = app.nodeQuery(type).getAsList();
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
fail("Unexpected exception.");
}
// verify that only count entities have been created.
assertEquals("Invalid concurrent validation result", count, result.size());
executor.shutdownNow();
}
@Test
public void testConcurrentValidationWithInheritance() {
final int count = 100;
try (final Tx tx = app.tx()) {
app.create(SchemaNode.class,
new NodeAttribute(SchemaNode.name, "Item"),
new NodeAttribute(new StringProperty("_name"), "+String!")
);
app.create(SchemaNode.class,
new NodeAttribute(SchemaNode.name, "ItemDerived"),
new NodeAttribute(SchemaNode.extendsClass, "org.structr.dynamic.Item")
);
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
fail("Unexpected exception.");
}
final Class baseType = StructrApp.getConfiguration().getNodeEntityClass("Item");
final Class derivedType = StructrApp.getConfiguration().getNodeEntityClass("ItemDerived");
assertNotNull(baseType);
assertNotNull(derivedType);
final PropertyKey name = StructrApp.getConfiguration().getPropertyKeyForJSONName(baseType, "name", false);
assertNotNull(name);
final Runnable tester = new Runnable() {
@Override
public void run() {
for (int i=0; i<count; i++) {
// testing must be done in an isolated transaction
try (final Tx tx = app.tx()) {
if (Math.random() < 0.5) {
app.create(derivedType, "Item" + i);
} else {
app.create(baseType, "Item" + i);
}
tx.success();
} catch (FrameworkException ignore) {}
}
}
};
// submit three test instances
final ExecutorService executor = Executors.newCachedThreadPool();
final Future f1 = executor.submit(tester);
final Future f2 = executor.submit(tester);
final Future f3 = executor.submit(tester);
try {
f1.get();
f2.get();
f3.get();
} catch (Throwable ex) {}
List<GraphObject> result = null;
try (final Tx tx = app.tx()) {
result = app.nodeQuery(baseType).getAsList();
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
fail("Unexpected exception.");
}
// verify that only count entities have been created.
assertEquals("Invalid concurrent validation result", count, result.size());
executor.shutdownNow();
}
@Test
public void testConcurrentValidationOnDynamicProperty() {
final int count = 100;
try (final Tx tx = app.tx()) {
app.create(SchemaNode.class,
new NodeAttribute(SchemaNode.name, "Item"),
new NodeAttribute(new StringProperty("_testXYZ"), "+String!")
);
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
fail("Unexpected exception.");
}
final Class type = StructrApp.getConfiguration().getNodeEntityClass("Item");
assertNotNull(type);
final PropertyKey testXYZ = StructrApp.getConfiguration().getPropertyKeyForJSONName(type, "testXYZ", false);
assertNotNull(testXYZ);
final Runnable tester = new Runnable() {
@Override
public void run() {
for (int i=0; i<count; i++) {
// testing must be done in an isolated transaction
try (final Tx tx = app.tx()) {
app.create(type, new NodeAttribute(testXYZ, "Item" + i));
tx.success();
} catch (FrameworkException fex) {}
}
}
};
// submit three test instances
final ExecutorService executor = Executors.newCachedThreadPool();
final Future f1 = executor.submit(tester);
final Future f2 = executor.submit(tester);
final Future f3 = executor.submit(tester);
try {
f1.get();
f2.get();
f3.get();
} catch (Throwable ex) {}
List<GraphObject> result = null;
try (final Tx tx = app.tx()) {
result = app.nodeQuery(type).getAsList();
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
fail("Unexpected exception.");
}
// verify that only count entities have been created.
assertEquals("Invalid concurrent validation result", count, result.size());
executor.shutdownNow();
}
@Test
public void testNamePropertyValidation() {
// The goal of this test is to ensure that validation
// only includes actual derived classes.
// override name property
try (final Tx tx = app.tx()) {
// create some nodes with identical names
app.create(Group.class, "unique");
app.create(TestOne.class, "unique");
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
fail("Unexpected exception.");
}
try (final Tx tx = app.tx()) {
// should succeed
app.create(TestTwelve.class, new NodeAttribute<>(AbstractNode.name, "unique"));
tx.success();
} catch (FrameworkException fex) {
fail("Uniqueness constraint includes wrong type(s)!");
}
}
// ----- string property validation tests -----
@Test
public void testEmptyStringPropertyValidationWithEmptyStrings() {
try (final Tx tx = app.tx()) {
app.create(SchemaNode.class,
new NodeAttribute<>(AbstractNode.name, "Test"),
new NodeAttribute<>(new StringProperty("_testUnique"), "String!")
);
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
fail("Unexpected exception.");
}
final Class testType = StructrApp.getConfiguration().getNodeEntityClass("Test");
if (testType != null) {
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "testUnique");
if (key != null) {
String uuid = null;
try (final Tx tx = app.tx()) {
// for string properties, null equals the empty string
uuid = app.create(testType, new NodeAttribute<>(key, "")).getUuid();
app.create(testType, new NodeAttribute<>(key, ""));
tx.success();
fail("Uniqueness constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid uniqueness validation result", "testUnique", token.getProperty());
assertEquals("Invalid uniqueness validation result", "Test", token.getType());
assertEquals("Invalid uniqueness validation result", "already_taken", token.getToken());
assertEquals("Invalid uniqueness validation result", uuid, token.getDetail());
}
}
}
}
@Test
public void testEmptyStringPropertyValidationWithNulls() {
try (final Tx tx = app.tx()) {
app.create(SchemaNode.class,
new NodeAttribute<>(AbstractNode.name, "Test"),
new NodeAttribute<>(new StringProperty("_testUnique"), "String!")
);
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
fail("Unexpected exception.");
}
final Class testType = StructrApp.getConfiguration().getNodeEntityClass("Test");
if (testType != null) {
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "testUnique");
if (key != null) {
String uuid = null;
try (final Tx tx = app.tx()) {
// for string properties, null equals the empty string
uuid = app.create(testType, new NodeAttribute<>(key, null)).getUuid();
app.create(testType, new NodeAttribute<>(key, null));
tx.success();
} catch (FrameworkException fex) {
fail("Invalid uniqueness constraint validation for null values!");
}
}
}
}
@Test
public void testStringPropertyUniqueness() {
try (final Tx tx = app.tx()) {
app.create(SchemaNode.class,
new NodeAttribute<>(AbstractNode.name, "Test"),
new NodeAttribute<>(new StringProperty("_testUnique"), "String!")
);
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
fail("Unexpected exception.");
}
final Class testType = StructrApp.getConfiguration().getNodeEntityClass("Test");
if (testType != null) {
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "testUnique");
if (key != null) {
try (final Tx tx = app.tx()) {
// key must be unique, but can empty
app.create(testType, new NodeAttribute<>(key, "unique"));
app.create(testType, new NodeAttribute<>(key, ""));
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
fail("Unexpected exception.");
}
for (int i=0; i<5; i++) {
try (final Tx tx = app.tx()) {
app.create(testType, new NodeAttribute<>(key, "unique"));
tx.success();
fail("Uniqueness constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid uniqueness validation result", "testUnique", token.getProperty());
assertEquals("Invalid uniqueness validation result", "Test", token.getType());
assertEquals("Invalid uniqueness validation result", "already_taken", token.getToken());
}
}
}
}
}
@Test
public void testInheritedStringPropertyUniqueness() {
try (final Tx tx = app.tx()) {
final SchemaNode testType = app.create(SchemaNode.class,
new NodeAttribute<>(AbstractNode.name, "Test"),
new NodeAttribute<>(new StringProperty("_testUnique"), "String!")
);
app.create(SchemaNode.class,
new NodeAttribute<>(AbstractNode.name, "TestDerived"),
new NodeAttribute<>(SchemaNode.extendsClass, "org.structr.dynamic.Test")
);
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
fail("Unexpected exception.");
}
final Class testType = StructrApp.getConfiguration().getNodeEntityClass("TestDerived");
if (testType != null) {
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "testUnique");
if (key != null) {
try (final Tx tx = app.tx()) {
// key must be unique, but can empty
app.create(testType, new NodeAttribute<>(key, "unique"));
app.create(testType, new NodeAttribute<>(key, ""));
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
fail("Unexpected exception.");
}
for (int i=0; i<5; i++) {
try (final Tx tx = app.tx()) {
app.create(testType, new NodeAttribute<>(key, "unique"));
tx.success();
fail("Uniqueness constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid uniqueness validation result", "testUnique", token.getProperty());
assertEquals("Invalid uniqueness validation result", "TestDerived", token.getType());
assertEquals("Invalid uniqueness validation result", "already_taken", token.getToken());
}
}
}
}
}
@Test
public void testStringPropertyUniquenessAgain() {
try (final Tx tx = app.tx()) {
app.create(SchemaNode.class,
new NodeAttribute<>(AbstractNode.name, "Test"),
new NodeAttribute<>(new StringProperty("_testUnique"), "String!")
);
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
fail("Unexpected exception.");
}
final Class testType = StructrApp.getConfiguration().getNodeEntityClass("Test");
if (testType != null) {
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "testUnique");
if (key != null) {
final Random random = new Random();
try (final Tx tx = app.tx()) {
app.create(testType, new NodeAttribute<>(AbstractNode.name, "unique06"), new NodeAttribute<>(key, "unique00"));
app.create(testType, new NodeAttribute<>(AbstractNode.name, "unique05"), new NodeAttribute<>(key, "unique01"));
app.create(testType, new NodeAttribute<>(AbstractNode.name, "unique04"), new NodeAttribute<>(key, "unique02"));
app.create(testType, new NodeAttribute<>(AbstractNode.name, "unique03"), new NodeAttribute<>(key, "unique03"));
app.create(testType, new NodeAttribute<>(AbstractNode.name, "unique02"), new NodeAttribute<>(key, "unique04"));
app.create(testType, new NodeAttribute<>(AbstractNode.name, "unique01"), new NodeAttribute<>(key, "unique05"));
app.create(testType, new NodeAttribute<>(AbstractNode.name, "unique00"), new NodeAttribute<>(key, "unique06"));
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
fail("Unexpected exception.");
}
for (int i=0; i<5; i++) {
try (final Tx tx = app.tx()) {
app.create(testType, new NodeAttribute<>(key, "unique0" + random.nextInt(7)));
tx.success();
fail("Uniqueness constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid uniqueness validation result", "testUnique", token.getProperty());
assertEquals("Invalid uniqueness validation result", "Test", token.getType());
assertEquals("Invalid uniqueness validation result", "already_taken", token.getToken());
}
}
}
}
}
@Test
public void testStringPropertyNotNull() {
try (final Tx tx = app.tx()) {
app.create(SchemaNode.class,
new NodeAttribute<>(AbstractNode.name, "Test"),
new NodeAttribute<>(new StringProperty("_nonempty"), "+String")
);
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
fail("Unexpected exception.");
}
final Class testType = StructrApp.getConfiguration().getNodeEntityClass("Test");
if (testType != null) {
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "nonempty");
if (key != null) {
try (final Tx tx = app.tx()) {
app.create(testType, new NodeAttribute<>(key, null));
tx.success();
fail("Not empty constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid uniqueness validation result", "nonempty", token.getProperty());
assertEquals("Invalid uniqueness validation result", "Test", token.getType());
assertEquals("Invalid uniqueness validation result", "must_not_be_empty", token.getToken());
}
}
}
}
@Test
public void testStringPropertyRegexMatch() {
final String keyName = "regex";
final Class testType = createTypeWithProperty("Test", keyName, "String([a-zA-Z0-9]+)");
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, keyName);
if (key != null) {
try (final Tx tx = app.tx()) {
app.create(testType, new NodeAttribute<>(key, "abcdefg_"));
tx.success();
fail("Regex constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid regex validation result", 422, fex.getStatus());
assertEquals("Invalid regex validation result", "regex", token.getProperty());
assertEquals("Invalid regex validation result", "Test", token.getType());
assertEquals("Invalid regex validation result", "must_match", token.getToken());
}
}
}
// ----- array property validation tests -----
@Test
public void testArrayPropertyNotNullValidation() {
final String keyName = "stringArray";
final Class testType = createTypeWithProperty("Test", keyName, "+String[]");
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, keyName);
if (key != null) {
try (final Tx tx = app.tx()) {
app.create(testType, new NodeAttribute<>(key, null));
tx.success();
fail("Array property validation failed!");
} catch (FrameworkException fex) {
final ErrorToken token = fex.getErrorBuffer().getErrorTokens().get(0);
assertEquals("Invalid uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid uniqueness validation result", keyName, token.getProperty());
assertEquals("Invalid uniqueness validation result", "Test", token.getType());
assertEquals("Invalid uniqueness validation result", "must_not_be_empty", token.getToken());
}
}
}
@Test
public void testArrayPropertyUniquenessValidation() {
final String keyName = "stringArray";
final Class<NodeInterface> testType = createTypeWithProperty("Test", keyName, "String[]!");
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, keyName);
String uuid1 = null;
String uuid2 = null;
if (key != null) {
// test failure
try (final Tx tx = app.tx()) {
uuid1 = app.create(testType, new NodeAttribute<>(key, new String[] { "one", "two" } )).getUuid();
uuid2 = app.create(testType, new NodeAttribute<>(key, new String[] { "one", "two" } )).getUuid();
tx.success();
fail("Array property validation failed!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid uniqueness validation result", keyName, token.getProperty());
assertEquals("Invalid uniqueness validation result", "Test", token.getType());
assertEquals("Invalid uniqueness validation result", "already_taken", token.getToken());
assertEquals("Invalid uniqueness validation result", uuid1, token.getDetail());
}
removeInstances(testType);
// test success
try (final Tx tx = app.tx()) {
app.create(testType, new NodeAttribute<>(key, new String[] { "one" } ));
app.create(testType, new NodeAttribute<>(key, new String[] { "one", "two" } ));
app.create(testType, new NodeAttribute<>(key, new String[] { "one", "two", "three" } ));
tx.success();
} catch (FrameworkException fex) {
fail("Array property validation error!");
}
}
}
// ----- boolean property validation tests -----
@Test
public void testBooleanPropertyNotNullValidation() {
final String keyName = "notNull";
final Class<NodeInterface> testType = createTypeWithProperty("Test", keyName, "+Boolean");
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, keyName);
if (key != null) {
// test failure
try (final Tx tx = app.tx()) {
/* Boolean properties are special. A boolean property will
* _always_ have a value, i.e. "null" equals "false" and
* will be returned as false.
*
* => a boolean property value can never be null!
*/
app.create(testType, new NodeAttribute<>(key, null));
app.create(testType, new NodeAttribute<>(key, true));
app.create(testType, new NodeAttribute<>(key, false));
tx.success();
} catch (FrameworkException fex) {
fail("Unexpected array property validation exception.");
}
}
}
@Test
public void testBooleanPropertyUniquenessValidation() {
final String keyName = "unique";
final Class<NodeInterface> testType = createTypeWithProperty("Test", keyName, "Boolean!");
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, keyName);
String uuid = null;
if (key != null) {
// test failure
try (final Tx tx = app.tx()) {
uuid = app.create(testType, new NodeAttribute<>(key, true)).getUuid();
app.create(testType, new NodeAttribute<>(key, false));
app.create(testType, new NodeAttribute<>(key, true));
tx.success();
fail("Array property uniqueness constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid uniqueness validation result", 1, tokens.size());
assertEquals("Invalid uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid uniqueness validation result", keyName, token.getProperty());
assertEquals("Invalid uniqueness validation result", "Test", token.getType());
assertEquals("Invalid uniqueness validation result", "already_taken", token.getToken());
assertEquals("Invalid uniqueness validation result", uuid, token.getDetail());
}
}
}
// ----- date property validation tests -----
@Test
public void testDatePropertyUniquenessValidation() {
final String keyName = "unique";
final Class<NodeInterface> testType = createTypeWithProperty("Test", keyName, "Date!");
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, keyName);
final Date date = new Date();
String uuid = null;
if (key != null) {
// test failure
try (final Tx tx = app.tx()) {
uuid = app.create(testType, new NodeAttribute<>(key, date)).getUuid();
app.create(testType, new NodeAttribute<>(key, date));
tx.success();
fail("Date property uniqueness constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid date validation result", 1, tokens.size());
assertEquals("Invalid date validation result", 422, fex.getStatus());
assertEquals("Invalid date validation result", keyName, token.getProperty());
assertEquals("Invalid date validation result", "Test", token.getType());
assertEquals("Invalid date validation result", "already_taken", token.getToken());
assertEquals("Invalid date validation result", uuid, token.getDetail());
}
}
}
@Test
public void testDatePropertyNotNullValidation() {
final String keyName = "notnull";
final Class<NodeInterface> testType = createTypeWithProperty("Test", keyName, "+Date");
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, keyName);
if (key != null) {
// test failure
try (final Tx tx = app.tx()) {
app.create(testType, new NodeAttribute<>(key, null));
tx.success();
fail("Date property not null constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid date validation result", 1, tokens.size());
assertEquals("Invalid date validation result", 422, fex.getStatus());
assertEquals("Invalid date validation result", keyName, token.getProperty());
assertEquals("Invalid date validation result", "Test", token.getType());
assertEquals("Invalid date validation result", "must_not_be_empty", token.getToken());
}
}
}
// ----- double property validation tests -----
@Test
public void testDoublePropertyUniquenessValidation() {
final String keyName = "unique";
final Class<NodeInterface> testType = createTypeWithProperty("Test", keyName, "Double!");
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, keyName);
String uuid = null;
if (key != null) {
// test failure
try (final Tx tx = app.tx()) {
uuid = app.create(testType, new NodeAttribute<>(key, 0.123)).getUuid();
app.create(testType, new NodeAttribute<>(key, 0.123));
tx.success();
fail("Double property uniqueness constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid double validation result", 1, tokens.size());
assertEquals("Invalid double validation result", 422, fex.getStatus());
assertEquals("Invalid double validation result", keyName, token.getProperty());
assertEquals("Invalid double validation result", "Test", token.getType());
assertEquals("Invalid double validation result", "already_taken", token.getToken());
assertEquals("Invalid double validation result", uuid, token.getDetail());
}
}
}
@Test
public void testDoublePropertyNotNullValidation() {
final String keyName = "notnull";
final Class<NodeInterface> testType = createTypeWithProperty("Test", keyName, "+Double");
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, keyName);
if (key != null) {
// test failure
try (final Tx tx = app.tx()) {
app.create(testType, new NodeAttribute<>(key, null));
tx.success();
fail("Double property not null constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid double validation result", 1, tokens.size());
assertEquals("Invalid double validation result", 422, fex.getStatus());
assertEquals("Invalid double validation result", keyName, token.getProperty());
assertEquals("Invalid double validation result", "Test", token.getType());
assertEquals("Invalid double validation result", "must_not_be_empty", token.getToken());
}
}
}
@Test
public void testDoublePropertyRangeValidation1() {
final Class<NodeInterface> testType = createTypeWithProperty("Test", "range1", "+Double([1,5])");
final PropertyKey range1 = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "range1");
checkRangeSuccess(testType, range1, 1.0);
checkRangeSuccess(testType, range1, 1.00001);
checkRangeSuccess(testType, range1, 1.1);
checkRangeSuccess(testType, range1, 2.2);
checkRangeSuccess(testType, range1, 3.3);
checkRangeSuccess(testType, range1, 4.4);
checkRangeSuccess(testType, range1, 4.999999);
checkRangeSuccess(testType, range1, 5.0);
try { checkRangeError(testType, range1, -0.00001); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 0.00001); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 0.51); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 5.00000001); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
}
@Test
public void testDoublePropertyRangeValidation2() {
final Class<NodeInterface> testType = createTypeWithProperty("Test", "range1", "+Double([0.0,0.5])");
final PropertyKey range1 = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "range1");
checkRangeSuccess(testType, range1, -0.0);
checkRangeSuccess(testType, range1, 0.0);
checkRangeSuccess(testType, range1, 0.00001);
checkRangeSuccess(testType, range1, 0.1);
checkRangeSuccess(testType, range1, 0.2);
checkRangeSuccess(testType, range1, 0.3);
checkRangeSuccess(testType, range1, 0.4);
checkRangeSuccess(testType, range1, 0.49999);
checkRangeSuccess(testType, range1, 0.5);
try { checkRangeError(testType, range1, -0.00001); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 0.51); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 1.51); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
}
@Test
public void testDoublePropertyRangeValidation3() {
final Class<NodeInterface> testType = createTypeWithProperty("Test", "range1", "+Double([0.0,0.5[)");
final PropertyKey range1 = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "range1");
checkRangeSuccess(testType, range1, -0.0);
checkRangeSuccess(testType, range1, 0.0);
checkRangeSuccess(testType, range1, 0.00001);
checkRangeSuccess(testType, range1, 0.1);
checkRangeSuccess(testType, range1, 0.2);
checkRangeSuccess(testType, range1, 0.3);
checkRangeSuccess(testType, range1, 0.4);
checkRangeSuccess(testType, range1, 0.49999);
try { checkRangeError(testType, range1, -0.00001); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 0.5); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 0.51); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 1.51); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
}
@Test
public void testDoublePropertyRangeValidation4() {
final Class<NodeInterface> testType = createTypeWithProperty("Test", "range1", "+Double(]0.0,0.5])");
final PropertyKey range1 = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "range1");
checkRangeSuccess(testType, range1, 0.00001);
checkRangeSuccess(testType, range1, 0.1);
checkRangeSuccess(testType, range1, 0.2);
checkRangeSuccess(testType, range1, 0.3);
checkRangeSuccess(testType, range1, 0.4);
checkRangeSuccess(testType, range1, 0.49999);
checkRangeSuccess(testType, range1, 0.5);
try { checkRangeError(testType, range1, -0.0); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 0.0); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, -0.00001); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 0.51); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 1.51); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
}
@Test
public void testDoublePropertyRangeValidation5() {
final Class<NodeInterface> testType = createTypeWithProperty("Test", "range1", "+Double(]0.0,0.5[)");
final PropertyKey range1 = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "range1");
checkRangeSuccess(testType, range1, 0.00001);
checkRangeSuccess(testType, range1, 0.1);
checkRangeSuccess(testType, range1, 0.2);
checkRangeSuccess(testType, range1, 0.3);
checkRangeSuccess(testType, range1, 0.4);
checkRangeSuccess(testType, range1, 0.49999);
try { checkRangeError(testType, range1, -0.0); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 0.0); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, -0.00001); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 0.51); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 1.51); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 5.0); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
}
// ----- enum property validation tests -----
@Test
public void testEnumPropertyUniquenessValidation() {
final String keyName = "unique";
final Class<NodeInterface> testType = createTypeWithProperty("Test", keyName, "Enum(one, two, three)!");
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, keyName);
String uuid = null;
if (key != null) {
// test failure
try (final Tx tx = app.tx()) {
final Object value = ((EnumProperty)key).getEnumType().getEnumConstants()[0];
uuid = app.create(testType, new NodeAttribute<>(key, value)).getUuid();
app.create(testType, new NodeAttribute<>(key, value));
tx.success();
fail("Enum property uniqueness constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid enum validation result", 1, tokens.size());
assertEquals("Invalid enum validation result", 422, fex.getStatus());
assertEquals("Invalid enum validation result", keyName, token.getProperty());
assertEquals("Invalid enum validation result", "Test", token.getType());
assertEquals("Invalid enum validation result", "already_taken", token.getToken());
assertEquals("Invalid enum validation result", uuid, token.getDetail());
}
}
}
@Test
public void testEnumPropertyNotNullValidation() {
final String keyName = "notnull";
final Class<NodeInterface> testType = createTypeWithProperty("Test", keyName, "+Enum(one, two, three)");
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, keyName);
// test failure
try (final Tx tx = app.tx()) {
app.create(testType, new NodeAttribute<>(key, null));
tx.success();
fail("Enum property not null constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid enum validation result", 1, tokens.size());
assertEquals("Invalid enum validation result", 422, fex.getStatus());
assertEquals("Invalid enum validation result", keyName, token.getProperty());
assertEquals("Invalid enum validation result", "Test", token.getType());
assertEquals("Invalid enum validation result", "must_not_be_empty", token.getToken());
}
}
// ----- int property validation tests -----
@Test
public void testIntPropertyUniquenessValidation() {
final String keyName = "unique";
final Class<NodeInterface> testType = createTypeWithProperty("Test", keyName, "Integer!");
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, keyName);
String uuid = null;
if (key != null) {
// test failure
try (final Tx tx = app.tx()) {
uuid = app.create(testType, new NodeAttribute<>(key, 42)).getUuid();
app.create(testType, new NodeAttribute<>(key, 42));
tx.success();
fail("Int property uniqueness constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid int validation result", 1, tokens.size());
assertEquals("Invalid int validation result", 422, fex.getStatus());
assertEquals("Invalid int validation result", keyName, token.getProperty());
assertEquals("Invalid int validation result", "Test", token.getType());
assertEquals("Invalid int validation result", "already_taken", token.getToken());
assertEquals("Invalid int validation result", uuid, token.getDetail());
}
}
}
@Test
public void testIntPropertyNotNullValidation() {
final String keyName = "notnull";
final Class<NodeInterface> testType = createTypeWithProperty("Test", keyName, "+Integer");
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, keyName);
if (key != null) {
// test failure
try (final Tx tx = app.tx()) {
app.create(testType, new NodeAttribute<>(key, null));
tx.success();
fail("Int property not null constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid int validation result", 1, tokens.size());
assertEquals("Invalid int validation result", 422, fex.getStatus());
assertEquals("Invalid int validation result", keyName, token.getProperty());
assertEquals("Invalid int validation result", "Test", token.getType());
assertEquals("Invalid int validation result", "must_not_be_empty", token.getToken());
}
}
}
@Test
public void testIntPropertyRangeValidation1() {
final Class<NodeInterface> testType = createTypeWithProperty("Test", "range1", "+Integer([1,5])");
final PropertyKey range1 = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "range1");
checkRangeSuccess(testType, range1, 1);
checkRangeSuccess(testType, range1, 2);
checkRangeSuccess(testType, range1, 3);
checkRangeSuccess(testType, range1, 4);
checkRangeSuccess(testType, range1, 5);
try { checkRangeError(testType, range1, -0); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 0); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 6); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
}
@Test
public void testIntPropertyRangeValidation3() {
final Class<NodeInterface> testType = createTypeWithProperty("Test", "range1", "+Integer([0,5[)");
final PropertyKey range1 = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "range1");
checkRangeSuccess(testType, range1, -0);
checkRangeSuccess(testType, range1, 0);
checkRangeSuccess(testType, range1, 1);
checkRangeSuccess(testType, range1, 2);
checkRangeSuccess(testType, range1, 3);
checkRangeSuccess(testType, range1, 4);
try { checkRangeError(testType, range1, 5); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 6); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
}
@Test
public void testIntPropertyRangeValidation4() {
final Class<NodeInterface> testType = createTypeWithProperty("Test", "range1", "+Integer(]0,5])");
final PropertyKey range1 = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "range1");
checkRangeSuccess(testType, range1, 1);
checkRangeSuccess(testType, range1, 2);
checkRangeSuccess(testType, range1, 3);
checkRangeSuccess(testType, range1, 4);
checkRangeSuccess(testType, range1, 5);
try { checkRangeError(testType, range1, 0); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 6); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
}
@Test
public void testIntPropertyRangeValidation5() {
final Class<NodeInterface> testType = createTypeWithProperty("Test", "range1", "+Integer(]0,5[)");
final PropertyKey range1 = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "range1");
checkRangeSuccess(testType, range1, 1);
checkRangeSuccess(testType, range1, 2);
checkRangeSuccess(testType, range1, 3);
checkRangeSuccess(testType, range1, 4);
try { checkRangeError(testType, range1, 0); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 5); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 6); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
}
// ----- long property validation tests -----
@Test
public void testLongPropertyUniquenessValidation() {
final String keyName = "unique";
final Class<NodeInterface> testType = createTypeWithProperty("Test", keyName, "Long!");
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, keyName);
String uuid = null;
if (key != null) {
// test failure
try (final Tx tx = app.tx()) {
uuid = app.create(testType, new NodeAttribute<>(key, 42000000000L)).getUuid();
app.create(testType, new NodeAttribute<>(key, 42000000000L));
tx.success();
fail("Long property uniqueness constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid long validation result", 1, tokens.size());
assertEquals("Invalid long validation result", 422, fex.getStatus());
assertEquals("Invalid long validation result", keyName, token.getProperty());
assertEquals("Invalid long validation result", "Test", token.getType());
assertEquals("Invalid long validation result", "already_taken", token.getToken());
assertEquals("Invalid long validation result", uuid, token.getDetail());
}
}
}
@Test
public void testLongPropertyNotNullValidation() {
final String keyName = "notnull";
final Class<NodeInterface> testType = createTypeWithProperty("Test", keyName, "+Long");
final PropertyKey key = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, keyName);
if (key != null) {
// test failure
try (final Tx tx = app.tx()) {
app.create(testType, new NodeAttribute<>(key, null));
tx.success();
fail("Long property not null constraint violated!");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid long validation result", 1, tokens.size());
assertEquals("Invalid long validation result", 422, fex.getStatus());
assertEquals("Invalid long validation result", keyName, token.getProperty());
assertEquals("Invalid long validation result", "Test", token.getType());
assertEquals("Invalid long validation result", "must_not_be_empty", token.getToken());
}
}
}
@Test
public void testLongPropertyRangeValidation1() {
final Class<NodeInterface> testType = createTypeWithProperty("Test", "range1", "+Long([1,5])");
final PropertyKey range1 = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "range1");
checkRangeSuccess(testType, range1, 1);
checkRangeSuccess(testType, range1, 2);
checkRangeSuccess(testType, range1, 3);
checkRangeSuccess(testType, range1, 4);
checkRangeSuccess(testType, range1, 5);
try { checkRangeError(testType, range1, -0); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 0); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 6); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
}
@Test
public void testLongPropertyRangeValidation3() {
final Class<NodeInterface> testType = createTypeWithProperty("Test", "range1", "+Long([0,5[)");
final PropertyKey range1 = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "range1");
checkRangeSuccess(testType, range1, -0);
checkRangeSuccess(testType, range1, 0);
checkRangeSuccess(testType, range1, 1);
checkRangeSuccess(testType, range1, 2);
checkRangeSuccess(testType, range1, 3);
checkRangeSuccess(testType, range1, 4);
try { checkRangeError(testType, range1, 5); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 6); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
}
@Test
public void testLongPropertyRangeValidation4() {
final Class<NodeInterface> testType = createTypeWithProperty("Test", "range1", "+Long(]0,5])");
final PropertyKey range1 = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "range1");
checkRangeSuccess(testType, range1, 1);
checkRangeSuccess(testType, range1, 2);
checkRangeSuccess(testType, range1, 3);
checkRangeSuccess(testType, range1, 4);
checkRangeSuccess(testType, range1, 5);
try { checkRangeError(testType, range1, 0); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 6); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
}
@Test
public void testLongPropertyRangeValidation5() {
final Class<NodeInterface> testType = createTypeWithProperty("Test", "range1", "+Long(]0,5[)");
final PropertyKey range1 = StructrApp.getConfiguration().getPropertyKeyForJSONName(testType, "range1");
checkRangeSuccess(testType, range1, 1);
checkRangeSuccess(testType, range1, 2);
checkRangeSuccess(testType, range1, 3);
checkRangeSuccess(testType, range1, 4);
try { checkRangeError(testType, range1, 0); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 5); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
try { checkRangeError(testType, range1, 6); } catch (FrameworkException fex) { checkException(fex, 1, 422, "Test", "range1", "must_be_in_range"); }
}
// schema relationship node validation
@Test
public void testSchemaRelationshipNodeValidation() {
try (final Tx tx = app.tx()) {
app.create(SchemaRelationshipNode.class,
new NodeAttribute<>(SchemaRelationshipNode.sourceNode, null),
new NodeAttribute<>(SchemaRelationshipNode.targetNode, null)
);
tx.success();
fail("SchemaRelationshipNode constraint violation, source and target node must not be null.");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
assertEquals("Invalid SchemaRelationshipNode validation result", 3, tokens.size());
assertEquals("Invalid SchemaRelationshipNode validation result", 422, fex.getStatus());
final ErrorToken token1 = tokens.get(0);
final ErrorToken token2 = tokens.get(1);
final ErrorToken token3 = tokens.get(2);
assertEquals("Invalid SchemaRelationshipNode validation result", "SchemaRelationshipNode", token1.getType());
assertEquals("Invalid SchemaRelationshipNode validation result", "relationshipType", token1.getProperty());
assertEquals("Invalid SchemaRelationshipNode validation result", "must_not_be_empty", token1.getToken());
assertEquals("Invalid SchemaRelationshipNode validation result", "SchemaRelationshipNode", token2.getType());
assertEquals("Invalid SchemaRelationshipNode validation result", "sourceNode", token2.getProperty());
assertEquals("Invalid SchemaRelationshipNode validation result", "must_not_be_empty", token2.getToken());
assertEquals("Invalid SchemaRelationshipNode validation result", "SchemaRelationshipNode", token3.getType());
assertEquals("Invalid SchemaRelationshipNode validation result", "targetNode", token3.getProperty());
assertEquals("Invalid SchemaRelationshipNode validation result", "must_not_be_empty", token3.getToken());
}
try (final Tx tx = app.tx()) {
app.create(SchemaRelationshipNode.class,
new NodeAttribute<>(SchemaRelationshipNode.relationshipType, "test"),
new NodeAttribute<>(SchemaRelationshipNode.sourceNode, null),
new NodeAttribute<>(SchemaRelationshipNode.targetNode, null)
);
tx.success();
fail("SchemaRelationshipNode constraint violation, source and target node must not be null.");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
assertEquals("Invalid SchemaRelationshipNode validation result", 2, tokens.size());
assertEquals("Invalid SchemaRelationshipNode validation result", 422, fex.getStatus());
final ErrorToken token1 = tokens.get(0);
final ErrorToken token2 = tokens.get(1);
assertEquals("Invalid SchemaRelationshipNode validation result", "SchemaRelationshipNode", token1.getType());
assertEquals("Invalid SchemaRelationshipNode validation result", "sourceNode", token1.getProperty());
assertEquals("Invalid SchemaRelationshipNode validation result", "must_not_be_empty", token1.getToken());
assertEquals("Invalid SchemaRelationshipNode validation result", "SchemaRelationshipNode", token2.getType());
assertEquals("Invalid SchemaRelationshipNode validation result", "targetNode", token2.getProperty());
assertEquals("Invalid SchemaRelationshipNode validation result", "must_not_be_empty", token2.getToken());
}
try (final Tx tx = app.tx()) {
app.create(SchemaRelationshipNode.class,
new NodeAttribute<>(SchemaRelationshipNode.relationshipType, "test"),
new NodeAttribute<>(SchemaRelationshipNode.sourceNode, app.nodeQuery(SchemaNode.class).andName("Group").getFirst()),
new NodeAttribute<>(SchemaRelationshipNode.targetNode, null)
);
tx.success();
fail("SchemaRelationshipNode constraint violation, target node must not be null.");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid SchemaRelationshipNode validation result", 1, tokens.size());
assertEquals("Invalid SchemaRelationshipNode validation result", 422, fex.getStatus());
assertEquals("Invalid SchemaRelationshipNode validation result", "SchemaRelationshipNode", token.getType());
assertEquals("Invalid SchemaRelationshipNode validation result", "targetNode", token.getProperty());
assertEquals("Invalid SchemaRelationshipNode validation result", "must_not_be_empty", token.getToken());
}
try (final Tx tx = app.tx()) {
app.create(SchemaRelationshipNode.class,
new NodeAttribute<>(SchemaRelationshipNode.relationshipType, "test"),
new NodeAttribute<>(SchemaRelationshipNode.sourceNode, null),
new NodeAttribute<>(SchemaRelationshipNode.targetNode, app.nodeQuery(SchemaNode.class).andName("Group").getFirst())
);
tx.success();
fail("SchemaRelationshipNode constraint violation, source node must not be null.");
} catch (FrameworkException fex) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid SchemaRelationshipNode validation result", 1, tokens.size());
assertEquals("Invalid SchemaRelationshipNode validation result", 422, fex.getStatus());
assertEquals("Invalid SchemaRelationshipNode validation result", "SchemaRelationshipNode", token.getType());
assertEquals("Invalid SchemaRelationshipNode validation result", "sourceNode", token.getProperty());
assertEquals("Invalid SchemaRelationshipNode validation result", "must_not_be_empty", token.getToken());
}
}
// ----- private methods -----
private void checkRangeSuccess(final Class<NodeInterface> type, final PropertyKey key, final Object value) {
try (final Tx tx = app.tx()) {
app.create(type, new NodeAttribute<>(key, value));
tx.success();
} catch (FrameworkException fex) {
fail("Property range constraint validation failure!");
}
}
private void checkRangeError(final Class<NodeInterface> type, final PropertyKey key, final Object value) throws FrameworkException {
try (final Tx tx = app.tx()) {
app.create(type, new NodeAttribute<>(key, value));
tx.success();
fail("Property range constraint violated!");
} catch (FrameworkException fex) {
checkException(fex, 1, 422, "Test", "range1", "must_be_in_range");
}
}
private void checkException(final FrameworkException fex, final int numberOfTokens, final int statusCode, final String typeName, final String keyName, final String errorToken) {
checkException(fex, numberOfTokens, statusCode, typeName, keyName, errorToken, null);
}
private void checkException(final FrameworkException fex, final int numberOfTokens, final int statusCode, final String typeName, final String keyName, final String errorToken, final String uuid) {
final List<ErrorToken> tokens = fex.getErrorBuffer().getErrorTokens();
final ErrorToken token = tokens.get(0);
assertEquals("Invalid validation result", numberOfTokens, tokens.size());
assertEquals("Invalid validation result", statusCode, fex.getStatus());
assertEquals("Invalid validation result", keyName, token.getProperty());
assertEquals("Invalid validation result", typeName, token.getType());
assertEquals("Invalid validation result", errorToken, token.getToken());
if (uuid != null) {
assertEquals("Invalid validation result", uuid, token.getDetail());
}
}
private Class createTypeWithProperty(final String typeName, final String keyName, final String keyType) {
try (final Tx tx = app.tx()) {
app.create(SchemaNode.class,
new NodeAttribute<>(AbstractNode.name, typeName),
new NodeAttribute<>(new StringProperty("_" + keyName), keyType)
);
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
fail("Unexpected exception.");
}
return StructrApp.getConfiguration().getNodeEntityClass(typeName);
}
private void removeInstances(final Class<NodeInterface> type) {
// clear database
try (final Tx tx = app.tx()) {
for (final NodeInterface node : app.nodeQuery(type).getAsList()) {
app.delete(node);
}
tx.success();
} catch (FrameworkException fex) {
fail("Unexpected exception.");
}
}
}