libzypp  17.31.31
LoadTestcase.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include "LoadTestcase.h"
13 #include "HelixHelpers.h"
14 #include "YamlTestcaseHelpers.h"
15 #include <zypp/PathInfo.h>
16 #include <zypp/base/LogControl.h>
17 
19 
20  static const std::string helixControlFile = "solver-test.xml";
21  static const std::string yamlControlFile = "zypp-control.yaml";
22 
26 
27  bool loadHelix (const Pathname &filename, std::string *err);
28 
29  bool loadYaml ( const Pathname &path, std::string *err);
30  };
31 
32 
34  {
35  std::vector<Node> nodes;
36  Impl *clone() const { return new Impl(*this); }
37  };
38 
40  {
41  std::string name;
42  std::string value;
43  std::map<std::string, std::string> properties;
44  std::vector<std::shared_ptr<Node>> children;
45  Impl *clone() const { return new Impl(*this); }
46  };
47 
48  TestcaseTrial::TestcaseTrial() : _pimpl ( new Impl() )
49  { }
50 
52  { }
53 
54  const std::vector<TestcaseTrial::Node> &TestcaseTrial::nodes() const
55  { return _pimpl->nodes; }
56 
57  std::vector<TestcaseTrial::Node> &TestcaseTrial::nodes()
58  { return _pimpl->nodes; }
59 
60  TestcaseTrial::Node::Node() : _pimpl ( new Impl() )
61  { }
62 
64  { }
65 
66  const std::string &TestcaseTrial::Node::name() const
67  { return _pimpl->name; }
68 
70  { return _pimpl->name; }
71 
72  const std::string &TestcaseTrial::Node::value() const
73  { return _pimpl->value; }
74 
76  { return _pimpl->value; }
77 
78  const std::string &TestcaseTrial::Node::getProp( const std::string &name, const std::string &def ) const
79  {
80  auto it { _pimpl->properties.find( name ) };
81  return it == _pimpl->properties.end() ? def : it->second;
82  }
83 
84  const std::map<std::string, std::string> &TestcaseTrial::Node::properties() const
85  { return _pimpl->properties; }
86 
87  std::map<std::string, std::string> &TestcaseTrial::Node::properties()
88  { return _pimpl->properties; }
89 
90  const std::vector<std::shared_ptr<TestcaseTrial::Node> > &TestcaseTrial::Node::children() const
91  { return _pimpl->children; }
92 
93  std::vector<std::shared_ptr<TestcaseTrial::Node> > &TestcaseTrial::Node::children()
94  { return _pimpl->children; }
95 
96  bool LoadTestcase::Impl::loadHelix(const zypp::filesystem::Pathname &filename, std::string *err)
97  {
98  xmlDocPtr xml_doc = xmlParseFile ( filename.c_str() );
99  if (xml_doc == NULL) {
100  if ( err ) *err = (str::Str() << "Can't parse test file '" << filename << "'");
101  return false;
102  }
103 
104 
105  auto root = helix::detail::XmlNode (xmlDocGetRootElement (xml_doc));
106 
107  DBG << "Parsing file '" << filename << "'" << std::endl;
108 
109  if (!root.equals("test")) {
110  if ( err ) *err = (str::Str() << "Node not 'test' in parse_xml_test():" << root.name() << "'");
111  return false;
112  }
113 
114  bool setupDone = false;
115  auto node = root.children();
116  while (node) {
117  if (node->type() == XML_ELEMENT_NODE) {
118  if (node->equals( "setup" )) {
119  if ( setupDone ) {
120  if ( err ) *err = "Multiple setup tags found, this is not supported";
121  return false;
122  }
123  setupDone = true;
124  if ( !helix::detail::parseSetup( *node, _setup, err ) )
125  return false;
126 
127  } else if (node->equals( "trial" )) {
128  if ( !setupDone ) {
129  if ( err ) *err = "Any trials must be preceded by the setup!";
130  return false;
131  }
132  TestcaseTrial trial;
133  if ( !helix::detail::parseTrial( *node, trial, err ) )
134  return false;
135  _trials.push_back( trial );
136  } else {
137  ERR << "Unknown tag '" << node->name() << "' in test" << std::endl;
138  }
139  }
140  node = ( node->next() );
141  }
142  xmlFreeDoc (xml_doc);
143  return true;
144  }
145 
146  bool LoadTestcase::Impl::loadYaml(const zypp::filesystem::Pathname &path, std::string *err)
147  {
148  DBG << "Parsing file '" << path << "'" << std::endl;
149 
150  const auto makeError = [&]( const std::string_view &errStr ){
151  if ( err ) *err = errStr;
152  return false;
153  };
154 
155  YAML::Node control;
156  try {
157  control = YAML::LoadFile( path.asString() );
158 
159  if ( control.Type() != YAML::NodeType::Map )
160  return makeError("Root node must be of type Map.");
161 
162  const auto &setup = control["setup"];
163  if ( !setup )
164  return makeError("The 'setup' section is required.");
165 
166  if ( !yamltest::detail::parseSetup( setup, _setup, err) )
167  return false;
168 
169  const auto &trials = control["trials"];
170  if ( !trials )
171  return makeError("The 'trials' section is required.");
172  if ( trials.Type() != YAML::NodeType::Sequence )
173  return makeError("The 'trials' section must be of type Sequence.");
174 
175  for ( const auto &trial : trials ) {
177  if ( !trial["trial"] )
178  return makeError("Every element in the trials sequence needs to have the 'trial' key.");
179 
180  if ( !yamltest::detail::parseTrial( trial["trial"], t, err) )
181  return false;
182  _trials.push_back( t );
183  }
184  } catch ( YAML::Exception &e ) {
185  if ( err ) *err = e.what();
186  return false;
187  } catch ( ... ) {
188  if ( err ) *err = "Unknown error when parsing the control file";
189  return false;
190  }
191  return true;
192  }
193 
195  { }
196 
198  { }
199 
200  bool LoadTestcase::loadTestcaseAt(const zypp::filesystem::Pathname &path, std::string *err)
201  {
202  const auto t = testcaseTypeAt( path );
203  if ( t == LoadTestcase::None ) {
204  if ( err ) *err = "Unsopported or no testcase in directory";
205  return false;
206  }
207 
208  // reset everything
209  _pimpl.reset( new Impl() );
210  _pimpl->_setup.data().globalPath = path;
211 
212  switch (t) {
213  case LoadTestcase::Helix:
214  return _pimpl->loadHelix( path / helixControlFile, err );
215  case LoadTestcase::Yaml:
216  return _pimpl->loadYaml( path / yamlControlFile, err );
217  default:
218  return false;
219  }
220  }
221 
223  {
224  if ( filesystem::PathInfo( path / helixControlFile ).isFile() ) {
225  return LoadTestcase::Helix;
226  } else if ( filesystem::PathInfo( path / yamlControlFile ).isFile() ) {
227  return LoadTestcase::Yaml;
228  }
229  return LoadTestcase::None;
230  }
231 
233  {
234  return _pimpl->_setup;
235  }
236 
238  {
239  return _pimpl->_trials;
240  }
241 
242 }
std::ostream & node(std::ostream &out_r, const std::string &name_r, Node::Attr attr_r)
Definition: Xml.h:203
bool loadTestcaseAt(const zypp::Pathname &path, std::string *err)
bool parseTrial(const XmlNode &trial, zypp::misc::testcase::TestcaseTrial &target, std::string *)
Definition: HelixHelpers.h:303
const TestcaseSetup & setupInfo() const
std::vector< std::shared_ptr< Node > > children
Definition: LoadTestcase.cc:44
static const std::string helixControlFile
Definition: LoadTestcase.cc:20
const char * c_str() const
String representation.
Definition: Pathname.h:110
bool loadYaml(const Pathname &path, std::string *err)
bool parseSetup(const XmlNode &setup, zypp::misc::testcase::TestcaseSetup &t, std::string *err)
Definition: HelixHelpers.h:138
const std::map< std::string, std::string > & properties() const
Definition: LoadTestcase.cc:84
const std::string & value() const
Definition: LoadTestcase.cc:72
#define ERR
Definition: Logger.h:98
bool parseTrial(const YAML::Node &trial, zypp::misc::testcase::TestcaseTrial &target, std::string *err)
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition: String.h:211
static Type testcaseTypeAt(const zypp::Pathname &path)
const std::string & asString() const
String representation.
Definition: Pathname.h:91
const std::string & getProp(const std::string &name, const std::string &def=std::string()) const
Definition: LoadTestcase.cc:78
static const std::string yamlControlFile
Definition: LoadTestcase.cc:21
const std::vector< Node > & nodes() const
Definition: LoadTestcase.cc:54
bool loadHelix(const Pathname &filename, std::string *err)
Definition: LoadTestcase.cc:96
const std::vector< std::shared_ptr< Node > > & children() const
Definition: LoadTestcase.cc:90
std::map< std::string, std::string > properties
Definition: LoadTestcase.cc:43
RWCOW_pointer< Impl > _pimpl
Definition: LoadTestcase.h:54
std::unique_ptr< Impl > _pimpl
Definition: LoadTestcase.h:80
const std::string & name() const
Definition: LoadTestcase.cc:66
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:220
std::vector< TestcaseTrial > TestcaseTrials
Definition: LoadTestcase.h:62
bool parseSetup(const YAML::Node &setup, zypp::misc::testcase::TestcaseSetup &t, std::string *err)
#define DBG
Definition: Logger.h:95
const TestcaseTrials & trialInfo() const