2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2016-2018 Ericsson. All rights reserved.
4 * Modifications Copyright (C) 2020 Nordix Foundation.
5 * ================================================================================
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.apex.plugins.context.schema.avro;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertNull;
27 import static org.junit.Assert.assertThrows;
30 import java.io.IOException;
31 import java.util.HashMap;
32 import org.apache.avro.generic.GenericRecord;
33 import org.apache.avro.util.Utf8;
34 import org.junit.After;
35 import org.junit.Before;
36 import org.junit.Test;
37 import org.onap.policy.apex.context.ContextRuntimeException;
38 import org.onap.policy.apex.context.SchemaHelper;
39 import org.onap.policy.apex.context.impl.schema.SchemaHelperFactory;
40 import org.onap.policy.apex.context.parameters.ContextParameterConstants;
41 import org.onap.policy.apex.context.parameters.SchemaParameters;
42 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
43 import org.onap.policy.apex.model.basicmodel.concepts.AxKey;
44 import org.onap.policy.apex.model.basicmodel.service.ModelService;
45 import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchema;
46 import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchemas;
47 import org.onap.policy.common.parameters.ParameterService;
48 import org.onap.policy.common.utils.resources.TextFileUtils;
51 * The Class TestAvroSchemaMap.
53 * @author Liam Fallon (liam.fallon@ericsson.com)
56 public class AvroSchemaMapTest {
57 private final AxKey testKey = new AxArtifactKey("AvroTest", "0.0.1");
58 private AxContextSchemas schemas;
59 private String longMapSchema;
60 private String addressMapSchema;
61 private String addressMapSchemaInvalidFields;
66 * @throws IOException Signals that an I/O exception has occurred.
69 public void initTest() throws IOException {
70 schemas = new AxContextSchemas(new AxArtifactKey("AvroSchemas", "0.0.1"));
71 ModelService.registerModel(AxContextSchemas.class, schemas);
72 longMapSchema = TextFileUtils.getTextFileAsString("src/test/resources/avsc/MapExampleLong.avsc");
73 addressMapSchema = TextFileUtils.getTextFileAsString("src/test/resources/avsc/MapExampleAddress.avsc");
74 addressMapSchemaInvalidFields =
75 TextFileUtils.getTextFileAsString("src/test/resources/avsc/MapExampleAddressInvalidFields.avsc");
82 public void initContext() {
83 SchemaParameters schemaParameters = new SchemaParameters();
84 schemaParameters.setName(ContextParameterConstants.SCHEMA_GROUP_NAME);
85 schemaParameters.getSchemaHelperParameterMap().put("AVRO", new AvroSchemaHelperParameters());
86 ParameterService.register(schemaParameters);
93 public void clearContext() {
94 ParameterService.deregister(ContextParameterConstants.SCHEMA_GROUP_NAME);
98 * Test valid schemas with substitutions.
100 * @throws IOException Signals that an I/O exception has occurred.
103 public void testValidSubstitutions() throws IOException {
104 final String subst1 = "{\"type\":\"record\",\"name\":\"Subst1\","
105 + "\"fields\":[{\"name\": \"A_DasH_B\",\"type\":\"string\"}]}";
106 final AxContextSchema avroSubstSchema1 = new AxContextSchema(
107 new AxArtifactKey("AvroSubst1", "0.0.1"), "AVRO", subst1);
108 schemas.getSchemasMap().put(avroSubstSchema1.getKey(), avroSubstSchema1);
110 SchemaHelper schemaHelperSubst1 = new SchemaHelperFactory()
111 .createSchemaHelper(testKey, avroSubstSchema1.getKey());
112 final GenericRecord subst1A = (GenericRecord) schemaHelperSubst1.unmarshal("{\"A-B\":\"foo\"}");
113 assertEquals(new Utf8("foo"), subst1A.get("A_DasH_B"));
114 assertNull(subst1A.get("A-B"));
115 final Throwable exception1 = assertThrows(ContextRuntimeException.class,
116 () -> schemaHelperSubst1.unmarshal("{\"A-B\":123}"));
117 assertNotNull(exception1.getCause());
118 assertEquals("Expected string. Got VALUE_NUMBER_INT", exception1.getCause().getMessage());
120 final String subst2 = "{\"type\":\"record\",\"name\":\"Subst2\","
121 + "\"fields\":[{\"name\": \"C_DoT_D\",\"type\":\"int\"}]}";
122 final AxContextSchema avroSubstSchema2 = new AxContextSchema(
123 new AxArtifactKey("AvroSubst2", "0.0.1"), "AVRO", subst2);
124 schemas.getSchemasMap().put(avroSubstSchema2.getKey(), avroSubstSchema2);
126 final SchemaHelper schemaHelperSubst2 = new SchemaHelperFactory()
127 .createSchemaHelper(testKey, avroSubstSchema2.getKey());
128 final GenericRecord subst2A = (GenericRecord) schemaHelperSubst2.unmarshal("{\"C.D\":123}");
129 assertEquals(123, subst2A.get("C_DoT_D"));
130 assertNull(subst2A.get("C.D"));
131 final Throwable exception2 = assertThrows(ContextRuntimeException.class,
132 () -> schemaHelperSubst2.unmarshal("{\"C_DoT_D\":\"bar\"}"));
133 assertNotNull(exception2.getCause());
134 assertEquals("Expected int. Got VALUE_STRING", exception2.getCause().getMessage());
136 final String subst3 = "{\"type\":\"record\",\"name\":\"Subst3\","
137 + "\"fields\":[{\"name\": \"E_ColoN_F\",\"type\":\"boolean\"}]}";
138 final AxContextSchema avroSubstSchema3 = new AxContextSchema(
139 new AxArtifactKey("AvroSubst3", "0.0.1"), "AVRO", subst3);
140 schemas.getSchemasMap().put(avroSubstSchema3.getKey(), avroSubstSchema3);
142 final SchemaHelper schemaHelperSubst3 = new SchemaHelperFactory()
143 .createSchemaHelper(testKey, avroSubstSchema3.getKey());
144 final GenericRecord subst3A = (GenericRecord) schemaHelperSubst3.unmarshal("{\"E:F\":true}");
145 assertEquals(true, subst3A.get("E_ColoN_F"));
146 assertNull(subst3A.get("E:F"));
147 final Throwable exception3 = assertThrows(ContextRuntimeException.class,
148 () -> schemaHelperSubst3.unmarshal("{\"E_ColoN_F\":\"gaz\"}"));
149 assertNotNull(exception3.getCause());
150 assertEquals("Expected boolean. Got VALUE_STRING", exception3.getCause().getMessage());
154 * Test invalid schemas without substitutions.
156 * @throws IOException Signals that an I/O exception has occurred.
159 public void testInValidSubstitutions() throws IOException {
160 final String fail1 = "{\"type\":\"record\",\"name\":\"Fail1\","
161 + "\"fields\":[{\"name\": \"A-B\",\"type\":\"string\"}]}";
162 final AxContextSchema avroFailSchema1 = new AxContextSchema(
163 new AxArtifactKey("AvroFail1", "0.0.1"), "AVRO", fail1);
164 schemas.getSchemasMap().put(avroFailSchema1.getKey(), avroFailSchema1);
165 final Throwable exception1 = assertThrows(ContextRuntimeException.class,
166 () -> new SchemaHelperFactory().createSchemaHelper(testKey, avroFailSchema1.getKey()));
167 assertNotNull(exception1.getCause());
168 assertEquals("Illegal character in: A-B", exception1.getCause().getMessage());
170 final String fail2 = "{\"type\":\"record\",\"name\":\"Fail2\","
171 + "\"fields\":[{\"name\": \"C.D\",\"type\":\"int\"}]}";
172 final AxContextSchema avroFailSchema2 = new AxContextSchema(
173 new AxArtifactKey("AvroFail2", "0.0.1"), "AVRO", fail2);
174 schemas.getSchemasMap().put(avroFailSchema2.getKey(), avroFailSchema2);
175 final Throwable exception2 = assertThrows(ContextRuntimeException.class,
176 () -> new SchemaHelperFactory().createSchemaHelper(testKey, avroFailSchema2.getKey()));
177 assertNotNull(exception2.getCause());
178 assertEquals("Illegal character in: C.D", exception2.getCause().getMessage());
180 final String fail3 = "{\"type\":\"record\",\"name\":\"Fail3\","
181 + "\"fields\":[{\"name\": \"E:F\",\"type\":\"boolean\"}]}";
182 final AxContextSchema avroFailSchema3 = new AxContextSchema(
183 new AxArtifactKey("AvroFail3", "0.0.1"), "AVRO", fail3);
184 schemas.getSchemasMap().put(avroFailSchema3.getKey(), avroFailSchema3);
185 final Throwable exception3 = assertThrows(ContextRuntimeException.class,
186 () -> new SchemaHelperFactory().createSchemaHelper(testKey, avroFailSchema3.getKey()));
187 assertNotNull(exception3.getCause());
188 assertEquals("Illegal character in: E:F", exception3.getCause().getMessage());
194 * @throws IOException Signals that an I/O exception has occurred.
197 public void testMapInit() throws IOException {
198 final AxContextSchema avroSchema =
199 new AxContextSchema(new AxArtifactKey("AvroRecord", "0.0.1"), "AVRO", addressMapSchema);
201 schemas.getSchemasMap().put(avroSchema.getKey(), avroSchema);
202 final SchemaHelper schemaHelper = new SchemaHelperFactory().createSchemaHelper(testKey, avroSchema.getKey());
204 final HashMap<?, ?> newMapEmpty = (HashMap<?, ?>) schemaHelper.createNewInstance();
205 assertEquals(0, newMapEmpty.size());
207 final String inString = TextFileUtils.getTextFileAsString("src/test/resources/data/MapExampleAddressFull.json");
208 final HashMap<?, ?> newMapFull = (HashMap<?, ?>) schemaHelper.createNewInstance(inString);
210 assertEquals("{\"streetaddress\": \"221 B Baker St.\", \"city\": \"London\"}",
211 newMapFull.get(new Utf8("address2")).toString());
215 * Test long map unmarshal marshal.
217 * @throws IOException Signals that an I/O exception has occurred.
220 public void testLongMapUnmarshalMarshal() throws IOException {
221 final AxContextSchema avroSchema =
222 new AxContextSchema(new AxArtifactKey("AvroMap", "0.0.1"), "AVRO", longMapSchema);
224 schemas.getSchemasMap().put(avroSchema.getKey(), avroSchema);
225 final SchemaHelper schemaHelper = new SchemaHelperFactory().createSchemaHelper(testKey, avroSchema.getKey());
227 testUnmarshalMarshal(schemaHelper, "src/test/resources/data/MapExampleLongNull.json");
228 testUnmarshalMarshal(schemaHelper, "src/test/resources/data/MapExampleLongFull.json");
232 * Test address map unmarshal marshal.
234 * @throws IOException Signals that an I/O exception has occurred.
237 public void testAddressMapUnmarshalMarshal() throws IOException {
238 final AxContextSchema avroSchema =
239 new AxContextSchema(new AxArtifactKey("AvroMap", "0.0.1"), "AVRO", addressMapSchema);
241 schemas.getSchemasMap().put(avroSchema.getKey(), avroSchema);
242 final SchemaHelper schemaHelper = new SchemaHelperFactory().createSchemaHelper(testKey, avroSchema.getKey());
244 testUnmarshalMarshal(schemaHelper, "src/test/resources/data/MapExampleAddressNull.json");
245 testUnmarshalMarshal(schemaHelper, "src/test/resources/data/MapExampleAddressFull.json");
249 * Test sub record create.
251 * @throws IOException Signals that an I/O exception has occurred.
254 public void testSubRecordCreateRecord() throws IOException {
255 final AxContextSchema avroSchema =
256 new AxContextSchema(new AxArtifactKey("AvroMap", "0.0.1"), "AVRO", addressMapSchema);
258 schemas.getSchemasMap().put(avroSchema.getKey(), avroSchema);
259 final SchemaHelper schemaHelper = new SchemaHelperFactory().createSchemaHelper(testKey, avroSchema.getKey());
261 GenericRecord subRecord = (GenericRecord) schemaHelper.createNewSubInstance("AddressUSRecord");
262 assertNull(subRecord.get("streetAddress"));
266 * Test address map unmarshal marshal invalid fields.
268 * @throws IOException Signals that an I/O exception has occurred.
271 public void testAddressMapUnmarshalMarshalInvalidFields() throws IOException {
272 final AxContextSchema avroSchema =
273 new AxContextSchema(new AxArtifactKey("AvroMap", "0.0.1"), "AVRO", addressMapSchemaInvalidFields);
275 schemas.getSchemasMap().put(avroSchema.getKey(), avroSchema);
276 final SchemaHelper schemaHelper = new SchemaHelperFactory().createSchemaHelper(testKey, avroSchema.getKey());
278 testUnmarshalMarshal(schemaHelper, "src/test/resources/data/MapExampleAddressInvalidFields.json");
280 String vals = TextFileUtils.getTextFileAsString("src/test/resources/data/MapExampleAddressInvalidFields.json");
281 final HashMap<?, ?> newMapFull = (HashMap<?, ?>) schemaHelper.createNewInstance(vals);
282 final String expect = "{\"street_DasH_address\": \"Wayne Manor\", \"the_DoT_city\": \"Gotham City\", "
283 + "\"the_ColoN_code\": \"BatCave7\"}";
284 assertEquals(expect, newMapFull.get(new Utf8("address_DoT_3")).toString());
288 * Test unmarshal marshal.
290 * @param schemaHelper the schema helper
291 * @param fileName the file name
292 * @throws IOException Signals that an I/O exception has occurred.
294 private void testUnmarshalMarshal(final SchemaHelper schemaHelper, final String fileName) throws IOException {
295 final String originalInString = TextFileUtils.getTextFileAsString(fileName);
296 final HashMap<?, ?> firstDecodedMap = (HashMap<?, ?>) schemaHelper.unmarshal(originalInString);
298 final String outString = schemaHelper.marshal2String(firstDecodedMap);
300 final File tempOutFile = File.createTempFile("ApexAvro", ".json");
301 TextFileUtils.putStringAsFile(outString, tempOutFile);
303 final String decodeEncodeInString = TextFileUtils.getTextFileAsString(fileName);
304 tempOutFile.delete();
306 final HashMap<?, ?> secondDecodedMap = (HashMap<?, ?>) schemaHelper.unmarshal(decodeEncodeInString);
308 // Now check that our doubly encoded map equals the first decoded map, Java map equals
309 // checks values and keys
310 assertEquals(firstDecodedMap, secondDecodedMap);