Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / solver / detail / Testcase.cc
index 9fc923f..695a706 100644 (file)
 #include <sstream>
 #include <streambuf>
 
+#define ZYPP_USE_RESOLVER_INTERNALS
+
 #include "zypp/solver/detail/Testcase.h"
 #include "zypp/base/Logger.h"
 #include "zypp/base/LogControl.h"
-#include "zypp/ZConfig.h"
-#include "zypp/PathInfo.h"
-#include "zypp/Product.h"
-#include "zypp/Package.h"
-#include "zypp/Edition.h"
-#include "zypp/parser/xml_escape_parser.hpp"
+#include "zypp/base/GzStream.h"
 #include "zypp/base/String.h"
 #include "zypp/base/PtrTypes.h"
-#include "zypp/Capabilities.h"
-#include "zypp/sat/Solvable.h"
+#include "zypp/base/NonCopyable.h"
+#include "zypp/base/ReferenceCounted.h"
+
+#include "zypp/parser/xml/XmlEscape.h"
 
+#include "zypp/ZConfig.h"
+#include "zypp/PathInfo.h"
+#include "zypp/ResPool.h"
+#include "zypp/Repository.h"
+#include "zypp/target/modalias/Modalias.h"
+
+#include "zypp/sat/detail/PoolImpl.h"
+#include "zypp/solver/detail/Resolver.h"
+#include "zypp/solver/detail/SystemCheck.h"
 
 /////////////////////////////////////////////////////////////////////////
 namespace zypp
@@ -45,15 +53,14 @@ namespace zypp
 using namespace std;
 using namespace zypp::str;
 
-IMPL_PTR_TYPE(HelixResolvable);
+//---------------------------------------------------------------------------
 
-static std::string xml_escape( const std::string &text )
+inline std::string xml_escape( const std::string &text )
 {
-  iobind::parser::xml_escape_parser parser;
-  return parser.escape(text);
+  return zypp::xml::escape(text);
 }
 
-static std::string xml_tag_enclose( const std::string &text, const std::string &tag, bool escape = false )
+inline std::string xml_tag_enclose( const std::string &text, const std::string &tag, bool escape = false )
 {
   string result;
   result += "<" + tag + ">";
@@ -67,7 +74,6 @@ static std::string xml_tag_enclose( const std::string &text, const std::string &
   return result;
 }
 
-
 template<class T>
 std::string helixXML( const T &obj ); //undefined
 
@@ -95,7 +101,52 @@ template<>
 std::string helixXML( const Capability &cap )
 {
     stringstream str;
-    str << "<dep name='" << xml_escape(cap.asString()) << "'  />" << endl;
+    CapDetail detail = cap.detail();
+    if (detail.isSimple()) {
+       if (detail.isVersioned()) {
+           str << "<dep name='" << xml_escape(detail.name().asString()) << "'"
+               << " op='" << xml_escape(detail.op().asString()) << "'"
+               << " version='" <<  xml_escape(detail.ed().version()) << "'";
+           if (!detail.ed().release().empty())
+               str << " release='" << xml_escape(detail.ed().release()) << "'";
+           if (detail.ed().epoch() != Edition::noepoch)
+               str << " epoch='" << xml_escape(numstring(detail.ed().epoch())) << "'";
+           str << " />" << endl;
+       } else {
+           str << "<dep name='" << xml_escape(cap.asString()) << "' />" << endl;
+       }
+    } else if (detail.isExpression()) {
+       if (detail.capRel() == CapDetail::CAP_AND
+           && detail.lhs().detail().isNamed()
+           && detail.rhs().detail().isNamed()) {
+           // packageand dependency
+           str << "<dep name='packageand("
+               << IdString(detail.lhs().id()) << ":"
+               << IdString(detail.rhs().id()) << ")' />" << endl;
+       } else if (detail.capRel() == CapDetail::CAP_NAMESPACE
+           && detail.lhs().id() == NAMESPACE_OTHERPROVIDERS) {
+           str << "<dep name='otherproviders("
+               << IdString(detail.rhs().id()) << ")' />" << endl;
+       } else {
+           // modalias ?
+           IdString packageName;
+           if (detail.capRel() == CapDetail::CAP_AND) {
+               packageName = IdString(detail.lhs().id());
+               detail = detail.rhs().detail();
+           }
+           if (detail.capRel() == CapDetail::CAP_NAMESPACE
+               && detail.lhs().id() == NAMESPACE_MODALIAS) {
+               str << "<dep name='modalias(";
+               if (!packageName.empty())
+                   str << packageName << ":";
+               str << IdString(detail.rhs().id()) << ")' />" << endl;
+           } else {
+               str << "<!--- ignoring '" << xml_escape(cap.asString()) << "' -->" << endl;
+           }
+       }
+    } else {
+       str << "<!--- ignoring '" << xml_escape(cap.asString()) << "' -->" << endl;
+    }
 
     return str.str();
 }
@@ -128,249 +179,73 @@ std::string helixXML( const CapabilitySet &caps )
     return str.str();
 }
 
