libzypp  17.31.0
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  if ( _pimpl->properties.find( name) == _pimpl->properties.end() )
81  return def;
82  return _pimpl->properties.at( name );
83  }
84 
85  const std::map<std::string, std::string> &TestcaseTrial::Node::properties() const
86  { return _pimpl->properties; }
87 
88  std::map<std::string, std::string> &TestcaseTrial::Node::properties()
89  { return _pimpl->properties; }
90 
91  const std::vector<std::shared_ptr<TestcaseTrial::Node> > &TestcaseTrial::Node::children() const
92  { return _pimpl->children; }
93 
94  std::vector<std::shared_ptr<TestcaseTrial::Node> > &TestcaseTrial::Node::children()
95  { return _pimpl->children; }
96 
97  bool LoadTestcase::Impl::loadHelix(const zypp::filesystem::Pathname &filename, std::string *err)
98  {
99  xmlDocPtr xml_doc = xmlParseFile ( filename.c_str() );
100  if (xml_doc == NULL) {
101  if ( err ) *err = (str::Str() << "Can't parse test file '" << filename << "'");
102  return false;
103  }
104 
105 
106  auto root = helix::detail::XmlNode (xmlDocGetRootElement (xml_doc));
107 
108  DBG << "Parsing file '" << filename << "'" << std::endl;
109 
110  if (!root.equals("test")) {
111  if ( err ) *err = (str::Str() << "Node not 'test' in parse_xml_test():" << root.name() << "'");
112  return false;
113  }
114 
115  bool setupDone = false;
116  auto node = root.children();
117  while (node) {
118  if (node->type() == XML_ELEMENT_NODE) {
119  if (node->equals( "setup" )) {
120  if ( setupDone ) {
121  if ( err ) *err = "Multiple setup tags found, this is not supported";
122  return false;
123  }
124  setupDone = true;
125  if ( !helix::detail::parseSetup( *node, _setup, err ) )
126  return false;
127 
128  } else if (node->equals( "trial" )) {
129  if ( !setupDone ) {
130  if ( err ) *err = "Any trials must be preceded by the setup!";
131  return false;
132  }
133  TestcaseTrial trial;
134  if ( !helix::detail::parseTrial( *node, trial, err ) )
135  return false;
136  _trials.push_back( trial );
137  } else {
138  ERR << "Unknown tag '" << node->name() << "' in test" << std::endl;
139  }
140  }
141  node = ( node->next() );
142  }
143  xmlFreeDoc (xml_doc);
144  return true;
145  }
146 
147  bool LoadTestcase::Impl::loadYaml(const zypp::filesystem::Pathname &path, std::string *err)
148  {
149  DBG << "Parsing file '" << path << "'" << std::endl;
150 
151  const auto makeError = [&]( const std::string_view &errStr ){
152  if ( err ) *err = errStr;
153  return false;
154  };
155 
156  YAML::Node control;
157  try {
158  control = YAML::LoadFile( path.asString() );
159 
160  if ( control.Type() != YAML::NodeType::Map )
161  return makeError("Root node must be of type Map.");
162 
163  const auto &setup = control["setup"];
164  if ( !setup )
165  return makeError("The 'setup' section is required.");
166 
167  if ( !yamltest::detail::parseSetup( setup, _setup, err) )
168  return false;
169 
170  const auto &trials = control["trials"];
171  if ( !trials )
172  return makeError("The 'trials' section is required.");
173  if ( trials.Type() != YAML::NodeType::Sequence )
174  return makeError("The 'trials' section must be of type Sequence.");
175 
176  for ( const auto &trial : trials ) {
178  if ( !trial["trial"] )
179  return makeError("Every element in the trials sequence needs to have the 'trial' key.");
180 
181  if ( !yamltest::detail::parseTrial( trial["trial"], t, err) )
182  return false;
183  _trials.push_back( t );
184  }
185  } catch ( YAML::Exception &e ) {
186  if ( err ) *err = e.what();
187  return false;
188  } catch ( ... ) {
189  if ( err ) *err = "Unknown error when parsing the control file";
190  return false;
191  }
192  return true;
193  }
194 
196  { }
197 
199  { }
200 
201  bool LoadTestcase::loadTestcaseAt(const zypp::filesystem::Pathname &path, std::string *err)
202  {
203  const auto t = testcaseTypeAt( path );
204  if ( t == LoadTestcase::None ) {
205  if ( err ) *err = "Unsopported or no testcase in directory";
206  return false;
207  }
208 
209  // reset everything
210  _pimpl.reset( new Impl() );
211  _pimpl->_setup.data().globalPath = path;
212 
213  switch (t) {
214  case LoadTestcase::Helix:
215  return _pimpl->loadHelix( path / helixControlFile, err );
216  case LoadTestcase::Yaml:
217  return _pimpl->loadYaml( path / yamlControlFile, err );
218  default:
219  return false;
220  }
221  }
222 
224  {
225  if ( filesystem::PathInfo( path / helixControlFile ).isFile() ) {
226  return LoadTestcase::Helix;
227  } else if ( filesystem::PathInfo( path / yamlControlFile ).isFile() ) {
228  return LoadTestcase::Yaml;
229  }
230  return LoadTestcase::None;
231  }
232 
234  {
235  return _pimpl->_setup;
236  }
237 
239  {
240  return _pimpl->_trials;
241  }
242 
243 }
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:85
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:97
const std::vector< std::shared_ptr< Node > > & children() const
Definition: LoadTestcase.cc:91
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