1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/misc/LoadTestcase.cc
12 #include "LoadTestcase.h"
13 #include "HelixHelpers.h"
14 #include "YamlTestcaseHelpers.h"
15 #include <zypp/PathInfo.h>
16 #include <zypp/base/LogControl.h>
17 #include <zypp/Repository.h>
18 #include <zypp/RepoManager.h>
19 #include <zypp/sat/Pool.h>
21 #define ZYPP_USE_RESOLVER_INTERNALS
22 #include <zypp/solver/detail/SystemCheck.h>
24 namespace zypp::misc::testcase {
26 static const std::string helixControlFile = "solver-test.xml";
27 static const std::string yamlControlFile = "zypp-control.yaml";
29 struct LoadTestcase::Impl {
31 std::vector<TestcaseTrial> _trials;
33 bool loadHelix (const Pathname &filename, std::string *err);
35 bool loadYaml ( const Pathname &path, std::string *err);
39 bool LoadTestcase::Impl::loadHelix(const zypp::filesystem::Pathname &filename, std::string *err)
41 xmlDocPtr xml_doc = xmlParseFile ( filename.c_str() );
42 if (xml_doc == NULL) {
43 if ( err ) *err = (str::Str() << "Can't parse test file '" << filename << "'");
48 auto root = helix::detail::XmlNode (xmlDocGetRootElement (xml_doc));
50 DBG << "Parsing file '" << filename << "'" << std::endl;
52 if (!root.equals("test")) {
53 if ( err ) *err = (str::Str() << "Node not 'test' in parse_xml_test():" << root.name() << "'");
57 bool setupDone = false;
58 auto node = root.children();
60 if (node->type() == XML_ELEMENT_NODE) {
61 if (node->equals( "setup" )) {
63 if ( err ) *err = "Multiple setup tags found, this is not supported";
67 if ( !helix::detail::parseSetup( *node, _setup, err ) )
70 } else if (node->equals( "trial" )) {
72 if ( err ) *err = "Any trials must be preceeded by the setup!";
76 if ( !helix::detail::parseTrial( *node, trial, err ) )
78 _trials.push_back( trial );
80 ERR << "Unknown tag '" << node->name() << "' in test" << std::endl;
83 node = ( node->next() );
89 bool LoadTestcase::Impl::loadYaml(const zypp::filesystem::Pathname &path, std::string *err)
91 DBG << "Parsing file '" << path << "'" << std::endl;
93 const auto makeError = [&]( const std::string_view &errStr ){
94 if ( err ) *err = errStr;
100 control = YAML::LoadFile( path.asString() );
102 if ( control.Type() != YAML::NodeType::Map )
103 return makeError("Root node must be of type Map.");
105 const auto &setup = control["setup"];
107 return makeError("The 'setup' section is required.");
109 if ( !yamltest::detail::parseSetup( setup, _setup, err) )
112 const auto &trials = control["trials"];
114 return makeError("The 'trials' section is required.");
115 if ( trials.Type() != YAML::NodeType::Sequence )
116 return makeError("The 'trials' section must be of type Sequence.");
118 for ( const auto &trial : trials ) {
119 zypp::misc::testcase::TestcaseTrial t;
120 if ( !trial["trial"] )
121 return makeError("Every element in the trials sequence needs to have the 'trial' key.");
123 if ( !yamltest::detail::parseTrial( trial["trial"], t, err) )
125 _trials.push_back( t );
127 } catch ( YAML::Exception &e ) {
128 if ( err ) *err = e.what();
131 if ( err ) *err = "Unknown error when parsing the control file";
137 LoadTestcase::LoadTestcase() : _pimpl( new Impl() )
140 LoadTestcase::~LoadTestcase()
143 bool LoadTestcase::loadTestcaseAt(const zypp::filesystem::Pathname &path, std::string *err)
145 const auto t = testcaseTypeAt( path );
146 if ( t == LoadTestcase::None ) {
147 if ( err ) *err = "Unsopported or no testcase in directory";
152 _pimpl.reset( new Impl() );
153 _pimpl->_setup.globalPath = path;
156 case LoadTestcase::Helix:
157 return _pimpl->loadHelix( path / helixControlFile, err );
158 case LoadTestcase::Yaml:
159 return _pimpl->loadYaml( path / yamlControlFile, err );
165 LoadTestcase::Type LoadTestcase::testcaseTypeAt(const zypp::filesystem::Pathname &path)
167 if ( filesystem::PathInfo( path / helixControlFile ).isFile() ) {
168 return LoadTestcase::Helix;
169 } else if ( filesystem::PathInfo( path / yamlControlFile ).isFile() ) {
170 return LoadTestcase::Yaml;
172 return LoadTestcase::None;
175 const TestcaseSetup &LoadTestcase::setupInfo() const
177 return _pimpl->_setup;
180 const std::vector<TestcaseTrial> &LoadTestcase::trialInfo() const
182 return _pimpl->_trials;
185 const std::string &TestcaseTrial::Node::getProp( const std::string &name, const std::string &def ) const
187 if ( properties.find( name) == properties.end() )
189 return properties.at( name );
192 bool TestcaseSetup::applySetup( RepoManager &manager) const
194 const auto &setup = *this;
195 if ( !setup.architecture.empty() )
197 MIL << "Setting architecture to '" << setup.architecture << "'" << std::endl;
198 ZConfig::instance().setSystemArchitecture( setup.architecture );
199 setenv ("ZYPP_TESTSUITE_FAKE_ARCH", setup.architecture.c_str(), 1);
202 if ( setup.systemRepo ) {
203 if (!loadRepo( manager, setup, *setup.systemRepo ) )
205 ERR << "Can't setup 'system'" << std::endl;
210 if ( !setup.hardwareInfoFile.empty() ) {
211 setenv( "ZYPP_MODALIAS_SYSFS", setup.hardwareInfoFile.asString().c_str(), 1 );
212 MIL << "setting HardwareInfo to: " << setup.hardwareInfoFile.asString() << std::endl;
215 for ( const auto &channel : setup.repos ) {
216 if ( !loadRepo( manager, setup, channel ) )
218 ERR << "Can't setup 'channel'" << std::endl;
223 if ( !setup.systemCheck.empty() ) {
224 MIL << "setting systemCheck to: " << setup.systemCheck.asString() << std::endl;
225 SystemCheck::instance().setFile( setup.systemCheck );
231 bool TestcaseSetup::loadRepo( zypp::RepoManager &manager, const TestcaseSetup &setup, const RepoData &data )
233 Pathname pathname = setup.globalPath + data.path;
234 MIL << "'" << pathname << "'" << std::endl;
238 using TrType = zypp::misc::testcase::TestcaseRepoType;
240 if ( data.type == TrType::Url ) {
242 MIL << "Load from Url '" << data.path << "'" << std::endl;
245 nrepo.setAlias ( data.alias );
246 nrepo.setName ( data.alias );
247 nrepo.setEnabled ( true );
248 nrepo.setAutorefresh( false );
249 nrepo.setPriority ( data.priority );
250 nrepo.addBaseUrl ( Url(data.path) );
252 manager.refreshMetadata( nrepo );
253 manager.buildCache( nrepo );
254 manager.loadFromCache( nrepo );
256 catch ( Exception & excpt_r ) {
257 ZYPP_CAUGHT (excpt_r);
258 ERR << "Couldn't load packages from Url '" << data.path << "'" << std::endl;
264 MIL << "Load from File '" << pathname << "'" << std::endl;
265 zypp::Repository satRepo;
267 if ( data.alias == "@System" ) {
268 satRepo = zypp::sat::Pool::instance().systemRepo();
270 satRepo = zypp::sat::Pool::instance().reposInsert( data.alias );
275 nrepo.setAlias ( data.alias );
276 nrepo.setName ( data.alias );
277 nrepo.setEnabled ( true );
278 nrepo.setAutorefresh( false );
279 nrepo.setPriority ( data.priority );
280 nrepo.addBaseUrl ( pathname.asUrl() );
282 satRepo.setInfo (nrepo);
283 if ( data.type == TrType::Helix )
284 satRepo.addHelix( pathname );
286 satRepo.addTesttags( pathname );
287 MIL << "Loaded " << satRepo.solvablesSize() << " resolvables from " << ( data.path.empty()?pathname.asString():data.path) << "." << std::endl;
289 catch ( Exception & excpt_r ) {
290 ZYPP_CAUGHT (excpt_r);
291 ERR << "Couldn't load packages from XML file '" << data.path << "'" << std::endl;