-
-template<>
-std::string helixXML( const Dependencies &dep )
-{
-    stringstream str;
-    if ( dep[Dep::PROVIDES].size() > 0 )
-       str << TAB << xml_tag_enclose(helixXML(dep[Dep::PROVIDES]), "provides") << endl;
-    if ( dep[Dep::CONFLICTS].size() > 0 )
-       str << TAB << xml_tag_enclose(helixXML(dep[Dep::CONFLICTS]), "conflicts") << endl;
-    if ( dep[Dep::OBSOLETES].size() > 0 )
-       str << TAB << xml_tag_enclose(helixXML(dep[Dep::OBSOLETES]), "obsoletes") << endl;
-    if ( dep[Dep::FRESHENS].size() > 0 )
-       str << TAB << xml_tag_enclose(helixXML(dep[Dep::FRESHENS]), "freshens") << endl;
-    if ( dep[Dep::REQUIRES].size() > 0 )
-       str << TAB << xml_tag_enclose(helixXML(dep[Dep::REQUIRES]), "requires") << endl;
-    if ( dep[Dep::RECOMMENDS].size() > 0 )
-       str << TAB << xml_tag_enclose(helixXML(dep[Dep::RECOMMENDS]), "recommends") << endl;
-    if ( dep[Dep::ENHANCES].size() > 0 )
-       str << TAB << xml_tag_enclose(helixXML(dep[Dep::ENHANCES]), "enhances") << endl;
-    if ( dep[Dep::SUPPLEMENTS].size() > 0 )
-       str << TAB << xml_tag_enclose(helixXML(dep[Dep::SUPPLEMENTS]), "supplements") << endl;
-    if ( dep[Dep::SUGGESTS].size() > 0 )
-       str << TAB << xml_tag_enclose(helixXML(dep[Dep::SUGGESTS]), "suggests") << endl;
-    return str.str();
-}
-
-inline string helixXML( const Resolvable::constPtr &obj, Dep deptag_r )
+inline string helixXML( const PoolItem & obj, Dep deptag_r )
 {
   stringstream out;
-  Capabilities caps( obj->dep(deptag_r) );
+  Capabilities caps( obj[deptag_r] );
   if ( ! caps.empty() )
     out << TAB << xml_tag_enclose(helixXML(caps), deptag_r.asString()) << endl;
   return out.str();
 }
 
