2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.yangtools.yang.parser.repo;
11 import static junit.framework.Assert.assertEquals;
12 import static junit.framework.Assert.assertFalse;
13 import static junit.framework.Assert.assertNotNull;
14 import static junit.framework.Assert.assertSame;
15 import static junit.framework.Assert.assertTrue;
16 import static junit.framework.Assert.fail;
17 import static org.hamcrest.MatcherAssert.assertThat;
18 import static org.junit.matchers.JUnitMatchers.both;
19 import static org.junit.matchers.JUnitMatchers.hasItem;
20 import static org.mockito.Mockito.spy;
21 import static org.mockito.Mockito.times;
22 import static org.mockito.Mockito.verify;
24 import com.google.common.base.Function;
25 import com.google.common.base.Objects;
26 import com.google.common.base.Optional;
27 import com.google.common.collect.Collections2;
28 import com.google.common.collect.Lists;
29 import com.google.common.io.Files;
30 import com.google.common.io.InputSupplier;
31 import com.google.common.util.concurrent.CheckedFuture;
32 import com.google.common.util.concurrent.FutureCallback;
33 import com.google.common.util.concurrent.Futures;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.util.Arrays;
38 import java.util.List;
39 import java.util.concurrent.ExecutionException;
40 import org.apache.commons.io.IOUtils;
41 import org.junit.Test;
42 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
43 import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
44 import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
45 import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
46 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
47 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
48 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
49 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
50 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
51 import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
52 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceListener;
53 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
54 import org.opendaylight.yangtools.yang.model.repo.util.FilesystemSchemaSourceCache;
55 import org.opendaylight.yangtools.yang.parser.util.ASTSchemaSource;
56 import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer;
58 public class SharedSchemaRepositoryTest {
61 public void testSimpleSchemaContext() throws Exception {
62 final SharedSchemaRepository sharedSchemaRepository = new SharedSchemaRepository("netconf-mounts");
64 final SettableSchemaProvider<ASTSchemaSource> remoteInetTypesYang = getImmediateYangSourceProviderFromResource("/ietf/ietf-inet-types@2010-09-24.yang");
65 remoteInetTypesYang.register(sharedSchemaRepository);
66 final CheckedFuture<ASTSchemaSource, SchemaSourceException> registeredSourceFuture = sharedSchemaRepository.getSchemaSource(remoteInetTypesYang.getId(), ASTSchemaSource.class);
67 assertFalse(registeredSourceFuture.isDone());
69 final SchemaContextFactory fact = sharedSchemaRepository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
71 final CheckedFuture<SchemaContext, SchemaResolutionException> schemaContextFuture
72 = fact.createSchemaContext(Lists.newArrayList(remoteInetTypesYang.getId()));
74 assertFalse(schemaContextFuture.isDone());
77 remoteInetTypesYang.setResult();
78 assertEquals(remoteInetTypesYang.getSchemaSourceRepresentation(), registeredSourceFuture.get());
80 // Verify schema created successfully
81 assertTrue(schemaContextFuture.isDone());
82 final SchemaContext firstSchemaContext = schemaContextFuture.checkedGet();
83 assertSchemaContext(firstSchemaContext, 1);
85 // Try same schema second time
86 final CheckedFuture<SchemaContext, SchemaResolutionException> secondSchemaFuture =
87 sharedSchemaRepository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT)
88 .createSchemaContext(Lists.newArrayList(remoteInetTypesYang.getId()));
90 // Verify second schema created successfully immediately
91 assertTrue(secondSchemaFuture.isDone());
92 // Assert same context instance is returned from first and second attempt
93 assertSame(firstSchemaContext, secondSchemaFuture.checkedGet());
97 public void testTwoSchemaContextsSharingSource() throws Exception {
98 final SharedSchemaRepository sharedSchemaRepository = new SharedSchemaRepository("netconf-mounts");
100 final SettableSchemaProvider<ASTSchemaSource> remoteInetTypesYang = getImmediateYangSourceProviderFromResource("/ietf/ietf-inet-types@2010-09-24.yang");
101 remoteInetTypesYang.register(sharedSchemaRepository);
102 remoteInetTypesYang.setResult();
103 final SettableSchemaProvider<ASTSchemaSource> remoteTopologyYang = getImmediateYangSourceProviderFromResource("/ietf/network-topology@2013-10-21.yang");
104 remoteTopologyYang.register(sharedSchemaRepository);
105 remoteTopologyYang.setResult();
106 final SettableSchemaProvider<ASTSchemaSource> remoteModuleNoRevYang = getImmediateYangSourceProviderFromResource("/no-revision/module-without-revision.yang");
107 remoteModuleNoRevYang.register(sharedSchemaRepository);
109 final SchemaContextFactory fact = sharedSchemaRepository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
111 final CheckedFuture<SchemaContext, SchemaResolutionException> inetAndTopologySchemaContextFuture
112 = fact.createSchemaContext(Lists.newArrayList(remoteInetTypesYang.getId(), remoteTopologyYang.getId()));
113 assertTrue(inetAndTopologySchemaContextFuture.isDone());
114 assertSchemaContext(inetAndTopologySchemaContextFuture.checkedGet(), 2);
116 final CheckedFuture<SchemaContext, SchemaResolutionException> inetAndNoRevSchemaContextFuture
117 = fact.createSchemaContext(Lists.newArrayList(remoteInetTypesYang.getId(), remoteModuleNoRevYang.getId()));
118 assertFalse(inetAndNoRevSchemaContextFuture.isDone());
120 remoteModuleNoRevYang.setResult();
121 assertTrue(inetAndNoRevSchemaContextFuture.isDone());
122 assertSchemaContext(inetAndNoRevSchemaContextFuture.checkedGet(), 2);
126 public void testFailedSchemaContext() throws Exception {
127 final SharedSchemaRepository sharedSchemaRepository = new SharedSchemaRepository("netconf-mounts");
129 final SettableSchemaProvider<ASTSchemaSource> remoteInetTypesYang = getImmediateYangSourceProviderFromResource("/ietf/ietf-inet-types@2010-09-24.yang");
130 remoteInetTypesYang.register(sharedSchemaRepository);
132 final SchemaContextFactory fact = sharedSchemaRepository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
134 // Make source appear
135 final Throwable ex = new IllegalStateException("failed schema");
136 remoteInetTypesYang.setException(ex);
138 final CheckedFuture<SchemaContext, SchemaResolutionException> schemaContextFuture
139 = fact.createSchemaContext(Lists.newArrayList(remoteInetTypesYang.getId()));
142 schemaContextFuture.checkedGet();
143 } catch (final SchemaResolutionException e) {
144 assertNotNull(e.getCause());
145 assertNotNull(e.getCause().getCause());
146 assertSame(ex, e.getCause().getCause());
150 fail("Schema context creation should have failed");
154 public void testDifferentCosts() throws Exception {
155 final SharedSchemaRepository sharedSchemaRepository = new SharedSchemaRepository("netconf-mounts");
157 final SettableSchemaProvider<ASTSchemaSource> immediateInetTypesYang = spy(getImmediateYangSourceProviderFromResource("/ietf/ietf-inet-types@2010-09-24.yang"));
158 immediateInetTypesYang.register(sharedSchemaRepository);
159 immediateInetTypesYang.setResult();
161 final SettableSchemaProvider<ASTSchemaSource> remoteInetTypesYang = spy(getRemoteYangSourceProviderFromResource("/ietf/ietf-inet-types@2010-09-24.yang"));
162 remoteInetTypesYang.register(sharedSchemaRepository);
163 remoteInetTypesYang.setResult();
165 final SchemaContextFactory fact = sharedSchemaRepository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
167 final CheckedFuture<SchemaContext, SchemaResolutionException> schemaContextFuture
168 = fact.createSchemaContext(Lists.newArrayList(remoteInetTypesYang.getId()));
170 assertSchemaContext(schemaContextFuture.checkedGet(), 1);
172 final SourceIdentifier id = immediateInetTypesYang.getId();
173 verify(remoteInetTypesYang, times(0)).getSource(id);
174 verify(immediateInetTypesYang).getSource(id);
178 public void testWithCacheStartup() throws Exception {
179 final SharedSchemaRepository sharedSchemaRepository = new SharedSchemaRepository("netconf-mounts");
181 class CountingSchemaListener implements SchemaSourceListener {
182 List<PotentialSchemaSource<?>> registeredSources = Lists.newArrayList();
185 public void schemaSourceEncountered(final SchemaSourceRepresentation source) {
189 public void schemaSourceRegistered(final Iterable<PotentialSchemaSource<?>> sources) {
190 for (final PotentialSchemaSource<?> source : sources) {
191 registeredSources.add(source);
196 public void schemaSourceUnregistered(final PotentialSchemaSource<?> source) {
200 final File storageDir = Files.createTempDir();
202 final CountingSchemaListener listener = new CountingSchemaListener();
203 sharedSchemaRepository.registerSchemaSourceListener(listener);
205 final File test = new File(storageDir, "test.yang");
206 Files.copy(new StringSupplier("content-test"), test);
208 final File test2 = new File(storageDir, "test@2012-12-12.yang");
209 Files.copy(new StringSupplier("content-test-2012"), test2);
211 final File test3 = new File(storageDir, "test@2013-12-12.yang");
212 Files.copy(new StringSupplier("content-test-2013"), test3);
214 final File test4 = new File(storageDir, "module@2010-12-12.yang");
215 Files.copy(new StringSupplier("content-module-2010"), test4);
218 final FilesystemSchemaSourceCache<YangTextSchemaSource> cache = new FilesystemSchemaSourceCache<>(sharedSchemaRepository, YangTextSchemaSource.class, storageDir);
219 sharedSchemaRepository.registerSchemaSourceListener(cache);
221 assertEquals(4, listener.registeredSources.size());
223 final Function<PotentialSchemaSource<?>, SourceIdentifier> potSourceToSID = new Function<PotentialSchemaSource<?>, SourceIdentifier>() {
225 public SourceIdentifier apply(final PotentialSchemaSource<?> input) {
226 return input.getSourceIdentifier();
229 assertThat(Collections2.transform(listener.registeredSources, potSourceToSID),
230 both(hasItem(new SourceIdentifier("test", Optional.<String>absent())))
231 .and(hasItem(new SourceIdentifier("test", Optional.of("2012-12-12"))))
232 .and(hasItem(new SourceIdentifier("test", Optional.of("2013-12-12"))))
233 .and(hasItem(new SourceIdentifier("module", Optional.of("2010-12-12"))))
238 public void testWithCacheRunning() throws Exception {
239 final SharedSchemaRepository sharedSchemaRepository = new SharedSchemaRepository("netconf-mounts");
241 final File storageDir = Files.createTempDir();
243 final FilesystemSchemaSourceCache<YangTextSchemaSource> cache = new FilesystemSchemaSourceCache<>(sharedSchemaRepository, YangTextSchemaSource.class, storageDir);
244 sharedSchemaRepository.registerSchemaSourceListener(cache);
246 final SourceIdentifier runningId = new SourceIdentifier("running", Optional.of("2012-12-12"));
248 sharedSchemaRepository.registerSchemaSource(new SchemaSourceProvider<YangTextSchemaSource>() {
250 public CheckedFuture<YangTextSchemaSource, SchemaSourceException> getSource(final SourceIdentifier sourceIdentifier) {
251 return Futures.<YangTextSchemaSource, SchemaSourceException>immediateCheckedFuture(new YangTextSchemaSource(runningId) {
253 protected Objects.ToStringHelper addToStringAttributes(final Objects.ToStringHelper toStringHelper) {
254 return toStringHelper;
258 public InputStream openStream() throws IOException {
259 return IOUtils.toInputStream("running");
263 }, PotentialSchemaSource.create(runningId, YangTextSchemaSource.class, PotentialSchemaSource.Costs.REMOTE_IO.getValue()));
265 final TextToASTTransformer transformer = TextToASTTransformer.create(sharedSchemaRepository, sharedSchemaRepository);
266 sharedSchemaRepository.registerSchemaSourceListener(transformer);
268 // Request schema to make repository notify the cache
269 final CheckedFuture<SchemaContext, SchemaResolutionException> schemaFuture = sharedSchemaRepository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT).createSchemaContext(Lists.newArrayList(runningId));
270 Futures.addCallback(schemaFuture, new FutureCallback<SchemaContext>() {
272 public void onSuccess(final SchemaContext result) {
273 fail("Creation of schema context should fail from non-regular sources");
277 public void onFailure(final Throwable t) {
278 // Creation of schema context fails, since we do not provide regular sources, but we just want to check cache
279 final List<File> cachedSchemas = Arrays.asList(storageDir.listFiles());
280 assertEquals(1, cachedSchemas.size());
281 assertEquals(Files.getNameWithoutExtension(cachedSchemas.get(0).getName()), "running@2012-12-12");
287 } catch (final ExecutionException e) {
288 assertNotNull(e.getCause());
289 assertEquals(MissingSchemaSourceException.class, e.getCause().getClass());
293 fail("Creation of schema context should fail from non-regular sources");
296 private void assertSchemaContext(final SchemaContext schemaContext, final int moduleSize) {
297 assertNotNull(schemaContext);
298 assertEquals(moduleSize, schemaContext.getModules().size());
301 private SettableSchemaProvider<ASTSchemaSource> getRemoteYangSourceProviderFromResource(final String resourceName) throws Exception {
302 final ResourceYangSource yangSource = new ResourceYangSource(resourceName);
303 final CheckedFuture<ASTSchemaSource, SchemaSourceException> aSTSchemaSource = TextToASTTransformer.TRANSFORMATION.apply(yangSource);
304 return SettableSchemaProvider.createRemote(aSTSchemaSource.get(), ASTSchemaSource.class);
307 private SettableSchemaProvider<ASTSchemaSource> getImmediateYangSourceProviderFromResource(final String resourceName) throws Exception {
308 final ResourceYangSource yangSource = new ResourceYangSource(resourceName);
309 final CheckedFuture<ASTSchemaSource, SchemaSourceException> aSTSchemaSource = TextToASTTransformer.TRANSFORMATION.apply(yangSource);
310 return SettableSchemaProvider.createImmediate(aSTSchemaSource.get(), ASTSchemaSource.class);
313 private class StringSupplier implements InputSupplier<InputStream> {
314 private final String s;
316 public StringSupplier(final String s) {
321 public InputStream getInput() throws IOException {
322 return IOUtils.toInputStream(s);