abc9335aebd911308f757e2a2d9b8bc3ff084c3a
[policy/apex-pdp.git] /
1 /*-
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
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.apex.plugins.context.schema.avro;
23
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;
28
29 import java.io.File;
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;
49
50 /**
51  * The Class TestAvroSchemaMap.
52  *
53  * @author Liam Fallon (liam.fallon@ericsson.com)
54  * @version
55  */
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;
62
63     /**
64      * Inits the test.
65      *
66      * @throws IOException Signals that an I/O exception has occurred.
67      */
68     @Before
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");
76     }
77
78     /**
79      * Inits the context.
80      */
81     @Before
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);
87     }
88
89     /**
90      * Clear context.
91      */
92     @After
93     public void clearContext() {
94         ParameterService.deregister(ContextParameterConstants.SCHEMA_GROUP_NAME);
95     }
96
97     /**
98      * Test valid schemas with substitutions.
99      *
100      * @throws IOException Signals that an I/O exception has occurred.
101      */
102     @Test
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);
109
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());
119
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);
125
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());
135
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);
141
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());
151     }
152
153     /**
154      * Test invalid schemas without substitutions.
155      *
156      * @throws IOException Signals that an I/O exception has occurred.
157      */
158     @Test
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());
169
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());
179
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());
189     }
190
191     /**
192      * Test map init.
193      *
194      * @throws IOException Signals that an I/O exception has occurred.
195      */
196     @Test
197     public void testMapInit() throws IOException {
198         final AxContextSchema avroSchema =
199                 new AxContextSchema(new AxArtifactKey("AvroRecord", "0.0.1"), "AVRO", addressMapSchema);
200
201         schemas.getSchemasMap().put(avroSchema.getKey(), avroSchema);
202         final SchemaHelper schemaHelper = new SchemaHelperFactory().createSchemaHelper(testKey, avroSchema.getKey());
203
204         final HashMap<?, ?> newMapEmpty = (HashMap<?, ?>) schemaHelper.createNewInstance();
205         assertEquals(0, newMapEmpty.size());
206
207         final String inString = TextFileUtils.getTextFileAsString("src/test/resources/data/MapExampleAddressFull.json");
208         final HashMap<?, ?> newMapFull = (HashMap<?, ?>) schemaHelper.createNewInstance(inString);
209
210         assertEquals("{\"streetaddress\": \"221 B Baker St.\", \"city\": \"London\"}",
211                 newMapFull.get(new Utf8("address2")).toString());
212     }
213
214     /**
215      * Test long map unmarshal marshal.
216      *
217      * @throws IOException Signals that an I/O exception has occurred.
218      */
219     @Test
220     public void testLongMapUnmarshalMarshal() throws IOException {
221         final AxContextSchema avroSchema =
222                 new AxContextSchema(new AxArtifactKey("AvroMap", "0.0.1"), "AVRO", longMapSchema);
223
224         schemas.getSchemasMap().put(avroSchema.getKey(), avroSchema);
225         final SchemaHelper schemaHelper = new SchemaHelperFactory().createSchemaHelper(testKey, avroSchema.getKey());
226
227         testUnmarshalMarshal(schemaHelper, "src/test/resources/data/MapExampleLongNull.json");
228         testUnmarshalMarshal(schemaHelper, "src/test/resources/data/MapExampleLongFull.json");
229     }
230
231     /**
232      * Test address map unmarshal marshal.
233      *
234      * @throws IOException Signals that an I/O exception has occurred.
235      */
236     @Test
237     public void testAddressMapUnmarshalMarshal() throws IOException {
238         final AxContextSchema avroSchema =
239                 new AxContextSchema(new AxArtifactKey("AvroMap", "0.0.1"), "AVRO", addressMapSchema);
240
241         schemas.getSchemasMap().put(avroSchema.getKey(), avroSchema);
242         final SchemaHelper schemaHelper = new SchemaHelperFactory().createSchemaHelper(testKey, avroSchema.getKey());
243
244         testUnmarshalMarshal(schemaHelper, "src/test/resources/data/MapExampleAddressNull.json");
245         testUnmarshalMarshal(schemaHelper, "src/test/resources/data/MapExampleAddressFull.json");
246     }
247
248     /**
249      * Test sub record create.
250      *
251      * @throws IOException Signals that an I/O exception has occurred.
252      */
253     @Test
254     public void testSubRecordCreateRecord() throws IOException {
255         final AxContextSchema avroSchema =
256                 new AxContextSchema(new AxArtifactKey("AvroMap", "0.0.1"), "AVRO", addressMapSchema);
257
258         schemas.getSchemasMap().put(avroSchema.getKey(), avroSchema);
259         final SchemaHelper schemaHelper = new SchemaHelperFactory().createSchemaHelper(testKey, avroSchema.getKey());
260
261         GenericRecord subRecord = (GenericRecord) schemaHelper.createNewSubInstance("AddressUSRecord");
262         assertNull(subRecord.get("streetAddress"));
263     }
264
265     /**
266      * Test address map unmarshal marshal invalid fields.
267      *
268      * @throws IOException Signals that an I/O exception has occurred.
269      */
270     @Test
271     public void testAddressMapUnmarshalMarshalInvalidFields() throws IOException {
272         final AxContextSchema avroSchema =
273                 new AxContextSchema(new AxArtifactKey("AvroMap", "0.0.1"), "AVRO", addressMapSchemaInvalidFields);
274
275         schemas.getSchemasMap().put(avroSchema.getKey(), avroSchema);
276         final SchemaHelper schemaHelper = new SchemaHelperFactory().createSchemaHelper(testKey, avroSchema.getKey());
277
278         testUnmarshalMarshal(schemaHelper, "src/test/resources/data/MapExampleAddressInvalidFields.json");
279
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());
285     }
286
287     /**
288      * Test unmarshal marshal.
289      *
290      * @param schemaHelper the schema helper
291      * @param fileName the file name
292      * @throws IOException Signals that an I/O exception has occurred.
293      */
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);
297
298         final String outString = schemaHelper.marshal2String(firstDecodedMap);
299
300         final File tempOutFile = File.createTempFile("ApexAvro", ".json");
301         TextFileUtils.putStringAsFile(outString, tempOutFile);
302
303         final String decodeEncodeInString = TextFileUtils.getTextFileAsString(fileName);
304         tempOutFile.delete();
305
306         final HashMap<?, ?> secondDecodedMap = (HashMap<?, ?>) schemaHelper.unmarshal(decodeEncodeInString);
307
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);
311     }
312 }