Belle II Software development
conditions_metadataprovider.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <framework/database/MetadataProvider.h>
10#include <framework/logging/Logger.h>
11#include <framework/utilities/testhelpers/Fixtures.h>
12#include <gtest/gtest.h>
13
14using namespace Belle2;
15using namespace Conditions;
16
17namespace {
20 class TestMetadataProvider final: public MetadataProvider {
22 std::vector<PayloadMetadata> m_testpayloads;
23 public:
25 explicit TestMetadataProvider(const std::vector<PayloadMetadata>& payloads): m_testpayloads(payloads) {}
29 std::string getGlobaltagStatus(const std::string& name) override
30 {
31 if (name.empty()) {
32 B2ERROR("This globaltag is missing" << LogVar("globaltag", "") << LogVar("error", "missing"));
33 }
34 // later we want to test payloads from different tags so if the tagname starts with "tag" assume valid;
35 if (name.substr(0, 3) == "tag") {
36 return "PUBLISHED";
37 }
38 // otherwise just treat the tag name as its status to allow testing tag states
39 return name;
40 }
44 bool updatePayloads(const std::string& globaltag, int exp, int run) override
45 {
46 IntervalOfValidity iov(exp, run, exp, run);
47 int count{0};
48 for (auto p : m_testpayloads) {
49 if (p.globaltag == globaltag and p.iov.contains(iov)) {
50 addPayload(std::move(p), "testprovider");
51 ++count;
52 }
53 }
54 return count > 0;
55 }
56 };
57
59 using MetadataProviderTest = TestHelpers::LogMessageTest;
60
62 TEST_F(MetadataProviderTest, tagstates)
63 {
64 TestMetadataProvider provider({});
65 EXPECT_TRUE(provider.setTags({"TESTING", "VALIDATED", "RUNNING", "PUBLISHED"}));
66 EXPECT_FALSE(provider.setTags({"OPEN"}));
67 // this will also conveniently fail if the first expect did produce an error
68 expectErrorWithVariables({{"globaltag", "OPEN"}, {"status", "OPEN"}});
69 EXPECT_FALSE(provider.setTags({"INVALID"}));
70 expectErrorWithVariables({{"globaltag", "INVALID"}, {"status", "INVALID"}});
71 // also fail if the OPEN one is somewhere in the middle
72 EXPECT_FALSE(provider.setTags({"TESTING", "VALIDATED", "OPEN", "RUNNING", "PUBLISHED"}));
73 expectErrorWithVariables({{"globaltag", "OPEN"}, {"status", "OPEN"}});
74 provider.setUsableTagStates({"OPEN", "INVALID"});
75 EXPECT_TRUE(provider.setTags({"OPEN"}));
76 EXPECT_FALSE(provider.setTags({"INVALID"}));
77 expectErrorWithVariables({{"globaltag", "INVALID"}, {"status", "INVALID"}});
78 EXPECT_FALSE(provider.setTags({""}));
79 expectErrorWithVariables({{"globaltag", ""}, {"error", "missing"}});
80 }
81
83 TEST_F(MetadataProviderTest, exception)
84 {
85 TestMetadataProvider provider({});
86 std::vector<PayloadMetadata> query{PayloadMetadata{"A"}};
87 ASSERT_TRUE(provider.setTags({"tag1"}));
88 ASSERT_THROW(provider.getPayloads(0, 0, query), std::runtime_error);
89 }
90
93 TEST_F(MetadataProviderTest, onlyfillneeded)
94 {
95 TestMetadataProvider provider({
96 //name, tag, ignore, ignore, ignore, exp, run, exp, run, revision
97 PayloadMetadata{"A", "tag1", "", "", "", 0, 0, -1, -1, 2},
98 });
99 std::vector<PayloadMetadata> query{PayloadMetadata{"A"}, PayloadMetadata{"B"}};
100 // A is in the tag but already set. B isn't in the tag but already set so no error
101 query[0].revision = 1;
102 query[1].revision = 1;
103 ASSERT_TRUE(provider.setTags({"tag1"}));
104 ASSERT_TRUE(provider.getPayloads(0, 0, query));
105 // so no log messages please
106 expectMessage(LogConfig::c_Error, 0, true);
107 // and everything as it was
108 EXPECT_EQ(query[0].name, "A");
109 EXPECT_EQ(query[0].revision, 1);
110 EXPECT_EQ(query[1].name, "B");
111 EXPECT_EQ(query[1].revision, 1);
112 }
113
115 TEST_F(MetadataProviderTest, payloads)
116 {
117 TestMetadataProvider provider({
118 //name, tag, ignore, ignore, ignore, exp, run, exp, run, revision
119 PayloadMetadata{"A", "tag1", "", "", "", 0, 0, -1, -1, 1},
120 PayloadMetadata{"A", "tag1", "", "", "", 1, 0, 1, 10, 3},
121 PayloadMetadata{"A", "tag1", "", "", "", 1, 0, 1, 10, 2},
122 PayloadMetadata{"B", "tag1", "", "", "", 1, 0, 1, 10, 1},
123 });
124 std::vector<PayloadMetadata> query{PayloadMetadata{"A"}, PayloadMetadata{"B"}};
125 ASSERT_TRUE(provider.setTags({"tag1"}));
126 ASSERT_FALSE(provider.getPayloads(0, 0, query));
127 expectErrorWithVariables({{"globaltags", "tag1"}, {"name", "B"}, {"experiment", "0"}, {"run", "0"}});
128 EXPECT_EQ(query[0].revision, 1);
129 EXPECT_EQ(query[1].revision, 0);
130 // try for exp 1, there should be something for both payloads and A should be in revision 3.
131 // Howewer metadata provider only fills missing info so we need new query structure
132 query = {PayloadMetadata{"A"}, PayloadMetadata{"B"}};
133 EXPECT_TRUE(provider.getPayloads(1, 0, query));
134 EXPECT_EQ(query[0].revision, 3);
135 EXPECT_EQ(query[1].revision, 1);
136 // and back to exp 0 and we want the same result as before.
137 query = {PayloadMetadata{"A"}, PayloadMetadata{"B"}};
138 EXPECT_FALSE(provider.getPayloads(0, 0, query));
139 expectErrorWithVariables({{"globaltags", "tag1"}, {"name", "B"}, {"experiment", "0"}, {"run", "0"}});
140 EXPECT_EQ(query[0].revision, 1);
141 EXPECT_EQ(query[1].revision, 0);
142 // so let's try this again but mark B as optional. Same result but no error
143 query = {PayloadMetadata{"A"}, PayloadMetadata{"B", false}};
144 EXPECT_TRUE(provider.getPayloads(0, 0, query));
145 EXPECT_EQ(query[0].revision, 1);
146 EXPECT_EQ(query[1].revision, 0);
147 EXPECT_EQ(query[1].required, false);
148 }
149
150 TEST_F(MetadataProviderTest, payloads_multiple_gt)
151 {
152 TestMetadataProvider provider({
153 //name, tag, ignore, ignore, ignore, exp, run, exp, run, revision
154 PayloadMetadata{"A", "tag1", "", "", "", 0, 0, -1, -1, 1},
155 PayloadMetadata{"A", "tag2", "", "", "", 0, 0, -1, -1, 2},
156 PayloadMetadata{"B", "tag2", "", "", "", 0, 0, -1, -1, 2},
157 });
158 // In this case A should be taken from tag1 even if it exists in tag2.
159 // But B can only come from tag2
160 ASSERT_TRUE(provider.setTags({"tag1", "tag2"}));
161 std::vector<PayloadMetadata> query = {PayloadMetadata{"A"}, PayloadMetadata{"B"}};
162 EXPECT_TRUE(provider.getPayloads(1, 0, query));
163 EXPECT_EQ(query[0].revision, 1);
164 EXPECT_EQ(query[1].revision, 2);
165 EXPECT_EQ(query[0].globaltag, "tag1");
166 EXPECT_EQ(query[1].globaltag, "tag2");
167 }
168}
Base class for a payload metadata provider.
virtual std::string getGlobaltagStatus(const std::string &name)=0
Check the status of a global tag with the given name.
void addPayload(PayloadMetadata &&payload, const std::string &messagePrefix="")
Add a payload information to the internal list.
virtual bool updatePayloads(const std::string &globaltag, int exp, int run)=0
Update the list of existing payloads from a given globaltag, exp and run combination.
A class that describes the interval of experiments/runs for which an object in the database is valid.
@ c_Error
Error: for things that went wrong and have to be fixed.
Definition: LogConfig.h:30
Test fixture to be able to check the contents and types of emitted log messages in detail.
Definition: Fixtures.h:23
Class to store variables with their name which were sent to the logging service.
Abstract base class for different kinds of events.
Simple struct to group all information necessary for a single payload.
size_t revision
the revision of the payload