-std::string helixXML( const PoolItem &item )
+std::string helixXML( const PoolItem & item )
 {
-  const Resolvable::constPtr resolvable = item.resolvable();
   stringstream str;
-  str << "<" << toLower (resolvable->kind().asString()) << ">" << endl;
-  str << TAB << xml_tag_enclose (resolvable->name(), "name", true) << endl;
-  str << TAB << xml_tag_enclose (item->vendor(), "vendor", true) << endl;
-  if ( isKind<Package>(resolvable) ) {
+  str << "<" << item.kind() << ">" << endl;
+  str << TAB << xml_tag_enclose( item.name(), "name", true ) << endl;
+  str << TAB << xml_tag_enclose( item.vendor().asString(), "vendor", true ) << endl;
+  str << TAB << xml_tag_enclose( item.buildtime().asSeconds(), "buildtime", true ) << endl;
+  if ( isKind<Package>( item ) ) {
       str << TAB << "<history>" << endl << TAB << "<update>" << endl;
-      str << TAB2 << helixXML (resolvable->arch()) << endl;
-      str << TAB2 << helixXML (resolvable->edition()) << endl;
+      str << TAB2 << helixXML( item.arch() ) << endl;
+      str << TAB2 << helixXML( item.edition() ) << endl;
       str << TAB << "</update>" << endl << TAB << "</history>" << endl;
   } else {
-      str << TAB << helixXML (resolvable->arch()) << endl;
-      str << TAB << helixXML (resolvable->edition()) << endl;
+      str << TAB << helixXML( item.arch() ) << endl;
+      str << TAB << helixXML( item.edition() ) << endl;
   }
-  str << helixXML( resolvable, Dep::PROVIDES);
-  str << helixXML( resolvable, Dep::PREREQUIRES);
-  str << helixXML( resolvable, Dep::CONFLICTS);
-  str << helixXML( resolvable, Dep::OBSOLETES);
-  str << helixXML( resolvable, Dep::FRESHENS);
-  str << helixXML( resolvable, Dep::REQUIRES);
-  str << helixXML( resolvable, Dep::RECOMMENDS);
-  str << helixXML( resolvable, Dep::ENHANCES);
-  str << helixXML( resolvable, Dep::SUPPLEMENTS);
-  str << helixXML( resolvable, Dep::SUGGESTS);
-
-  str << "</" << toLower (resolvable->kind().asString()) << ">" << endl;
+  str << helixXML( item, Dep::PROVIDES );
+  str << helixXML( item, Dep::PREREQUIRES );
+  str << helixXML( item, Dep::CONFLICTS );
+  str << helixXML( item, Dep::OBSOLETES );
+  str << helixXML( item, Dep::REQUIRES );
+  str << helixXML( item, Dep::RECOMMENDS );
+  str << helixXML( item, Dep::ENHANCES );
+  str << helixXML( item, Dep::SUPPLEMENTS );
+  str << helixXML( item, Dep::SUGGESTS );
+
+  str << "</" << item.kind() << ">" << endl;
   return str.str();
 }
 
-//---------------------------------------------------------------------------
-
-Testcase::Testcase()
-    :dumpPath("/var/log/YaST2/solverTestcase")
-{
-}
-
-Testcase::Testcase(const std::string & path)
-    :dumpPath(path)
-{
-}
-
-
-Testcase::~Testcase()
-{
-}
-
-
-bool Testcase::createTestcasePool(const ResPool &pool)
-{
-    PathInfo path (dumpPath);
-
-    if ( !path.isExist() ) {
-       if (zypp::filesystem::mkdir (dumpPath)!=0) {
-           ERR << "Cannot create directory " << dumpPath << endl;
-           return false;
-       }
-    } else {
-       if (!path.isDir()) {
-           ERR << dumpPath << " is not a directory." << endl;
-           return false;
-       }
-       // remove old stuff
-       zypp::filesystem::clean_dir (dumpPath);
-    }
-    
-    RepositoryTable            repoTable;
-    HelixResolvable    system (dumpPath + "/solver-system.xml.gz");    
-
-    for ( ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it )
-    {
-       if ( it->status().isInstalled() ) {
-           // system channel
-           system.addResolvable (*it);
-       } else {
-           // repo channels
-           sat::Repo repo  = it->resolvable()->satSolvable().repo();
-           if (repoTable.find (repo) == repoTable.end()) {
-               repoTable[repo] = new HelixResolvable(dumpPath + "/"
-                                                     + str::numstring((long)repo.id())
-                                                     + "-package.xml.gz");
-           }
-           repoTable[repo]->addResolvable (*it);
-       }
-    }  
-    return true;
-}
-
-bool Testcase::createTestcase(Resolver & resolver, bool dumpPool, bool runSolver)
-{
-    PathInfo path (dumpPath);
-
-    if ( !path.isExist() ) {
-       if (zypp::filesystem::mkdir (dumpPath)!=0) {
-           ERR << "Cannot create directory " << dumpPath << endl;
-           return false;
-       }
-    } else {
-       if (!path.isDir()) {
-           ERR << dumpPath << " is not a directory." << endl;
-           return false;
-       }
-       // remove old stuff if pool will be dump
-       if (dumpPool)
-           zypp::filesystem::clean_dir (dumpPath);
-    }
-
-    if (runSolver) {
-       zypp::base::LogControl::instance().logfile( dumpPath +"/y2log" );
-       zypp::base::LogControl::TmpExcessive excessive;
-
-       resolver.reset(true); // true = resetting all valid solverresults
-       resolver.resolvePool();
-
-       zypp::base::LogControl::instance().logfile( "/var/log/YaST2/y2log" );
-    }
-
-    ResPool pool       = resolver.pool();
-    RepositoryTable    repoTable;
-    PoolItemList       items_to_install;
-    PoolItemList       items_to_remove;
-    PoolItemList       items_locked;
-    PoolItemList       items_keep;
-    PoolItemList       language;
-    HelixResolvable_Ptr        system = NULL;
-
-    if (dumpPool)
-       system = new HelixResolvable(dumpPath + "/solver-system.xml.gz");
-
-    for ( ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it )
-    {
-       Resolvable::constPtr res = it->resolvable();
-
-#warning NO MORE LANGUAGE RESOLVABLE
-        // - use pools list of requested locales and pass it as 'LocaleList language'
-        // - restore the list via Pool::setRequestedLocales.
-#if 0
-       if (isKind<Language>(res)) {
-           if ( it->status().isInstalled()
-                || it->status().isToBeInstalled()) {
-               language.push_back (*it);
-           }
-       } else {
-#endif
-           if ( system && it->status().isInstalled() ) {
-               // system channel
-               system->addResolvable (*it);
-           } else {
-               // repo channels
-               sat::Repo repo  = it->resolvable()->satSolvable().repo();
-               if (dumpPool) {
-                   if (repoTable.find (repo) == repoTable.end()) {
-                       repoTable[repo] = new HelixResolvable(dumpPath + "/"
-                                                             + str::numstring((long)repo.id())
-                                                             + "-package.xml.gz");
-                   }
-                   repoTable[repo]->addResolvable (*it);
-               }
-           }
-
-           if ( it->status().isToBeInstalled()
-                && !(it->status().isBySolver())) {
-               items_to_install.push_back (*it);
-           }
-           if ( it->status().isKept()
-                && !(it->status().isBySolver())) {
-               items_keep.push_back (*it);
-           }
-           if ( it->status().isToBeUninstalled()
-                && !(it->status().isBySolver())) {
-               items_to_remove.push_back (*it);
-           }
-           if ( it->status().isLocked()
-                && !(it->status().isBySolver())) {
-               items_locked.push_back (*it);
-           }
-    }
-
-    // writing control file "*-test.xml"
-
-    HelixControl control (dumpPath + "/solver-test.xml",
-                         repoTable,
-                         ZConfig::instance().systemArchitecture(),
-                         language);
-
-    for (PoolItemList::const_iterator iter = items_to_install.begin(); iter != items_to_install.end(); iter++) {
-       control.installResolvable (iter->resolvable(), iter->status());
-    }
+///////////////////////////////////////////////////////////////////
+//
+//     CLASS NAME : HelixResolvable
+/**
+ * Creates a file in helix format which includes all available
+ * or installed packages,patches,selections.....
+ **/
+class  HelixResolvable : public base::ReferenceCounted, private base::NonCopyable{
 
-    for (PoolItemList::const_iterator iter = items_locked.begin(); iter != items_locked.end(); iter++) {
-       control.lockResolvable (iter->resolvable(), iter->status());
-    }
+  private:
+    std::string dumpFile; // Path of the generated testcase
+    ofgzstream *file;
 
-    for (PoolItemList::const_iterator iter = items_keep.begin(); iter != items_keep.end(); iter++) {
-       control.keepResolvable (iter->resolvable(), iter->status());
-    }
+  public:
+    HelixResolvable (const std::string & path);
+    ~HelixResolvable ();
 
-    for (PoolItemList::const_iterator iter = items_to_remove.begin(); iter != items_to_remove.end(); iter++) {
-       control.deleteResolvable (iter->resolvable(), iter->status());
-    }
+    void addResolvable (const PoolItem item)
+    { *file << helixXML (item); }
 
-    control.addDependencies (resolver.extraRequires(), resolver.extraConflicts());
+    std::string filename ()
+    { return dumpFile; }
+};
 
-    return true;
-}
+DEFINE_PTR_TYPE(HelixResolvable);
+IMPL_PTR_TYPE(HelixResolvable);
 
-//---------------------------------------------------------------------------
+typedef std::map<Repository, HelixResolvable_Ptr> RepositoryTable;
 
 HelixResolvable::HelixResolvable(const std::string & path)
     :dumpFile (path)
@@ -389,19 +264,55 @@ HelixResolvable::~HelixResolvable()
     delete(file);
 }
 
-
-void HelixResolvable::addResolvable(const PoolItem item)
-{
-    *file << helixXML (item);
-}
-
-//---------------------------------------------------------------------------
+///////////////////////////////////////////////////////////////////
+//
+//     CLASS NAME : HelixControl
+/**
+ * Creates a file in helix format which contains all controll
+ * action of a testcase ( file is known as *-test.xml)
+ **/
+class  HelixControl {
+
+  private:
+    std::string dumpFile; // Path of the generated testcase
+    std::ofstream *file;
+
+  public:
+    HelixControl (const std::string & controlPath,
+                 const RepositoryTable & sourceTable,
+                 const Arch & systemArchitecture,
+                 const target::Modalias::ModaliasList & modaliasList,
+                 const std::set<std::string> & multiversionSpec,
+                 const std::string & systemPath,
+                 const bool forceResolve,
+                 const bool onlyRequires,
+                 const bool ignorealreadyrecommended);
+    HelixControl ();
+    ~HelixControl ();
+
+    void installResolvable( const PoolItem & pi_r );
+    void lockResolvable( const PoolItem & pi_r );
+    void keepResolvable( const PoolItem & pi_r );
+    void deleteResolvable( const PoolItem & pi_r );
+    void addDependencies (const CapabilitySet &capRequire, const CapabilitySet &capConflict);
+    void addUpgradeRepos( const std::set<Repository> & upgradeRepos_r );
+
+    void distupgrade ();
+    void verifySystem ();
+    void update ();
+
+    std::string filename () { return dumpFile; }
+};
 
 HelixControl::HelixControl(const std::string & controlPath,
                           const RepositoryTable & repoTable,
                           const Arch & systemArchitecture,
-                          const PoolItemList &languages,
-                          const std::string & systemPath)
+                          const target::Modalias::ModaliasList & modaliasList,
+                          const std::set<std::string> & multiversionSpec,
+                          const std::string & systemPath,
+                          const bool forceResolve,
+                          const bool onlyRequires,
+                          const bool ignorealreadyrecommended)
     :dumpFile (controlPath)
 {
     file = new ofstream(controlPath.c_str());
@@ -427,19 +338,61 @@ HelixControl::HelixControl(const std::string & controlPath,
        }
        *file << TAB << "- path        : " << repo.path() << endl;
        *file << TAB << "- type        : " << repo.type() << endl;
+       *file << TAB << "- generated   : " << (it->first.generatedTimestamp()).form( "%Y-%m-%d %H:%M:%S" ) << endl;
+       *file << TAB << "- outdated    : " << (it->first.suggestedExpirationTimestamp()).form( "%Y-%m-%d %H:%M:%S" ) << endl;
        *file << TAB << " -->" << endl;
 
-       *file << TAB << "<channel file=\"" << it->first.id()
-             << "-package.xml.gz\" name=\"" << repo.alias()
+       *file << TAB << "<channel file=\"" << str::numstring((long)it->first.id())
+             << "-package.xml.gz\" name=\"" << repo.alias() << "\""
+             << " priority=\"" << repo.priority()
              << "\" />" << endl << endl;
     }
