/*
* ModeShape (http://www.modeshape.org)
*
* 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.modeshape.sequencer.cnd;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.AUTO_CREATED;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.CHILD_NODE_DEFINITION;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.DEFAULT_PRIMARY_TYPE;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.DEFAULT_VALUES;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.HAS_ORDERABLE_CHILD_NODES;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.IS_ABSTRACT;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.IS_FULL_TEXT_SEARCHABLE;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.IS_MIXIN;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.IS_QUERYABLE;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.IS_QUERY_ORDERABLE;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.MANDATORY;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.MULTIPLE;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.NAME;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.NODE_TYPE;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.NODE_TYPE_NAME;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.ON_PARENT_VERSION;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.PROPERTY_DEFINITION;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.PROTECTED;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.REQUIRED_PRIMARY_TYPES;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.REQUIRED_TYPE;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.SAME_NAME_SIBLINGS;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.SUPERTYPES;
import static org.modeshape.sequencer.cnd.CndSequencerLexicon.VALUE_CONSTRAINTS;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Value;
import javax.jcr.version.OnParentVersionAction;
import org.junit.Test;
import org.modeshape.jcr.api.JcrConstants;
import org.modeshape.jcr.sequencer.AbstractSequencerTest;
import org.modeshape.schematic.internal.annotation.FixFor;
/**
* Unit test for {@link CndSequencer}
*
* @author Horia Chiorean
*/
public class CndSequencerTest extends AbstractSequencerTest {
@Override
protected InputStream getRepositoryConfigStream() {
return resourceStream("sequencer/cnd/repo-config.json");
}
@Test
public void sequenceImages() throws Exception {
Node imagesNode = createNodeWithContentFromFile("images.cnd", "sequencer/cnd/images.cnd");
verifyImageMetadataNode(imagesNode);
verifyEmbeddedImageNode(imagesNode);
}
private void verifyEmbeddedImageNode( Node imagesNode ) throws Exception {
Node embeddedImageNode = getOutputNode(imagesNode, "image:embeddedImage");
assertNotNull(embeddedImageNode);
new NodeDefinitionVerifier().name("image:embeddedImage").nodeTypeName("image:embeddedImage").mixin(true).verifyNode(embeddedImageNode);
NodeIterator nodesIterator = embeddedImageNode.getNodes();
Node propertyDefinition = nodesIterator.nextNode();
new PropertyDefinitionVerifier().name("image:width").mandatory(false).requiredType("long").verify(propertyDefinition);
assertFalse(nodesIterator.hasNext());
}
private void verifyImageMetadataNode( Node imagesNode ) throws Exception {
Node imageMetadataNode = getOutputNode(imagesNode, "image:metadata");
assertNotNull(imageMetadataNode);
new NodeDefinitionVerifier().name("image:metadata").superTypes("nt:unstructured", "mix:mimeType").nodeTypeName("image:metadata").verifyNode(imageMetadataNode);
NodeIterator nodesIterator = imageMetadataNode.getNodes();
Node propertyDefinition = nodesIterator.nextNode();
new PropertyDefinitionVerifier().name("image:formatName").mandatory(true).requiredType("string").valueConstraints("JPEG",
"GIF",
"PNG",
"BMP",
"PCX",
"IFF",
"RAS",
"PBM",
"PGM",
"PPM",
"PSD").verify(propertyDefinition);
propertyDefinition = nodesIterator.nextNode();
new PropertyDefinitionVerifier().name("image:width").mandatory(false).requiredType("long").verify(propertyDefinition);
propertyDefinition = nodesIterator.nextNode();
new PropertyDefinitionVerifier().name("image:progressive").mandatory(false).requiredType("boolean").verify(propertyDefinition);
Node childNodeDefinition = nodesIterator.nextNode();
new NodeDefinitionVerifier().name("image:subImage").sameNameSiblings(true).requiredPrimaryTypes("image:embeddedImage").defaultPrimaryType("image:embeddedImage").verifyChildNode(childNodeDefinition);
assertFalse(nodesIterator.hasNext());
}
@Test
public void ignoreInvalidFiles() throws Exception {
final Node invalidNode = createNodeWithContentFromFile("invalid.cnd", "sequencer/cnd/invalid.cnd");
Thread.sleep(TimeUnit.MILLISECONDS.convert(2, TimeUnit.SECONDS));
NodeIterator nodeIterator = invalidNode.getNodes();
assertEquals("/invalid.cnd/jcr:content", nodeIterator.nextNode().getPath());
assertFalse(nodeIterator.hasNext());
}
@Test
@FixFor("MODE-2658")
public void shouldRemovePreviousOutputWhenSequencingSameInput() throws Exception {
Node imagesNode = createNodeWithContentFromFile("images.cnd", "sequencer/cnd/images.cnd");
Node imageMetadataNode = getOutputNode("/sequenced/images.cnd");
assertNotNull(imageMetadataNode);
imagesNode.remove();
session.save();
createNodeWithContentFromFile("images.cnd", "sequencer/cnd/images.cnd");
imageMetadataNode = getOutputNode("/sequenced/images.cnd");
assertNotNull(imageMetadataNode);
Node sequencedRoot = session.getNode("/sequenced");
assertEquals("Previous output should've been removed",1, sequencedRoot.getNodes().getSize());
}
protected List<String> sortedListToLowerCase( List<String> valuesList ) {
List<String> result = new ArrayList<String>();
for (String value : valuesList) {
result.add(value.toLowerCase());
}
Collections.sort(result);
return result;
}
protected List<String> sortedValuesToLowerCase( Value[] values ) throws Exception {
List<String> result = new ArrayList<String>();
for (Value value : values) {
result.add(value.getString().toLowerCase());
}
Collections.sort(result);
return result;
}
protected class NodeDefinitionVerifier {
private String name;
private boolean mixin = false;
private boolean isAbstract = false;
private boolean isQueryable = true;
private String nodeTypeName;
private boolean hasOrderableChildNodes = false;
private List<String> superTypes = Collections.emptyList();
private boolean autoCreated = false;
private boolean mandatory = false;
private String onParentVersion = OnParentVersionAction.ACTIONNAME_COPY.toLowerCase();
private boolean isProtected = false;
private String defaultPrimaryType;
private List<String> requiredPrimaryTypes = Collections.emptyList();
private boolean sameNameSiblings = false;
NodeDefinitionVerifier autoCreated( final boolean autoCreated ) {
this.autoCreated = autoCreated;
return this;
}
NodeDefinitionVerifier name( final String name ) {
this.name = name.toLowerCase();
return this;
}
NodeDefinitionVerifier mixin( final boolean mixin ) {
this.mixin = mixin;
return this;
}
NodeDefinitionVerifier isAbstract( final boolean isAbstract ) {
this.isAbstract = isAbstract;
return this;
}
NodeDefinitionVerifier isQueryable( final boolean isQueryable ) {
this.isQueryable = isQueryable;
return this;
}
NodeDefinitionVerifier nodeTypeName( final String nodeTypeName ) {
this.nodeTypeName = nodeTypeName.toLowerCase();
return this;
}
NodeDefinitionVerifier hasOrderableChildNodes( final boolean hasOrderableChildNodes ) {
this.hasOrderableChildNodes = hasOrderableChildNodes;
return this;
}
NodeDefinitionVerifier superTypes( final String... superTypes ) {
this.superTypes = sortedListToLowerCase(Arrays.asList(superTypes));
return this;
}
NodeDefinitionVerifier mandatory( final boolean mandatory ) {
this.mandatory = mandatory;
return this;
}
NodeDefinitionVerifier onParentVersion( final String onParentVersion ) {
this.onParentVersion = onParentVersion;
return this;
}
NodeDefinitionVerifier isProtected( final boolean isProtected ) {
this.isProtected = isProtected;
return this;
}
NodeDefinitionVerifier requiredPrimaryTypes( final String... requiredPrimaryTypes ) {
this.requiredPrimaryTypes = sortedListToLowerCase(Arrays.asList(requiredPrimaryTypes));
return this;
}
NodeDefinitionVerifier sameNameSiblings( boolean sameNameSiblings ) {
this.sameNameSiblings = sameNameSiblings;
return this;
}
NodeDefinitionVerifier defaultPrimaryType( final String defaultPrimaryType ) {
this.defaultPrimaryType = defaultPrimaryType.toLowerCase();
return this;
}
void verifyNode( Node nodeDefinition ) throws Exception {
assertEquals(NODE_TYPE.toLowerCase(),
nodeDefinition.getProperty(JcrConstants.JCR_PRIMARY_TYPE).getString().toLowerCase());
assertEquals(mixin, nodeDefinition.getProperty(IS_MIXIN).getBoolean());
assertEquals(isAbstract, nodeDefinition.getProperty(IS_ABSTRACT).getBoolean());
assertEquals(isQueryable, nodeDefinition.getProperty(IS_QUERYABLE).getBoolean());
assertNotNull(nodeTypeName);
assertEquals(nodeTypeName, nodeDefinition.getProperty(NODE_TYPE_NAME).getString().toLowerCase());
assertEquals(hasOrderableChildNodes, nodeDefinition.getProperty(HAS_ORDERABLE_CHILD_NODES).getBoolean());
assertEquals(superTypes, sortedValuesToLowerCase(nodeDefinition.getProperty(SUPERTYPES).getValues()));
}
void verifyChildNode( Node childNodeDefinition ) throws Exception {
assertEquals(CHILD_NODE_DEFINITION.toLowerCase(),
childNodeDefinition.getProperty(JcrConstants.JCR_PRIMARY_TYPE).getString().toLowerCase());
assertNotNull(name);
assertEquals(name, childNodeDefinition.getProperty(NAME).getString().toLowerCase());
assertEquals(autoCreated, childNodeDefinition.getProperty(AUTO_CREATED).getBoolean());
assertEquals(mandatory, childNodeDefinition.getProperty(MANDATORY).getBoolean());
assertNotNull(onParentVersion);
assertEquals(onParentVersion, childNodeDefinition.getProperty(ON_PARENT_VERSION).getString().toLowerCase());
assertEquals(isProtected, childNodeDefinition.getProperty(PROTECTED).getBoolean());
assertNotNull(defaultPrimaryType);
assertEquals(defaultPrimaryType, childNodeDefinition.getProperty(DEFAULT_PRIMARY_TYPE).getString().toLowerCase());
assertEquals(requiredPrimaryTypes,
sortedValuesToLowerCase(childNodeDefinition.getProperty(REQUIRED_PRIMARY_TYPES).getValues()));
assertEquals(sameNameSiblings, childNodeDefinition.getProperty(SAME_NAME_SIBLINGS).getBoolean());
assertEquals(sameNameSiblings, childNodeDefinition.getProperty(SAME_NAME_SIBLINGS).getBoolean());
}
}
private class PropertyDefinitionVerifier {
private String name;
private boolean autoCreated = false;
private boolean mandatory = false;
private String onParentVersion = OnParentVersionAction.ACTIONNAME_COPY.toLowerCase();
private boolean isProtected = false;
private String requiredType;
private List<String> valueConstraints = Collections.emptyList();
private List<String> defaultValues = Collections.emptyList();
private boolean multiple = false;
private boolean fullTextSearchable = true;
private boolean queryOrderable = true;
protected PropertyDefinitionVerifier() {
}
@SuppressWarnings( "unused" )
PropertyDefinitionVerifier autoCreated( boolean autoCreated ) {
this.autoCreated = autoCreated;
return this;
}
@SuppressWarnings( "unused" )
PropertyDefinitionVerifier defaultValues( String... defaultValues ) {
this.defaultValues = sortedListToLowerCase(Arrays.asList(defaultValues));
return this;
}
@SuppressWarnings( "unused" )
PropertyDefinitionVerifier fullTextSearchable( boolean fullTextSearchable ) {
this.fullTextSearchable = fullTextSearchable;
return this;
}
@SuppressWarnings( "unused" )
PropertyDefinitionVerifier isProtected( boolean isProtected ) {
this.isProtected = isProtected;
return this;
}
PropertyDefinitionVerifier mandatory( boolean mandatory ) {
this.mandatory = mandatory;
return this;
}
@SuppressWarnings( "unused" )
PropertyDefinitionVerifier multiple( boolean multiple ) {
this.multiple = multiple;
return this;
}
PropertyDefinitionVerifier name( String name ) {
this.name = name.toLowerCase();
return this;
}
@SuppressWarnings( "unused" )
PropertyDefinitionVerifier onParentVersion( String onParentVersion ) {
this.onParentVersion = onParentVersion.toLowerCase();
return this;
}
@SuppressWarnings( "unused" )
PropertyDefinitionVerifier queryOrderable( boolean queryOrderable ) {
this.queryOrderable = queryOrderable;
return this;
}
PropertyDefinitionVerifier requiredType( String requiredType ) {
this.requiredType = requiredType;
return this;
}
PropertyDefinitionVerifier valueConstraints( String... valueConstraints ) {
this.valueConstraints = sortedListToLowerCase(Arrays.asList(valueConstraints));
return this;
}
void verify( Node propertyDefinition ) throws Exception {
assertEquals(PROPERTY_DEFINITION.toLowerCase(),
propertyDefinition.getProperty(JcrConstants.JCR_PRIMARY_TYPE).getString().toLowerCase());
assertNotNull(name);
assertEquals(name, propertyDefinition.getProperty(NAME).getString().toLowerCase());
assertEquals(autoCreated, propertyDefinition.getProperty(AUTO_CREATED).getBoolean());
assertEquals(mandatory, propertyDefinition.getProperty(MANDATORY).getBoolean());
assertEquals(multiple, propertyDefinition.getProperty(MULTIPLE).getBoolean());
assertEquals(fullTextSearchable, propertyDefinition.getProperty(IS_FULL_TEXT_SEARCHABLE).getBoolean());
assertEquals(queryOrderable, propertyDefinition.getProperty(IS_QUERY_ORDERABLE).getBoolean());
assertEquals(isProtected, propertyDefinition.getProperty(PROTECTED).getBoolean());
assertNotNull(onParentVersion);
assertEquals(onParentVersion, propertyDefinition.getProperty(ON_PARENT_VERSION).getString().toLowerCase());
assertNotNull(requiredType);
assertEquals(requiredType, propertyDefinition.getProperty(REQUIRED_TYPE).getString().toLowerCase());
assertEquals(valueConstraints, sortedValuesToLowerCase(propertyDefinition.getProperty(VALUE_CONSTRAINTS).getValues()));
assertEquals(defaultValues, sortedValuesToLowerCase(propertyDefinition.getProperty(DEFAULT_VALUES).getValues()));
}
}
}