e0be45059468a7b02a3ca9573569dbe78f312185
[platform/upstream/libzypp.git] / zypp / misc / LoadTestcase.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file  zypp/misc/LoadTestcase.cc
10  *
11 */
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>
20
21 #define ZYPP_USE_RESOLVER_INTERNALS
22 #include <zypp/solver/detail/SystemCheck.h>
23
24 namespace zypp::misc::testcase {
25
26   static const std::string helixControlFile = "solver-test.xml";
27   static const std::string yamlControlFile  = "zypp-control.yaml";
28
29   struct LoadTestcase::Impl {
30     TestcaseSetup _setup;
31     std::vector<TestcaseTrial> _trials;
32
33     bool loadHelix (const Pathname &filename, std::string *err);
34
35     bool loadYaml  ( const Pathname &path, std::string *err);
36   };
37
38
39   bool LoadTestcase::Impl::loadHelix(const zypp::filesystem::Pathname &filename, std::string *err)
40   {
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 << "'");
44       return false;
45     }
46
47
48     auto root = helix::detail::XmlNode (xmlDocGetRootElement (xml_doc));
49
50     DBG << "Parsing file '" << filename << "'" << std::endl;
51
52     if (!root.equals("test")) {
53       if ( err ) *err = (str::Str() << "Node not 'test' in parse_xml_test():" << root.name() << "'");
54       return false;
55     }
56
57     bool setupDone = false;
58     auto node = root.children();
59     while (node) {
60       if (node->type() == XML_ELEMENT_NODE) {
61         if (node->equals( "setup" )) {
62           if ( setupDone ) {
63             if ( err ) *err = "Multiple setup tags found, this is not supported";
64             return false;
65           }
66           setupDone = true;
67           if ( !helix::detail::parseSetup( *node, _setup, err ) )
68             return false;
69
70         } else if (node->equals( "trial" )) {
71           if ( !setupDone ) {
72             if ( err ) *err = "Any trials must be preceeded by the setup!";
73             return false;
74           }
75           TestcaseTrial trial;
76           if ( !helix::detail::parseTrial( *node, trial, err ) )
77             return false;
78           _trials.push_back( trial );
79         } else {
80           ERR << "Unknown tag '" << node->name() << "' in test" << std::endl;
81         }
82       }
83       node = ( node->next() );
84     }
85     xmlFreeDoc (xml_doc);
86     return true;
87   }
88
89   bool LoadTestcase::Impl::loadYaml(const zypp::filesystem::Pathname &path, std::string *err)
90   {
91     DBG << "Parsing file '" << path << "'" << std::endl;
92
93     const auto makeError = [&]( const std::string_view &errStr ){
94       if ( err ) *err = errStr;
95       return false;
96     };
97
98     YAML::Node control;
99     try {
100       control = YAML::LoadFile( path.asString() );
101
102       if ( control.Type() != YAML::NodeType::Map )
103         return makeError("Root node must be of type Map.");
104
105       const auto &setup = control["setup"];
106       if ( !setup )
107         return makeError("The 'setup' section is required.");
108
109       if ( !yamltest::detail::parseSetup( setup, _setup, err) )
110         return false;
111
112       const auto &trials = control["trials"];
113       if ( !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.");
117
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.");
122
123         if ( !yamltest::detail::parseTrial( trial["trial"], t, err) )
124           return false;
125         _trials.push_back( t );
126       }
127     } catch ( YAML::Exception &e ) {
128       if ( err ) *err = e.what();
129       return false;
130     } catch ( ... )  {
131       if ( err ) *err = "Unknown error when parsing the control file";
132       return false;
133     }
134     return true;
135   }
136
137   LoadTestcase::LoadTestcase() : _pimpl( new Impl() )
138   { }
139
140   LoadTestcase::~LoadTestcase()
141   { }
142
143   bool LoadTestcase::loadTestcaseAt(const zypp::filesystem::Pathname &path, std::string *err)
144   {
145     const auto t = testcaseTypeAt( path );
146     if ( t == LoadTestcase::None ) {
147       if ( err ) *err = "Unsopported or no testcase in directory";
148       return false;
149     }
150
151     // reset everything
152     _pimpl.reset( new Impl() );
153     _pimpl->_setup.globalPath = path;
154
155     switch (t) {
156       case LoadTestcase::Helix:
157         return _pimpl->loadHelix( path / helixControlFile, err );
158       case LoadTestcase::Yaml:
159         return _pimpl->loadYaml( path / yamlControlFile, err );
160       default:
161         return false;
162     }
163   }
164
165   LoadTestcase::Type LoadTestcase::testcaseTypeAt(const zypp::filesystem::Pathname &path)
166   {
167     if ( filesystem::PathInfo( path / helixControlFile ).isFile() ) {
168       return LoadTestcase::Helix;
169     } else if ( filesystem::PathInfo( path / yamlControlFile ).isFile() ) {
170       return LoadTestcase::Yaml;
171     }
172     return LoadTestcase::None;
173   }
174
175   const TestcaseSetup &LoadTestcase::setupInfo() const
176   {
177     return _pimpl->_setup;
178   }
179
180   const std::vector<TestcaseTrial> &LoadTestcase::trialInfo() const
181   {
182     return _pimpl->_trials;
183   }
184
185   const std::string &TestcaseTrial::Node::getProp( const std::string &name, const std::string &def ) const
186   {
187     if ( properties.find( name) == properties.end() )
188       return def;
189     return properties.at( name );
190   }
191
192   bool TestcaseSetup::applySetup( RepoManager &manager) const
193   {
194     const auto &setup = *this;
195     if ( !setup.architecture.empty() )
196     {
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);
200     }
201
202     if ( setup.systemRepo ) {
203       if (!loadRepo( manager, setup, *setup.systemRepo ) )
204       {
205         ERR << "Can't setup 'system'" << std::endl;
206         return false;
207       }
208     }
209
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;
213     }
214
215     for ( const auto &channel : setup.repos ) {
216       if ( !loadRepo( manager, setup, channel )  )
217       {
218         ERR << "Can't setup 'channel'" << std::endl;
219         return false;
220       }
221     }
222
223     if ( !setup.systemCheck.empty() ) {
224       MIL << "setting systemCheck to: " << setup.systemCheck.asString() << std::endl;
225       SystemCheck::instance().setFile( setup.systemCheck );
226     }
227
228     return true;
229   }
230
231   bool TestcaseSetup::loadRepo( zypp::RepoManager &manager, const TestcaseSetup &setup, const RepoData &data )
232   {
233     Pathname pathname = setup.globalPath + data.path;
234     MIL << "'" << pathname << "'" << std::endl;
235
236     Repository repo;
237
238     using TrType = zypp::misc::testcase::TestcaseRepoType;
239
240     if ( data.type == TrType::Url ) {
241       try {
242         MIL << "Load from Url '" << data.path << "'" << std::endl;
243
244         RepoInfo nrepo;
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) );
251
252         manager.refreshMetadata( nrepo );
253         manager.buildCache( nrepo );
254         manager.loadFromCache( nrepo );
255       }
256       catch ( Exception & excpt_r ) {
257         ZYPP_CAUGHT (excpt_r);
258         ERR << "Couldn't load packages from Url '" << data.path << "'" << std::endl;
259         return false;
260       }
261     }
262     else {
263       try {
264         MIL << "Load from File '" << pathname << "'" << std::endl;
265         zypp::Repository satRepo;
266
267         if ( data.alias == "@System" ) {
268           satRepo = zypp::sat::Pool::instance().systemRepo();
269         } else {
270           satRepo = zypp::sat::Pool::instance().reposInsert( data.alias );
271         }
272
273         RepoInfo nrepo;
274
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() );
281
282         satRepo.setInfo (nrepo);
283         if ( data.type == TrType::Helix )
284           satRepo.addHelix( pathname );
285         else
286           satRepo.addTesttags( pathname );
287         MIL << "Loaded " << satRepo.solvablesSize() << " resolvables from " << ( data.path.empty()?pathname.asString():data.path) << "." << std::endl;
288       }
289       catch ( Exception & excpt_r ) {
290         ZYPP_CAUGHT (excpt_r);
291         ERR << "Couldn't load packages from XML file '" << data.path << "'" << std::endl;
292         return false;
293       }
294     }
295     return true;
296   }
297
298
299
300 }