diff --git a/AtlasTest/CITest/AnalysisBase.cmake b/AtlasTest/CITest/AnalysisBase.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..18198fb31304d67bee08bf5bb78ae2c43c5bbb9e
--- /dev/null
+++ b/AtlasTest/CITest/AnalysisBase.cmake
@@ -0,0 +1,12 @@
+# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
+#
+# CI test definitions for the AnalysisBase project
+# --> README.md before you modify this file
+#
+
+atlas_add_citest( EMPFlowData
+   LOG_IGNORE_PATTERN "Cannot interpolate outside histogram domain" # ANALYSISTO-1165
+   SCRIPT CI_EMPFlowDatatest.py )
+
+atlas_add_citest( EMPFlowMC
+   SCRIPT CI_EMPFlowMCtest.py )
diff --git a/AtlasTest/CITest/AthGeneration.cmake b/AtlasTest/CITest/AthGeneration.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..83fac0a7a509a2f199fe3d83eaa5b97537d1f714
--- /dev/null
+++ b/AtlasTest/CITest/AthGeneration.cmake
@@ -0,0 +1,9 @@
+# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+#
+# CI test definitions for the AthGeneration project
+# --> README.md before you modify this file
+#
+
+atlas_add_citest( DuplicateClass
+   SCRIPT python -c 'import ROOT'
+   PROPERTIES FAIL_REGULAR_EXPRESSION "class .* is already in" )
diff --git a/AtlasTest/CITest/AthSimulation.cmake b/AtlasTest/CITest/AthSimulation.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..456f743b390f3edf5d4afbe55459ad1369f5ccc0
--- /dev/null
+++ b/AtlasTest/CITest/AthSimulation.cmake
@@ -0,0 +1,13 @@
+# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+#
+# CI test definitions for the AthSimulation project
+# --> README.md before you modify this file
+#
+
+atlas_add_citest( DuplicateClass
+   SCRIPT python -c 'import ROOT'
+   PROPERTIES FAIL_REGULAR_EXPRESSION "class .* is already in" )
+
+# TODO:
+#   G4ExHive
+#   SimulationTier0
diff --git a/AtlasTest/CITest/Athena.cmake b/AtlasTest/CITest/Athena.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..ba94b57e44081df7a2f6a1d427f1de415abf9cbb
--- /dev/null
+++ b/AtlasTest/CITest/Athena.cmake
@@ -0,0 +1,122 @@
+# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
+#
+# CI test definitions for the Athena project
+# --> README.md before you modify this file
+#
+
+#################################################################################
+# General
+#################################################################################
+atlas_add_citest( DuplicateClass
+   SCRIPT python -c 'import ROOT'
+   PROPERTIES FAIL_REGULAR_EXPRESSION "class .* is already in" )
+
+# TODO: minimal set of tests for now
+return()
+
+#################################################################################
+# Reconstruction
+#################################################################################
+atlas_add_citest( q431
+   SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/test/q431.sh
+   ENVIRONMENT ATHENA_CORE_NUMBER=8
+   PROPERTIES PROCESSORS 8
+   POST_EXEC_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/test/checkReco.sh master_q431_AOD_digest_500events.ref master_q431_AOD_content_500events.ref" )
+
+atlas_add_citest( q431_DAODPHYS
+   SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/test/DAODPhys.sh PHYS ../q431/myAOD.pool.root
+   PROPERTIES REQUIRED_FILES ../q431/myAOD.pool.root
+   DEPENDS q431 )
+
+atlas_add_citest( q431_DAODPHYSLite
+   SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/test/DAODPhys.sh PHYSLITE ../q431/myAOD.pool.root
+   PROPERTIES REQUIRED_FILES ../q431/myAOD.pool.root
+   DEPENDS q431 )
+
+atlas_add_citest( q221
+   SCRIPT Reco_tf.py --AMI q221 --athenaopts='--threads=1' --outputAODFile=myAOD.pool.root
+   POST_EXEC_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/test/checkReco.sh master_q221_AOD_digest.ref master_q221_AOD_content.ref" )
+
+atlas_add_citest( q440
+   SCRIPT Reco_tf.py --AMI q440 --maxEvents=5 --athenaopts='RDOtoRDOTrigger:--threads=1' )
+
+atlas_add_citest( MuonReconstructionConfig
+   SCRIPT python -m MuonConfig.MuonReconstructionConfig --run )
+
+atlas_add_citest( MuonCombinedReconstructionConfig
+   SCRIPT python -m MuonCombinedConfig.MuonCombinedReconstructionConfig --run )
+
+atlas_add_citest( CaloTopoClusterConfig
+   SCRIPT python -m CaloRec.CaloTopoClusterConfig --run )
+
+#################################################################################
+# DQ
+#################################################################################
+atlas_add_citest( Run3DQr21ESD
+   SCRIPT Run3DQTestingDriver.py 'Input.Files=["/cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/Tier0ChainTests/q431/21.0/myESD.pool.root"]' DQ.Steering.doHLTMon=False --threads=1 )
+
+atlas_add_citest( q221_Run3DQ
+   PRE_EXEC_SCRIPT "cp ../q221/HLTMonitoring*.json ."
+   SCRIPT Run3DQTestingDriver.py 'Input.Files=["../q221/myAOD.pool.root"]' DQ.Environment=AOD --threads=1
+   PROPERTIES REQUIRED_FILES ../q221/myAOD.pool.root
+   DEPENDS q221 )
+
+#################################################################################
+# Digitization/Simulation
+#################################################################################
+atlas_add_citest( DigitizationNewConfig
+   SCRIPT DigitizationConfigNew_test.py )
+
+atlas_add_citest( FastChain
+   SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/test/FastChain.sh )
+
+atlas_add_citest( G4ExHive
+   SCRIPT athena.py --threads=4 --evtMax=50 G4AtlasApps/jobOptions.G4AtlasMT.py
+   PROPERTIES PROCESSORS 4 )
+
+atlas_add_citest( MuonDigiReco_digi
+   SCRIPT Digi_tf.py --inputHITSFile /cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/MuonRecRTT/Run3/HITS/AsymmetricLayout_HITS_v2.root --imf False --outputRDOFile OUT_RDO.root --conditionsTag OFLCOND-MC16-SDR-RUN3-02 )
+
+atlas_add_citest( MuonDigiReco_reco
+   SCRIPT Reco_tf.py --inputRDOFile ../MuonDigiReco_digi/OUT_RDO.root --autoConfiguration everything --imf False --outputESDFile OUT_ESD.root
+   PROPERTIES REQUIRED_FILES ../MuonDigiReco_digi/OUT_RDO.root
+   DEPENDS MuonDigiReco_digi
+   POST_EXEC_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/test/checkMuonDigiReco.sh )
+
+atlas_add_ciTest( Overlay_digi
+   SCRIPT Digi_tf.py --AMI d1609 )
+
+atlas_add_ciTest( Overlay_reco
+   SCRIPT Reco_tf.py --AMI r12276 --inputHITSFile /cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/Tier0ChainTests/mc16_13TeV.410470.PhPy8EG_A14_ttbar_hdamp258p75_nonallhad.simul.HITS.e6337_s3126/HITS.12860054._032508.pool.root.1 --inputRDO_BKGFile ../Overlay_digi/MC_premixing_MT.RDO.pool.root --athenaopts='--threads=1'
+   PROPERTIES REQUIRED_FILES ../Overlay_digi/MC_premixing_MT.RDO.pool.root
+   DEPENDS Overlay_digi )
+
+atlas_add_citest( OverlayTier0
+   SCRIPT RunTier0Tests.py -o -n )
+
+#################################################################################
+# Trigger
+#################################################################################
+atlas_add_citest( Trigger_athenaHLT_decodeBS
+   SCRIPT test_trigP1_v1Dev_decodeBS_build.py )
+
+atlas_add_citest( Trigger_athenaHLT_data
+   SCRIPT test_trigP1_v1PhysP1_build.py )
+
+atlas_add_citest( Trigger_athena_MC
+   SCRIPT test_trigAna_RDOtoRDOTrig_v1Dev_build.py )
+
+atlas_add_citest( Trigger_athena_data
+   SCRIPT test_trig_data_v1Dev_build.py )
+
+atlas_add_citest( Trigger_athena_cosmic
+   SCRIPT test_trig_data_v1Cosmic_build.py )
+
+atlas_add_citest( Trigger_athena_data_NewConfig
+   SCRIPT test_trig_data_newJO_build.py )
+
+#################################################################################
+# Upgrade
+#################################################################################
+atlas_add_citest( PhaseIIUpgrade
+   SCRIPT RunWorkflowTests_Run4.py --CI -e '--maxEvents 5' )
diff --git a/AtlasTest/CITest/CMakeLists.txt b/AtlasTest/CITest/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c7b4e89226403539b39ff0b166c44834834f8d69
--- /dev/null
+++ b/AtlasTest/CITest/CMakeLists.txt
@@ -0,0 +1,28 @@
+# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
+#
+# This package contains the CI test definitions that are run for each MR.
+# The actual test definition can be found in separate <PROJECT>.cmake files.
+#
+
+# Declare the package name:
+atlas_subdir( CITest )
+
+# CI tests are disabled by default:
+option( ATLAS_ENABLE_CI_TESTS "Set up tests in CITest package" OFF )
+if( NOT ATLAS_ENABLE_CI_TESTS )
+   return()
+endif()
+
+# Include CI test utilities:
+include( cmake/CITestFunctions.cmake )
+
+# Include CI test definitions:
+foreach( project Athena AnalysisBase AthGeneration AthSimulation )
+   # Detect project name for full and WorkDir builds:
+   # - ATLAS_PROJECT: set to parent project in WorkDir
+   # - CMAKE_PROJECT_NAME: project name in full builds
+   if( ATLAS_PROJECT STREQUAL ${project} OR CMAKE_PROJECT_NAME STREQUAL ${project} )
+      message( STATUS "Enabling CI tests for project ${project}" )
+      include( ${project}.cmake )
+   endif()
+endforeach()
diff --git a/AtlasTest/CITest/README.md b/AtlasTest/CITest/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..494054490e4adf9e3bdc8d87cf1aa4f9c3b32a79
--- /dev/null
+++ b/AtlasTest/CITest/README.md
@@ -0,0 +1,96 @@
+Tests defined in this package are run for every merge request. Only experts should modify
+these as they have a significant impact on the CI turnaround time.
+
+[TOC]
+
+## Test definition
+- Test are defined in separate files for each project (e.g. [`Athena.cmake`](Athena.cmake)).
+- Tests should have a short self-explanatory name. Do not add the word "test" to the name itself.
+- If tests depend on each other consider using a common basename and delimit the steps with an underscore, 
+  e.g. `Muon_digi`, `Muon_reco`.
+- Use the dedicated [`atlas_add_citest`](cmake/CITestFunctions.cmake) command for test definitions,
+  which is an extension of the regular [`atlas_add_test`](https://twiki.cern.ch/twiki/bin/view/AtlasComputing/SoftwareDevelopmentWorkBookCMakeInAtlas#atlas_add_test) command. It has a few extra arguments and sets
+  different defaults suitable for CI tests.
+- Additional properties can be set using the `PROPERTIES` keyword. See the 
+[cmake documentation](https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html#test-properties) for a full list.
+
+**Simple tests** should be added inline:
+```cmake
+atlas_add_citest( q221
+   SCRIPT Reco_tf.py --AMI q221 )
+```
+For more **complex commands**, or **any command that contains a semicolon (`;`)** use a dedicated script. 
+Either one available within the release:
+```cmake
+atlas_add_citest( Digitization_NewConfig
+   SCRIPT DigitizationConfigNew_test.py )
+```
+or add a script to the [`test/`](test/) folder:
+```cmake
+atlas_add_citest( FastChain
+   SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/test/FastChain.sh )
+```
+**Test dependencies** can be declared via the `DEPENDS` keyword
+```cmake
+atlas_add_citest( Test1 ... )
+atlas_add_citest( Test2 ...
+   DEPENDS Test1
+   [PROPERTIES REQUIRED_FILES ../Test1/myAOD.pool.root]
+)
+```
+The optional `REQUIRED_FILES` property ensures that the test is not even started 
+if the input file is missing. These tests then appear as "Not Run" in the test summary
+(instead of "Failed"). Use a relative path to the other test's working directory.
+
+For **MT/MP-tests**, add the number of required CPU cores (used for job scheduling):
+```cmake
+atlas_add_citest( ...
+   PROPERTIES PROCESSORS 8 )
+```
+Rather than matching the number of actual cores used, this number should reflect the
+expected system load. E.g. if a job runs with 8 threads but the system load during running is
+significant lower, one can reduce this number to allow other jobs to run in parallel.
+
+### Post-processing
+All tests defined with `atlas_add_citest` run a [default post-processing script](cmake/citest_post.sh.in) 
+that checks the log file for errors using [`noerror.sh`](../TestTools/).
+An additional post-processing script can be specified with the 
+`POST_EXEC_SCRIPT` keyword. The overall test result will be the exit code of that 
+post-processing script! The orignal test result is stored in the
+`${ATLAS_CTEST_TESTSTATUS}` environment variable and can be used in the post-processing
+script if needed.
+
+To temporarily ignore an error message, use:
+```cmake
+atlas_add_citest( ...
+   LOG_IGNORE_PATTERN "my error to ignore" )
+```
+
+New post-processing scripts should be made as general as possible and named as
+[`test/checkXYZ.sh`](test/).
+
+
+## Running the tests
+The tests in this package can be run locally like any other unit tests after compiling
+the package locally and running `ctest`.
+
+To avoid running the CI tests as part of the regular unit testing in the nightly build, 
+the tests are disabled by default. To enable them (e.g. for CI builds), the following
+needs to be added to the `cmake` command line:
+```sh
+cmake -DATLAS_ENABLE_CI_TESTS=TRUE ...
+```
+This is done already by default for partial `WorkDir` builds so a regular developer does
+not need to worry about this.
+
+All tests in this package carry the "CITest" label and therefore they can be included/excluded
+in `ctest` runs, via:
+```sh
+ctest -L CITest   # only run CI tests
+ctest -LE CITest  # run all tests, except CI tests
+```
+
+## Internals
+- All tests are run in a separate working directory in the build area: `AtlasTest/CITest/CMakeFiles/ciTestRun/<test>/` where `<test>` is the name used in `atlas_add_citest`.
+- The main test log file within the working directory is named `<test>.log`. 
+- If you want to verify the final command that is being run (useful e.g. to debug issues with quotes), check the content of `AtlasTest/CITest/test-bin/<test>.exe` in the build area.
diff --git a/AtlasTest/CITest/cmake/CITestFunctions.cmake b/AtlasTest/CITest/cmake/CITestFunctions.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..9cc830c002759d7e259acab078da58ba5d576447
--- /dev/null
+++ b/AtlasTest/CITest/cmake/CITestFunctions.cmake
@@ -0,0 +1,45 @@
+# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+
+# Function to setup CI tests. Acccepts the same arguments as
+# atlas_add_test and sets some suitable defaults:
+#
+# - tests are run within their own working directory (cleaned before each run)
+# - default (long) timeout
+# - use default post-processing script for log files
+#
+# Additonal arguments:
+#
+#   DEPENDS otherTest: define test dependency on `otherTest`
+#
+function( atlas_add_citest testName )
+   # Look for possible extra arguments:
+   cmake_parse_arguments( ARG "" "DEPENDS;POST_EXEC_SCRIPT" "" ${ARGN} )
+
+   # create and prepare clearing of working directory:
+   set( _workDir "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/ciTestRun/${testName}" )
+   set( _preExec "rm -rf ${_workDir}/*" )
+   file( MAKE_DIRECTORY "${_workDir}" )
+
+   # configure post-processing:
+   if( ARG_POST_EXEC_SCRIPT )
+      set( CI_POST_EXEC_SCRIPT ${ARG_POST_EXEC_SCRIPT} )
+   else()
+      set( CI_POST_EXEC_SCRIPT "true" )  # shell builtin always returning success
+   endif()
+
+   configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/citest_post.sh.in
+      ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${testName}_citest_post.sh @ONLY )
+
+   atlas_add_test( ${testName}
+      PROPERTIES WORKING_DIRECTORY ${_workDir}
+      PROPERTIES TIMEOUT 3600
+      PRE_EXEC_SCRIPT ${_preExec}
+      POST_EXEC_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${testName}_citest_post.sh
+      ${ARG_UNPARSED_ARGUMENTS} )
+
+   if( ARG_DEPENDS )
+      set_property( TEST CITest_${testName}_ctest
+         PROPERTY DEPENDS "CITest_${ARG_DEPENDS}_ctest" )
+   endif()
+
+endfunction( atlas_add_citest )
diff --git a/AtlasTest/CITest/cmake/citest_post.sh.in b/AtlasTest/CITest/cmake/citest_post.sh.in
new file mode 100755
index 0000000000000000000000000000000000000000..5430c046867cab0e8a82525fc7f14621a876a0ba
--- /dev/null
+++ b/AtlasTest/CITest/cmake/citest_post.sh.in
@@ -0,0 +1,28 @@
+#!/usr/bin/bash
+#
+# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+#
+# Post-processing script used for all CI tests
+#
+
+# check log file for errors:
+echo "----------------------------------------------------------"
+noerror.sh
+logStatus=$?
+
+# user-defined post-processing script:
+@CI_POST_EXEC_SCRIPT@
+postStatus=$?
+
+# return failure if any step failed:
+status=$(( ${ATLAS_CTEST_TESTSTATUS} || ${logStatus} || ${postStatus} ))
+
+echo "----------------------------------------------------------"
+echo "| ${ATLAS_CTEST_TESTNAME} test result: ${status}"
+echo "----------------------------------------------------------"
+echo "| CI test:            ${ATLAS_CTEST_TESTSTATUS}"
+echo "| CI log check:       ${logStatus}"
+echo "| CI post-processing: ${postStatus}"
+echo "----------------------------------------------------------"
+
+exit $status
diff --git a/AtlasTest/CITest/test/DAODPhys.sh b/AtlasTest/CITest/test/DAODPhys.sh
new file mode 100755
index 0000000000000000000000000000000000000000..f3537555bd3939a31edb728fc879bb8c5b25bc90
--- /dev/null
+++ b/AtlasTest/CITest/test/DAODPhys.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/bash
+# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+
+format=$1
+inputAOD=$2
+
+Reco_tf.py --AMI q431 \
+           --steering doRAWtoALL \
+           --inputAODFile ${inputAOD} \
+           --outputDAODFile pool.root \
+           --reductionConf ${format} \
+           --preExec 'AODtoDAOD:from AthenaCommon.DetFlags import DetFlags;DetFlags.detdescr.all_setOff();DetFlags.BField_setOn()'
diff --git a/AtlasTest/CITest/test/FastChain.sh b/AtlasTest/CITest/test/FastChain.sh
new file mode 100755
index 0000000000000000000000000000000000000000..da3a3c74011c6994f00b309f9f5174921b26634f
--- /dev/null
+++ b/AtlasTest/CITest/test/FastChain.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/bash
+# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+
+FastChain_tf.py \
+    --simulator ATLFASTIIF_G4MS \
+    --useISF True \
+    --randomSeed 123 \
+    --enableLooperKiller True \
+    --inputEVNTFile "/cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/ISF_Validation/mc12_valid.110401.PowhegPythia_P2012_ttbar_nonallhad.evgen.EVNT.e3099.01517252._000001.pool.root.1" \
+    --outputRDOFile RDO_CG.pool.root \
+    --maxEvents 2 \
+    --skipEvents 0 \
+    --geometryVersion default:ATLAS-R2-2016-01-00-01 \
+    --conditionsTag default:OFLCOND-MC16-SDR-16 \
+    --preSimExec 'from TrkDetDescrSvc.TrkDetDescrJobProperties import TrkDetFlags;TrkDetFlags.TRT_BuildStrawLayers=True;from Digitization.DigitizationFlags import digitizationFlags;digitizationFlags.experimentalDigi=["NewMerge"]' \
+    --postInclude='PyJobTransforms/UseFrontier.py' \
+    --DataRunNumber '284500' \
+    --imf False
diff --git a/AtlasTest/CITest/test/checkMuonDigiReco.sh b/AtlasTest/CITest/test/checkMuonDigiReco.sh
new file mode 100755
index 0000000000000000000000000000000000000000..0a93b5ab16dae30892bc58b6a72d1af2afc69949
--- /dev/null
+++ b/AtlasTest/CITest/test/checkMuonDigiReco.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+
+if [[ ${ATLAS_CTEST_TESTSTATUS} -ne 0 ]]; then
+    echo "Test failed. Not running post-processing."
+    exit ${ATLAS_CTEST_TESTSTATUS}
+fi
+
+# ensure that the output ESD has all types of muon technologies present
+echo "Checking reconstruction output..."
+checkxAOD.py OUT_ESD.root | grep Container > content.txt
+for value in RPC_Measurements TGC_Measurements STGC_Measurements MM_Measurements CSC_Measurements MDT_DriftCircles
+do
+  if grep -q ${value} "content.txt"; then
+    echo "${value} present"
+  else
+    echo "${value} not found, exit"
+    exit 1
+  fi
+done
+
+exit 0
diff --git a/AtlasTest/CITest/test/checkReco.sh b/AtlasTest/CITest/test/checkReco.sh
new file mode 100755
index 0000000000000000000000000000000000000000..857f342b16fd1f2ab1c9727d1006867f18fef4af
--- /dev/null
+++ b/AtlasTest/CITest/test/checkReco.sh
@@ -0,0 +1,49 @@
+#!/usr/bin/bash
+# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+#
+# Post-test script for typical reconstruction tests.
+#
+if [ $# -ne 2 ]; then
+    echo "Syntax: `basename $0` digest_reference content_reference"
+    exit 1
+fi
+
+if [[ ${ATLAS_CTEST_TESTSTATUS} -ne 0 ]]; then
+    echo "Test failed. Not running post-processing."
+    exit ${ATLAS_CTEST_TESTSTATUS}
+fi
+
+input="myAOD.pool.root"
+ref_digest=$1
+ref_content=$2
+
+# get references:
+get_files -data -remove ${ref_digest} ${ref_content}
+
+# xAODDigest:
+xAODDigest.py ${input} digest.txt
+
+if ! diff -qs ${ref_digest} digest.txt; then
+    echo "TEST WARNING: The xAODDigest diff failed!"
+    echo "The output (>) differs from the reference (<)."
+    echo "If differences are expected apply the following patch:"
+    head -n1 ${ref_digest}
+    diff ${ref_digest} digest.txt
+    exit 1
+fi
+
+# checkFile:
+acmd.py chk-file myAOD.pool.root | \
+    awk '/---/{flag=1;next}/===/{flag=0}flag' | \
+    awk '{print $10}' | sort > content.txt
+
+# TODO: update reference instead of applying trigger exclusions
+if ! diff -I '^HLT' -I '^LVL1' -I '^L1' -qs ${ref_content} content.txt; then
+  echo "TEST WARNING: The xAOD object content check failed!"
+  echo "The output (>) differs from the reference (<)."
+  echo "If differences are expected apply the following patch:"
+  diff ${ref_content} content.txt
+  exit 1
+fi
+
+exit 0
diff --git a/AtlasTest/CITest/test/q431.sh b/AtlasTest/CITest/test/q431.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9157326d5536c206bdef7d1b8cf1ab48ca87a9b3
--- /dev/null
+++ b/AtlasTest/CITest/test/q431.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/bash
+# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+
+Reco_tf.py --AMI q431 --multithreaded True --steering='doRAWtoALL' \
+           --preExec 'all:from AthenaMonitoring.DQMonFlags import DQMonFlags; DQMonFlags.doMonitoring=True; DQMonFlags.doNewMonitoring=True; DQMonFlags.doHLTMon=False' \
+           --imf False --maxEvents 500 --outputAODFile=myAOD.pool.root --outputHISTFile=myHIST.root
diff --git a/Build/AtlasBuildScripts/build_project.sh b/Build/AtlasBuildScripts/build_project.sh
index d915575e63754e97bdee8dc1af54ed0c1dbc0938..2cd7ac1b24959c3e0c8d829e066ae1fb754dd029 100644
--- a/Build/AtlasBuildScripts/build_project.sh
+++ b/Build/AtlasBuildScripts/build_project.sh
@@ -120,6 +120,8 @@ fi
 # partially successful build...)
 if [ "${ATLAS_CI_BUILD}" = "1" ]; then
    set -e
+   # Enable build of CITest package
+   ATLAS_EXTRA_CMAKE_ARGS+=(-DATLAS_ENABLE_CI_TESTS:BOOL=TRUE)
 else
    set +e
 fi
diff --git a/Projects/AnalysisBase/package_filters.txt b/Projects/AnalysisBase/package_filters.txt
index d8927f7cf44029b15448ccbfe93e8febc8fc61b5..8c8c4bfd9076ab70d57113bf094c06fd82709176 100644
--- a/Projects/AnalysisBase/package_filters.txt
+++ b/Projects/AnalysisBase/package_filters.txt
@@ -22,6 +22,7 @@
 # intended for analysis.
 
 + AsgExternal/Asg_Test
++ AtlasTest/CITest
 + AtlasTest/TestTools
 + Calorimeter/CaloGeoHelpers
 + Control/AthContainers
diff --git a/Projects/AthAnalysis/package_filters.txt b/Projects/AthAnalysis/package_filters.txt
index 45cb1fc4ceb9565b7334c35952d554947a90d86c..60fe602bcb1955df60ab64b7b26c443203ed2c34 100644
--- a/Projects/AthAnalysis/package_filters.txt
+++ b/Projects/AthAnalysis/package_filters.txt
@@ -5,6 +5,7 @@
 
 # Testing package(s):
 + AsgExternal/Asg_Test
++ AtlasTest/CITest
 + AtlasTest/TestTools
 
 # Core xAOD reading:
diff --git a/Projects/AthDataQuality/package_filters.txt b/Projects/AthDataQuality/package_filters.txt
index 535a5f1ca84735d281d68c3af566c68fcba3e7f0..33179e54fc64c3042164bdd91dd867796c74c83e 100644
--- a/Projects/AthDataQuality/package_filters.txt
+++ b/Projects/AthDataQuality/package_filters.txt
@@ -1,6 +1,7 @@
 #
 # Packages to build as part of the AthDataQuality project.
 #
++ AtlasTest/CITest
 + AtlasTest/TestTools
 + Control/CxxUtils
 + DataQuality/DQDefects
diff --git a/Projects/AthGeneration/package_filters.txt b/Projects/AthGeneration/package_filters.txt
index 6180c7fe7539198296136a7af9e6555f1f9af1a1..45c87280bc2293bd30786d7cb7bfbb6fe3b3aa39 100644
--- a/Projects/AthGeneration/package_filters.txt
+++ b/Projects/AthGeneration/package_filters.txt
@@ -3,6 +3,7 @@
 #
 
 + AsgExternal/Asg_Test
++ AtlasTest/CITest
 + AtlasTest/TestTools
 + Calorimeter/CaloConditions
 + Calorimeter/CaloCondBlobObjs
diff --git a/Projects/AthSimulation/package_filters.txt b/Projects/AthSimulation/package_filters.txt
index f7cde0f6cc4bd65a6bc83df1e154f9b1acba838b..346fbdf92772f1602f57f5c797f3ef02afbb140d 100644
--- a/Projects/AthSimulation/package_filters.txt
+++ b/Projects/AthSimulation/package_filters.txt
@@ -6,6 +6,7 @@
 + AtlasGeometryCommon/BeamPipeGeoModel
 + AtlasGeometryCommon/GeoModelEnvelopes
 + AtlasGeometryCommon/SubDetectorEnvelopes
++ AtlasTest/CITest
 + AtlasTest/TestTools
 + Calorimeter/CaloAlignment/CaloAlignmentTools
 + Calorimeter/CaloCnv/CaloDetMgrDetDescrCnv
diff --git a/Projects/DetCommon/package_filters.txt b/Projects/DetCommon/package_filters.txt
index 3a3b5ef5c408f88ba707059b4bb0acb0784da59e..29a7e0b1ba716c02acbe131e101bbcc1935a75ff 100644
--- a/Projects/DetCommon/package_filters.txt
+++ b/Projects/DetCommon/package_filters.txt
@@ -3,6 +3,7 @@
 # Package filtering rules for the DetCommon project build.
 #
 
++ AtlasTest/CITest
 + AtlasTest/TestTools
 + Control/CxxUtils
 + Database/ConnectionManagement/AtlasAuthentication
diff --git a/Projects/VP1Light/package_filters.txt b/Projects/VP1Light/package_filters.txt
index e2351eb6bd12a8d5a2c8ecc30f21e95caf665ca1..2f73dde9fb817087c3cf36ec129c8501facf374d 100644
--- a/Projects/VP1Light/package_filters.txt
+++ b/Projects/VP1Light/package_filters.txt
@@ -13,6 +13,7 @@
 + DetectorDescription/GeoPrimitives
 #
 # Utility packages
++ AtlasTest/CITest
 + AtlasTest/TestTools
 + Calorimeter/CaloGeoHelpers
 + Control/AthToolSupport/.*
diff --git a/Projects/WorkDir/CMakeLists.txt b/Projects/WorkDir/CMakeLists.txt
index 6a3ee4da643591cac8138cdaa6e92b6239ce571e..0e97de9b6e029f13061d19ad97a3cd9accd87729 100644
--- a/Projects/WorkDir/CMakeLists.txt
+++ b/Projects/WorkDir/CMakeLists.txt
@@ -16,6 +16,11 @@ project( WorkDir )
 set( CMAKE_CUDA_ARCHITECTURES "52" CACHE STRING
    "CUDA architectures to build code for" )
 
+# Enable the CI tests in the CITest package in case the user wants to
+# run them locally:
+set( ATLAS_ENABLE_CI_TESTS TRUE CACHE BOOL
+   "Set up tests in CITest package" )
+
 # Let the user pick up updated AtlasCMake/AtlasLCG versions for testing.
 # Remember that it's not a problem if AtlasCMake is not found, that's why
 # we use the QUIET keyword.