diff --git a/DataFormats/FEDRawData/README.md b/DataFormats/FEDRawData/README.md
new file mode 100644
index 0000000000000..0cc3c76428f37
--- /dev/null
+++ b/DataFormats/FEDRawData/README.md
@@ -0,0 +1,10 @@
+# DataFormats/FEDRawData
+
+## `FEDRawDataCollection`
+
+The class `FEDRawDataCollection` is part of the RAW data, and any changes must be backwards compatible. In order to ensure it can be read by all future CMSSW releases, there is a `TestFEDRawDataCollectionFormat` unit test, which makes use of the `TestReadFEDRawDataCollection` analyzer and the `TestWriteFEDRawDataCollection` producer. The unit test checks that the object can be read properly from
+
+* a file written by the same release
+* files written by (some) earlier releases
+
+If the persistent format of class `FEDRawDataCollection` gets changed in the future, please adjust the `TestReadFEDRawDataCollection` and `TestWriteFEDRawDataCollection` modules accordingly. It is important that every member container has some content in this test. Please also add a new file to the [https://github.com/cms-data/DataFormats-FEDRawData/](https://github.com/cms-data/DataFormats-FEDRawData/) repository, and update the `TestFEDRawDataCollectionFormat` unit test to read the newly created file. The file name should contain the release or pre-release with which it was written.
diff --git a/DataFormats/FEDRawData/test/BuildFile.xml b/DataFormats/FEDRawData/test/BuildFile.xml
index c69c5fdc725d3..28fbaa29c7152 100644
--- a/DataFormats/FEDRawData/test/BuildFile.xml
+++ b/DataFormats/FEDRawData/test/BuildFile.xml
@@ -1,4 +1,14 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/DataFormats/FEDRawData/test/TestFEDRawDataCollectionFormat.sh b/DataFormats/FEDRawData/test/TestFEDRawDataCollectionFormat.sh
new file mode 100755
index 0000000000000..ba15b3bb6619a
--- /dev/null
+++ b/DataFormats/FEDRawData/test/TestFEDRawDataCollectionFormat.sh
@@ -0,0 +1,19 @@
+#!/bin/sh -ex
+
+function die { echo $1: status $2 ; exit $2; }
+
+LOCAL_TEST_DIR=${SCRAM_TEST_PATH}
+
+cmsRun ${LOCAL_TEST_DIR}/create_FEDRawDataCollection_test_file_cfg.py || die 'Failure using create_FEDRawDataCollection_test_file_cfg.py' $?
+
+file=testFEDRawDataCollection.root
+
+cmsRun ${LOCAL_TEST_DIR}/test_readFEDRawDataCollection_cfg.py "$file" || die "Failure using test_readFEDRawDataCollection_cfg.py $file" $?
+
+oldFiles="testFEDRawDataCollection_CMSSW_13_0_0.root testFEDRawDataCollection_CMSSW_13_1_0_pre3.root"
+for file in $oldFiles; do
+ inputfile=$(edmFileInPath DataFormats/FEDRawData/data/$file) || die "Failure edmFileInPath DataFormats/FEDRawData/data/$file" $?
+ cmsRun ${LOCAL_TEST_DIR}/test_readFEDRawDataCollection_cfg.py "$inputfile" || die "Failed to read old file $file" $?
+done
+
+exit 0
diff --git a/DataFormats/FEDRawData/test/TestReadFEDRawDataCollection.cc b/DataFormats/FEDRawData/test/TestReadFEDRawDataCollection.cc
new file mode 100644
index 0000000000000..788a5153dd51a
--- /dev/null
+++ b/DataFormats/FEDRawData/test/TestReadFEDRawDataCollection.cc
@@ -0,0 +1,95 @@
+// -*- C++ -*-
+//
+// Package: DataFormats/FEDRawData
+// Class: TestReadFEDRawDataCollection
+//
+/**\class edmtest::TestReadFEDRawDataCollection
+ Description: Used as part of tests that ensure the FEDRawDataCollection
+ data format can be persistently written and in a subsequent process
+ read. First, this is done using the current release version for writing
+ and reading. In addition, the output file of the write process should
+ be saved permanently each time the FEDRawDataCollection persistent data
+ format changes. In unit tests, we read each of those saved files to verify
+ that the current releases can read older versions of the data format.
+*/
+// Original Author: W. David Dagenhart
+// Created: 1 May 2023
+
+#include "DataFormats/FEDRawData/interface/FEDRawData.h"
+#include "DataFormats/FEDRawData/interface/FEDRawDataCollection.h"
+#include "FWCore/Framework/interface/Event.h"
+#include "FWCore/Framework/interface/Frameworkfwd.h"
+#include "FWCore/Framework/interface/global/EDAnalyzer.h"
+#include "FWCore/Framework/interface/MakerMacros.h"
+#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
+#include "FWCore/ParameterSet/interface/ParameterSet.h"
+#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
+#include "FWCore/Utilities/interface/EDGetToken.h"
+#include "FWCore/Utilities/interface/Exception.h"
+#include "FWCore/Utilities/interface/InputTag.h"
+#include "FWCore/Utilities/interface/StreamID.h"
+
+#include
+
+namespace edmtest {
+
+ class TestReadFEDRawDataCollection : public edm::global::EDAnalyzer<> {
+ public:
+ TestReadFEDRawDataCollection(edm::ParameterSet const&);
+ void analyze(edm::StreamID, edm::Event const&, edm::EventSetup const&) const override;
+ void throwWithMessage(const char*) const;
+ static void fillDescriptions(edm::ConfigurationDescriptions&);
+
+ private:
+ // Two FEDRawData elements should be enough to verify we can read
+ // and write the whole collection. I arbitrarily chose elements
+ // 0 and 3 of the Collection. Values are meaningless, we just
+ // verify what we read matches what we wrote. For purposes of
+ // this test that is enough.
+ std::vector expectedFEDData0_;
+ std::vector expectedFEDData3_;
+ edm::EDGetTokenT fedRawDataCollectionToken_;
+ };
+
+ TestReadFEDRawDataCollection::TestReadFEDRawDataCollection(edm::ParameterSet const& iPSet)
+ : expectedFEDData0_(iPSet.getParameter>("expectedFEDData0")),
+ expectedFEDData3_(iPSet.getParameter>("expectedFEDData3")),
+ fedRawDataCollectionToken_(consumes(iPSet.getParameter("fedRawDataCollectionTag"))) {}
+
+ void TestReadFEDRawDataCollection::analyze(edm::StreamID, edm::Event const& iEvent, edm::EventSetup const&) const {
+ auto const& fedRawDataCollection = iEvent.get(fedRawDataCollectionToken_);
+ auto const& fedData0 = fedRawDataCollection.FEDData(0);
+ if (fedData0.size() != expectedFEDData0_.size()) {
+ throwWithMessage("fedData0 does not have expected size");
+ }
+ for (unsigned int i = 0; i < fedData0.size(); ++i) {
+ if (fedData0.data()[i] != expectedFEDData0_[i]) {
+ throwWithMessage("fedData0 does not have expected contents");
+ }
+ }
+ auto const& fedData3 = fedRawDataCollection.FEDData(3);
+ if (fedData3.size() != expectedFEDData3_.size()) {
+ throwWithMessage("fedData3 does not have expected size");
+ }
+ for (unsigned int i = 0; i < fedData3.size(); ++i) {
+ if (fedData3.data()[i] != expectedFEDData3_[i]) {
+ throwWithMessage("fedData3 does not have expected contents");
+ }
+ }
+ }
+
+ void TestReadFEDRawDataCollection::throwWithMessage(const char* msg) const {
+ throw cms::Exception("TestFailure") << "TestReadFEDRawDataCollection::analyze, " << msg;
+ }
+
+ void TestReadFEDRawDataCollection::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
+ edm::ParameterSetDescription desc;
+ desc.add>("expectedFEDData0");
+ desc.add>("expectedFEDData3");
+ desc.add("fedRawDataCollectionTag");
+ descriptions.addDefault(desc);
+ }
+} // namespace edmtest
+
+using edmtest::TestReadFEDRawDataCollection;
+DEFINE_FWK_MODULE(TestReadFEDRawDataCollection);
diff --git a/DataFormats/FEDRawData/test/TestWriteFEDRawDataCollection.cc b/DataFormats/FEDRawData/test/TestWriteFEDRawDataCollection.cc
new file mode 100644
index 0000000000000..ff846686598f9
--- /dev/null
+++ b/DataFormats/FEDRawData/test/TestWriteFEDRawDataCollection.cc
@@ -0,0 +1,80 @@
+// -*- C++ -*-
+//
+// Package: DataFormats/FEDRawData
+// Class: TestWriteFEDRawDataCollection
+//
+/**\class edmtest::TestWriteFEDRawDataCollection
+ Description: Used as part of tests that ensure the FEDRawDataCollection
+ data format can be persistently written and in a subsequent process
+ read. First, this is done using the current release version for writing
+ and reading. In addition, the output file of the write process should
+ be saved permanently each time the FEDRawDataCollection persistent data
+ format changes. In unit tests, we read each of those saved files to verify
+ that the current releases can read older versions of the data format.
+*/
+// Original Author: W. David Dagenhart
+// Created: 1 May 2023
+
+#include "DataFormats/FEDRawData/interface/FEDRawData.h"
+#include "DataFormats/FEDRawData/interface/FEDRawDataCollection.h"
+#include "FWCore/Framework/interface/Event.h"
+#include "FWCore/Framework/interface/Frameworkfwd.h"
+#include "FWCore/Framework/interface/global/EDProducer.h"
+#include "FWCore/Framework/interface/MakerMacros.h"
+#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
+#include "FWCore/ParameterSet/interface/ParameterSet.h"
+#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
+#include "FWCore/Utilities/interface/EDPutToken.h"
+#include "FWCore/Utilities/interface/StreamID.h"
+
+#include
+#include
+#include
+
+namespace edmtest {
+
+ class TestWriteFEDRawDataCollection : public edm::global::EDProducer<> {
+ public:
+ TestWriteFEDRawDataCollection(edm::ParameterSet const&);
+ void produce(edm::StreamID, edm::Event&, edm::EventSetup const&) const override;
+ static void fillDescriptions(edm::ConfigurationDescriptions&);
+
+ private:
+ std::vector fedData0_;
+ std::vector fedData3_;
+ edm::EDPutTokenT fedRawDataCollectionPutToken_;
+ };
+
+ TestWriteFEDRawDataCollection::TestWriteFEDRawDataCollection(edm::ParameterSet const& iPSet)
+ : fedData0_(iPSet.getParameter>("FEDData0")),
+ fedData3_(iPSet.getParameter>("FEDData3")),
+ fedRawDataCollectionPutToken_(produces()) {}
+
+ void TestWriteFEDRawDataCollection::produce(edm::StreamID, edm::Event& iEvent, edm::EventSetup const&) const {
+ auto fedRawDataCollection = std::make_unique();
+ FEDRawData& fedData0 = fedRawDataCollection->FEDData(0);
+ FEDRawData& fedData3 = fedRawDataCollection->FEDData(3);
+
+ fedData0.resize(fedData0_.size());
+ unsigned char* dataPtr0 = fedData0.data();
+ for (unsigned int i = 0; i < fedData0_.size(); ++i) {
+ dataPtr0[i] = fedData0_[i];
+ }
+ fedData3.resize(fedData3_.size());
+ unsigned char* dataPtr3 = fedData3.data();
+ for (unsigned int i = 0; i < fedData3_.size(); ++i) {
+ dataPtr3[i] = fedData3_[i];
+ }
+ iEvent.put(fedRawDataCollectionPutToken_, std::move(fedRawDataCollection));
+ }
+
+ void TestWriteFEDRawDataCollection::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
+ edm::ParameterSetDescription desc;
+ desc.add>("FEDData0");
+ desc.add>("FEDData3");
+ descriptions.addDefault(desc);
+ }
+} // namespace edmtest
+
+using edmtest::TestWriteFEDRawDataCollection;
+DEFINE_FWK_MODULE(TestWriteFEDRawDataCollection);
diff --git a/DataFormats/FEDRawData/test/create_FEDRawDataCollection_test_file_cfg.py b/DataFormats/FEDRawData/test/create_FEDRawDataCollection_test_file_cfg.py
new file mode 100644
index 0000000000000..02d2d7bfd3638
--- /dev/null
+++ b/DataFormats/FEDRawData/test/create_FEDRawDataCollection_test_file_cfg.py
@@ -0,0 +1,22 @@
+import FWCore.ParameterSet.Config as cms
+
+process = cms.Process("PROD")
+
+process.load("FWCore.MessageService.MessageLogger_cfi")
+
+process.source = cms.Source("EmptySource")
+process.maxEvents.input = 1
+
+process.fedRawDataCollectionProducer = cms.EDProducer("TestWriteFEDRawDataCollection",
+ # Test values below are meaningless. We just make sure when we read
+ # we get the same values.
+ FEDData0 = cms.vuint32(0, 1, 2, 3, 4, 5, 6, 7),
+ FEDData3 = cms.vuint32(100, 101, 102, 103, 104, 105, 106, 107)
+)
+
+process.out = cms.OutputModule("PoolOutputModule",
+ fileName = cms.untracked.string('testFEDRawDataCollection.root')
+)
+
+process.path = cms.Path(process.fedRawDataCollectionProducer)
+process.endPath = cms.EndPath(process.out)
diff --git a/DataFormats/FEDRawData/test/test_readFEDRawDataCollection_cfg.py b/DataFormats/FEDRawData/test/test_readFEDRawDataCollection_cfg.py
new file mode 100644
index 0000000000000..67389987c3424
--- /dev/null
+++ b/DataFormats/FEDRawData/test/test_readFEDRawDataCollection_cfg.py
@@ -0,0 +1,21 @@
+import FWCore.ParameterSet.Config as cms
+import sys
+
+process = cms.Process("READ")
+
+process.source = cms.Source("PoolSource", fileNames = cms.untracked.vstring("file:"+sys.argv[2]))
+process.maxEvents.input = 1
+
+process.testReadFEDRawDataCollection = cms.EDAnalyzer("TestReadFEDRawDataCollection",
+ fedRawDataCollectionTag = cms.InputTag("fedRawDataCollectionProducer", "", "PROD"),
+ expectedFEDData0 = cms.vuint32(0, 1, 2, 3, 4, 5, 6, 7),
+ expectedFEDData3 = cms.vuint32(100, 101, 102, 103, 104, 105, 106, 107)
+)
+
+process.out = cms.OutputModule("PoolOutputModule",
+ fileName = cms.untracked.string('testFEDRawDataCollection2.root')
+)
+
+process.path = cms.Path(process.testReadFEDRawDataCollection)
+
+process.endPath = cms.EndPath(process.out)