Package org.lilyproject.repository.impl.test

Source Code of org.lilyproject.repository.impl.test.ValueTypeTest

/*
* Copyright 2010 Outerthought bvba
*
* 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.lilyproject.repository.impl.test;

import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URI;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;

import org.apache.hadoop.hbase.util.Bytes;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.lilyproject.bytes.api.ByteArray;
import org.lilyproject.bytes.api.DataInput;
import org.lilyproject.bytes.api.DataOutput;
import org.lilyproject.bytes.impl.DataInputImpl;
import org.lilyproject.bytes.impl.DataOutputImpl;
import org.lilyproject.hadooptestfw.TestHelper;
import org.lilyproject.repository.api.Blob;
import org.lilyproject.repository.api.FieldType;
import org.lilyproject.repository.api.HierarchyPath;
import org.lilyproject.repository.api.IdGenerator;
import org.lilyproject.repository.api.IdentityRecordStack;
import org.lilyproject.repository.api.Link;
import org.lilyproject.repository.api.QName;
import org.lilyproject.repository.api.Record;
import org.lilyproject.repository.api.RecordException;
import org.lilyproject.repository.api.RecordType;
import org.lilyproject.repository.api.RecordTypeBuilder;
import org.lilyproject.repository.api.Repository;
import org.lilyproject.repository.api.RepositoryException;
import org.lilyproject.repository.api.Scope;
import org.lilyproject.repository.api.TypeException;
import org.lilyproject.repository.api.TypeManager;
import org.lilyproject.repository.api.UnknownValueTypeEncodingException;
import org.lilyproject.repository.api.ValueType;
import org.lilyproject.repository.api.ValueTypeFactory;
import org.lilyproject.repository.impl.valuetype.AbstractValueType;
import org.lilyproject.repotestfw.RepositorySetup;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

public class ValueTypeTest {

    private static final RepositorySetup repoSetup = new RepositorySetup();

    private static TypeManager typeManager;
    private static Repository repository;
    private static IdGenerator idGenerator;

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        TestHelper.setupLogging();
        // TODO this test relies on all blobs being inline blobs, since it reuses blob values
        repoSetup.setBlobLimits(Long.MAX_VALUE, -1);
        repoSetup.setupCore();
        repoSetup.setupRepository();

        typeManager = repoSetup.getTypeManager();
        repository = (Repository)repoSetup.getRepositoryManager().getDefaultRepository().getDefaultTable();
        idGenerator = repoSetup.getIdGenerator();
    }

    @AfterClass
    public static void tearDownAfterClass() throws Exception {
        repoSetup.stop();
    }

    @Before
    public void setUp() throws Exception {
    }

    @After
    public void tearDown() throws Exception {
    }

    @Test
    public void testFooType() throws Exception {
        try {
            runValueTypeTests("fooRecordTypeId", "FOO", "foo", "bar", "pub");
            fail("Excpeting TypeException");
        } catch (TypeException expected) {
        }
    }

    @Test
    public void testStringType() throws Exception {
        runValueTypeTests("stringRecordTypeId", "STRING", "foo", "bar", "pub");
    }

    @Test
    public void testIntegerType() throws Exception {
        runValueTypeTests("integerRecordTypeId", "INTEGER", Integer.MIN_VALUE, 0, Integer.MAX_VALUE);
    }

    @Test
    public void testLongType() throws Exception {
        runValueTypeTests("longRecordTypeId", "LONG", Long.MIN_VALUE, Long.valueOf(0), Long.MAX_VALUE);
    }

    @Test
    public void testDoubleType() throws Exception {
        runValueTypeTests("doubleRecordTypeId", "DOUBLE", Double.MIN_VALUE, Double.valueOf(0), Double.MAX_VALUE);
    }

    @Test
    public void testDecimalType() throws Exception {
        runValueTypeTests("decimalRecordTypeId", "DECIMAL", BigDecimal.valueOf(Double.MIN_EXPONENT), BigDecimal.ZERO, BigDecimal.valueOf(Long.MAX_VALUE));
    }

    @Test
    public void testBooleanType() throws Exception {
        runValueTypeTests("booleanRecordTypeId", "BOOLEAN", true, false, true);
    }

    @Test
    public void testDateTimeType() throws Exception {
        runValueTypeTests("dateTimeRecordTypeId", "DATETIME", new DateTime(DateTimeZone.UTC), new DateTime(Long.MAX_VALUE, DateTimeZone.UTC), new DateTime(Long.MIN_VALUE, DateTimeZone.UTC));
    }

    @Test
    public void testDateType() throws Exception {
        runValueTypeTests("dateRecordTypeId", "DATE", new LocalDate(DateTimeZone.UTC), new LocalDate(2900, 10, 14), new LocalDate(1300, 5, 4));
    }

    @Test
    public void testUriType() throws Exception {
        runValueTypeTests("uriRecordTypeId", "URI", URI.create("http://foo.com/bar"), URI.create("file://foo/com/bar.txt"), URI.create("https://site/index.html"));
    }

    @Test
    public void testByteArrayType() throws Exception {
        runValueTypeTests("byteArrayRecordTypeId", "BYTEARRAY", new ByteArray(Bytes.toBytes("bytes1")), new ByteArray(
                Bytes.toBytes("bytes2")), new ByteArray(Bytes.toBytes("bbb")));
    }

    @Test
    public void testBlobType() throws Exception {
        Blob blob1 = new Blob("text/html", Long.MAX_VALUE, null);
        writeBlob(blob1, Bytes.toBytes("aKey"));
        Blob blob2 = new Blob("image/jpeg", Long.MIN_VALUE, "images/image.jpg");
        writeBlob(blob2, Bytes.toBytes("anotherKey"));
        Blob blob3 = new Blob("text/plain", Long.valueOf(0), null);
        writeBlob(blob3, Bytes.toBytes("thirdKey"));

        runValueTypeTests("blobTypeId", "BLOB", blob1, blob2, blob3);
    }

    private void writeBlob(Blob blob, byte[] bytes) throws RepositoryException, InterruptedException, IOException {
        OutputStream bos = repository.getOutputStream(blob);
        bos.write(bytes);
        bos.close();
    }

    @Test
    public void testRecordType() throws Exception {
        FieldType fieldType1 = typeManager.createFieldType(typeManager.newFieldType(typeManager.getValueType("STRING"), new QName("testRecordType", "field1"), Scope.NON_VERSIONED));
        FieldType fieldType2 = typeManager.createFieldType(typeManager.newFieldType(typeManager.getValueType("INTEGER"), new QName("testRecordType", "field2"), Scope.NON_VERSIONED));
        RecordTypeBuilder rtBuilder = typeManager.recordTypeBuilder();
        RecordType valueTypeRT = rtBuilder.name(new QName("testRecordType", "recordValueTypeRecordType"))
            .field(fieldType1.getId(), false)
            .field(fieldType2.getId(), true)
            .create();

        Record recordField1 = repository.recordBuilder()
            .recordType(valueTypeRT.getName(), 1L)
            .field(fieldType1.getName(), "abc")
            .field(fieldType2.getName(), 123)
            .build();
        Record recordField2 = repository.recordBuilder()
            .recordType(valueTypeRT.getName(), 1L)
            .field(fieldType1.getName(), "def")
            .field(fieldType2.getName(), 456)
            .build();
        Record recordField3 = repository.recordBuilder()
            .recordType(valueTypeRT.getName(), 1L)
            .field(fieldType1.getName(), "xyz")
            .field(fieldType2.getName(), 888)
            .build();

        testType("recordValueTypeId", "RECORD<{testRecordType}recordValueTypeRecordType>", recordField1);
        testType("recordValueTypeId", "LIST<RECORD<{testRecordType}recordValueTypeRecordType>>", Arrays.asList(recordField1, recordField2));
        testType("recordValueTypeId", "PATH<RECORD<{testRecordType}recordValueTypeRecordType>>", new HierarchyPath(recordField1, recordField2));
        testType("recordValueTypeId", "LIST<PATH<RECORD<{testRecordType}recordValueTypeRecordType>>>", Arrays.asList(new HierarchyPath(recordField1, recordField2), new HierarchyPath(recordField1, recordField3)));
    }

    @Test
    public void testLinkType() throws Exception {
        FieldType fieldType1 = typeManager.createFieldType(typeManager.newFieldType(typeManager.getValueType("STRING"), new QName("testLinkType", "field1"), Scope.NON_VERSIONED));
        RecordTypeBuilder rtBuilder = typeManager.recordTypeBuilder();
        RecordType valueTypeRT = rtBuilder.name(new QName("testLinkType", "linkValueTypeRecordType"))
            .field(fieldType1.getId(), false)
            .create();

        testType("recordValueTypeId", "LINK", new Link(idGenerator.newRecordId()));
        testType("recordValueTypeId", "LINK<{testLinkType}linkValueTypeRecordType>", new Link(idGenerator.newRecordId()));
        testType("recordValueTypeId", "LIST<LINK<{testLinkType}linkValueTypeRecordType>>", Arrays.asList(new Link(idGenerator.newRecordId()), new Link(idGenerator.newRecordId())));
        testType("recordValueTypeId", "LIST<LINK>", Arrays.asList(new Link(idGenerator.newRecordId()), new Link(idGenerator.newRecordId())));
        testType("recordValueTypeId", "PATH<LINK<{testLinkType}linkValueTypeRecordType>>", new HierarchyPath(new Link(idGenerator.newRecordId()), new Link(idGenerator.newRecordId())));
        testType("recordValueTypeId", "PATH<LINK>", new HierarchyPath(new Link(idGenerator.newRecordId()), new Link(idGenerator.newRecordId())));
        testType("recordValueTypeId", "LIST<PATH<LINK<{testLinkType}linkValueTypeRecordType>>>", Arrays.asList(new HierarchyPath(new Link(idGenerator.newRecordId()), new Link(idGenerator.newRecordId())), new HierarchyPath(new Link(idGenerator.newRecordId()), new Link(idGenerator.newRecordId()))));
        testType("recordValueTypeId", "LIST<PATH<LINK>>", Arrays.asList(new HierarchyPath(new Link(idGenerator.newRecordId()), new Link(idGenerator.newRecordId())), new HierarchyPath(new Link(idGenerator.newRecordId()), new Link(idGenerator.newRecordId()))));
    }


    @Test
    public void testNewValueType() throws Exception {
        typeManager.registerValueType(XYValueType.NAME, factory());
        runValueTypeTests("xyRecordTypeId", "XY", new XYCoordinates(-1, 1), new XYCoordinates(Integer.MIN_VALUE, Integer.MAX_VALUE), new XYCoordinates(666, 777));
    }

    @Test
    public void testComparators() throws Exception {
        Comparator comparator = typeManager.getValueType("LONG").getComparator();
        assertTrue(comparator.compare(new Long(2), new Long(5)) < 0);
        assertTrue(comparator.compare(new Long(5), new Long(5)) == 0);

        comparator = typeManager.getValueType("DOUBLE").getComparator();
        assertTrue(comparator.compare(new Double(2.2d), new Double(5.5d)) < 0);

        comparator = typeManager.getValueType("BLOB").getComparator();
        assertNull(comparator);

        comparator = typeManager.getValueType("DATE").getComparator();
        assertTrue(comparator.compare(new LocalDate(2012, 5, 5), new LocalDate(2013, 5, 5)) < 0);
        assertTrue(comparator.compare(new LocalDate(2012, 5, 5), new LocalDate(2012, 5, 5)) == 0);

        comparator = typeManager.getValueType("URI").getComparator();
        assertNull(comparator);

        comparator = typeManager.getValueType("DECIMAL").getComparator();
        assertTrue(comparator.compare(new BigDecimal("2"), new BigDecimal("5")) < 0);
        assertTrue(comparator.compare(new BigDecimal("5"), new BigDecimal("5")) == 0);

        comparator = typeManager.getValueType("BOOLEAN").getComparator();
        assertTrue(comparator.compare(Boolean.FALSE, Boolean.TRUE) < 0);
        assertTrue(comparator.compare(Boolean.TRUE, Boolean.TRUE) == 0);

        comparator = typeManager.getValueType("DATETIME").getComparator();
        assertTrue(comparator.compare(new DateTime(2012, 5, 5, 6, 7, 8, 9), new DateTime(2012, 5, 5, 6, 7, 8, 10)) < 0);
        assertTrue(comparator.compare(new DateTime(2012, 5, 5, 6, 7, 8, 9), new DateTime(2012, 5, 5, 6, 7, 8, 9)) == 0);

        comparator = typeManager.getValueType("STRING").getComparator();
        assertTrue(comparator.compare("a", "b") < 0);
        assertTrue(comparator.compare("a", "a") == 0);

        comparator = typeManager.getValueType("INTEGER").getComparator();
        assertTrue(comparator.compare(new Integer(2), new Integer(5)) < 0);
        assertTrue(comparator.compare(new Integer(5), new Integer(5)) == 0);

        comparator = typeManager.getValueType("LINK").getComparator();
        assertNull(comparator);

        comparator = typeManager.getValueType("LIST<STRING>").getComparator();
        assertNull(comparator);

        comparator = typeManager.getValueType("PATH<STRING>").getComparator();
        assertNull(comparator);

        comparator = typeManager.getValueType("RECORD<{testRecordType}recordValueTypeRecordType>").getComparator();
        assertNull(comparator);
    }

    private void runValueTypeTests(String name, String valueType, Object value1, Object value2, Object value3) throws Exception {
        testType(name, valueType, value1);
        testType(name, "LIST<"+valueType+">", Arrays.asList(value1, value2));
        testType(name, "PATH<"+valueType+">", new HierarchyPath(value1, value2));
        testType(name, "LIST<PATH<"+valueType+">>", Arrays.asList(new HierarchyPath(value1, value2), new HierarchyPath(value1, value3)));
    }

    private void testType(String name, String valueType,
                    Object fieldValue) throws Exception {
        String testName = name+valueType;
        QName fieldTypeName = new QName("valueTypeTest", testName+"FieldId");
        FieldType fieldType = typeManager.createFieldType(typeManager.newFieldType(typeManager.getValueType(
                        valueType), fieldTypeName, Scope.VERSIONED));
        RecordType recordType = typeManager.newRecordType(new QName("valueTypeTest", testName+"RecordTypeId"));
        recordType.addFieldTypeEntry(typeManager.newFieldTypeEntry(fieldType.getId(), true));
        recordType = typeManager.createRecordType(recordType);

        Record record = repository.newRecord(idGenerator.newRecordId());
        record.setRecordType(recordType.getName(), recordType.getVersion());
        record.setField(fieldType.getName(), fieldValue);
        repository.create(record);

        Record actualRecord = repository.read(record.getId());
        assertEquals(fieldValue, actualRecord.getField(fieldType.getName()));
    }

    public class XYValueType extends AbstractValueType implements ValueType {
        private Random random = new Random();

        public static final String NAME = "XY";

        @Override
        public String getBaseName() {
            return NAME;
        }

        @Override
        public ValueType getDeepestValueType() {
            return this;
        }

        @Override
        public Object read(DataInput dataInput) throws UnknownValueTypeEncodingException {
            byte encodingVersion = dataInput.readByte();
            int x;
            int y;
            if ((byte)1 == encodingVersion) {
                x = dataInput.readInt();
                y = dataInput.readInt();
            } else if ((byte)2 == encodingVersion) {
                y = dataInput.readInt();
                x = dataInput.readInt();
            } else {
                throw new UnknownValueTypeEncodingException(NAME, encodingVersion);
            }
            return new XYCoordinates(x, y);
        }

        @Override
        public void write(Object value, DataOutput dataOutput, IdentityRecordStack parentRecords) {
            if (random.nextBoolean()) {
                dataOutput.writeByte((byte)1); // encoding version 1
                dataOutput.writeInt(((XYCoordinates) value).getX());
                dataOutput.writeInt(((XYCoordinates) value).getY());
            } else {
                dataOutput.writeByte((byte)2); // encoding version 2
                dataOutput.writeInt(((XYCoordinates) value).getY());
                dataOutput.writeInt(((XYCoordinates) value).getX());

            }
        }

        @Override
        public Class getType() {
            return XYCoordinates.class;
        }

        @Override
        public Comparator getComparator() {
            return null;
        }
    }

    //
    // Factory
    //
    public ValueTypeFactory factory() {
        return new XYValueTypeFactory();
    }

    public class XYValueTypeFactory implements ValueTypeFactory {
        @Override
        public ValueType getValueType(String typeParams) {
            return new XYValueType();
        }
    }

    private class XYCoordinates {
        private final int x;
        private final int y;

        XYCoordinates(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }

        @Override
        public String toString() {
            return "["+x+","+y+"]";
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + getOuterType().hashCode();
            result = prime * result + x;
            result = prime * result + y;
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            XYCoordinates other = (XYCoordinates) obj;
            if (!getOuterType().equals(other.getOuterType())) {
                return false;
            }
            if (x != other.x) {
                return false;
            }
            if (y != other.y) {
                return false;
            }
            return true;
        }

        private ValueTypeTest getOuterType() {
            return ValueTypeTest.this;
        }
    }

    @Test
    public void testRecordVTTypeInVT() throws Exception {
        String ns = "testRecordVTTypeInVT";
        // Create a fieldType to be used as a field in a record type to be used as the type for a RecordValueType
        FieldType fieldType1 = typeManager.createFieldType(typeManager.newFieldType(typeManager.getValueType("STRING"), new QName(ns, "field1"), Scope.NON_VERSIONED));
        // Create a record type to be used as the type for a RecordValueType
        RecordType rt1 = typeManager.recordTypeBuilder()
            .name(new QName(ns, "rt1"))
            .field(fieldType1.getId(), false)
            .create();

        // Make a RecordValueType with the record type specified
        ValueType recordVT1 = typeManager.getValueType("RECORD<{"+ns+"}rt1>");

        // Create a fieldType with as value type a RecordValueType
        FieldType fieldType2 = typeManager.createFieldType(typeManager.newFieldType(recordVT1, new QName(ns, "field2"), Scope.NON_VERSIONED));
        // Create a recordType with a field of this field type
        RecordType rt2 = typeManager.recordTypeBuilder()
            .name(new QName(ns, "rt2"))
            .field(fieldType2.getId(), false)
            .create();

        // Make a record to be used as field value
        Record recordField = repository.recordBuilder().field(new QName(ns, "field1"), "abc").build();
        // Create a record with a record as field
        Record createdRecord = repository.recordBuilder().recordType(new QName(ns, "rt2")).field(new QName(ns,"field2"), recordField).create();

        // Read the record and check the field of the record-field
        Record readRecord = repository.read(createdRecord.getId());
        Record readRecordField = (Record)readRecord.getField(new QName(ns, "field2"));
        assertEquals("abc", recordField.getField(new QName(ns, "field1")));

        assertNull(readRecordField.getId()); // The record field should have no Id
        assertNull(readRecordField.getVersion()); // The record field should have no version
    }

    @Test
    public void testRecordVTNested() throws Exception {
        String ns = "testRecordVTNested";
        // Create a fieldType to be used as a field in a record type to be used as the type for a RecordValueType
        FieldType fieldType1 = typeManager.createFieldType(typeManager.newFieldType(typeManager.getValueType("STRING"), new QName(ns, "field1"), Scope.NON_VERSIONED));
        // Create a record type to be used as the type for a RecordValueType
        RecordType rt1 = typeManager.recordTypeBuilder()
            .name(new QName(ns, "rt1"))
            .field(fieldType1.getId(), false)
            .create();

        // Make a RecordValueType with the record type specified
        ValueType recordVT1 = typeManager.getValueType("RECORD<{"+ns+"}rt1>");

        // Create a fieldType with as value type a RecordValueType
        FieldType fieldType2 = typeManager.createFieldType(typeManager.newFieldType(recordVT1, new QName(ns, "field2"), Scope.NON_VERSIONED));
        // Create a recordType with a field of this field type
        RecordType rt2 = typeManager.recordTypeBuilder()
            .name(new QName(ns, "rt2"))
            .field(fieldType2.getId(), false)
            .create();

        // Create a fieldType with as value type a 'nested' RecordValueType
        ValueType recordVT2 = typeManager.getValueType("RECORD<{"+ns+"}rt2>");
        FieldType fieldType3 = typeManager.createFieldType(typeManager.newFieldType(recordVT2, new QName(ns, "field3"), Scope.NON_VERSIONED));
        RecordType rt3 = typeManager.recordTypeBuilder()
            .name(new QName(ns, "rt3"))
            .field(fieldType3.getId(), false)
            .create();

        // Make nested records
        Record recordField1 = repository.recordBuilder().field(new QName(ns, "field1"), "abc").build();

        Record recordField2 = repository.recordBuilder().field(new QName(ns, "field2"), recordField1).build();

        // Create a record with nested records
        Record createdRecord = repository.recordBuilder().recordType(new QName(ns, "rt3")).field(new QName(ns,"field3"), recordField2).create();

        // Read the record and check the field of the record-field
        Record readRecord = repository.read(createdRecord.getId());
        Record nestedRecord1 = readRecord.getField(new QName(ns, "field3"));
        Record nestedRecord2 = nestedRecord1.getField(new QName(ns, "field2"));
        assertEquals("abc", nestedRecord2.getField(new QName(ns, "field1")));
    }

    @Test
    public void testRecordVTTypeInRecord() throws Exception {
        String ns = "testRecordVTTypeInRecord";
        // Create a fieldType to be used as a field in a record type to be used as the type for a RecordValueType
        FieldType fieldType1 = typeManager.createFieldType(typeManager.newFieldType(typeManager.getValueType("STRING"), new QName(ns, "field1"), Scope.NON_VERSIONED));
        // Create a record type to be used as the type for a RecordValueType
        RecordType rt1 = typeManager.recordTypeBuilder().name(new QName(ns, "rt1")).field(fieldType1.getId(), false).create();

        // Create record types to be used as versioned and versioned-mutable record types, which should be ignored
        RecordType vrt = typeManager.recordTypeBuilder().name(new QName(ns, "vrt")).field(fieldType1.getId(), false).create();
        RecordType vmrt = typeManager.recordTypeBuilder().name(new QName(ns, "vmrt")).field(fieldType1.getId(), false).create();

        // Make a RecordValueType without the record type specified
        ValueType recordVT1 = typeManager.getValueType("RECORD");

        // Create a fieldType with as value type a RecordValueType
        FieldType fieldType2 = typeManager.createFieldType(typeManager.newFieldType(recordVT1, new QName(ns, "field2"), Scope.NON_VERSIONED));
        // Create a recordType with a field of this field type
        RecordType rt2 = typeManager.recordTypeBuilder()
            .name(new QName(ns, "rt2"))
            .field(fieldType2.getId(), false)
            .create();

        // Make a record to be used as field value, specify the record type here
        Record recordField = repository.recordBuilder().recordType(new QName(ns, "rt1")).field(new QName(ns, "field1"), "abc").build();
        recordField.setRecordType(Scope.VERSIONED, new QName(ns, "vrt"), null); // This record type should be ignored
        recordField.setRecordType(Scope.VERSIONED_MUTABLE, new QName(ns, "vmrt"), null); // This record type should be ignored

        // Create a record with a record as field
        Record createdRecord = repository.recordBuilder().recordType(new QName(ns, "rt2")).field(new QName(ns,"field2"), recordField).create();

        // Read the record and check the field of the record-field
        Record readRecord = repository.read(createdRecord.getId());
        Record readRecordField = (Record)readRecord.getField(new QName(ns, "field2"));
        assertEquals("abc", readRecordField.getField(new QName(ns, "field1")));
        assertEquals(new QName(ns, "rt1"), readRecordField.getRecordTypeName(Scope.NON_VERSIONED));
        assertNull(readRecordField.getRecordTypeName(Scope.VERSIONED));
        assertNull(readRecordField.getRecordTypeName(Scope.VERSIONED_MUTABLE));
    }

    @Test
    public void testRecordVTNoTypeDefined() throws Exception {
        String ns = "testRecordVTNoTypeDefined";
        // Create a fieldType to be used as a field in a record type to be used as the type for a RecordValueType
        FieldType fieldType1 = typeManager.createFieldType(typeManager.newFieldType(typeManager.getValueType("STRING"), new QName(ns, "field1"), Scope.NON_VERSIONED));
        // Create a record type to be used as the type for a RecordValueType
        RecordType rt1 = typeManager.recordTypeBuilder()
            .name(new QName(ns, "rt1"))
            .field(fieldType1.getId(), false)
            .create();

        // Make a RecordValueType without the record type specified
        ValueType recordVT1 = typeManager.getValueType("RECORD");

        // Create a fieldType with as value type a RecordValueType
        FieldType fieldType2 = typeManager.createFieldType(typeManager.newFieldType(recordVT1, new QName(ns, "field2"), Scope.NON_VERSIONED));

        // Create a recordType with a field of this field type
        RecordType rt2 = typeManager.recordTypeBuilder()
            .name(new QName(ns, "rt2"))
            .field(fieldType2.getId(), false)
            .create();

        // Make a record to be used as field value, don't specify the record type here either
        Record recordField = repository.recordBuilder().field(new QName(ns, "field1"), "abc").build();

        // Create a record with a record as field
        try {
            Record createdRecord = repository.recordBuilder().recordType(new QName(ns, "rt2")).field(new QName(ns,"field2"), recordField).create();
            Assert.fail();
        } catch (RepositoryException expected) {
        }
    }

    @Test
    public void testRecordVTUndefinedField() throws Exception {
        String ns = "testRecordVTUndefinedField";
        // Create a fieldType to be used as a field in a record type to be used as the type for a RecordValueType
        FieldType fieldType1 = typeManager.createFieldType(typeManager.newFieldType(typeManager.getValueType("STRING"), new QName(ns, "field1"), Scope.NON_VERSIONED));
        FieldType fieldType1b = typeManager.createFieldType(typeManager.newFieldType(typeManager.getValueType("STRING"), new QName(ns, "field1b"), Scope.NON_VERSIONED));
        // Create a record type to be used as the type for a RecordValueType
        RecordType rt1 = typeManager.recordTypeBuilder()
            .name(new QName(ns, "rt1"))
            .field(fieldType1.getId(), false)
            .field(fieldType1b.getId(), false)
            .create();

        // Make a RecordValueType without the record type specified
        ValueType recordVT1 = typeManager.getValueType("RECORD");

        // Create a fieldType with as value type a RecordValueType
        FieldType fieldType2 = typeManager.createFieldType(typeManager.newFieldType(recordVT1, new QName(ns, "field2"), Scope.NON_VERSIONED));
        // Create a recordType with a field of this field type
        RecordType rt2 = typeManager.recordTypeBuilder()
            .name(new QName(ns, "rt2"))
            .field(fieldType2.getId(), false)
            .create();

        // Make a record to be used as field value, specify the record type here
        // Only fill in field1, not field1b
        Record recordField = repository.recordBuilder().recordType(new QName(ns, "rt1")).field(new QName(ns, "field1"), "abc").build();

        // Create a record with a record as field
        Record createdRecord = repository.recordBuilder().recordType(new QName(ns, "rt2")).field(new QName(ns,"field2"), recordField).create();

        // Read the record and check the field of the record-field
        Record readRecord = repository.read(createdRecord.getId());
        Record readRecordInRecord = (Record)readRecord.getField(new QName(ns, "field2"));
        assertEquals("abc", readRecordInRecord.getField(new QName(ns, "field1")));
        Assert.assertFalse(readRecordInRecord.hasField(new QName(ns, "field1b")));

    }

    @Test
    public void testRecordVTUnallowedField() throws Exception {
        String ns = "testRecordVTUnallowedField";
        // Create a fieldType to be used as a field in a record type to be used as the type for a RecordValueType
        FieldType fieldType1 = typeManager.createFieldType(typeManager.newFieldType(typeManager.getValueType("STRING"), new QName(ns, "field1"), Scope.NON_VERSIONED));
        FieldType fieldType1b = typeManager.createFieldType(typeManager.newFieldType(typeManager.getValueType("STRING"), new QName(ns, "field1b"), Scope.NON_VERSIONED));
        // Create a record type to be used as the type for a RecordValueType
        // Do not add fieldType1b to the record type
        RecordType rt1 = typeManager.recordTypeBuilder()
            .name(new QName(ns, "rt1"))
            .field(fieldType1.getId(), false)
            .create();

        // Make a RecordValueType without the record type specified
        ValueType recordVT1 = typeManager.getValueType("RECORD");

        // Create a fieldType with as value type a RecordValueType
        FieldType fieldType2 = typeManager.createFieldType(typeManager.newFieldType(recordVT1, new QName(ns, "field2"), Scope.NON_VERSIONED));
        // Create a recordType with a field of this field type
        RecordType rt2 = typeManager.recordTypeBuilder()
            .name(new QName(ns, "rt2"))
            .field(fieldType2.getId(), false)
            .create();

        // Make a record to be used as field value, specify the record type here
        Record recordField = repository.recordBuilder()
            .recordType(new QName(ns, "rt1"))
            .field(new QName(ns, "field1"), "abc")
            .field(new QName(ns, "field1b"), "def") // Also fill in field1b, although the recordType does not specify it
            .build();

        // Create a record with a record as field
        try {
            repository.recordBuilder().recordType(new QName(ns, "rt2")).field(new QName(ns,"field2"), recordField).create();
            Assert.fail();
        } catch (RepositoryException expected) {

        }
    }

    @Test
    public void testRecordVTReadWrite() throws Exception {
        String ns = "testRecordVTWrite";
     // Create a fieldType to be used as a field in a record type to be used as the type for a RecordValueType
        FieldType fieldType1 = typeManager.createFieldType(typeManager.newFieldType(typeManager.getValueType("STRING"), new QName(ns, "field1"), Scope.NON_VERSIONED));
        // Create a record type to be used as the type for a RecordValueType
        RecordType rt1 = typeManager.recordTypeBuilder().name(new QName(ns, "rt1")).field(fieldType1.getId(), false).create();

        // Make a RecordValueType without the record type specified
        ValueType recordVT = typeManager.getValueType("RECORD");


        RecordType rt2 = typeManager.recordTypeBuilder()
            .name(new QName(ns, "rt2"))
            .supertype().id(rt1.getId()).add()
            .create();



        // Create a record with a record as field
        Record createdRecord = repository.recordBuilder()
                .recordType(new QName(ns, "rt2"))
                .field(new QName(ns,"field1"), "def")
                .create();


        DataOutput dataOutput = new DataOutputImpl();

        // Do a write and lets not get exceptions
        recordVT.write(createdRecord, dataOutput, new IdentityRecordStack());

        DataInput dataInput = new DataInputImpl(dataOutput.toByteArray());

        // Do a read and lets not get exceptions
        Record readRecord = recordVT.read(dataInput);

        assertEquals(createdRecord.getFields(), readRecord.getFields());
    }

    @Test
    public void testInvalidValueTypeSyntax() throws Exception {
        try {
            typeManager.getValueType("LIST<");
            fail("expected exception");
        } catch (IllegalArgumentException e) {
            // expected
        }

        try {
            typeManager.getValueType("LIST<>");
            fail("expected exception");
        } catch (IllegalArgumentException e) {
            // expected
        }

        try {
            typeManager.getValueType("LIST<!");
            fail("expected exception");
        } catch (IllegalArgumentException e) {
            // expected
        }

        try {
            typeManager.getValueType("LIST<STRING<>");
            fail("expected exception");
        } catch (IllegalArgumentException e) {
            // expected
        }

        try {
            typeManager.getValueType("RECORD<!namespace}name>");
            fail("expected exception");
        } catch (IllegalArgumentException e) {
            // expected
        }
    }
}
TOP

Related Classes of org.lilyproject.repository.impl.test.ValueTypeTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.