-    for (PoolItemList::const_iterator iter = languages.begin(); iter != languages.end(); iter++) {
-       *file << TAB << "<locale name=\"" <<  iter->resolvable()->name()
+
+    // HACK: directly access sat::pool
+    const sat::Pool & satpool( sat::Pool::instance() );
+
+    // RequestedLocales
+    const LocaleSet & addedLocales( satpool.getAddedRequestedLocales() );
+    const LocaleSet & removedLocales( satpool.getRemovedRequestedLocales() );
+    const LocaleSet & requestedLocales( satpool.getRequestedLocales() );
+
+    for ( Locale l : requestedLocales )
+    {
+      const char * fate = ( addedLocales.count(l) ? "\" fate=\"added" : "" );
+      *file << TAB << "<locale name=\"" << l << fate << "\" />" << endl;
+    }
+    for ( Locale l : removedLocales )
+    {
+      *file << TAB << "<locale name=\"" << l << "\" fate=\"removed\" />" << endl;
+    }
+
+    // AutoInstalled
+    for ( IdString::IdType n : satpool.autoInstalled() )
+    {
+      *file << TAB << "<autoinst name=\"" << IdString(n) << "\" />" << endl;
+    }
+
+
+
+    for_( it, modaliasList.begin(), modaliasList.end() ) {
+       *file << TAB << "<modalias name=\"" <<  *it
+             << "\" />" << endl;
+    }
+
+    for_( it, multiversionSpec.begin(), multiversionSpec.end() ) {
+       *file << TAB << "<multiversion name=\"" <<  *it
              << "\" />" << endl;
     }
+
+    if (forceResolve)
+       *file << TAB << "<forceResolve/>" << endl;
+    if (onlyRequires)
+       *file << TAB << "<onlyRequires/>" << endl;
+    if (ignorealreadyrecommended)
+       *file << TAB << "<ignorealreadyrecommended/>" << endl;
+
     *file << "</setup>" << endl
-         << "<trial>" << endl
-         << "<showpool all=\"yes\"/>" << endl;
+         << "<trial>" << endl;
 }
 
 HelixControl::HelixControl()
