2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2016-2018 Ericsson. All rights reserved.
4 * Modifications Copyright (C) 2020-2021 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);
166 SchemaHelperFactory sh = new SchemaHelperFactory();
167 AxArtifactKey ak = avroFailSchema1.getKey();
168 final Throwable exception1 = assertThrows(ContextRuntimeException.class,
169 () -> sh.createSchemaHelper(testKey, ak));
170 assertNotNull(exception1.getCause());
171 assertEquals("Illegal character in: A-B", exception1.getCause().getMessage());
173 final String fail2 = "{\"type\":\"record\",\"name\":\"Fail2\","
174 + "\"fields\":[{\"name\": \"C.D\",\"type\":\"int\"}]}";
175 final AxContextSchema avroFailSchema2 = new AxContextSchema(
176 new AxArtifactKey("AvroFail2", "0.0.1"), "AVRO", fail2);
177 schemas.getSchemasMap().put(avroFailSchema2.getKey(), avroFailSchema2);
179 AxArtifactKey ak2 = avroFailSchema2.getKey();
180 final Throwable exception2 = assertThrows(ContextRuntimeException.class,
181 () -> sh.createSchemaHelper(testKey, ak2));
182 assertNotNull(exception2.getCause());
183 assertEquals("Illegal character in: C.D", exception2.getCause().getMessage());
185 final String fail3 = "{\"type\":\"record\",\"name\":\"Fail3\","
186 + "\"fields\":[{\"name\": \"E:F\",\"type\":\"boolean\"}]}";
187 final AxContextSchema avroFailSchema3 = new AxContextSchema(
188 new AxArtifactKey("AvroFail3", "0.0.1"), "AVRO", fail3);
189 schemas.getSchemasMap().put(avroFailSchema3.getKey(), avroFailSchema3);
190 AxArtifactKey ak3 = avroFailSchema3.getKey();
191 final Throwable exception3 = assertThrows(ContextRuntimeException.class,
192 () -> sh.createSchemaHelper(testKey, ak3));
193 assertNotNull(exception3.getCause());
194 assertEquals("Illegal character in: E:F", exception3.getCause().getMessage());
200 * @throws IOException Signals that an I/O exception has occurred.
203 public void testMapInit() throws IOException {
204 final AxContextSchema avroSchema =
205 new AxContextSchema(new AxArtifactKey("AvroRecord", "0.0.1"), "AVRO", addressMapSchema);
207 schemas.getSchemasMap().put(avroSchema.getKey(), avroSchema);
208 final SchemaHelper schemaHelper = new SchemaHelperFactory().createSchemaHelper(testKey, avroSchema.getKey());
210 final HashMap<?, ?> newMapEmpty = (HashMap<?, ?>) schemaHelper.createNewInstance();
211 assertEquals(0, newMapEmpty.size());
213 final String inString = TextFileUtils.getTextFileAsString("src/test/resources/data/MapExampleAddressFull.json");
214 final HashMap<?, ?> newMapFull = (HashMap<?, ?>) schemaHelper.createNewInstance(inString);
216 assertEquals("{\"streetaddress\": \"221 B Baker St.\", \"city\": \"London\"}",
217 newMapFull.get(new Utf8("address2")).toString());
221 * Test long map unmarshal marshal.
223 * @throws IOException Signals that an I/O exception has occurred.
226 public void testLongMapUnmarshalMarshal() throws IOException {
227 final AxContextSchema avroSchema =
228 new AxContextSchema(new AxArtifactKey("AvroMap", "0.0.1"), "AVRO", longMapSchema);
230 schemas.getSchemasMap().put(avroSchema.getKey(), avroSchema);
231 final SchemaHelper schemaHelper = new SchemaHelperFactory().createSchemaHelper(testKey, avroSchema.getKey());
233 testUnmarshalMarshal(schemaHelper, "src/test/resources/data/MapExampleLongNull.json");
234 testUnmarshalMarshal(schemaHelper, "src/test/resources/data/MapExampleLongFull.json");
238 * Test address map unmarshal marshal.
240 * @throws IOException Signals that an I/O exception has occurred.
243 public void testAddressMapUnmarshalMarshal() throws IOException {
244 final AxContextSchema avroSchema =
245 new AxContextSchema(new AxArtifactKey("AvroMap", "0.0.1"), "AVRO", addressMapSchema);
247 schemas.getSchemasMap().put(avroSchema.getKey(), avroSchema);
248 final SchemaHelper schemaHelper = new SchemaHelperFactory().createSchemaHelper(testKey, avroSchema.getKey());
250 testUnmarshalMarshal(schemaHelper, "src/test/resources/data/MapExampleAddressNull.json");
251 testUnmarshalMarshal(schemaHelper, "src/test/resources/data/MapExampleAddressFull.json");
255 * Test sub record create.
257 * @throws IOException Signals that an I/O exception has occurred.
260 public void testSubRecordCreateRecord() throws IOException {
261 final AxContextSchema avroSchema =
262 new AxContextSchema(new AxArtifactKey("AvroMap", "0.0.1"), "AVRO", addressMapSchema);
264 schemas.getSchemasMap().put(avroSchema.getKey(), avroSchema);
265 final SchemaHelper schemaHelper = new SchemaHelperFactory().createSchemaHelper(testKey, avroSchema.getKey());
267 GenericRecord subRecord = (GenericRecord) schemaHelper.createNewSubInstance("AddressUSRecord");
268 assertNull(subRecord.get("streetAddress"));
272 * Test address map unmarshal marshal invalid fields.
274 * @throws IOException Signals that an I/O exception has occurred.
277 public void testAddressMapUnmarshalMarshalInvalidFields() throws IOException {
278 final AxContextSchema avroSchema =
279 new AxContextSchema(new AxArtifactKey("AvroMap", "0.0.1"), "AVRO", addressMapSchemaInvalidFields);
281 schemas.getSchemasMap().put(avroSchema.getKey(), avroSchema);
282 final SchemaHelper schemaHelper = new SchemaHelperFactory().createSchemaHelper(testKey, avroSchema.getKey());
284 testUnmarshalMarshal(schemaHelper, "src/test/resources/data/MapExampleAddressInvalidFields.json");
286 String vals = TextFileUtils.getTextFileAsString("src/test/resources/data/MapExampleAddressInvalidFields.json");
287 final HashMap<?, ?> newMapFull = (HashMap<?, ?>) schemaHelper.createNewInstance(vals);
288 final String expect = "{\"street_DasH_address\": \"Wayne Manor\", \"the_DoT_city\": \"Gotham City\", "
289 + "\"the_ColoN_code\": \"BatCave7\"}";
290 assertEquals(expect, newMapFull.get(new Utf8("address_DoT_3")).toString());
294 * Test unmarshal marshal.
296 * @param schemaHelper the schema helper
297 * @param fileName the file name
298 * @throws IOException Signals that an I/O exception has occurred.
300 private void testUnmarshalMarshal(final SchemaHelper schemaHelper, final String fileName) throws IOException {
301 final String originalInString = TextFileUtils.getTextFileAsString(fileName);
302 final HashMap<?, ?> firstDecodedMap = (HashMap<?, ?>) schemaHelper.unmarshal(originalInString);
304 final String outString = schemaHelper.marshal2String(firstDecodedMap);
306 final File tempOutFile = File.createTempFile("ApexAvro", ".json");
307 TextFileUtils.putStringAsFile(outString, tempOutFile);
309 final String decodeEncodeInString = TextFileUtils.getTextFileAsString(fileName);
310 tempOutFile.delete();
312 final HashMap<?, ?> secondDecodedMap = (HashMap<?, ?>) schemaHelper.unmarshal(decodeEncodeInString);
314 // Now check that our doubly encoded map equals the first decoded map, Java map equals
315 // checks values and keys
316 assertEquals(firstDecodedMap, secondDecodedMap);