Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-01-31 02:19:32

0001 
0002 #include "DataFormats/Common/interface/Handle.h"
0003 #include "DataFormats/Provenance/interface/BranchID.h"
0004 #include "DataFormats/Provenance/interface/Parentage.h"
0005 #include "DataFormats/Provenance/interface/ProductProvenance.h"
0006 #include "DataFormats/Provenance/interface/ProductProvenanceLookup.h"
0007 #include "DataFormats/Provenance/interface/Provenance.h"
0008 #include "DataFormats/TestObjects/interface/ToyProducts.h"
0009 #include "FWCore/Framework/interface/global/EDAnalyzer.h"
0010 #include "FWCore/Framework/interface/Event.h"
0011 #include "FWCore/Framework/interface/MakerMacros.h"
0012 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0013 #include "FWCore/ServiceRegistry/interface/Service.h"
0014 #include "FWCore/Utilities/interface/InputTag.h"
0015 #include "FWCore/Utilities/interface/EDGetToken.h"
0016 
0017 #include <iostream>
0018 #include <map>
0019 #include <set>
0020 #include <string>
0021 #include <vector>
0022 
0023 namespace {
0024   void getAncestors(edm::Event const& e, edm::BranchID const& branchID, std::set<edm::BranchID>& ancestors) {
0025     const edm::Provenance& prov = e.getProvenance(branchID);
0026     if (prov.productProvenance()) {
0027       for (auto const& parent : prov.productProvenance()->parentage().parents()) {
0028         ancestors.insert(parent);
0029         getAncestors(e, parent, ancestors);
0030       }
0031     }
0032   }
0033 
0034   // Does the same thing as the previous function in a different
0035   // way. The previous function goes through the links in the
0036   // ProductsResolver which for SubProcesses could lead to a different
0037   // retriever. In SubProcesses, the following function follows the
0038   // links in the retrievers themselves. Both should give the same answer.
0039   void getAncestorsFromRetriever(edm::ProductProvenanceLookup const* retriever,
0040                                  edm::BranchID const& branchID,
0041                                  std::set<edm::BranchID>& ancestors) {
0042     edm::ProductProvenance const* productProvenance = retriever->branchIDToProvenance(branchID);
0043     if (productProvenance) {
0044       for (auto const& parent : productProvenance->parentage().parents()) {
0045         ancestors.insert(parent);
0046         getAncestorsFromRetriever(retriever, parent, ancestors);
0047       }
0048     }
0049   }
0050 }  // namespace
0051 
0052 namespace edmtest {
0053 
0054   class TestParentage : public edm::global::EDAnalyzer<> {
0055   public:
0056     explicit TestParentage(edm::ParameterSet const& pset);
0057     ~TestParentage() override = default;
0058 
0059     void analyze(edm::StreamID, edm::Event const& e, edm::EventSetup const& es) const override;
0060 
0061     static void fillDescriptions(edm::ConfigurationDescriptions& iDesc);
0062 
0063   private:
0064     edm::EDGetTokenT<IntProduct> token_;
0065     std::vector<std::string> expectedAncestors_;
0066     bool callGetProvenance_;
0067   };
0068 
0069   TestParentage::TestParentage(edm::ParameterSet const& pset)
0070       : token_(consumes(pset.getParameter<edm::InputTag>("inputTag"))),
0071         expectedAncestors_(pset.getParameter<std::vector<std::string> >("expectedAncestors")),
0072         callGetProvenance_(pset.getUntrackedParameter<bool>("callGetProvenance", true)) {}
0073 
0074   void TestParentage::fillDescriptions(edm::ConfigurationDescriptions& iDesc) {
0075     edm::ParameterSetDescription ps;
0076     ps.add<edm::InputTag>("inputTag");
0077     ps.add<std::vector<std::string> >("expectedAncestors")
0078         ->setComment(
0079             "Module labels for data products directly/indirectly obtained to make data product retrieved using "
0080             "'inputTag'.");
0081     ps.addUntracked<bool>("callGetProvenance", true)
0082         ->setComment("Use Event::getProvenance to get ancestor provenance.");
0083 
0084     iDesc.addDefault(ps);
0085   }
0086 
0087   void TestParentage::analyze(edm::StreamID, edm::Event const& e, edm::EventSetup const&) const {
0088     edm::Handle<IntProduct> h = e.getHandle(token_);
0089     *h;
0090     edm::Provenance const* prov = h.provenance();
0091 
0092     if (not prov) {
0093       throw cms::Exception("MissingProvenance") << "Failed to get provenance for 'inputTag'";
0094     }
0095     if (prov->originalBranchID() != prov->productDescription().originalBranchID()) {
0096       throw cms::Exception("InconsistentBranchID")
0097           << " test of Provenance::originalBranchID function failed. Expected "
0098           << prov->productDescription().originalBranchID() << " but see " << prov->originalBranchID();
0099     }
0100 
0101     std::set<std::string> expectedAncestors(expectedAncestors_.begin(), expectedAncestors_.end());
0102 
0103     // Currently we need to turn off this part of the test of when calling
0104     // from a SubProcess and the parentage includes a product not kept
0105     // in the SubProcess. This might get fixed someday ...
0106     auto toException = [](auto& ex, auto const& ancestors) {
0107       for (auto const& a : ancestors) {
0108         ex << a << ", ";
0109       }
0110     };
0111 
0112     if (callGetProvenance_) {
0113       std::set<edm::BranchID> ancestors;
0114       getAncestors(e, prov->branchID(), ancestors);
0115 
0116       std::set<std::string> ancestorLabels;
0117       for (edm::BranchID const& ancestor : ancestors) {
0118         try {
0119           ancestorLabels.insert(e.getStableProvenance(ancestor).moduleLabel());
0120         } catch (cms::Exception& iEx) {
0121           edm::LogSystem("MissingProvenance") << "the provenance for BranchID " << ancestor << " is missing\n"
0122                                               << iEx.what();
0123           ancestorLabels.insert("");
0124         }
0125       }
0126       if (ancestorLabels != expectedAncestors) {
0127         cms::Exception ex("WrongAncestors");
0128         ex << "ancestors from Event::getProvenance\n";
0129         toException(ex, ancestorLabels);
0130         ex << "\n do not match expected ancestors\n";
0131         toException(ex, expectedAncestors);
0132         throw ex;
0133       }
0134     }
0135 
0136     auto const* retriever = prov->store();
0137     std::set<edm::BranchID> ancestorsFromRetriever;
0138     getAncestorsFromRetriever(retriever, prov->originalBranchID(), ancestorsFromRetriever);
0139 
0140     std::set<std::string> ancestorLabels2;
0141     for (edm::BranchID const& ancestor : ancestorsFromRetriever) {
0142       try {
0143         ancestorLabels2.insert(e.getStableProvenance(ancestor).moduleLabel());
0144       } catch (cms::Exception& iEx) {
0145         edm::LogSystem("MissingProvenance")
0146             << "the provenance from Retriever for BranchID " << ancestor << " is missing\n"
0147             << iEx.what();
0148         ancestorLabels2.insert("");
0149       }
0150     }
0151     if (ancestorLabels2 != expectedAncestors) {
0152       cms::Exception ex("WrongAncestors");
0153       ex << "ancestors from ParentageRetriever\n";
0154       toException(ex, ancestorLabels2);
0155       ex << "\n do not match expected ancestors\n";
0156       toException(ex, expectedAncestors);
0157       throw ex;
0158     }
0159   }
0160 }  // namespace edmtest
0161 
0162 using edmtest::TestParentage;
0163 DEFINE_FWK_MODULE(TestParentage);