@@ -452,44 +405,50 @@ HelixControl::~HelixControl()
 {
     *file << "</trial>" << endl
          << "</test>" << endl;
+    delete(file);
 }
 
-void HelixControl::installResolvable(const ResObject::constPtr &resObject,
-                                    const ResStatus &status)
+void HelixControl::installResolvable( const PoolItem & pi_r )
 {
-    *file << "<install channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
-         << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
-         << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
-         << " status=\"" << status << "\""
+    *file << "<install channel=\"" << pi_r.repoInfo().alias() << "\""
+          << " kind=\"" << pi_r.kind() << "\""
+         << " name=\"" << pi_r.name() << "\""
+         << " arch=\"" << pi_r.arch() << "\""
+         << " version=\"" << pi_r.edition().version() << "\""
+         << " release=\"" << pi_r.edition().release() << "\""
+         << " status=\"" << pi_r.status() << "\""
          << "/>" << endl;
 }
 
-void HelixControl::lockResolvable(const ResObject::constPtr &resObject,
-                                 const ResStatus &status)
+void HelixControl::lockResolvable( const PoolItem & pi_r )
 {
-    *file << "<lock channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
-         << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
-         << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
-         << " status=\"" << status << "\""
+    *file << "<lock channel=\"" << pi_r.repoInfo().alias() << "\""
+          << " kind=\"" << pi_r.kind() << "\""
+         << " name=\"" << pi_r.name() << "\""
+         << " arch=\"" << pi_r.arch() << "\""
+         << " version=\"" << pi_r.edition().version() << "\""
+         << " release=\"" << pi_r.edition().release() << "\""
+         << " status=\"" << pi_r.status() << "\""
          << "/>" << endl;
 }
 
