From: Robert Varga Date: Wed, 14 Dec 2016 13:30:40 +0000 (+0100) Subject: BUG-7267: catch RuntimeExceptions when processing sources X-Git-Tag: release/carbon~216 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=0048b68fcb198ac3ec97d3efe1e47c5cfa20a619;p=yangtools.git BUG-7267: catch RuntimeExceptions when processing sources This adds wrapping of all RuntimeExceptions when building EffectiveSchemaContext. This will allow users to identify the offending source. Since raw RuntimeExceptions should not be happening, but rather should be specialized to SourceException and its subclasses, also emit a warning guiding users to file issues to fix codepaths which do not do so. Also fixes up some instances where we use checkArgument() and we ca actually use SourceException.throwIf(). Change-Id: Ie1c3d05b39b251996b746c38c5b7a51946b19ff5 Signed-off-by: Robert Varga --- diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/BuildGlobalContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/BuildGlobalContext.java index 8781a3a442..6e67cd340b 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/BuildGlobalContext.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/BuildGlobalContext.java @@ -205,21 +205,37 @@ class BuildGlobalContext extends NamespaceStorageSupport implements NamespaceBeh return transformEffective(); } + private SomeModifiersUnresolvedException propagateException(final SourceSpecificContext source, + final RuntimeException cause) throws SomeModifiersUnresolvedException { + final SourceIdentifier sourceId = Utils.createSourceIdentifier(source.getRoot()); + if (!(cause instanceof SourceException)) { + /* + * This should not be happening as all our processing should provide SourceExceptions. + * We will wrap the exception to provide enough information to identify the problematic model, + * but also emit a warning so the offending codepath will get fixed. + */ + LOG.warn("Unexpected error processing source {}. Please file an issue with this model attached.", + sourceId, cause); + } + + throw new SomeModifiersUnresolvedException(currentPhase, sourceId, cause); + } + private EffectiveSchemaContext transformEffective() throws ReactorException { Preconditions.checkState(finishedPhase == ModelProcessingPhase.EFFECTIVE_MODEL); final List> rootStatements = new ArrayList<>(sources.size()); final List> rootEffectiveStatements = new ArrayList<>(sources.size()); - SourceIdentifier sourceId = null; try { for (final SourceSpecificContext source : sources) { final RootStatementContext root = source.getRoot(); - sourceId = Utils.createSourceIdentifier(root); - rootStatements.add(root.buildDeclared()); - rootEffectiveStatements.add(root.buildEffective()); + try { + rootStatements.add(root.buildDeclared()); + rootEffectiveStatements.add(root.buildEffective()); + } catch (final RuntimeException ex) { + throw propagateException(source, ex); + } } - } catch (final SourceException ex) { - throw new SomeModifiersUnresolvedException(currentPhase, sourceId, ex); } finally { RecursiveObjectLeaker.cleanup(); } @@ -241,9 +257,8 @@ class BuildGlobalContext extends NamespaceStorageSupport implements NamespaceBeh for (final SourceSpecificContext source : sources) { try { source.loadStatements(); - } catch (final SourceException ex) { - final SourceIdentifier sourceId = Utils.createSourceIdentifier(source.getRoot()); - throw new SomeModifiersUnresolvedException(currentPhase, sourceId, ex); + } catch (final RuntimeException ex) { + throw propagateException(source, ex); } } } @@ -298,35 +313,33 @@ class BuildGlobalContext extends NamespaceStorageSupport implements NamespaceBeh private void completePhaseActions() throws ReactorException { Preconditions.checkState(currentPhase != null); final List sourcesToProgress = Lists.newArrayList(sources); - SourceIdentifier sourceId = null; - try { - boolean progressing = true; - while (progressing) { - // We reset progressing to false. - progressing = false; - final Iterator currentSource = sourcesToProgress.iterator(); - while (currentSource.hasNext()) { - final SourceSpecificContext nextSourceCtx = currentSource.next(); - sourceId = Utils.createSourceIdentifier(nextSourceCtx.getRoot()); + boolean progressing = true; + while (progressing) { + // We reset progressing to false. + progressing = false; + final Iterator currentSource = sourcesToProgress.iterator(); + while (currentSource.hasNext()) { + final SourceSpecificContext nextSourceCtx = currentSource.next(); + try { final PhaseCompletionProgress sourceProgress = nextSourceCtx.tryToCompletePhase(currentPhase); switch (sourceProgress) { - case FINISHED: - currentSource.remove(); - // Fallback to progress, since we were able to make - // progress in computation - case PROGRESS: - progressing = true; - break; - case NO_PROGRESS: - // Noop - break; - default: - throw new IllegalStateException("Unsupported phase progress " + sourceProgress); + case FINISHED: + currentSource.remove(); + // Fallback to progress, since we were able to make + // progress in computation + case PROGRESS: + progressing = true; + break; + case NO_PROGRESS: + // Noop + break; + default: + throw new IllegalStateException("Unsupported phase progress " + sourceProgress); } + } catch (RuntimeException ex) { + throw propagateException(nextSourceCtx, ex); } } - } catch (final SourceException e) { - throw new SomeModifiersUnresolvedException(currentPhase, sourceId, e); } if (!sourcesToProgress.isEmpty()) { final SomeModifiersUnresolvedException buildFailure = addSourceExceptions(sourcesToProgress); diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AugmentStatementImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AugmentStatementImpl.java index 19c644ed39..7651bc0615 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AugmentStatementImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AugmentStatementImpl.java @@ -7,7 +7,6 @@ */ package org.opendaylight.yangtools.yang.parser.stmt.rfc6020; -import com.google.common.base.Preconditions; import com.google.common.base.Verify; import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.ImmutableSet; @@ -83,9 +82,10 @@ public class AugmentStatementImpl extends AbstractDeclaredStatement ctx, final String value) { - Preconditions.checkArgument(!PATH_REL_PATTERN1.matcher(value).matches() - && !PATH_REL_PATTERN2.matcher(value).matches(), - "An argument for augment can be only absolute path; or descendant if used in uses"); + SourceException.throwIf(PATH_REL_PATTERN1.matcher(value).matches() + || PATH_REL_PATTERN2.matcher(value).matches(), ctx.getStatementSourceReference(), + "Augment argument \'%s\' is not valid, it can be only absolute path; or descendant if used in uses", + value); return Utils.nodeIdentifierFromPath(ctx, value); } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementDefinition.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementDefinition.java index f4b9b4c440..37843bbfcf 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementDefinition.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementDefinition.java @@ -49,6 +49,7 @@ import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToSemVerModule import org.opendaylight.yangtools.yang.parser.spi.source.ImportedModuleContext; import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleIdentifier; import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToNamespace; +import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.ImportEffectiveStatementImpl; public class ImportStatementDefinition extends @@ -104,8 +105,10 @@ public class ImportStatementDefinition extends final URI importedModuleNamespace = importedModuleContext.getFromNamespace(ModuleNameToNamespace.class, moduleName); Verify.verifyNotNull(importedModuleNamespace); - final String impPrefix = firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class); - Verify.verifyNotNull(impPrefix); + final String impPrefix = SourceException.throwIfNull( + firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class), + stmt.getStatementSourceReference(), "Missing prefix statement"); + stmt.addToNs(ImpPrefixToNamespace.class, impPrefix, importedModuleNamespace); } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/KeyStatementImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/KeyStatementImpl.java index 451e6130b2..74f968f312 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/KeyStatementImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/KeyStatementImpl.java @@ -7,7 +7,6 @@ */ package org.opendaylight.yangtools.yang.parser.stmt.rfc6020; -import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet.Builder; import java.util.Collection; @@ -20,6 +19,7 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractDeclaredStatement import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils; +import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.KeyEffectiveStatementImpl; public class KeyStatementImpl extends AbstractDeclaredStatement> implements @@ -52,9 +52,8 @@ public class KeyStatementImpl extends AbstractDeclaredStatement ret = builder.build(); - - Preconditions.checkArgument(ret.size() == tokens, "Key argument '%s' contains duplicates. At %s", value, - ctx.getStatementSourceReference()); + SourceException.throwIf(ret.size() != tokens, ctx.getStatementSourceReference(), + "Key argument '%s' contains duplicates", value); return ret; } @@ -71,7 +70,7 @@ public class KeyStatementImpl extends AbstractDeclaredStatement, KeyStatement, + public void onFullDefinitionDeclared(final StmtContext.Mutable, KeyStatement, EffectiveStatement, KeyStatement>> stmt) { super.onFullDefinitionDeclared(stmt); SUBSTATEMENT_VALIDATOR.validate(stmt); diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java index 716a48fa9a..0a5bfbc8c0 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java @@ -52,6 +52,7 @@ import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier; import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; import org.opendaylight.yangtools.yang.model.util.RevisionAwareXPathImpl; import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType; +import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException; import org.opendaylight.yangtools.yang.parser.spi.meta.QNameCacheNamespace; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils; @@ -445,9 +446,9 @@ public final class Utils { try { final QName qName = Utils.qNameFromArgument(ctx, nodeName); qNames.add(qName); - } catch (final Exception e) { - throw new IllegalArgumentException( - String.format("Failed to parse node '%s' in path '%s'", nodeName, path), e); + } catch (final RuntimeException e) { + throw new SourceException(ctx.getStatementSourceReference(), e, + "Failed to parse node '%s' in path '%s'", nodeName, path); } } @@ -519,9 +520,9 @@ public final class Utils { break; } - Preconditions.checkArgument(qNameModule != null, - "Error in module '%s': can not resolve QNameModule for '%s'. Statement source at %s", - ctx.getRoot().rawStatementArgument(), value, ctx.getStatementSourceReference()); + qNameModule = InferenceException.throwIfNull(qNameModule, ctx.getStatementSourceReference(), + "Cannot resolve QNameModule for '%s'", value); + final QNameModule resultQNameModule; if (qNameModule.getRevision() == null) { resultQNameModule = QNameModule.create(qNameModule.getNamespace(), SimpleDateFormatUtil.DEFAULT_DATE_REV) @@ -582,9 +583,8 @@ public final class Utils { } public static DeviateKind parseDeviateFromString(final StmtContext ctx, final String deviateKeyword) { - return Preconditions.checkNotNull(KEYWORD_TO_DEVIATE_MAP.get(deviateKeyword), - "String '%s' is not valid deviate argument. Statement source at %s", deviateKeyword, - ctx.getStatementSourceReference()); + return SourceException.throwIfNull(KEYWORD_TO_DEVIATE_MAP.get(deviateKeyword), + ctx.getStatementSourceReference(), "String '%s' is not valid deviate argument", deviateKeyword); } public static Status parseStatus(final String value) { diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/AugmentArgumentParsingTest.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/AugmentArgumentParsingTest.java index 0f4c8fd22d..d72b1ed9c6 100644 --- a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/AugmentArgumentParsingTest.java +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/AugmentArgumentParsingTest.java @@ -10,6 +10,7 @@ package org.opendaylight.yangtools.yang.stmt; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.junit.Ignore; @@ -41,7 +42,7 @@ public class AugmentArgumentParsingTest { "/semantic-statement-parser/augment-arg-parsing/root-invalid-xpath.yang", false); @Test - public void validAugAbsTest() throws SourceException, ReactorException { + public void validAugAbsTest() throws ReactorException { BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(); addSources(reactor, IMPORTED, VALID_ARGS); @@ -51,7 +52,7 @@ public class AugmentArgumentParsingTest { } @Test - public void invalidAugRel1Test() throws SourceException, ReactorException { + public void invalidAugRel1Test() { BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(); addSources(reactor, INVALID_REL1); @@ -59,13 +60,13 @@ public class AugmentArgumentParsingTest { try { reactor.build(); fail("reactor.process should fail due to invalid relative path"); - } catch (Exception e) { - assertEquals(IllegalArgumentException.class, e.getClass()); + } catch (ReactorException e) { + assertSourceExceptionCause(e, "Augment argument './aug1/aug11' is not valid"); } } @Test - public void invalidAugRel2Test() throws SourceException, ReactorException { + public void invalidAugRel2Test() { BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(); addSources(reactor, INVALID_REL2); @@ -73,13 +74,13 @@ public class AugmentArgumentParsingTest { try { reactor.build(); fail("reactor.process should fail due to invalid relative path"); - } catch (Exception e) { - assertEquals(IllegalArgumentException.class, e.getClass()); + } catch (ReactorException e) { + assertSourceExceptionCause(e, "Augment argument '../aug1/aug11' is not valid"); } } @Test - public void invalidAugAbs() throws SourceException, ReactorException { + public void invalidAugAbs() { BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(); addSources(reactor, INVALID_ABS); @@ -87,13 +88,13 @@ public class AugmentArgumentParsingTest { try { reactor.build(); fail("reactor.process should fail due to invalid absolute path"); - } catch (Exception e) { - assertEquals(IllegalArgumentException.class, e.getClass()); + } catch (ReactorException e) { + assertSourceExceptionCause(e, "Augment argument '//aug1/aug11/aug111' is not valid"); } } @Test - public void invalidAugAbsPrefixedNoImp() throws SourceException, ReactorException { + public void invalidAugAbsPrefixedNoImp() { BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(); addSources(reactor, INVALID_ABS_PREFIXED_NO_IMP); @@ -101,8 +102,8 @@ public class AugmentArgumentParsingTest { try { reactor.build(); fail("reactor.process should fail due to missing import from augment path"); - } catch (Exception e) { - assertEquals(IllegalArgumentException.class, e.getClass()); + } catch (ReactorException e) { + assertSourceExceptionCause(e, "Failed to parse node 'imp:aug1'"); } } @@ -136,6 +137,12 @@ public class AugmentArgumentParsingTest { } } + private static void assertSourceExceptionCause(final Throwable e, final String start) { + final Throwable cause = e.getCause(); + assertTrue(cause instanceof SourceException); + assertTrue(cause.getMessage().startsWith(start)); + } + private static void addSources(final BuildAction reactor, final YangStatementSourceImpl... sources) { for (YangStatementSourceImpl source : sources) { reactor.addSource(source); diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/Bug4933Test.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/Bug4933Test.java index b927b18325..948f4e3ed1 100644 --- a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/Bug4933Test.java +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/Bug4933Test.java @@ -24,7 +24,7 @@ import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; public class Bug4933Test { @Test - public void test() throws SourceException, ReactorException, FileNotFoundException, URISyntaxException { + public void test() throws ReactorException, FileNotFoundException, URISyntaxException { SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug4933/correct"); assertNotNull(context); @@ -33,13 +33,14 @@ public class Bug4933Test { } @Test - public void incorrectKeywordTest() throws SourceException, ReactorException, FileNotFoundException, - URISyntaxException { + public void incorrectKeywordTest() throws FileNotFoundException, URISyntaxException { try { StmtTestUtils.parseYangSources("/bugs/bug4933/incorrect"); - fail("NullPointerException should be thrown."); - } catch (NullPointerException e) { - assertTrue(e.getMessage().startsWith("String 'not_supported' is not valid deviate argument. Statement source at")); + fail("ReactorException should be thrown."); + } catch (ReactorException e) { + final Throwable cause = e.getCause(); + assertTrue(cause instanceof SourceException); + assertTrue(cause.getMessage().startsWith("String 'not_supported' is not valid deviate argument")); } } } diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/KeyTest.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/KeyTest.java index 5c3eb5f16c..3d2a772ab1 100644 --- a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/KeyTest.java +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/KeyTest.java @@ -8,9 +8,10 @@ package org.opendaylight.yangtools.yang.stmt; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; + import org.junit.Test; import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException; import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; @@ -27,7 +28,7 @@ public class KeyTest { "/semantic-statement-parser/key-arg-parsing/key-comp-duplicate.yang", false); @Test - public void keySimpleTest() throws SourceException, ReactorException { + public void keySimpleTest() throws ReactorException { BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(); addSources(reactor, KEY_SIMPLE_AND_COMP); @@ -37,7 +38,7 @@ public class KeyTest { } @Test - public void keyCompositeInvalid() throws SourceException, ReactorException { + public void keyCompositeInvalid() { BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(); addSources(reactor, KEY_COMP_DUPLICATE); @@ -45,8 +46,10 @@ public class KeyTest { try { reactor.build(); fail("reactor.process should fail due to duplicate name in key"); - } catch (Exception e) { - assertEquals(IllegalArgumentException.class, e.getClass()); + } catch (ReactorException e) { + final Throwable cause = e.getCause(); + assertTrue(cause instanceof SourceException); + assertTrue(cause.getMessage().startsWith("Key argument 'key1 key2 key2' contains duplicates")); } } diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/SubstatementValidatorTest.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/SubstatementValidatorTest.java index f57a2a6a42..b4a2417718 100644 --- a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/SubstatementValidatorTest.java +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/SubstatementValidatorTest.java @@ -13,7 +13,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import com.google.common.base.VerifyException; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.io.UnsupportedEncodingException; @@ -78,7 +77,7 @@ public class SubstatementValidatorTest { @Test public void missingElementException() throws URISyntaxException, ReactorException { - expectedEx.expect(VerifyException.class); + expectedEx.expect(SomeModifiersUnresolvedException.class); TestUtils.loadModules(getClass().getResource("/substatement-validator/missing-element").toURI()); } diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/yin/YinFileStmtTest.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/yin/YinFileStmtTest.java index ed4d952184..69e4a6e606 100644 --- a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/yin/YinFileStmtTest.java +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/yin/YinFileStmtTest.java @@ -9,6 +9,8 @@ package org.opendaylight.yangtools.yang.stmt.yin; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.net.URISyntaxException; import java.util.Set; @@ -63,12 +65,19 @@ public class YinFileStmtTest { } // parsing yin file with duplicate key name in a list statement - @Test(expected = IllegalArgumentException.class) - public void readAndParseInvalidYinFileTest2() throws ReactorException { + public void readAndParseInvalidYinFileTest2() { CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(); addSources(reactor, INVALID_YIN_FILE_2); - EffectiveSchemaContext result = reactor.buildEffective(); - assertNotNull(result); + + try { + reactor.buildEffective(); + fail("Reactor exception should have been thrown"); + } catch (ReactorException e) { + final Throwable cause = e.getCause(); + assertTrue(cause instanceof SourceException); + assertTrue(cause.getMessage().startsWith( + "Key argument 'testing-string testing-string' contains duplicates")); + } } @Test