From 7257dc4ecacf3e4d08273c31accd945fb8f3e769 Mon Sep 17 00:00:00 2001 From: Tom Pantelis Date: Mon, 7 Mar 2016 06:20:13 -0500 Subject: [PATCH] Fix wait for schema in BindingToNormalizedNodeCodec The wait for schema mechanism does not work. A few issues were fixed: - FutureSchema did not add the FutureSchemaPredicate instances to the postponedOperations list so they always timed out. - The waitForSchema method in BindingToNormalizedNodeCodec checked for !futureSchema.waitForSchema so it only successfully returned on failure. - There was a timing issue in FutureSchema where a context update could occur just prior to adding a postponed operation to the list, in which case the operation may timeout if the new update contained the postponed criteria and another update didn't occur in time. To alleviate this, the sychronization was tighted up and runtime context is now stored in FutureSchema instead of BindingToNormalizedNodeCodec. - The runtimeContext field needs to be volatile. I also added a wait if the runtimeContext was null b/c onGlobalContextUpdated hadn't been initially notified yet. Added unit tests to cover the wait for schema mechanism. Change-Id: I7155dae021453d085f89d13dfd4b069178dd2fc8 Signed-off-by: Tom Pantelis --- .../impl/BindingToNormalizedNodeCodec.java | 39 ++-- .../md/sal/binding/impl/FutureSchema.java | 72 +++++-- .../impl/BindingNormalizedCodecTest.java | 191 ++++++++++++++++++ .../impl/test/BindingNormalizedCodecTest.java | 69 ------- 4 files changed, 267 insertions(+), 104 deletions(-) create mode 100644 opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/BindingNormalizedCodecTest.java delete mode 100644 opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/BindingNormalizedCodecTest.java diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java index 845f422911..ee60afbfd3 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java @@ -78,7 +78,6 @@ public final class BindingToNormalizedNodeCodec implements BindingCodecTreeFacto }); - private BindingRuntimeContext runtimeContext; private DataNormalizer legacyToNormalized; public BindingToNormalizedNodeCodec(final GeneratedClassLoadingStrategy classLoadingStrategy, @@ -91,7 +90,7 @@ public final class BindingToNormalizedNodeCodec implements BindingCodecTreeFacto final BindingNormalizedNodeCodecRegistry codecRegistry,final boolean waitForSchema) { this.classLoadingStrategy = Preconditions.checkNotNull(classLoadingStrategy,"classLoadingStrategy"); this.codecRegistry = Preconditions.checkNotNull(codecRegistry,"codecRegistry"); - this.futureSchema = waitForSchema ? new FutureSchema(WAIT_DURATION_SEC, TimeUnit.SECONDS) : null; + this.futureSchema = new FutureSchema(WAIT_DURATION_SEC, TimeUnit.SECONDS, waitForSchema); } YangInstanceIdentifier toYangInstanceIdentifierBlocking(final InstanceIdentifier binding) { @@ -227,13 +226,11 @@ public final class BindingToNormalizedNodeCodec implements BindingCodecTreeFacto } @Override - public void onGlobalContextUpdated(final SchemaContext arg0) { - legacyToNormalized = new DataNormalizer(arg0); - runtimeContext = BindingRuntimeContext.create(classLoadingStrategy, arg0); + public void onGlobalContextUpdated(final SchemaContext schemaContext) { + legacyToNormalized = new DataNormalizer(schemaContext); + BindingRuntimeContext runtimeContext = BindingRuntimeContext.create(classLoadingStrategy, schemaContext); codecRegistry.onBindingRuntimeContextUpdated(runtimeContext); - if(futureSchema != null) { - futureSchema.onRuntimeContextUpdated(runtimeContext); - } + futureSchema.onRuntimeContextUpdated(runtimeContext); } public Function>, Optional> deserializeFunction(final InstanceIdentifier path) { @@ -306,33 +303,37 @@ public final class BindingToNormalizedNodeCodec implements BindingCodecTreeFacto final QNameModule moduleName = BindingReflections.getQNameModule(modeledClass); final URI namespace = moduleName.getNamespace(); final Date revision = moduleName.getRevision(); - Module module = runtimeContext.getSchemaContext().findModuleByNamespaceAndRevision(namespace, revision); - if(module == null && futureSchema != null && futureSchema.waitForSchema(namespace,revision)) { - module = runtimeContext.getSchemaContext().findModuleByNamespaceAndRevision(namespace, revision); + Module module = runtimeContext().getSchemaContext().findModuleByNamespaceAndRevision(namespace, revision); + if(module == null && futureSchema.waitForSchema(namespace,revision)) { + module = runtimeContext().getSchemaContext().findModuleByNamespaceAndRevision(namespace, revision); } Preconditions.checkState(module != null, "Schema for %s is not available.", modeledClass); return module; } private void waitForSchema(final Collection> binding, final MissingSchemaException e) { - if(futureSchema != null) { - LOG.warn("Blocking thread to wait for schema convergence updates for {} {}",futureSchema.getDuration(), futureSchema.getUnit()); - if(!futureSchema.waitForSchema(binding)) { - return; - } + LOG.warn("Blocking thread to wait for schema convergence updates for {} {}", futureSchema.getDuration(), + futureSchema.getUnit()); + if(futureSchema.waitForSchema(binding)) { + return; } + throw e; } private Method findRpcMethod(final Class key, final RpcDefinition rpcDef) throws NoSuchMethodException { final String methodName = BindingMapping.getMethodName(rpcDef.getQName()); if(rpcDef.getInput() != null) { - final Class inputClz = runtimeContext.getClassForSchema(rpcDef.getInput()); + final Class inputClz = runtimeContext().getClassForSchema(rpcDef.getInput()); return key.getMethod(methodName, inputClz); } return key.getMethod(methodName); } + private BindingRuntimeContext runtimeContext() { + return futureSchema.runtimeContext(); + } + @Override public BindingCodecTree create(final BindingRuntimeContext context) { return codecRegistry.create(context); @@ -361,11 +362,11 @@ public final class BindingToNormalizedNodeCodec implements BindingCodecTreeFacto @SuppressWarnings("unchecked") public Set> getNotificationClasses(final Set interested) { final Set> result = new HashSet<>(); - final Set knownNotifications = runtimeContext.getSchemaContext().getNotifications(); + final Set knownNotifications = runtimeContext().getSchemaContext().getNotifications(); for (final NotificationDefinition notification : knownNotifications) { if (interested.contains(notification.getPath())) { try { - result.add((Class) runtimeContext.getClassForSchema(notification)); + result.add((Class) runtimeContext().getClassForSchema(notification)); } catch (final IllegalStateException e) { // Ignore LOG.warn("Class for {} is currently not known.",notification.getPath(),e); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/FutureSchema.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/FutureSchema.java index 2898ba7e37..fb70811840 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/FutureSchema.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/FutureSchema.java @@ -13,29 +13,51 @@ import com.google.common.base.Throwables; import com.google.common.util.concurrent.SettableFuture; import java.net.URI; import java.util.Collection; +import java.util.Collections; import java.util.Date; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import javax.annotation.concurrent.GuardedBy; import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext; import org.opendaylight.yangtools.yang.binding.Augmentation; class FutureSchema implements AutoCloseable { - private final List postponedOperations = new CopyOnWriteArrayList<>(); + @GuardedBy(value="postponedOperations") + private final Set postponedOperations = new LinkedHashSet<>(); private final long duration; private final TimeUnit unit; + private final boolean waitEnabled; + private volatile BindingRuntimeContext runtimeContext; - protected FutureSchema(final long time, final TimeUnit unit) { + protected FutureSchema(final long time, final TimeUnit unit, final boolean waitEnabled) { this.duration = time; this.unit = unit; + this.waitEnabled = waitEnabled; + } + + BindingRuntimeContext runtimeContext() { + BindingRuntimeContext localRuntimeContext = runtimeContext; + if(localRuntimeContext != null) { + return localRuntimeContext; + } + + if(waitForSchema(Collections.emptyList())) { + return runtimeContext; + } + + throw new IllegalStateException("No SchemaContext is available"); } void onRuntimeContextUpdated(final BindingRuntimeContext context) { - for (final FutureSchemaPredicate op : postponedOperations) { - op.unlockIfPossible(context); + synchronized(postponedOperations) { + runtimeContext = context; + for (final FutureSchemaPredicate op : postponedOperations) { + op.unlockIfPossible(context); + } } } @@ -49,8 +71,10 @@ class FutureSchema implements AutoCloseable { @Override public void close() { - for (final FutureSchemaPredicate op : postponedOperations) { - op.cancel(); + synchronized(postponedOperations) { + for (final FutureSchemaPredicate op : postponedOperations) { + op.cancel(); + } } } @@ -65,19 +89,16 @@ class FutureSchema implements AutoCloseable { } boolean waitForSchema(final URI namespace, final Date revision) { - final FutureSchemaPredicate postponedOp = new FutureSchemaPredicate() { - + return addPostponedOpAndWait(new FutureSchemaPredicate() { @Override public boolean apply(final BindingRuntimeContext input) { return input.getSchemaContext().findModuleByNamespaceAndRevision(namespace, revision) != null; } - }; - return postponedOp.waitForSchema(); + }); } boolean waitForSchema(final Collection> bindingClasses) { - final FutureSchemaPredicate postponedOp = new FutureSchemaPredicate() { - + return addPostponedOpAndWait(new FutureSchemaPredicate() { @Override public boolean apply(final BindingRuntimeContext context) { for (final Class clz : bindingClasses) { @@ -87,7 +108,24 @@ class FutureSchema implements AutoCloseable { } return true; } - }; + }); + } + + private boolean addPostponedOpAndWait(FutureSchemaPredicate postponedOp) { + if(!waitEnabled) { + return false; + } + + BindingRuntimeContext localRuntimeContext = runtimeContext; + synchronized(postponedOperations) { + postponedOperations.add(postponedOp); + + // If the runtimeContext changed, this op may now be satisfied so check it. + if(localRuntimeContext != runtimeContext) { + postponedOp.unlockIfPossible(runtimeContext); + } + } + return postponedOp.waitForSchema(); } @@ -102,7 +140,9 @@ class FutureSchema implements AutoCloseable { } catch (final TimeoutException e) { return false; } finally { - postponedOperations.remove(this); + synchronized(postponedOperations) { + postponedOperations.remove(this); + } } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/BindingNormalizedCodecTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/BindingNormalizedCodecTest.java new file mode 100644 index 0000000000..2716fb7c54 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/BindingNormalizedCodecTest.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.sal.binding.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import com.google.common.collect.ImmutableBiMap; +import com.google.common.collect.Multimaps; +import com.google.common.collect.SetMultimap; +import com.google.common.util.concurrent.Uninterruptibles; +import java.lang.reflect.Method; +import java.net.URI; +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import org.junit.Test; +import org.opendaylight.controller.md.sal.binding.test.AbstractSchemaAwareTest; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeLeafOnlyAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.bi.ba.rpcservice.rev140701.OpendaylightTestRpcServiceService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey; +import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator; +import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; +import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; +import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy; +import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.util.AbstractSchemaContext; +import javassist.ClassPool; + +public class BindingNormalizedCodecTest extends AbstractSchemaAwareTest { + + private static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo"); + private static final InstanceIdentifier BA_TOP_LEVEL_LIST = InstanceIdentifier + .builder(Top.class).child(TopLevelList.class, TOP_FOO_KEY).build(); + private static final InstanceIdentifier BA_TREE_LEAF_ONLY = BA_TOP_LEVEL_LIST.augmentation(TreeLeafOnlyAugment.class); + private static final InstanceIdentifier BA_TREE_COMPLEX_USES = BA_TOP_LEVEL_LIST.augmentation(TreeComplexUsesAugment.class); + private static final QName SIMPLE_VALUE_QNAME = QName.create(TreeComplexUsesAugment.QNAME, "simple-value"); + private static final QName NAME_QNAME = QName.create(Top.QNAME, "name"); + private static final YangInstanceIdentifier BI_TOP_LEVEL_LIST = YangInstanceIdentifier.builder(). + node(Top.QNAME).node(TopLevelList.QNAME).nodeWithKey( + TopLevelList.QNAME, NAME_QNAME, TOP_FOO_KEY.getName()).build(); + + + private BindingToNormalizedNodeCodec codec; + private SchemaContext context; + + @Override + protected void setupWithSchema(final SchemaContext context) { + this.context = context; + final DataObjectSerializerGenerator streamWriter = StreamWriterGenerator.create(JavassistUtils.forClassPool(ClassPool.getDefault())); + final BindingNormalizedNodeCodecRegistry registry = new BindingNormalizedNodeCodecRegistry(streamWriter); + codec = new BindingToNormalizedNodeCodec(GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(), registry, true); + }; + + @Test + public void testComplexAugmentationSerialization() { + codec.onGlobalContextUpdated(context); + final PathArgument lastArg = codec.toYangInstanceIdentifier(BA_TREE_COMPLEX_USES).getLastPathArgument(); + assertTrue(lastArg instanceof AugmentationIdentifier); + } + + + @Test + public void testLeafOnlyAugmentationSerialization() { + codec.onGlobalContextUpdated(context); + final PathArgument leafOnlyLastArg = codec.toYangInstanceIdentifier(BA_TREE_LEAF_ONLY).getLastPathArgument(); + assertTrue(leafOnlyLastArg instanceof AugmentationIdentifier); + assertTrue(((AugmentationIdentifier) leafOnlyLastArg).getPossibleChildNames().contains(SIMPLE_VALUE_QNAME)); + } + + @Test + public void testToYangInstanceIdentifierBlocking() { + codec.onGlobalContextUpdated(new EmptySchemaContext()); + + final CountDownLatch done = new CountDownLatch(1); + final AtomicReference yangId = new AtomicReference<>(); + final AtomicReference error = new AtomicReference<>(); + new Thread() { + @Override + public void run() { + try { + yangId.set(codec.toYangInstanceIdentifierBlocking(BA_TOP_LEVEL_LIST)); + } catch(RuntimeException e) { + error.set(e); + } finally { + done.countDown(); + } + } + }.start(); + + Uninterruptibles.sleepUninterruptibly(500, TimeUnit.MILLISECONDS); + codec.onGlobalContextUpdated(context); + + assertEquals("toYangInstanceIdentifierBlocking completed", true, + Uninterruptibles.awaitUninterruptibly(done, 3, TimeUnit.SECONDS)); + if(error.get() != null) { + throw error.get(); + } + + assertEquals("toYangInstanceIdentifierBlocking", BI_TOP_LEVEL_LIST, yangId.get()); + } + + @Test + public void testGetRpcMethodToSchemaPathWithNoInitialSchemaContext() { + testGetRpcMethodToSchemaPath(); + } + + @Test + public void testGetRpcMethodToSchemaPathBlocking() { + codec.onGlobalContextUpdated(new EmptySchemaContext()); + testGetRpcMethodToSchemaPath(); + } + + private void testGetRpcMethodToSchemaPath() { + final CountDownLatch done = new CountDownLatch(1); + final AtomicReference> retMap = new AtomicReference<>(); + final AtomicReference error = new AtomicReference<>(); + new Thread() { + @Override + public void run() { + try { + retMap.set(codec.getRpcMethodToSchemaPath(OpendaylightTestRpcServiceService.class)); + } catch(RuntimeException e) { + error.set(e); + } finally { + done.countDown(); + } + } + }.start(); + + Uninterruptibles.sleepUninterruptibly(500, TimeUnit.MILLISECONDS); + codec.onGlobalContextUpdated(context); + + assertEquals("getRpcMethodToSchemaPath completed", true, + Uninterruptibles.awaitUninterruptibly(done, 3, TimeUnit.SECONDS)); + if(error.get() != null) { + throw error.get(); + } + + for(Method method: retMap.get().keySet()) { + if(method.getName().equals("rockTheHouse")) { + return; + } + } + + fail("rockTheHouse RPC method not found"); + } + + static class EmptySchemaContext extends AbstractSchemaContext { + @Override + public Set getModules() { + return Collections.emptySet(); + } + + @Override + protected Map getIdentifiersToSources() { + return Collections.emptyMap(); + } + + @Override + protected SetMultimap getNamespaceToModules() { + return Multimaps.forMap(Collections.emptyMap()); + } + + @Override + protected SetMultimap getNameToModules() { + return Multimaps.forMap(Collections.emptyMap()); + } + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/BindingNormalizedCodecTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/BindingNormalizedCodecTest.java deleted file mode 100644 index a427392201..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/BindingNormalizedCodecTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.controller.md.sal.binding.impl.test; - -import static org.junit.Assert.assertTrue; - -import javassist.ClassPool; -import org.junit.Test; -import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; -import org.opendaylight.controller.md.sal.binding.test.AbstractSchemaAwareTest; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugment; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeLeafOnlyAugment; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey; -import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator; -import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; -import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; -import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy; -import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; - -public class BindingNormalizedCodecTest extends AbstractSchemaAwareTest { - - private static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo"); - private static final InstanceIdentifier BA_TOP_LEVEL_LIST = InstanceIdentifier - .builder(Top.class).child(TopLevelList.class, TOP_FOO_KEY).toInstance(); - private static final InstanceIdentifier BA_TREE_LEAF_ONLY = BA_TOP_LEVEL_LIST.augmentation(TreeLeafOnlyAugment.class); - private static final InstanceIdentifier BA_TREE_COMPLEX_USES = BA_TOP_LEVEL_LIST.augmentation(TreeComplexUsesAugment.class); - private static final QName SIMPLE_VALUE_QNAME = QName.create(TreeComplexUsesAugment.QNAME, "simple-value"); - - - private BindingToNormalizedNodeCodec codec; - - @Override - protected void setupWithSchema(final SchemaContext context) { - final DataObjectSerializerGenerator streamWriter = StreamWriterGenerator.create(JavassistUtils.forClassPool(ClassPool.getDefault())); - final BindingNormalizedNodeCodecRegistry registry = new BindingNormalizedNodeCodecRegistry(streamWriter); - codec = new BindingToNormalizedNodeCodec(GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(), registry); - codec.onGlobalContextUpdated(context); - }; - - @Test - public void testComplexAugmentationSerialization() { - - final PathArgument lastArg = codec.toYangInstanceIdentifier(BA_TREE_COMPLEX_USES).getLastPathArgument(); - assertTrue(lastArg instanceof AugmentationIdentifier); - } - - - @Test - public void testLeafOnlyAugmentationSerialization() { - - final PathArgument leafOnlyLastArg = codec.toYangInstanceIdentifier(BA_TREE_LEAF_ONLY).getLastPathArgument(); - assertTrue(leafOnlyLastArg instanceof AugmentationIdentifier); - assertTrue(((AugmentationIdentifier) leafOnlyLastArg).getPossibleChildNames().contains(SIMPLE_VALUE_QNAME)); - } - -} -- 2.36.6