-void HelixControl::keepResolvable(const ResObject::constPtr &resObject,
-                                 const ResStatus &status)
+void HelixControl::keepResolvable( const PoolItem & pi_r )
 {
-    *file << "<keep channel=\"" << resObject->repoInfo().alias() << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
-         << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
-         << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\""
-         << " status=\"" << status << "\""
+    *file << "<keep channel=\"" << pi_r.repoInfo().alias() << "\""
+          << " kind=\"" << pi_r.kind() << "\""
+         << " name=\"" << pi_r.name() << "\""
+         << " arch=\"" << pi_r.arch() << "\""
+         << " version=\"" << pi_r.edition().version() << "\""
+         << " release=\"" << pi_r.edition().release() << "\""
+         << " status=\"" << pi_r.status() << "\""
          << "/>" << endl;
 }
 
-void HelixControl::deleteResolvable(const ResObject::constPtr &resObject,
-                                   const ResStatus &status)
+void HelixControl::deleteResolvable( const PoolItem & pi_r )
 {
-    *file << "<uninstall " << " kind=\"" << toLower (resObject->kind().asString()) << "\""
-         << " name=\"" << resObject->name() << "\""
-         << " status=\"" << status << "\""
+    *file << "<uninstall  kind=\"" << pi_r.kind() << "\""
+         << " name=\"" << pi_r.name() << "\""
+         << " status=\"" << pi_r.status() << "\""
          << "/>" << endl;
 }
 
@@ -503,6 +462,154 @@ void HelixControl::addDependencies (const CapabilitySet & capRequire, const Capa
     }
 }
 
