bcbaa6ee8522d146b93ab7a912790d8d8f7ef57e
[yangtools.git] / parser / yang-parser-impl / src / test / java / org / opendaylight / yangtools / yang / parser / repo / SharedEffectiveModelContextFactoryTest.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.parser.repo;
9
10 import static java.util.Objects.requireNonNull;
11 import static org.hamcrest.CoreMatchers.instanceOf;
12 import static org.hamcrest.MatcherAssert.assertThat;
13 import static org.junit.Assert.assertNotNull;
14 import static org.junit.Assert.assertThrows;
15 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
16 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
17
18 import com.google.common.util.concurrent.ListenableFuture;
19 import java.util.concurrent.ExecutionException;
20 import org.junit.Before;
21 import org.junit.Test;
22 import org.junit.runner.RunWith;
23 import org.mockito.junit.MockitoJUnitRunner;
24 import org.opendaylight.yangtools.yang.common.Revision;
25 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
26 import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
27 import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
28 import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactoryConfiguration;
29 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
30 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
31 import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
32 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
33 import org.opendaylight.yangtools.yang.parser.rfc7950.ir.IRSchemaSource;
34 import org.opendaylight.yangtools.yang.parser.rfc7950.repo.TextToIRTransformer;
35
36 @RunWith(MockitoJUnitRunner.StrictStubs.class)
37 public class SharedEffectiveModelContextFactoryTest {
38
39     private final SharedSchemaRepository repository = new SharedSchemaRepository("test");
40
41     private final SchemaContextFactoryConfiguration config = SchemaContextFactoryConfiguration.getDefault();
42     private SourceIdentifier s1;
43     private SourceIdentifier s2;
44
45     @Before
46     public void setUp() {
47         final YangTextSchemaSource source1 = YangTextSchemaSource.forResource("/ietf/ietf-inet-types@2010-09-24.yang");
48         final YangTextSchemaSource source2 = YangTextSchemaSource.forResource("/ietf/iana-timezones@2012-07-09.yang");
49         s1 = RevisionSourceIdentifier.create("ietf-inet-types", Revision.of("2010-09-24"));
50         s2 = RevisionSourceIdentifier.create("iana-timezones", Revision.of("2012-07-09"));
51
52         final TextToIRTransformer transformer = TextToIRTransformer.create(repository, repository);
53         repository.registerSchemaSourceListener(transformer);
54
55         repository.registerSchemaSource(sourceIdentifier -> immediateFluentFuture(source1),
56             PotentialSchemaSource.create(s1, YangTextSchemaSource.class, 1));
57
58         repository.registerSchemaSource(sourceIdentifier -> immediateFluentFuture(source2),
59             PotentialSchemaSource.create(s2, YangTextSchemaSource.class, 1));
60     }
61
62     @Test
63     public void testCreateSchemaContextWithDuplicateRequiredSources() throws InterruptedException, ExecutionException {
64         final SharedEffectiveModelContextFactory sharedSchemaContextFactory =
65             new SharedEffectiveModelContextFactory(repository, config);
66         final ListenableFuture<EffectiveModelContext> schemaContext =
67                 sharedSchemaContextFactory.createEffectiveModelContext(s1, s1, s2);
68         assertNotNull(schemaContext.get());
69     }
70
71     @Test
72     public void testSourceRegisteredWithDifferentSI() throws Exception {
73         final YangTextSchemaSource source1 = YangTextSchemaSource.forResource("/ietf/ietf-inet-types@2010-09-24.yang");
74         final YangTextSchemaSource source2 = YangTextSchemaSource.forResource("/ietf/iana-timezones@2012-07-09.yang");
75         s1 = source1.getIdentifier();
76         s2 = source2.getIdentifier();
77
78         final SettableSchemaProvider<IRSchemaSource> provider =
79                 SharedSchemaRepositoryTest.getImmediateYangSourceProviderFromResource(
80                     "/no-revision/imported@2012-12-12.yang");
81         provider.setResult();
82         provider.register(repository);
83
84         // Register the same provider under source id without revision
85         final SourceIdentifier sIdWithoutRevision = RevisionSourceIdentifier.create(provider.getId().getName());
86         repository.registerSchemaSource(provider, PotentialSchemaSource.create(
87                 sIdWithoutRevision, IRSchemaSource.class, PotentialSchemaSource.Costs.IMMEDIATE.getValue()));
88
89         final SharedEffectiveModelContextFactory sharedSchemaContextFactory =
90             new SharedEffectiveModelContextFactory(repository, config);
91         final ListenableFuture<EffectiveModelContext> schemaContext =
92                 sharedSchemaContextFactory.createEffectiveModelContext(sIdWithoutRevision, provider.getId());
93         assertNotNull(schemaContext.get());
94     }
95
96     @Test
97     public void testTransientFailureWhilreRetrievingSchemaSource() throws Exception {
98         final RevisionSourceIdentifier s3 =
99             RevisionSourceIdentifier.create("network-topology", Revision.of("2013-10-21"));
100
101         repository.registerSchemaSource(new TransientFailureProvider(
102             YangTextSchemaSource.forResource("/ietf/network-topology@2013-10-21.yang")),
103             PotentialSchemaSource.create(s3, YangTextSchemaSource.class, 1));
104
105         final SharedEffectiveModelContextFactory sharedSchemaContextFactory =
106                 new SharedEffectiveModelContextFactory(repository, config);
107
108         ListenableFuture<EffectiveModelContext> schemaContext =
109                 sharedSchemaContextFactory.createEffectiveModelContext(s1, s3);
110
111         final ExecutionException exception = assertThrows(ExecutionException.class, schemaContext::get);
112         assertThat(exception.getCause(), instanceOf(MissingSchemaSourceException.class));
113
114         // check if future is invalidated and resolution of source is retried after failure
115         schemaContext = sharedSchemaContextFactory.createEffectiveModelContext(s1, s3);
116         assertNotNull(schemaContext.get());
117     }
118
119     /**
120      * Schema source provider that fails on first attempt of getSource() and succeeds on every subsequent call
121      * to simulate transient failures of source retrieval.
122      */
123     private static final class TransientFailureProvider implements SchemaSourceProvider<YangTextSchemaSource> {
124
125         private final YangTextSchemaSource schemaSource;
126         private boolean shouldFail = true;
127
128         private TransientFailureProvider(final YangTextSchemaSource schemaSource) {
129             this.schemaSource = requireNonNull(schemaSource);
130         }
131
132         @Override
133         public ListenableFuture<? extends YangTextSchemaSource> getSource(final SourceIdentifier sourceIdentifier) {
134             if (shouldFail) {
135                 shouldFail = false;
136                 return immediateFailedFluentFuture(new Exception("Transient test failure."));
137             }
138
139             return immediateFluentFuture(schemaSource);
140         }
141     }
142 }