Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-02-27 07:19:59

0001 /*
0002  *  interval_t.cc
0003  *  EDMProto
0004  *
0005  *  Created by Chris Jones on 3/30/05.
0006  *  Changed by Viji Sundararajan on 29-Jun-05.
0007  *
0008  */
0009 
0010 #include <unordered_map>
0011 #include <unordered_set>
0012 #include <algorithm>
0013 #include <cassert>
0014 #include <vector>
0015 
0016 #include "FWCore/Framework/interface/PathsAndConsumesOfModules.h"
0017 #include "FWCore/ServiceRegistry/interface/ESModuleConsumesInfo.h"
0018 #include "FWCore/ServiceRegistry/interface/ModuleConsumesESInfo.h"
0019 #include "FWCore/ServiceRegistry/interface/ModuleConsumesInfo.h"
0020 #include "FWCore/Utilities/interface/Exception.h"
0021 #include "FWCore/Utilities/interface/Transition.h"
0022 #include "DataFormats/Provenance/interface/ParameterSetID.h"
0023 #include "DataFormats/Provenance/interface/ModuleDescription.h"
0024 #include "DataFormats/Provenance/interface/ProcessConfiguration.h"
0025 #include "cppunit/extensions/HelperMacros.h"
0026 
0027 #include "makeDummyProcessConfiguration.h"
0028 
0029 namespace edm {
0030   class ESProducer;
0031 
0032   namespace eventsetup {
0033     struct ComponentDescription;
0034     class ESProductResolverProvider;
0035   }  // namespace eventsetup
0036 }  // namespace edm
0037 
0038 using ModuleDependsOnMap = std::map<std::string, std::vector<std::string>>;
0039 using PathToModules = std::unordered_map<std::string, std::vector<std::string>>;
0040 
0041 namespace {
0042   class PathsAndConsumesOfModulesForTest : public edm::PathsAndConsumesOfModulesBase {
0043   public:
0044     PathsAndConsumesOfModulesForTest(ModuleDependsOnMap const&, PathToModules const&);
0045 
0046   private:
0047     std::vector<std::string> const& doPaths() const final { return m_paths; }
0048     std::vector<std::string> const& doEndPaths() const final { return m_endPaths; }
0049     std::vector<edm::ModuleDescription const*> const& doAllModules() const final { return m_modules; }
0050     edm::ModuleDescription const* doModuleDescription(unsigned int moduleID) const final { return m_modules[moduleID]; }
0051     std::vector<edm::ModuleDescription const*> const& doModulesOnPath(unsigned int pathIndex) const final {
0052       return m_modulesOnPath[pathIndex];
0053     }
0054     std::vector<edm::ModuleDescription const*> const& doModulesOnEndPath(unsigned int endPathIndex) const final {
0055       return m_modulesOnEndPath[endPathIndex];
0056     }
0057     std::vector<edm::ModuleDescription const*> const& doModulesWhoseProductsAreConsumedBy(
0058         unsigned int moduleID, edm::BranchType branchType) const final {
0059       return m_modulesWhoseProductsAreConsumedBy[moduleID];
0060     }
0061 
0062     std::vector<edm::ModuleConsumesInfo> doModuleConsumesInfos(unsigned int moduleID) const final {
0063       return m_moduleConsumesInfo[moduleID];
0064     }
0065 
0066     unsigned int doLargestModuleID() const final {
0067       if (m_modules.empty()) {
0068         return 0;
0069       }
0070       return m_modules.size() - 1;
0071     }
0072 
0073     // The next 6 functions only exist to allow this to compile. These functions are
0074     // pure virtual in the base class. They're not used in this test and never get called.
0075     std::vector<edm::eventsetup::ComponentDescription const*> const& doESModulesWhoseProductsAreConsumedBy(
0076         unsigned int, edm::Transition) const {
0077       return m_dummy1;
0078     }
0079     std::vector<edm::ModuleConsumesESInfo> doModuleConsumesESInfos(unsigned int) const final { return {}; }
0080     std::vector<edm::eventsetup::ComponentDescription const*> const& doAllESModules() const { return m_dummy1; }
0081     edm::eventsetup::ComponentDescription const* doComponentDescription(unsigned int esModuleID) const final {
0082       return nullptr;
0083     }
0084     std::vector<std::vector<edm::eventsetup::ComponentDescription const*>> const&
0085     doESModulesWhoseProductsAreConsumedByESModule() const final {
0086       return m_dummy2;
0087     }
0088     std::vector<std::vector<edm::ESModuleConsumesInfo>> doESModuleConsumesInfos(unsigned int) const final { return {}; }
0089 
0090     std::vector<std::string> m_paths;
0091     std::vector<std::string> m_endPaths;
0092     std::vector<edm::ModuleDescription const*> m_modules;
0093     std::vector<std::vector<edm::ModuleConsumesInfo>> m_moduleConsumesInfo;
0094     std::vector<std::vector<edm::ModuleDescription const*>> m_modulesOnPath;
0095     std::vector<std::vector<edm::ModuleDescription const*>> m_modulesOnEndPath;
0096     std::vector<std::vector<edm::ModuleDescription const*>> m_modulesWhoseProductsAreConsumedBy;
0097     std::vector<edm::eventsetup::ComponentDescription const*> m_dummy1;
0098     std::vector<edm::ModuleDescription> m_cache;
0099     std::vector<std::vector<edm::eventsetup::ComponentDescription const*>> m_dummy2;
0100 
0101     static unsigned int indexForModule(std::string const& iName,
0102                                        std::unordered_map<std::string, unsigned int>& modsToIndex,
0103                                        std::unordered_map<unsigned int, std::string>& indexToMods) {
0104       auto found = modsToIndex.find(iName);
0105       unsigned int fromIndex;
0106       if (found == modsToIndex.end()) {
0107         fromIndex = modsToIndex.size();
0108         modsToIndex.emplace(iName, fromIndex);
0109         indexToMods.emplace(fromIndex, iName);
0110       } else {
0111         fromIndex = found->second;
0112       }
0113       return fromIndex;
0114     }
0115   };
0116   PathsAndConsumesOfModulesForTest::PathsAndConsumesOfModulesForTest(ModuleDependsOnMap const& iModDeps,
0117                                                                      PathToModules const& iPaths) {
0118     //setup module indicies
0119     std::unordered_map<std::string, unsigned int> modsToIndex;
0120     std::unordered_map<unsigned int, std::string> indexToMods;
0121 
0122     const edm::ProcessConfiguration pc = edmtest::makeDummyProcessConfiguration("TEST");
0123 
0124     //In actual configuration building, the source is always assigned id==0
0125     m_cache.emplace_back(
0126         edm::ParameterSetID{}, "source", "source", &pc, indexForModule("source", modsToIndex, indexToMods));
0127 
0128     for (auto const& md : iModDeps) {
0129       auto const lastSize = modsToIndex.size();
0130       auto index = indexForModule(md.first, modsToIndex, indexToMods);
0131       if (index == lastSize) {
0132         m_cache.emplace_back(edm::ParameterSetID{}, md.first, md.first, &pc, index);
0133       }
0134     }
0135     m_paths.reserve(iPaths.size());
0136     for (auto const& pToM : iPaths) {
0137       m_paths.push_back(pToM.first);
0138 
0139       for (auto const& mod : pToM.second) {
0140         auto const lastSize = modsToIndex.size();
0141         unsigned int index = indexForModule(mod, modsToIndex, indexToMods);
0142         if (index == lastSize) {
0143           m_cache.emplace_back(edm::ParameterSetID{}, mod, mod, &pc, index);
0144         }
0145       }
0146     }
0147     for (auto const& md : iModDeps) {
0148       for (auto const& dep : md.second) {
0149         auto const lastSize = modsToIndex.size();
0150         auto index = indexForModule(dep, modsToIndex, indexToMods);
0151         if (index == lastSize) {
0152           m_cache.emplace_back(edm::ParameterSetID{}, dep, dep, &pc, index);
0153         }
0154       }
0155     }
0156 
0157     if (not iPaths.empty()) {
0158       auto indexForTriggerResults = indexForModule("TriggerResults", modsToIndex, indexToMods);
0159       for (auto const& pToM : iPaths) {
0160         auto index = indexForModule(pToM.first, modsToIndex, indexToMods);
0161         m_cache.emplace_back(edm::ParameterSetID{}, "PathStatusInserter", pToM.first, &pc, index);
0162       }
0163       m_cache.emplace_back(
0164           edm::ParameterSetID{}, "TriggerResultInserter", "TriggerResults", &pc, indexForTriggerResults);
0165     }
0166 
0167     m_modules.reserve(m_cache.size());
0168     for (auto const& desc : m_cache) {
0169       m_modules.push_back(&desc);
0170     }
0171 
0172     //do consumes
0173     edm::TypeID dummy;
0174     m_moduleConsumesInfo.resize(m_modules.size());
0175     m_modulesWhoseProductsAreConsumedBy.resize(m_modules.size());
0176     for (auto const& md : iModDeps) {
0177       auto moduleID = modsToIndex[md.first];
0178       auto& consumes = m_moduleConsumesInfo[moduleID];
0179       consumes.reserve(md.second.size());
0180       for (auto const& dep : md.second) {
0181         consumes.emplace_back(dummy, dep.c_str(), "", "TEST", edm::InEvent, edm::PRODUCT_TYPE, true, false);
0182         m_modulesWhoseProductsAreConsumedBy[moduleID].push_back(m_modules[modsToIndex[dep]]);
0183         //m_modulesWhoseProductsAreConsumedBy[modsToIndex[dep]].push_back(m_modules[moduleID]);
0184       }
0185     }
0186 
0187     m_modulesOnPath.reserve(m_paths.size());
0188     for (auto const& pToM : iPaths) {
0189       m_modulesOnPath.emplace_back();
0190       auto& newPath = m_modulesOnPath.back();
0191       newPath.reserve(pToM.second.size());
0192       for (auto const& mod : pToM.second) {
0193         newPath.push_back(m_modules[modsToIndex[mod]]);
0194       }
0195     }
0196   }
0197 }  // namespace
0198 
0199 class test_checkForModuleDependencyCorrectness : public CppUnit::TestFixture {
0200   CPPUNIT_TEST_SUITE(test_checkForModuleDependencyCorrectness);
0201 
0202   CPPUNIT_TEST(onePathNoCycleTest);
0203   CPPUNIT_TEST(onePathHasCycleTest);
0204   CPPUNIT_TEST(twoPathsNoCycleTest);
0205   CPPUNIT_TEST(twoPathsWithCycleTest);
0206   CPPUNIT_TEST(duplicateModuleOnPathTest);
0207   CPPUNIT_TEST(selfCycleTest);
0208 
0209   CPPUNIT_TEST_SUITE_END();
0210 
0211 public:
0212   void setUp() {}
0213   void tearDown() {}
0214 
0215   void onePathNoCycleTest();
0216   void onePathHasCycleTest();
0217 
0218   void twoPathsNoCycleTest();
0219   void twoPathsWithCycleTest();
0220 
0221   void selfCycleTest();
0222 
0223   void duplicateModuleOnPathTest();
0224 
0225 private:
0226   bool testCase(ModuleDependsOnMap const& iModDeps, PathToModules const& iPaths) const {
0227     PathsAndConsumesOfModulesForTest pAndC(iModDeps, iPaths);
0228 
0229     checkForModuleDependencyCorrectness(pAndC, false);
0230     return true;
0231   }
0232 };
0233 
0234 ///registration of the test so that the runner can find it
0235 CPPUNIT_TEST_SUITE_REGISTRATION(test_checkForModuleDependencyCorrectness);
0236 
0237 void test_checkForModuleDependencyCorrectness::onePathNoCycleTest() {
0238   {
0239     ModuleDependsOnMap md = {{"C", {"B"}}, {"B", {"A"}}};
0240     PathToModules paths = {{"p", {"A", "B", "C"}}};
0241 
0242     CPPUNIT_ASSERT(testCase(md, paths));
0243   }
0244 
0245   {
0246     ModuleDependsOnMap md = {};
0247     PathToModules paths = {{"p", {"A", "B", "C"}}};
0248 
0249     CPPUNIT_ASSERT(testCase(md, paths));
0250   }
0251 
0252   {
0253     //Circular dependency but not connected to any path
0254     // NOTE: "A" is on the list since the ROOT of the
0255     // tree in the job is actually TriggerResults which
0256     // always connects to paths and end paths
0257     ModuleDependsOnMap md = {{"E", {"F"}}, {"F", {"G"}}, {"G", {"E"}}, {"A", {}}};
0258     PathToModules paths = {{"p", {"A", "B", "C"}}};
0259 
0260     CPPUNIT_ASSERT(testCase(md, paths));
0261   }
0262 }
0263 
0264 void test_checkForModuleDependencyCorrectness::onePathHasCycleTest() {
0265   {
0266     ModuleDependsOnMap md = {{"C", {"B"}}, {"B", {"A"}}};
0267     {
0268       PathToModules paths = {{"p", {"B", "A", "C"}}};
0269 
0270       CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0271     }
0272     {
0273       PathToModules paths = {{"p", {"B", "A"}}};
0274 
0275       CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0276     }
0277     {
0278       PathToModules paths = {{"p", {"C", "A"}}};
0279 
0280       CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0281     }
0282     {
0283       PathToModules paths = {{"p", {"C", "B"}}};
0284 
0285       CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0286     }
0287   }
0288 
0289   {
0290     ModuleDependsOnMap md = {{"C", {"B"}}};
0291     {
0292       PathToModules paths = {{"p", {"C", "A", "B"}}};
0293 
0294       CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0295     }
0296     {
0297       PathToModules paths = {{"p", {"A", "C", "B"}}};
0298 
0299       CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0300     }
0301     {
0302       PathToModules paths = {{"p", {"C", "B", "A"}}};
0303 
0304       CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0305     }
0306   }
0307   {
0308     ModuleDependsOnMap md = {{"A", {"p"}}};
0309     {
0310       PathToModules paths = {{"p", {"A"}}};
0311 
0312       CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0313     }
0314   }
0315 }
0316 
0317 void test_checkForModuleDependencyCorrectness::twoPathsNoCycleTest() {
0318   {
0319     ModuleDependsOnMap md = {{"C", {"B"}}};
0320 
0321     {
0322       PathToModules paths = {{"p1", {"A", "B", "C"}}, {"p2", {"A", "B", "C"}}};
0323 
0324       CPPUNIT_ASSERT(testCase(md, paths));
0325     }
0326 
0327     {
0328       //CDJ DEBUG THIS IS NOW FAILING
0329       PathToModules paths = {{"p1", {"A", "B", "C"}}, {"p2", {"B", "A", "C"}}};
0330 
0331       CPPUNIT_ASSERT(testCase(md, paths));
0332     }
0333     {
0334       PathToModules paths = {{"p1", {"A", "B", "C"}}, {"p2", {"B", "C", "A"}}};
0335 
0336       CPPUNIT_ASSERT(testCase(md, paths));
0337     }
0338     {
0339       PathToModules paths = {{"p1", {"B", "A", "C"}}, {"p2", {"A", "B", "C"}}};
0340 
0341       CPPUNIT_ASSERT(testCase(md, paths));
0342     }
0343     {
0344       PathToModules paths = {{"p1", {"B", "A", "C"}}, {"p2", {"B", "A", "C"}}};
0345 
0346       CPPUNIT_ASSERT(testCase(md, paths));
0347     }
0348     {
0349       PathToModules paths = {{"p1", {"B", "A", "C"}}, {"p2", {"B", "C", "A"}}};
0350 
0351       CPPUNIT_ASSERT(testCase(md, paths));
0352     }
0353     {
0354       PathToModules paths = {{"p1", {"B", "C", "A"}}, {"p2", {"A", "B", "C"}}};
0355 
0356       CPPUNIT_ASSERT(testCase(md, paths));
0357     }
0358     {
0359       PathToModules paths = {{"p1", {"B", "C", "A"}}, {"p2", {"B", "A", "C"}}};
0360 
0361       CPPUNIT_ASSERT(testCase(md, paths));
0362     }
0363     {
0364       PathToModules paths = {{"p1", {"B", "C", "A"}}, {"p2", {"B", "C", "A"}}};
0365 
0366       CPPUNIT_ASSERT(testCase(md, paths));
0367     }
0368   }
0369 
0370   {
0371     //Test all possible 3 module combinations
0372     ModuleDependsOnMap md = {};
0373     std::vector<std::string> moduleName = {"A", "B", "C"};
0374     std::vector<std::string> pathModules;
0375     for (unsigned int i = 0; i < 3; ++i) {
0376       pathModules.push_back(moduleName[i]);
0377       for (unsigned int j = 0; j < 3; ++j) {
0378         if (j == i) {
0379           continue;
0380         }
0381         pathModules.push_back(moduleName[j]);
0382         for (unsigned int k = 0; k < 3; ++k) {
0383           if (j == k or i == k) {
0384             continue;
0385           }
0386           pathModules.push_back(moduleName[k]);
0387 
0388           std::vector<std::string> path2Modules;
0389           for (unsigned int ii = 0; ii < 3; ++ii) {
0390             path2Modules.push_back(moduleName[ii]);
0391             for (unsigned int jj = 0; jj < 3; ++jj) {
0392               if (jj == ii) {
0393                 continue;
0394               }
0395               path2Modules.push_back(moduleName[jj]);
0396               for (unsigned int kk = 0; kk < 3; ++kk) {
0397                 if (jj == kk or ii == kk) {
0398                   continue;
0399                 }
0400                 path2Modules.push_back(moduleName[kk]);
0401                 PathToModules paths;
0402                 paths["p1"] = pathModules;
0403                 paths["p2"] = path2Modules;
0404                 CPPUNIT_ASSERT(testCase(md, paths));
0405                 path2Modules.pop_back();
0406               }
0407               path2Modules.pop_back();
0408             }
0409             path2Modules.pop_back();
0410           }
0411 
0412           pathModules.pop_back();
0413         }
0414         pathModules.pop_back();
0415       }
0416       pathModules.pop_back();
0417     }
0418   }
0419 
0420   {
0421     ModuleDependsOnMap md = {{"C", {"B"}}, {"B", {"A"}}, {"D", {"C"}}};
0422 
0423     {
0424       PathToModules paths = {{"p1", {"A", "C"}}, {"p2", {"B", "D"}}};
0425 
0426       CPPUNIT_ASSERT(testCase(md, paths));
0427     }
0428 
0429     {
0430       PathToModules paths = {{"p1", {"A", "D"}}, {"p2", {"B", "C"}}};
0431 
0432       CPPUNIT_ASSERT(testCase(md, paths));
0433     }
0434     {
0435       PathToModules paths = {{"p1", {"A", "B"}}, {"p2", {"C", "D"}}};
0436 
0437       CPPUNIT_ASSERT(testCase(md, paths));
0438     }
0439 
0440     {
0441       PathToModules paths = {{"p1", {"A"}}, {"p2", {"C", "D"}}};
0442 
0443       CPPUNIT_ASSERT(testCase(md, paths));
0444     }
0445     {
0446       PathToModules paths = {{"p1", {"A"}}, {"p2", {"D"}}};
0447 
0448       CPPUNIT_ASSERT(testCase(md, paths));
0449     }
0450     {
0451       PathToModules paths = {{"p1", {"A"}}, {"p2", {"C"}}};
0452 
0453       CPPUNIT_ASSERT(testCase(md, paths));
0454     }
0455 
0456     {
0457       PathToModules paths = {{"p1", {"B"}}, {"p2", {"D"}}};
0458 
0459       CPPUNIT_ASSERT(testCase(md, paths));
0460     }
0461 
0462     {
0463       PathToModules paths = {{"p1", {"B"}}, {"p2", {"C"}}};
0464 
0465       CPPUNIT_ASSERT(testCase(md, paths));
0466     }
0467     {
0468       PathToModules paths = {{"p1", {"C"}}, {"p2", {"D"}}};
0469 
0470       CPPUNIT_ASSERT(testCase(md, paths));
0471     }
0472 
0473     {
0474       PathToModules paths = {{"p1", {"A", "C"}}, {"p2", {"A", "D"}}};
0475 
0476       CPPUNIT_ASSERT(testCase(md, paths));
0477     }
0478     {
0479       PathToModules paths = {{"p1", {"A", "C"}}, {"p2", {"A", "D"}}};
0480 
0481       CPPUNIT_ASSERT(testCase(md, paths));
0482     }
0483   }
0484 
0485   {
0486     ModuleDependsOnMap md = {{"B", {"C"}}, {"D", {"A"}}};
0487     PathToModules paths = {{"p1", {"A", "B"}}, {"p2", {"C", "D"}}};
0488 
0489     CPPUNIT_ASSERT(testCase(md, paths));
0490   }
0491 
0492   {
0493     ModuleDependsOnMap md = {{"B", {"E"}}, {"E", {"C"}}, {"D", {"F"}}, {"F", {"A"}}};
0494     PathToModules paths = {{"p1", {"A", "B"}}, {"p2", {"C", "D"}}};
0495 
0496     CPPUNIT_ASSERT(testCase(md, paths));
0497   }
0498 
0499   {
0500     ModuleDependsOnMap md = {{"B", {"E"}}, {"E", {"C"}}, {"D", {"E"}}, {"E", {"A"}}};
0501     PathToModules paths = {{"p1", {"A", "B"}}, {"p2", {"C", "D"}}};
0502 
0503     CPPUNIT_ASSERT(testCase(md, paths));
0504   }
0505 
0506   {
0507     ModuleDependsOnMap md = {{"B", {"E"}}, {"C", {"E"}}, {"D", {"E"}}, {"A", {"E"}}};
0508     PathToModules paths = {{"p1", {"A", "B"}}, {"p2", {"C", "D"}}};
0509 
0510     CPPUNIT_ASSERT(testCase(md, paths));
0511   }
0512 
0513   {
0514     //Simplified schedule which was failing
0515     ModuleDependsOnMap md = {{"H", {"A"}}};
0516     PathToModules paths = {{"reco", {"I", "A", "H", "G", "F", "E"}}, {"val", {"E", "D", "C", "B", "A"}}};
0517 
0518     CPPUNIT_ASSERT(testCase(md, paths));
0519   }
0520 
0521   {
0522     //Simplified schedule which was failing
0523     ModuleDependsOnMap md = {{"B", {"X"}}, {"Y", {"Z"}}, {"Z", {"A"}}};
0524     PathToModules paths = {{"p1", {"X", "B", "A"}}, {"p2", {"A", "Z", "?", "Y", "X"}}};
0525 
0526     CPPUNIT_ASSERT(testCase(md, paths));
0527   }
0528   {
0529     //Simplified schedule which was failing
0530     ModuleDependsOnMap md = {{"B", {"X"}}, {"Y", {"Z"}}, {"Z", {"A"}}, {"?", {}}, {"A", {}}, {"X", {}}};
0531     PathToModules paths = {{"p1", {"X", "B", "A"}}, {"p2", {"A", "Z", "?", "Y", "X"}}};
0532     CPPUNIT_ASSERT(testCase(md, paths));
0533   }
0534 
0535   {
0536     //Simplified schedule which was failing
0537     // The data dependency for 'D" can be met
0538     // by the order of modules on path p2
0539     ModuleDependsOnMap md = {{"A_TR", {"zEP1", "zEP2"}}, {"D", {"B"}}, {"E", {"D"}}, {"zSEP3", {"A_TR"}}};
0540     PathToModules paths = {{"p1", {"E", "F", "zEP1"}}, {"p2", {"B", "C", "D", "zEP2"}}, {"p3", {"zSEP3", "B", "zEP3"}}};
0541 
0542     CPPUNIT_ASSERT(testCase(md, paths));
0543   }
0544 
0545   {
0546     //The same sequence of modules appear on a Path and EndPath
0547     // Check that the framework does not get confused when jumping
0548     // from one path to the other path just because of the
0549     // TriggerResults connection.
0550 
0551     ModuleDependsOnMap md = {{"A_TR", {"zEP1"}},
0552                              {"A", {"B"}},
0553                              {"B", {"H"}},
0554                              {"C", {}},
0555                              {"D", {}},
0556                              {"E", {}},
0557                              {"G", {"D"}},
0558                              {"H", {"D"}},
0559                              {"zEP1", {}},
0560                              {"zSEP2", {"A_TR"}}};
0561     PathToModules paths = {{"p2", {"D", "G", "H", "B", "C", "zEP1"}},
0562                            {"p3", {"A"}},  //Needed to make graph search start here
0563                            {"p1", {"zSEP2", "E", "D", "G", "H", "B", "C"}}};
0564 
0565     CPPUNIT_ASSERT(testCase(md, paths));
0566   }
0567 
0568   {
0569     //Have a module which can not be run initially be needed by two other modules
0570     ModuleDependsOnMap md = {{"out", {"A", "B"}}, {"A", {"D"}}, {"B", {"D"}}};
0571     PathToModules paths = {{"p1", {"filter", "D"}}, {"p2", {"out"}}};
0572     CPPUNIT_ASSERT(testCase(md, paths));
0573   }
0574   {
0575     //like above, but with path names reversed
0576     ModuleDependsOnMap md = {{"out", {"A", "B"}}, {"A", {"D"}}, {"B", {"D"}}};
0577     PathToModules paths = {{"p1", {"out"}}, {"p2", {"filter", "D"}}};
0578     CPPUNIT_ASSERT(testCase(md, paths));
0579   }
0580 
0581   {
0582     //Have a module which can not be run initially be needed by two other modules
0583     ModuleDependsOnMap md = {{"out", {"A", "B"}}, {"A", {"D"}}, {"B", {"D"}}, {"D", {"E"}}};
0584     PathToModules paths = {{"p1", {"filter", "E"}}, {"p2", {"out"}}};
0585     CPPUNIT_ASSERT(testCase(md, paths));
0586   }
0587   {
0588     //like above, but with path names reversed
0589     ModuleDependsOnMap md = {{"out", {"A", "B"}}, {"A", {"D"}}, {"B", {"D"}}, {"D", {"E"}}};
0590     PathToModules paths = {{"p1", {"out"}}, {"p2", {"filter", "E"}}};
0591     CPPUNIT_ASSERT(testCase(md, paths));
0592   }
0593 }
0594 
0595 void test_checkForModuleDependencyCorrectness::twoPathsWithCycleTest() {
0596   {
0597     ModuleDependsOnMap md = {{"C", {"B"}}, {"A", {"D"}}};
0598     PathToModules paths = {{"p1", {"A", "B"}}, {"p2", {"C", "D"}}};
0599 
0600     CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0601   }
0602 
0603   {
0604     //Add additional dependencies to test that they are ignored
0605     ModuleDependsOnMap md = {{"C", {"E", "F", "G", "B"}}, {"A", {"D"}}};
0606     PathToModules paths = {{"p1", {"A", "B"}}, {"p2", {"C", "D"}}};
0607 
0608     CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0609   }
0610 
0611   {
0612     ModuleDependsOnMap md = {{"C", {"B"}}, {"A", {"D"}}};
0613     PathToModules paths = {{"p1", {"A", "B"}}, {"p2", {"C", "D", "A"}}};
0614 
0615     CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0616   }
0617 
0618   {
0619     ModuleDependsOnMap md = {{"C", {"B"}}, {"A", {"D"}}, {"B", {"A"}}, {"D", {"C"}}};
0620     PathToModules paths = {{"p1", {"A", "B"}}, {"p2", {"C", "D"}}};
0621 
0622     CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0623   }
0624 
0625   {
0626     ModuleDependsOnMap md = {{"E", {"B"}}, {"C", {"E"}}, {"A", {"D"}}};
0627     PathToModules paths = {{"p1", {"A", "B"}}, {"p2", {"C", "D"}}};
0628 
0629     CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0630   }
0631 
0632   {
0633     ModuleDependsOnMap md = {{"A", {"B"}}, {"B", {"C"}}, {"C", {"D"}}, {"D", {"B"}}};
0634     PathToModules paths = {{"p1", {"A", "EP"}}};
0635 
0636     CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0637   }
0638 
0639   {
0640     //Simplified schedule which was failing
0641     ModuleDependsOnMap md = {{"B", {"X"}}, {"Y", {"Z"}}, {"Z", {"A"}}, {"?", {}}, {"A", {}}, {"X", {}}};
0642     //NOTE: p1 is inconsistent but with p2 it would be runnable.
0643     PathToModules paths = {{"p1", {"B", "A", "X"}}, {"p2", {"A", "Z", "?", "Y", "X"}}};
0644     CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0645   }
0646 
0647   {
0648     ModuleDependsOnMap md = {{"A_TR", {"EP1", "EP2"}},  //assigned aTR==0, EP1==1, EP2==2
0649                              {"C", {"A"}},
0650                              {"D", {"A"}},
0651                              {"E", {"D"}},
0652                              {"BP", {"A_TR"}}};
0653 
0654     PathToModules paths = {{"p1", {"A", "B", "C", "EP1"}}, {"p2", {"E", "EP2"}}, {"ep", {"BP", "A", "D"}}};
0655     CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0656   }
0657 
0658   {
0659     // The data dependency for 'D" can be met
0660     // by the order of modules on path p2
0661     // but NOT by path3
0662     ModuleDependsOnMap md = {{"A_TR", {"zEP1", "zEP2", "zEP3"}}, {"D", {"B"}}, {"E", {"D"}}, {"zSEP4", {"A_TR"}}};
0663     PathToModules paths = {{"p1", {"E", "F", "zEP1"}},
0664                            {"p2", {"Filter", "B", "C", "D", "zEP2"}},
0665                            {"p3", {"C", "D", "zEP3"}},
0666                            {"p4", {"zSEP4", "B", "zEP4"}}};
0667 
0668     CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0669   }
0670 
0671   {
0672     // The data dependency for 'D" can be met
0673     // by the order of modules on path p2
0674     // but NOT by path3
0675     ModuleDependsOnMap md = {{"A_TR", {"zEP1", "zEP2", "zEP3"}}, {"D", {"B"}}, {"E", {"D"}}, {"zSEP4", {"A_TR"}}};
0676     PathToModules paths = {{"p1", {"E", "F", "zEP1"}},
0677                            {"p2", {"Filter", "B", "D", "zEP2"}},
0678                            {"p3", {"C", "D", "zEP3"}},
0679                            {"p4", {"zSEP4", "B", "zEP4"}}};
0680 
0681     CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0682   }
0683 
0684   {
0685     // The data dependency for 'D" can be met
0686     // by the order of modules on path p2
0687     // but NOT by path3
0688     ModuleDependsOnMap md = {{"A_TR", {"zEP1", "zEP2"}}, {"B", {}}, {"zFilter", {"A_TR"}}};
0689     PathToModules paths = {{"p1", {"zFilter", "B", "zEP1"}}, {"p2", {"zFilter", "B", "zEP2"}}};
0690 
0691     CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0692   }
0693 
0694   {
0695     ModuleDependsOnMap md = {{"B", {"A"}}, {"C", {"B"}}, {"cFilter", {"C"}}};
0696     PathToModules paths = {{"p1", {"C", "cFilter", "D", "E", "F", "A", "B"}}, {"p2", {"oFilter", "D", "F", "B"}}};
0697 
0698     CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0699   }
0700 }
0701 
0702 void test_checkForModuleDependencyCorrectness::selfCycleTest() {
0703   {
0704     ModuleDependsOnMap md = {{"A", {"A"}}};
0705     PathToModules paths = {{"p", {"A"}}};
0706 
0707     CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0708   }
0709   {
0710     ModuleDependsOnMap md = {{"A", {"A"}}, {"B", {"A"}}};
0711     PathToModules paths = {{"p", {"B"}}};
0712 
0713     CPPUNIT_ASSERT_THROW(testCase(md, paths), cms::Exception);
0714   }
0715 }
0716 
0717 void test_checkForModuleDependencyCorrectness::duplicateModuleOnPathTest() {
0718   {
0719     ModuleDependsOnMap md = {{"C", {"B"}}, {"B", {"A"}}};
0720     PathToModules paths = {{"p", {"A", "B", "C", "A"}}};
0721 
0722     CPPUNIT_ASSERT(testCase(md, paths));
0723   }
0724 }