+void HelixControl::addUpgradeRepos( const std::set<Repository> & upgradeRepos_r )
+{
+  for_( it, upgradeRepos_r.begin(), upgradeRepos_r.end() )
+  {
+    *file << "<upgradeRepo name=\"" << it->alias() << "\"/>" << endl;
+  }
+}
+
+void HelixControl::distupgrade()
+{
+    *file << "<distupgrade/>" << endl;
+}
+
+void HelixControl::verifySystem()
+{
+    *file << "<verify/>" << endl;
+}
+
+void HelixControl::update()
+{
+    *file << "<update/>" << endl;
+}
+
+//---------------------------------------------------------------------------
+
+Testcase::Testcase()
+    :dumpPath("/var/log/YaST2/solverTestcase")
+{}
+
+Testcase::Testcase(const std::string & path)
+    :dumpPath(path)
+{}
+
+Testcase::~Testcase()
+{}
+
+bool Testcase::createTestcase(Resolver & resolver, bool dumpPool, bool runSolver)
+{
+    PathInfo path (dumpPath);
+
+    if ( !path.isExist() ) {
+       if (zypp::filesystem::assert_dir (dumpPath)!=0) {
+           ERR << "Cannot create directory " << dumpPath << endl;
+           return false;
+       }
+    } else {
+       if (!path.isDir()) {
+           ERR << dumpPath << " is not a directory." << endl;
+           return false;
+       }
+       // remove old stuff if pool will be dump
+       if (dumpPool)
+           zypp::filesystem::clean_dir (dumpPath);
+    }
+
+    if (runSolver) {
+        zypp::base::LogControl::TmpLineWriter tempRedirect;
+       zypp::base::LogControl::instance().logfile( dumpPath +"/y2log" );
+       zypp::base::LogControl::TmpExcessive excessive;
+
+       resolver.resolvePool();
+    }
+
+    ResPool pool       = resolver.pool();
+    RepositoryTable    repoTable;
+    PoolItemList       items_to_install;
+    PoolItemList       items_to_remove;
+    PoolItemList       items_locked;
+    PoolItemList       items_keep;
+    HelixResolvable_Ptr        system = NULL;
+
+    if (dumpPool)
+       system = new HelixResolvable(dumpPath + "/solver-system.xml.gz");
+
+    for ( const PoolItem & pi : pool )
+    {
+       if ( system && pi.status().isInstalled() ) {
+           // system channel
+           system->addResolvable( pi );
+       } else {
+           // repo channels
+           Repository repo  = pi.repository();
+           if (dumpPool) {
+               if (repoTable.find (repo) == repoTable.end()) {
+                   repoTable[repo] = new HelixResolvable(dumpPath + "/"
+                                                         + str::numstring((long)repo.id())
+                                                         + "-package.xml.gz");
+               }
+               repoTable[repo]->addResolvable( pi );
+           }
+       }
+
+       if ( pi.status().isToBeInstalled()
+            && !(pi.status().isBySolver())) {
+           items_to_install.push_back( pi );
+       }
+       if ( pi.status().isKept()
+            && !(pi.status().isBySolver())) {
+           items_keep.push_back( pi );
+       }
+       if ( pi.status().isToBeUninstalled()
+            && !(pi.status().isBySolver())) {
+           items_to_remove.push_back( pi );
+       }
+       if ( pi.status().isLocked()
+            && !(pi.status().isBySolver())) {
+           items_locked.push_back( pi );
+       }
+    }
+
+    // writing control file "*-test.xml"
+    HelixControl control (dumpPath + "/solver-test.xml",
+                         repoTable,
+                         ZConfig::instance().systemArchitecture(),
+                         target::Modalias::instance().modaliasList(),
+                         ZConfig::instance().multiversionSpec(),
+                         "solver-system.xml.gz",
+                         resolver.forceResolve(),
+                         resolver.onlyRequires(),
+                         resolver.ignoreAlreadyRecommended() );
+
+    for ( const PoolItem & pi : items_to_install )
+    { control.installResolvable( pi ); }
+
+    for ( const PoolItem & pi : items_locked )
+    { control.lockResolvable( pi ); }
+
+    for ( const PoolItem & pi : items_keep )
+    { control.keepResolvable( pi ); }
+
+    for ( const PoolItem & pi : items_to_remove )
+    { control.deleteResolvable( pi ); }
+
+    control.addDependencies (resolver.extraRequires(), resolver.extraConflicts());
+    control.addDependencies (SystemCheck::instance().requiredSystemCap(),
+                            SystemCheck::instance().conflictSystemCap());
+    control.addUpgradeRepos( resolver.upgradeRepos() );
+
+    if (resolver.isUpgradeMode())
+       control.distupgrade ();
+    if (resolver.isUpdateMode())
+       control.update();
+    if (resolver.isVerifyingMode())
+       control.verifySystem();
+
+    return true;
+}
+
 
       ///////////////////////////////////////////////////////////////////
     };// namespace detail