HONEYCOMB-266 - Test data injection with @InjectTestData
[honeycomb.git] / infra / test-utils / test-tools / src / main / java / io / fd / honeycomb / test / tools / factories / YangDataFactory.java
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package io.fd.honeycomb.test.tools.factories;
18
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21
22 import com.google.common.base.Optional;
23 import com.google.common.collect.Iterables;
24 import io.fd.honeycomb.translate.util.JsonUtils;
25 import java.io.IOException;
26 import java.util.AbstractMap;
27 import java.util.Map;
28 import javax.annotation.Nonnull;
29 import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
30 import org.opendaylight.yangtools.yang.binding.DataObject;
31 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
32 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
33 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
35 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
36 import org.opendaylight.yangtools.yang.data.util.AbstractModuleStringInstanceIdentifierCodec;
37 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
38 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
39 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
40
41 /**
42  * Common logic for reading of yang data
43  */
44 abstract class YangDataFactory {
45
46     final SchemaContext schemaContext;
47     final BindingToNormalizedNodeCodec serializer;
48     final AbstractModuleStringInstanceIdentifierCodec iidParser;
49
50     YangDataFactory(@Nonnull final SchemaContext schemaContext,
51                     @Nonnull final BindingToNormalizedNodeCodec serializer,
52                     @Nonnull final AbstractModuleStringInstanceIdentifierCodec iidParser) {
53         this.schemaContext = checkNotNull(schemaContext, "SchemaContext cannot be null");
54         this.serializer = checkNotNull(serializer, "Serializer cannot be null");
55         this.iidParser = checkNotNull(iidParser, "Instance identifier parser cannot be null");
56     }
57
58     DataObject getDataForNode(final YangInstanceIdentifier nodeYangIdentifier,
59                               final String resourcePath,
60                               final DataNodeContainer parentSchema)
61             throws DeserializationException, IOException {
62
63         // Reads resources from provided resource path
64         final ContainerNode rootData = getCheckedRootData(resourcePath, parentSchema);
65
66         // Now transform the single child from JSON into BA format
67         final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> actualData =
68                 extractCheckedSingleChild(rootData);
69
70         return getCheckedBinding(nodeYangIdentifier, actualData).getValue();
71     }
72
73     private ContainerNode getCheckedRootData(final String resourcePath, final DataNodeContainer parentSchema)
74             throws IOException {
75         // TODO the cast to SchemaNode is dangerous and would not work for Augments, Choices and some other nodes maybe. At least check
76         // TODO not sure if this is true, while testing this code was working fine event while processing choices/cases,
77         // TODO only problem is to find suitable codec that can process cases,etc
78         // Transform JSON into NormalizedNode
79
80         final ContainerNode rootData = JsonUtils.readJson(schemaContext,
81                 checkNotNull(this.getClass().getResource(resourcePath), "Unable to find resource %s", resourcePath)
82                         .openStream(), ((SchemaNode) parentSchema));
83
84         checkArgument(rootData.getValue().size() == 1, "Only a single data node is expected in %s, but there were: %s",
85                 resourcePath, rootData.getValue());
86         return rootData;
87     }
88
89     private DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> extractCheckedSingleChild(
90             final ContainerNode rootData) {
91         // Now transform the single child from JSON into BA format
92         final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> actualData =
93                 Iterables.getFirst(rootData.getValue(), null);
94
95         checkNotNull(actualData, "Unable to extract single child from %s", rootData);
96         return actualData;
97     }
98
99     private Map.Entry<InstanceIdentifier<? extends DataObject>, DataObject> getCheckedBinding(
100             final YangInstanceIdentifier nodeYangIdentifier,
101             final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> actualData)
102             throws DeserializationException {
103         final Optional<Map.Entry<InstanceIdentifier<? extends DataObject>, DataObject>> ba =
104                 serializer.toBinding(new AbstractMap.SimpleImmutableEntry<>(nodeYangIdentifier, actualData));
105
106         checkArgument(ba.isPresent(), "Unable to convert to binding %s", nodeYangIdentifier);
107         return ba.get();
108     }
109 }