package org.jboss.windup.config.loader; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import org.jboss.windup.config.AbstractRuleProvider; import org.jboss.windup.config.RuleProvider; import org.jboss.windup.config.metadata.MetadataBuilder; import org.jboss.windup.config.phase.DependentPhase; import org.jboss.windup.config.phase.RulePhase; import org.jboss.windup.util.exception.WindupMultiStringException; import org.junit.Assert; import org.junit.Test; import org.ocpsoft.rewrite.config.Configuration; public class RuleProviderSorterTest { private class Phase1 extends RulePhase { public Phase1() { super(Phase1.class); } @Override public Class<? extends RulePhase> getExecuteBefore() { return Phase2.class; } @Override public Class<? extends RulePhase> getExecuteAfter() { return null; } } private class Phase2 extends RulePhase { public Phase2() { super(Phase2.class); } @Override public Class<? extends RulePhase> getExecuteBefore() { return Phase3.class; } @Override public Class<? extends RulePhase> getExecuteAfter() { return null; } } private class Phase3 extends RulePhase { public Phase3() { super(Phase3.class); } @Override public Class<? extends RulePhase> getExecuteBefore() { return null; } @Override public Class<? extends RulePhase> getExecuteAfter() { return null; } } private class Phase4 extends RulePhase { public Phase4() { super(Phase4.class); } @Override public Class<? extends RulePhase> getExecuteBefore() { return null; } @Override public Class<? extends RulePhase> getExecuteAfter() { return Phase3.class; } } private static class WCPPhase1Class1 extends AbstractRuleProvider { public WCPPhase1Class1() { super(MetadataBuilder.forProvider(WCPPhase1Class1.class) .setPhase(Phase1.class)); } public WCPPhase1Class1(Class<? extends RuleProvider> dependency) { super(MetadataBuilder.forProvider(WCPPhase1Class1.class) .addExecuteAfter(dependency) .setPhase(Phase1.class)); } @Override public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext) { return null; } } private class WCPPhase1Class2 extends AbstractRuleProvider { public WCPPhase1Class2() { super(MetadataBuilder.forProvider(WCPPhase1Class2.class) .setPhase(Phase1.class) .addExecuteAfter(WCPPhase1Class1.class)); } @Override public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext) { return null; } } private class WCPPhaseDependentClass2 extends AbstractRuleProvider { public WCPPhaseDependentClass2() { super(MetadataBuilder.forProvider(WCPPhaseDependentClass2.class) .addExecuteAfter(WCPPhase1Class2.class)); } @Override public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext) { return null; } } private class WCPPhase1Class3 extends AbstractRuleProvider { public WCPPhase1Class3() { super(MetadataBuilder.forProvider(WCPPhase1Class3.class) .addExecuteAfter(WCPPhase1Class2.class) .setPhase(Phase1.class)); } @Override public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext) { return null; } } private class WCPPhase2Class1 extends AbstractRuleProvider { public WCPPhase2Class1() { super(MetadataBuilder.forProvider(WCPPhase2Class1.class) .setPhase(Phase2.class)); } @Override public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext) { return null; } } private class WCPPhase2Class3 extends AbstractRuleProvider { public WCPPhase2Class3() { super(MetadataBuilder.forProvider(WCPPhase2Class3.class) .addExecuteAfterId("WCPDependentPhase2Step2") .setPhase(Phase2.class)); } @Override public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext) { return null; } } private class WCPPhase2Class4 extends AbstractRuleProvider { public WCPPhase2Class4() { super(MetadataBuilder.forProvider(WCPPhase2Class4.class) .addExecuteAfterId("WCPPhase2Class3") .setPhase(Phase2.class)); } @Override public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext) { return null; } } private class WCPPhase1WrongPhaseDep extends AbstractRuleProvider { public WCPPhase1WrongPhaseDep() { super(MetadataBuilder.forProvider(WCPPhase1WrongPhaseDep.class) .addExecuteAfter(WCPPhase2Class1.class) .setPhase(Phase1.class)); } @Override public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext) { return null; } } private class WCPAcceptableCrossPhaseDep extends AbstractRuleProvider { public WCPAcceptableCrossPhaseDep() { super(MetadataBuilder.forProvider(WCPAcceptableCrossPhaseDep.class) .addExecuteAfter(WCPPhase2Class1.class) .setPhase(Phase3.class)); } @Override public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext) { return null; } } private class WCPDependentPhase2Step2 extends AbstractRuleProvider { public WCPDependentPhase2Step2() { super(MetadataBuilder.forProvider(WCPDependentPhase2Step2.class) .addExecuteAfter(WCPPhase2Class1.class) .addExecuteBefore(WCPPhase2Class3.class) .setPhase(DependentPhase.class)); } @Override public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext) { return null; } } private List<RulePhase> getPhases() { List<RulePhase> phases = new ArrayList<>(); // mix them up as we want to test sorting of these as well phases.add(new Phase3()); phases.add(new Phase1()); phases.add(new Phase4()); phases.add(new Phase2()); return phases; } @Test public void testSort() { AbstractRuleProvider v1 = new WCPPhase1Class1(); AbstractRuleProvider v2 = new WCPPhase1Class2(); AbstractRuleProvider vI = new WCPPhaseDependentClass2(); AbstractRuleProvider v3 = new WCPPhase1Class3(); AbstractRuleProvider v4 = new WCPPhase2Class1(); AbstractRuleProvider v5 = new WCPDependentPhase2Step2(); AbstractRuleProvider v6 = new WCPPhase2Class3(); AbstractRuleProvider v7 = new WCPPhase2Class4(); List<RuleProvider> ruleProviders = new ArrayList<>(); ruleProviders.add(v7); ruleProviders.add(v6); ruleProviders.add(vI); ruleProviders.add(v5); ruleProviders.add(v3); ruleProviders.add(v4); ruleProviders.add(v2); ruleProviders.add(v1); ruleProviders.addAll(getPhases()); List<RuleProvider> sortedRuleProviders = new ArrayList<>(RuleProviderSorter.sort(ruleProviders)); System.out.println("Results With Phases: " + sortedRuleProviders); /* * Remove phases (this makes asserting on the results easier) */ ListIterator<RuleProvider> iterator = sortedRuleProviders.listIterator(); while (iterator.hasNext()) { RuleProvider p = iterator.next(); if (p instanceof RulePhase) { iterator.remove(); } } System.out.println("Results without Phases: " + sortedRuleProviders); Assert.assertEquals(v1, sortedRuleProviders.get(0)); Assert.assertEquals(v2, sortedRuleProviders.get(1)); Assert.assertEquals(vI, sortedRuleProviders.get(2)); Assert.assertEquals(v3, sortedRuleProviders.get(3)); Assert.assertEquals(v4, sortedRuleProviders.get(4)); Assert.assertEquals(v5, sortedRuleProviders.get(5)); Assert.assertEquals(v6, sortedRuleProviders.get(6)); Assert.assertEquals(v7, sortedRuleProviders.get(7)); } @Test public void testSortCycle() { WCPPhase1Class1 v1 = new WCPPhase1Class1(WCPPhase1Class3.class); AbstractRuleProvider v2 = new WCPPhase1Class2(); AbstractRuleProvider v3 = new WCPPhase1Class3(); AbstractRuleProvider v4 = new WCPPhase2Class1(); List<RuleProvider> ruleProviders = new ArrayList<>(); ruleProviders.add(v3); ruleProviders.add(v4); ruleProviders.add(v2); ruleProviders.add(v1); try { RuleProviderSorter.sort(ruleProviders); Assert.fail("No cycles detected"); } catch (RuntimeException e) { Assert.assertTrue(e.getMessage().contains("Dependency cycles detected")); } } @Test public void testImproperCrossPhaseDependency() { AbstractRuleProvider v1 = new WCPPhase1Class1(); AbstractRuleProvider v2 = new WCPPhase1Class2(); AbstractRuleProvider v3 = new WCPPhase1Class3(); AbstractRuleProvider v4 = new WCPPhase2Class1(); AbstractRuleProvider v5 = new WCPPhase2Class3(); AbstractRuleProvider v6 = new WCPPhase2Class4(); AbstractRuleProvider wrongPhaseDep = new WCPPhase1WrongPhaseDep(); List<RuleProvider> ruleProviders = new ArrayList<>(); ruleProviders.add(v6); ruleProviders.add(v5); ruleProviders.add(v3); ruleProviders.add(v4); ruleProviders.add(v2); ruleProviders.add(v1); ruleProviders.add(wrongPhaseDep); try { RuleProviderSorter.sort(ruleProviders); Assert.fail("No improper phase dependencies detected!"); } catch (IncorrectPhaseDependencyException | WindupMultiStringException e) { // ignore... this exception is expected in this test } } @Test public void testAcceptableCrossPhaseDependency() { AbstractRuleProvider v1 = new WCPPhase1Class1(); AbstractRuleProvider v2 = new WCPPhase1Class2(); AbstractRuleProvider v3 = new WCPPhase1Class3(); AbstractRuleProvider v4 = new WCPPhase2Class1(); AbstractRuleProvider v5 = new WCPDependentPhase2Step2(); AbstractRuleProvider v6 = new WCPPhase2Class3(); AbstractRuleProvider v7 = new WCPPhase2Class4(); AbstractRuleProvider acceptablePhaseDep = new WCPAcceptableCrossPhaseDep(); List<RuleProvider> ruleProviders = new ArrayList<>(); ruleProviders.add(v7); ruleProviders.add(v6); ruleProviders.add(v5); ruleProviders.add(v3); ruleProviders.add(v4); ruleProviders.add(v2); ruleProviders.add(v1); ruleProviders.add(acceptablePhaseDep); try { RuleProviderSorter.sort(ruleProviders); } catch (IncorrectPhaseDependencyException e) { e.printStackTrace(); Assert.fail("This cross-dependency should be acceptable!"); } } @Test public void testPhaseSorting() { List<RuleProvider> ruleProviders = new ArrayList<>(); ruleProviders.addAll(getPhases()); List<RuleProvider> results = RuleProviderSorter.sort(ruleProviders); Assert.assertEquals(4, results.size()); int row = 0; Assert.assertTrue(results.get(row) instanceof Phase1); Assert.assertTrue(results.get(row).getMetadata().getExecuteAfter().isEmpty()); Assert.assertEquals(1, results.get(row).getMetadata().getExecuteBefore().size()); Assert.assertTrue(results.get(row).getMetadata().getExecuteBefore().get(0) == Phase2.class); row++; Assert.assertTrue(results.get(row) instanceof Phase2); Assert.assertEquals(1, results.get(row).getMetadata().getExecuteAfter().size()); Assert.assertEquals(1, results.get(row).getMetadata().getExecuteBefore().size()); Assert.assertTrue(results.get(row).getMetadata().getExecuteAfter().get(0) == Phase1.class); Assert.assertTrue(results.get(row).getMetadata().getExecuteBefore().get(0) == Phase3.class); row++; Assert.assertTrue(results.get(row) instanceof Phase3); Assert.assertEquals(1, results.get(row).getMetadata().getExecuteAfter().size()); Assert.assertEquals(1, results.get(row).getMetadata().getExecuteBefore().size()); Assert.assertTrue(results.get(row).getMetadata().getExecuteAfter().get(0) == Phase2.class); Assert.assertTrue(results.get(row).getMetadata().getExecuteBefore().get(0) == Phase4.class); row++; Assert.assertTrue(results.get(row) instanceof Phase4); Assert.assertEquals(1, results.get(row).getMetadata().getExecuteAfter().size()); Assert.assertEquals(0, results.get(row).getMetadata().getExecuteBefore().size()); Assert.assertTrue(results.get(row).getMetadata().getExecuteAfter().get(0) == Phase3.class); Assert.assertTrue(results.get(row).getMetadata().getExecuteBefore().isEmpty()); } }