BUG-997 Implement Filesystem source cache for schema repository
[yangtools.git] / yang / yang-parser-impl / src / test / java / org / opendaylight / yangtools / yang / parser / repo / SharedSchemaRepositoryTest.java
index ac7320c02c9ee1b691ba38cc8597496aa2e212f4..9a8790a428cf4f9eb1764d8c7941d86f1c9d2970 100644 (file)
@@ -14,24 +14,47 @@ import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertSame;
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.matchers.JUnitMatchers.both;
+import static org.junit.matchers.JUnitMatchers.hasItem;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import org.junit.Ignore;
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
+import com.google.common.io.InputSupplier;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import org.apache.commons.io.IOUtils;
 import org.junit.Test;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceListener;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
+import org.opendaylight.yangtools.yang.model.repo.util.FilesystemSchemaSourceCache;
 import org.opendaylight.yangtools.yang.parser.util.ASTSchemaSource;
 import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer;
 
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.CheckedFuture;
-
 public class SharedSchemaRepositoryTest {
 
     @Test
@@ -127,8 +150,6 @@ public class SharedSchemaRepositoryTest {
         fail("Schema context creation should have failed");
     }
 
-    // TODO
-    @Ignore("Costs are not considered when getting sources")
     @Test
     public void testDifferentCosts() throws Exception {
         final SharedSchemaRepository sharedSchemaRepository = new SharedSchemaRepository("netconf-mounts");
@@ -153,6 +174,125 @@ public class SharedSchemaRepositoryTest {
         verify(immediateInetTypesYang).getSource(id);
     }
 
+    @Test
+    public void testWithCacheStartup() throws Exception {
+        final SharedSchemaRepository sharedSchemaRepository = new SharedSchemaRepository("netconf-mounts");
+
+        class CountingSchemaListener implements SchemaSourceListener {
+            List<PotentialSchemaSource<?>> registeredSources = Lists.newArrayList();
+
+            @Override
+            public void schemaSourceEncountered(final SchemaSourceRepresentation source) {
+            }
+
+            @Override
+            public void schemaSourceRegistered(final Iterable<PotentialSchemaSource<?>> sources) {
+                for (final PotentialSchemaSource<?> source : sources) {
+                    registeredSources.add(source);
+                }
+            }
+
+            @Override
+            public void schemaSourceUnregistered(final PotentialSchemaSource<?> source) {
+            }
+        }
+
+        final File storageDir = Files.createTempDir();
+
+        final CountingSchemaListener listener = new CountingSchemaListener();
+        sharedSchemaRepository.registerSchemaSourceListener(listener);
+
+        final File test = new File(storageDir, "test.yang");
+        Files.copy(new StringSupplier("content-test"), test);
+
+        final File test2 = new File(storageDir, "test@2012-12-12.yang");
+        Files.copy(new StringSupplier("content-test-2012"), test2);
+
+        final File test3 = new File(storageDir, "test@2013-12-12.yang");
+        Files.copy(new StringSupplier("content-test-2013"), test3);
+
+        final File test4 = new File(storageDir, "module@2010-12-12.yang");
+        Files.copy(new StringSupplier("content-module-2010"), test4);
+
+
+        final FilesystemSchemaSourceCache<YangTextSchemaSource> cache = new FilesystemSchemaSourceCache<>(sharedSchemaRepository, YangTextSchemaSource.class, storageDir);
+        sharedSchemaRepository.registerSchemaSourceListener(cache);
+
+        assertEquals(4, listener.registeredSources.size());
+
+        final Function<PotentialSchemaSource<?>, SourceIdentifier> potSourceToSID = new Function<PotentialSchemaSource<?>, SourceIdentifier>() {
+            @Override
+            public SourceIdentifier apply(final PotentialSchemaSource<?> input) {
+                return input.getSourceIdentifier();
+            }
+        };
+        assertThat(Collections2.transform(listener.registeredSources, potSourceToSID),
+                both(hasItem(new SourceIdentifier("test", Optional.<String>absent())))
+                        .and(hasItem(new SourceIdentifier("test", Optional.of("2012-12-12"))))
+                        .and(hasItem(new SourceIdentifier("test", Optional.of("2013-12-12"))))
+                        .and(hasItem(new SourceIdentifier("module", Optional.of("2010-12-12"))))
+        );
+    }
+
+    @Test
+    public void testWithCacheRunning() throws Exception {
+        final SharedSchemaRepository sharedSchemaRepository = new SharedSchemaRepository("netconf-mounts");
+
+        final File storageDir = Files.createTempDir();
+
+        final FilesystemSchemaSourceCache<YangTextSchemaSource> cache = new FilesystemSchemaSourceCache<>(sharedSchemaRepository, YangTextSchemaSource.class, storageDir);
+        sharedSchemaRepository.registerSchemaSourceListener(cache);
+
+        final SourceIdentifier runningId = new SourceIdentifier("running", Optional.of("2012-12-12"));
+
+        sharedSchemaRepository.registerSchemaSource(new SchemaSourceProvider<YangTextSchemaSource>() {
+            @Override
+            public CheckedFuture<YangTextSchemaSource, SchemaSourceException> getSource(final SourceIdentifier sourceIdentifier) {
+                return Futures.<YangTextSchemaSource, SchemaSourceException>immediateCheckedFuture(new YangTextSchemaSource(runningId) {
+                    @Override
+                    protected Objects.ToStringHelper addToStringAttributes(final Objects.ToStringHelper toStringHelper) {
+                        return toStringHelper;
+                    }
+
+                    @Override
+                    public InputStream openStream() throws IOException {
+                        return IOUtils.toInputStream("running");
+                    }
+                });
+            }
+        }, PotentialSchemaSource.create(runningId, YangTextSchemaSource.class, PotentialSchemaSource.Costs.REMOTE_IO.getValue()));
+
+        final TextToASTTransformer transformer = TextToASTTransformer.create(sharedSchemaRepository, sharedSchemaRepository);
+        sharedSchemaRepository.registerSchemaSourceListener(transformer);
+
+        // Request schema to make repository notify the cache
+        final CheckedFuture<SchemaContext, SchemaResolutionException> schemaFuture = sharedSchemaRepository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT).createSchemaContext(Lists.newArrayList(runningId));
+        Futures.addCallback(schemaFuture, new FutureCallback<SchemaContext>() {
+            @Override
+            public void onSuccess(final SchemaContext result) {
+                fail("Creation of schema context should fail from non-regular sources");
+            }
+
+            @Override
+            public void onFailure(final Throwable t) {
+                // Creation of schema context fails, since we do not provide regular sources, but we just want to check cache
+                final List<File> cachedSchemas = Arrays.asList(storageDir.listFiles());
+                assertEquals(1, cachedSchemas.size());
+                assertEquals(Files.getNameWithoutExtension(cachedSchemas.get(0).getName()), "running@2012-12-12");
+            }
+        });
+
+        try {
+            schemaFuture.get();
+        } catch (final ExecutionException e) {
+            assertNotNull(e.getCause());
+            assertEquals(MissingSchemaSourceException.class, e.getCause().getClass());
+            return;
+        }
+
+        fail("Creation of schema context should fail from non-regular sources");
+    }
+
     private void assertSchemaContext(final SchemaContext schemaContext, final int moduleSize) {
         assertNotNull(schemaContext);
         assertEquals(moduleSize, schemaContext.getModules().size());
@@ -170,4 +310,16 @@ public class SharedSchemaRepositoryTest {
         return SettableSchemaProvider.createImmediate(aSTSchemaSource.get(), ASTSchemaSource.class);
     }
 
+    private class StringSupplier implements InputSupplier<InputStream> {
+        private final String s;
+
+        public StringSupplier(final String s) {
+            this.s = s;
+        }
+
+        @Override
+        public InputStream getInput() throws IOException {
+            return IOUtils.toInputStream(s);
+        }
+    }
 }