Hello community,

here is the log from the commit of package yast2 for openSUSE:Factory checked 
in at 2015-05-23 12:56:35
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/yast2 (Old)
 and      /work/SRC/openSUSE:Factory/.yast2.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "yast2"

Changes:
--------
--- /work/SRC/openSUSE:Factory/yast2/yast2.changes      2015-05-19 
23:23:24.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.yast2.new/yast2.changes 2015-05-23 
12:56:36.000000000 +0200
@@ -1,0 +2,13 @@
+Fri May 22 12:32:27 UTC 2015 - [email protected]
+
+- InstExtensionImage: add block variant for loading extension
+  (needed for FATE#317900)
+- 3.1.124
+
+-------------------------------------------------------------------
+Tue May 19 04:56:13 UTC 2015 - [email protected]
+
+- Add a class FsSnapshot for managing filesystem snapshots
+  (fate#317973).
+
+-------------------------------------------------------------------

Old:
----
  yast2-3.1.123.tar.bz2

New:
----
  yast2-3.1.124.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ yast2.spec ++++++
--- /var/tmp/diff_new_pack.8lYAtJ/_old  2015-05-23 12:56:36.000000000 +0200
+++ /var/tmp/diff_new_pack.8lYAtJ/_new  2015-05-23 12:56:36.000000000 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           yast2
-Version:        3.1.123
+Version:        3.1.124
 Release:        0
 Url:            https://github.com/yast/yast-yast2
 

++++++ yast2-3.1.123.tar.bz2 -> yast2-3.1.124.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-3.1.123/library/control/Makefile.am 
new/yast2-3.1.124/library/control/Makefile.am
--- old/yast2-3.1.123/library/control/Makefile.am       2015-05-18 
17:02:13.000000000 +0200
+++ new/yast2-3.1.124/library/control/Makefile.am       2015-05-22 
15:51:11.000000000 +0200
@@ -2,4 +2,4 @@
 # Makefile.am for xml/module
 #
 
-SUBDIRS = doc src testsuite
+SUBDIRS = doc src test testsuite
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-3.1.123/library/control/src/modules/InstExtensionImage.rb 
new/yast2-3.1.124/library/control/src/modules/InstExtensionImage.rb
--- old/yast2-3.1.123/library/control/src/modules/InstExtensionImage.rb 
2015-05-18 17:02:13.000000000 +0200
+++ new/yast2-3.1.124/library/control/src/modules/InstExtensionImage.rb 
2015-05-22 15:51:11.000000000 +0200
@@ -337,6 +337,29 @@
       nil
     end
 
+    # Load a rpm package from the media into the inst-sys and ensure its
+    # unloading after end of block.
+    # @param [String] package to load
+    # @param [Proc] Block to be yield
+    # @raises [RuntimeError] when package loading failed
+    #
+    # @example
+    #   InstExtensionImage.with_extension("snapper") do
+    #      WFM.Execute(path(".local.bash"), "snapper magic")
+    #   end
+    #
+    def with_extension(package, &block)
+      loading_msg = format(_("Loading to memory package '%s'"), package)
+      res = LoadExtension(package, loading_msg)
+      raise "Failed to load package. Please check logs." unless res
+      begin
+        block.call
+      ensure
+        unloading_msg = format(_("Removing from memory package '%s'"), package)
+        UnLoadExtension(package, unloading_msg)
+      end
+    end
+
     # Load a rpm package from the media into the inst-sys
     # @param [String] package  The path to package to be loaded (by default,
     # the package is expected in the /boot/<arch>/ directory of the media
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-3.1.123/library/control/test/InstExtensionImage_test.rb 
new/yast2-3.1.124/library/control/test/InstExtensionImage_test.rb
--- old/yast2-3.1.123/library/control/test/InstExtensionImage_test.rb   
1970-01-01 01:00:00.000000000 +0100
+++ new/yast2-3.1.124/library/control/test/InstExtensionImage_test.rb   
2015-05-22 15:51:11.000000000 +0200
@@ -0,0 +1,133 @@
+#! /usr/bin/env rspec
+
+require_relative "test_helper"
+
+Yast.import "InstExtensionImage"
+
+describe Yast::InstExtensionImage do
+  subject { Yast::InstExtensionImage }
+
+  describe ".LoadExtension" do
+    before do
+      # clean internal cache of already loaded extension
+      subject.instance_variable_set("@integrated_extensions", [])
+    end
+    it "returns false if package is nil" do
+      expect(subject.LoadExtension(nil, "msg")).to eq false
+    end
+
+    it "returns false if package is \"\"" do
+      expect(subject.LoadExtension("", "msg")).to eq false
+    end
+
+    it "returns true immediately if package is already loaded" do
+      subject.instance_variable_set("@integrated_extensions", ["snapper"])
+      expect(subject.LoadExtension("snapper", "msg")).to eq true
+    end
+
+    it "shows message as feedback when loading package" do
+      expect(Yast::Popup).to receive(:ShowFeedback).with("", "msg")
+
+      subject.LoadExtension("snapper", "msg")
+    end
+
+    it "calls extend CLI with given package" do
+      expect(Yast::WFM).to receive(:Execute)
+        .with(path(".local.bash_output"), "extend 'snapper'")
+        .and_return("exit" => 0)
+
+      subject.LoadExtension("snapper", "msg")
+    end
+
+    it "returns false if extend CLI failed" do
+      expect(Yast::WFM).to receive(:Execute)
+        .with(path(".local.bash_output"), "extend 'snapper'")
+        .and_return("exit" => 1)
+
+      expect(subject.LoadExtension("snapper", "msg")).to eq false
+    end
+  end
+
+  describe ".UnLoadExtension" do
+    before do
+      # set in internal cache that snapper is already loaded
+      subject.instance_variable_set("@integrated_extensions", ["snapper"])
+    end
+    it "returns false if package is nil" do
+      expect(subject.UnLoadExtension(nil, "msg")).to eq false
+    end
+
+    it "returns false if package is \"\"" do
+      expect(subject.UnLoadExtension("", "msg")).to eq false
+    end
+
+    it "returns true immediately if package is already unloaded" do
+      subject.instance_variable_set("@integrated_extensions", [])
+      expect(subject.UnLoadExtension("snapper", "msg")).to eq true
+    end
+
+    it "shows message as feedback when unloading package" do
+      expect(Yast::Popup).to receive(:ShowFeedback).with("", "msg")
+
+      subject.UnLoadExtension("snapper", "msg")
+    end
+
+    it "calls extend CLI with given package" do
+      expect(Yast::WFM).to receive(:Execute)
+        .with(path(".local.bash_output"), "extend -r 'snapper'")
+        .and_return("exit" => 0)
+
+      subject.UnLoadExtension("snapper", "msg")
+    end
+
+    it "returns false if extend CLI failed" do
+      expect(Yast::WFM).to receive(:Execute)
+        .with(path(".local.bash_output"), "extend -r 'snapper'")
+        .and_return("exit" => 1)
+
+      expect(subject.UnLoadExtension("snapper", "msg")).to eq false
+    end
+  end
+
+  describe ".with_extension" do
+    before do
+      # clean internal cache of already loaded extension
+      subject.instance_variable_set("@integrated_extensions", [])
+    end
+
+    it "loads package, executes block and unload package" do
+      expect(Yast::WFM).to receive(:Execute)
+        .with(path(".local.bash_output"), "extend 'snapper'")
+        .and_return("exit" => 0)
+      expect(Yast::WFM).to receive(:Execute)
+        .with(path(".local.bash_output"), "extend -r 'snapper'")
+        .and_return("exit" => 0)
+
+      res = nil
+      subject.with_extension("snapper") do
+        res = true
+      end
+
+      expect(res).to eq true
+    end
+
+    it "raises exception if package loading fails" do
+      expect(Yast::WFM).to receive(:Execute)
+        .with(path(".local.bash_output"), "extend 'snapper'")
+        .and_return("exit" => 1)
+
+      expect { subject.with_extension("snapper") {} }.to raise_error
+    end
+
+    it "unloads extension even if block raises exception" do
+      expect(Yast::WFM).to receive(:Execute)
+        .with(path(".local.bash_output"), "extend 'snapper'")
+        .and_return("exit" => 0)
+      expect(Yast::WFM).to receive(:Execute)
+        .with(path(".local.bash_output"), "extend -r 'snapper'")
+        .and_return("exit" => 0)
+
+      expect { subject.with_extension("snapper") { raise "expected" } }.to 
raise_error
+    end
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-3.1.123/library/control/test/Makefile.am 
new/yast2-3.1.124/library/control/test/Makefile.am
--- old/yast2-3.1.123/library/control/test/Makefile.am  1970-01-01 
01:00:00.000000000 +0100
+++ new/yast2-3.1.124/library/control/test/Makefile.am  2015-05-22 
15:51:11.000000000 +0200
@@ -0,0 +1,7 @@
+TESTS = \
+  InstExtensionImage_test.rb
+
+TEST_EXTENSIONS = .rb
+RB_LOG_COMPILER = rspec
+VERBOSE = 1
+EXTRA_DIST = $(TESTS) test_helper.rb
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-3.1.123/library/control/test/test_helper.rb 
new/yast2-3.1.124/library/control/test/test_helper.rb
--- old/yast2-3.1.123/library/control/test/test_helper.rb       1970-01-01 
01:00:00.000000000 +0100
+++ new/yast2-3.1.124/library/control/test/test_helper.rb       2015-05-22 
15:51:11.000000000 +0200
@@ -0,0 +1 @@
+require_relative "../../../test/test_helper.rb"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-3.1.123/library/system/src/Makefile.am 
new/yast2-3.1.124/library/system/src/Makefile.am
--- old/yast2-3.1.123/library/system/src/Makefile.am    2015-05-18 
17:02:13.000000000 +0200
+++ new/yast2-3.1.124/library/system/src/Makefile.am    2015-05-22 
15:51:11.000000000 +0200
@@ -29,7 +29,8 @@
 
 ylibdir = @ylibdir@/yast2
 ylib_DATA = \
-  lib/yast2/hw_detection.rb
+  lib/yast2/hw_detection.rb \
+  lib/yast2/fs_snapshot.rb
 
 
 EXTRA_DIST = $(module_DATA) $(client_DATA) $(ynclude_DATA) $(scrconf_DATA) 
$(desktop_DATA) $(ylib_DATA)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-3.1.123/library/system/src/lib/yast2/fs_snapshot.rb 
new/yast2-3.1.124/library/system/src/lib/yast2/fs_snapshot.rb
--- old/yast2-3.1.123/library/system/src/lib/yast2/fs_snapshot.rb       
1970-01-01 01:00:00.000000000 +0100
+++ new/yast2-3.1.124/library/system/src/lib/yast2/fs_snapshot.rb       
2015-05-22 15:51:11.000000000 +0200
@@ -0,0 +1,211 @@
+# encoding: utf-8
+
+# ***************************************************************************
+#
+# Copyright (c) 2015 SUSE LLC
+# All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, contact Novell, Inc.
+#
+# To contact Novell about this file by physical or electronic mail,
+# you may find current contact information at www.novell.com
+#
+# ***************************************************************************
+# File: fs_snapshot.rb
+#
+# Authors:
+#      Imobach Gonzalez Sosa <[email protected]>
+
+require "yast"
+require "date"
+
+module Yast2
+  # Represents the fact that Snapper is not configured for "/" (root).
+  class SnapperNotConfigured < StandardError
+    def initialize
+      super "Programming error: Snapper is not configured yet."
+    end
+  end
+
+  # Represents that does not exist a suitable 'pre' snapshot for a new 'post'
+  # snapshot.
+  class PreviousSnapshotNotFound < StandardError
+    def initialize
+      super "Previous snapshot was not found."
+    end
+  end
+
+  # Represents the fact that the snapshot could not be created.
+  class SnapshotCreationFailed < StandardError
+    def initialize
+      super "Filesystem snapshot could not be created."
+    end
+  end
+
+  # Class for managing filesystem snapshots. It's important to note that this
+  # class is intended to be used during installation/update so it uses the
+  # Snapper's CLI because the DBus interface is not available at that time.
+  class FsSnapshot
+    include Yast::Logger
+
+    FIND_CONFIG_CMD = "/usr/bin/snapper --no-dbus list-configs | grep \"^root 
\" >/dev/null"
+    CREATE_SNAPSHOT_CMD = "/usr/lib/snapper/installation-helper --step 5 
--snapshot-type %s --description \"%s\""
+    LIST_SNAPSHOTS_CMD = "LANG=en_US.UTF-8 /usr/bin/snapper --no-dbus list"
+    VALID_LINE_REGEX = /\A\w+\s+\| \d+/
+
+    attr_reader :number, :snapshot_type, :previous_number, :timestamp, :user,
+      :cleanup_algo, :description
+
+    # Determines whether snapper is configured or not
+    #
+    # @return [true,false] true if it's configured; false otherwise.
+    def self.configured?
+      out = Yast::SCR.Execute(Yast::Path.new(".target.bash_output"), 
FIND_CONFIG_CMD)
+      log.info("Checking if Snapper is configured: \"#{FIND_CONFIG_CMD}\" 
returned: #{out}")
+      out["exit"] == 0
+    end
+
+    # Creates a new 'single' snapshot
+    #
+    # @param description [String] Snapshot's description.
+    # @return [FsSnapshot] The created snapshot.
+    #
+    # @see FsSnapshot.create
+    def self.create_single(description)
+      create(:single, description)
+    end
+
+    # Creates a new 'pre' snapshot
+    #
+    # @param description [String] Snapshot's description.
+    # @return [FsSnapshot] The created snapshot.
+    #
+    # @see FsSnapshot.create
+    def self.create_pre(description)
+      create(:pre, description)
+    end
+
+    # Creates a new 'post' snapshot
+    #
+    # Each 'post' snapshot corresponds with a 'pre' one.
+    #
+    # @param description     [String] Snapshot's description.
+    # @param previous_number [Fixnum] Number of the previous snapshot
+    # @return [FsSnapshot] The created snapshot.
+    #
+    # @see FsSnapshot.create
+    def self.create_post(description, previous_number)
+      previous = find(previous_number)
+      if previous
+        create(:post, description, previous)
+      else
+        log.error "Previous filesystem snapshot was not found"
+        raise PreviousSnapshotNotFound
+      end
+    end
+
+    # Creates a new snapshot
+    #
+    # It raises an exception if Snapper is not configured or if snapshot
+    # creation fails.
+    #
+    # @param snapshot_type [Symbol]    Snapshot's type: :pre, :post or :single.
+    # @param description   [String]    Snapshot's description.
+    # @param previous      [FsSnashot] Previous snapshot.
+    # @return [FsSnapshot] The created snapshot if the operation was
+    #                      successful.
+    def self.create(snapshot_type, description, previous = nil)
+      raise SnapperNotConfigured unless configured?
+
+      cmd = format(CREATE_SNAPSHOT_CMD, snapshot_type, description)
+      cmd << format(" --pre-num %s", previous.number) if previous
+      out = Yast::SCR.Execute(Yast::Path.new(".target.bash_output"), cmd)
+      if out["exit"] == 0
+        find(out["stdout"].to_i) # The CREATE_SNAPSHOT_CMD returns the number 
of the new snapshot.
+      else
+        log.error "Snapshot could not be created: #{cmd} returned: #{out}"
+        raise SnapshotCreationFailed
+      end
+    end
+    private_class_method :create
+
+    # Returns all snapshots
+    #
+    # It raises an exception if Snapper is not configured.
+    #
+    # @return [Array<FsSnapshot>] All snapshots that exist in the system.
+    def self.all
+      raise SnapperNotConfigured unless configured?
+
+      out = Yast::SCR.Execute(Yast::Path.new(".target.bash_output"), 
LIST_SNAPSHOTS_CMD)
+      lines = out["stdout"].lines.grep(VALID_LINE_REGEX) # relevant lines from 
output.
+      log.info("Retrieving snapshots list: #{LIST_SNAPSHOTS_CMD} returned: 
#{out}")
+      lines.map do |line|
+        data = line.split("|").map(&:strip)
+        begin
+          timestamp = DateTime.parse(data[3])
+        rescue ArgumentError
+          log.warn("Error when parsing date/time: #{timestamp}")
+          timestamp = nil
+        end
+        previous_number = data[2] == "" ? nil : data[2].to_i
+        new(data[1].to_i, data[0].to_sym, previous_number, timestamp, data[4],
+          data[5].to_sym, data[6])
+      end
+    end
+
+    # Finds a snapshot by its number
+    #
+    # It raises an exception if Snapper is not configured.
+    #
+    # @param nubmer [Fixnum] Number of the snapshot to search for.
+    # @return [FsSnapshot,nil] The snapshot with the number +number+ if found.
+    #                          Otherwise, it returns nil.
+    # @see FsSnapshot.all
+    def self.find(number)
+      all.find { |s| s.number == number }
+    end
+
+    # FsSnapshot constructor
+    #
+    # This method is not intended to be called by users of FsSnapshot class.
+    # Instead, class methods must be used.
+    #
+    # @param number          [Fixnum]        Snapshot's number.
+    # @param snapshot_type   [Symbol]        Snapshot's type: :pre, :post or 
:single.
+    # @param previous_number [Fixnum]        Previous snapshot's number.
+    # @param timestamp       [DateTime]      Timestamp
+    # @param user            [String]        Snapshot's owner username.
+    # @param cleanup_algo    [String]        Clean-up algorithm.
+    # @param description     [String]        Snapshot's description.
+    # @return [FsSnapshot] New FsSnapshot object.
+    def initialize(number, snapshot_type, previous_number, timestamp, user, 
cleanup_algo, description)
+      @number = number
+      @snapshot_type = snapshot_type
+      @previous_number = previous_number
+      @timestamp = timestamp
+      @user = user
+      @cleanup_algo = cleanup_algo
+      @description = description
+    end
+
+    private_class_method :new
+
+    # Returns the previous snapshot
+    #
+    # @return [FsSnapshot, nil] Object representing the previous snapshot.
+    def previous
+      @previous ||= @previous_number ? FsSnapshot.find(@previous_number) : nil
+    end
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-3.1.123/library/system/test/Makefile.am 
new/yast2-3.1.124/library/system/test/Makefile.am
--- old/yast2-3.1.123/library/system/test/Makefile.am   2015-05-18 
17:02:13.000000000 +0200
+++ new/yast2-3.1.124/library/system/test/Makefile.am   2015-05-22 
15:51:11.000000000 +0200
@@ -1,6 +1,7 @@
 TESTS = \
   kernel_test.rb \
-  hw_detection_test.rb
+  hw_detection_test.rb \
+  fs_snapshot_test.rb
 
 TEST_EXTENSIONS = .rb
 RB_LOG_COMPILER = rspec
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-3.1.123/library/system/test/fixtures/empty-snapper-list.txt 
new/yast2-3.1.124/library/system/test/fixtures/empty-snapper-list.txt
--- old/yast2-3.1.123/library/system/test/fixtures/empty-snapper-list.txt       
1970-01-01 01:00:00.000000000 +0100
+++ new/yast2-3.1.124/library/system/test/fixtures/empty-snapper-list.txt       
2015-05-22 15:51:11.000000000 +0200
@@ -0,0 +1,2 @@
+Type   | #  | Pre # | Date                             | User | Cleanup | 
Description  | Userdata     
+-------+----+-------+----------------------------------+------+---------+--------------+--------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-3.1.123/library/system/test/fixtures/snapper-list.txt 
new/yast2-3.1.124/library/system/test/fixtures/snapper-list.txt
--- old/yast2-3.1.123/library/system/test/fixtures/snapper-list.txt     
1970-01-01 01:00:00.000000000 +0100
+++ new/yast2-3.1.124/library/system/test/fixtures/snapper-list.txt     
2015-05-22 15:51:11.000000000 +0200
@@ -0,0 +1,7 @@
+Type   | #  | Pre # | Date                             | User | Cleanup | 
Description  | Userdata     
+-------+----+-------+----------------------------------+------+---------+--------------+--------------
+single | 0  |       |                                  | root |         | 
current      |              
+pre    | 1  |       | Wed 13 May 2015 04:14:14 PM WEST | root | number  | 
zypp(y2base) | important=no 
+pre    | 3  |       | Wed 13 May 2015 05:01:47 PM WEST | root | number  | 
zypp(zypper) | important=no 
+post   | 4  | 3     | Wed 13 May 2015 05:03:13 PM WEST | root | number  | 
zypp(zypper) | important=no 
+single | 5  |       | Wed 13 May 2015 05:11:25 PM WEST | root |         |      
        |              
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/yast2-3.1.123/library/system/test/fs_snapshot_test.rb 
new/yast2-3.1.124/library/system/test/fs_snapshot_test.rb
--- old/yast2-3.1.123/library/system/test/fs_snapshot_test.rb   1970-01-01 
01:00:00.000000000 +0100
+++ new/yast2-3.1.124/library/system/test/fs_snapshot_test.rb   2015-05-22 
15:51:11.000000000 +0200
@@ -0,0 +1,325 @@
+#!/usr/bin/env rspec
+
+require_relative "test_helper"
+require "yast2/fs_snapshot"
+
+describe Yast2::FsSnapshot do
+  def logger
+    described_class.log
+  end
+
+  FIND_CONFIG = "/usr/bin/snapper --no-dbus list-configs | grep \"^root \" 
>/dev/null"
+  LIST_SNAPSHOTS = "LANG=en_US.UTF-8 /usr/bin/snapper --no-dbus list"
+
+  describe ".configured?" do
+    before do
+      allow(Yast::SCR).to receive(:Execute)
+        .with(path(".target.bash_output"), FIND_CONFIG)
+        .and_return("stdout" => "", "exit" => find_code)
+    end
+
+    context "when snapper's configuration does not exist" do
+      let(:find_code) { 1 }
+
+      it "returns false" do
+        expect(logger).to receive(:info).with(/Checking if Snapper is 
configured/)
+        expect(described_class.configured?).to eq(false)
+      end
+    end
+
+    context "when snapper's configuration exists" do
+      let(:find_code) { 0 }
+
+      it "returns false" do
+        expect(described_class.configured?).to eq(true)
+      end
+    end
+  end
+
+  describe ".create_single" do
+    CREATE_SINGLE_SNAPSHOT = "/usr/lib/snapper/installation-helper --step 5 "\
+      "--snapshot-type single --description \"some-description\""
+
+    before do
+      allow(Yast2::FsSnapshot).to receive(:configured?).and_return(configured)
+    end
+
+    context "when snapper is configured" do
+      let(:configured) { true }
+
+      before do
+        allow(Yast::SCR).to receive(:Execute)
+          .with(path(".target.bash_output"), CREATE_SINGLE_SNAPSHOT)
+          .and_return(output)
+      end
+
+      context "when snapshot creation fails" do
+        let(:output) { { "stdout" => "", "exit" => 1 } }
+
+        it "logs the error and returns nil" do
+          expect(logger).to receive(:error).with(/Snapshot could not be 
created/)
+          expect { described_class.create_single("some-description") }
+            .to raise_error(Yast2::SnapshotCreationFailed)
+        end
+      end
+
+      context "when snapshot creation is successful" do
+        let(:output) { { "stdout" => "2", "exit" => 0 } }
+        let(:dummy_snapshot) { double("snapshot") }
+
+        it "returns the created snapshot" do
+          expect(described_class).to receive(:find).with(2)
+            .and_return(dummy_snapshot)
+          snapshot = described_class.create_single("some-description")
+          expect(snapshot).to be(dummy_snapshot)
+        end
+      end
+    end
+
+    context "when snapper is not configured" do
+      let(:configured) { false }
+
+      it "raises an exception" do
+        expect { described_class.create_single("some-description") }
+          .to raise_error(Yast2::SnapperNotConfigured)
+      end
+    end
+  end
+
+  describe ".create_pre" do
+    CREATE_PRE_SNAPSHOT = "/usr/lib/snapper/installation-helper --step 5 "\
+      "--snapshot-type pre --description \"some-description\""
+
+    before do
+      allow(Yast2::FsSnapshot).to receive(:configured?).and_return(configured)
+    end
+
+    context "when snapper is configured" do
+      let(:configured) { true }
+
+      before do
+        allow(Yast::SCR).to receive(:Execute)
+          .with(path(".target.bash_output"), CREATE_PRE_SNAPSHOT)
+          .and_return(output)
+      end
+
+      context "when snapshot creation fails" do
+        let(:output) { { "stdout" => "", "exit" => 1 } }
+
+        it "logs the error and returns nil" do
+          expect(logger).to receive(:error).with(/Snapshot could not be 
created/)
+          expect { described_class.create_pre("some-description") }
+            .to raise_error(Yast2::SnapshotCreationFailed)
+        end
+      end
+
+      context "when snapshot creation is successful" do
+        let(:output) { { "stdout" => "2", "exit" => 0 } }
+        let(:dummy_snapshot) { double("snapshot") }
+
+        it "returns the created snapshot" do
+          expect(described_class).to receive(:find).with(2)
+            .and_return(dummy_snapshot)
+          snapshot = described_class.create_pre("some-description")
+          expect(snapshot).to be(dummy_snapshot)
+        end
+      end
+    end
+
+    context "when snapper is not configured" do
+      let(:configured) { false }
+
+      it "raises an exception" do
+        expect { described_class.create_pre("some-description") }
+          .to raise_error(Yast2::SnapperNotConfigured)
+      end
+    end
+  end
+
+  describe ".create_post" do
+    CREATE_POST_SNAPSHOT = "/usr/lib/snapper/installation-helper --step 5 "\
+      "--snapshot-type post --description \"some-description\" --pre-num 2"
+
+    before do
+      allow(Yast2::FsSnapshot).to receive(:configured?).and_return(configured)
+    end
+
+    context "when snapper is configured" do
+      let(:configured) { true }
+
+      let(:pre_snapshot) { double("snapshot", snapshot_type: :pre, number: 2) }
+      let(:dummy_snapshot) { double("snapshot") }
+      let(:snapshots) { [pre_snapshot] }
+      let(:output) { { "stdout" => "3", "exit" => 0 } }
+
+      before do
+        allow(Yast::SCR).to receive(:Execute)
+          .with(path(".target.bash_output"), CREATE_POST_SNAPSHOT)
+          .and_return(output)
+        allow(Yast2::FsSnapshot).to receive(:all)
+          .and_return(snapshots)
+      end
+
+      context "when previous snapshot exists" do
+        let(:snapshots) { [pre_snapshot] }
+
+        context "when snapshot creation is successful" do
+          it "returns the created snapshot" do
+            allow(Yast2::FsSnapshot).to 
receive(:find).with(pre_snapshot.number)
+              .and_return(pre_snapshot)
+            expect(Yast2::FsSnapshot).to receive(:find).with(3)
+              .and_return(dummy_snapshot)
+            expect(described_class.create_post("some-description", 
pre_snapshot.number))
+              .to be(dummy_snapshot)
+          end
+        end
+
+        context "when snapshot creation fails" do
+          let(:output) { { "stdout" => "", "exit" => 1 } }
+
+          it "logs the error and raises an exception" do
+            expect(logger).to receive(:error).with(/Snapshot could not be 
created/)
+            expect { described_class.create_post("some-description", 
pre_snapshot.number) }
+              .to raise_error(Yast2::SnapshotCreationFailed)
+          end
+        end
+      end
+
+      context "when previous snapshot does not exist" do
+        it "logs the error and raises an exception" do
+          expect(logger).to receive(:error).with(/Previous filesystem snapshot 
was not found/)
+          expect { described_class.create_post("some-description", 100) }
+            .to raise_error(Yast2::PreviousSnapshotNotFound)
+        end
+      end
+    end
+
+    context "when snapper is not configured" do
+      let(:configured) { false }
+
+      it "raises an exception" do
+        expect { described_class.create_post("some-description", 1) }
+          .to raise_error(Yast2::SnapperNotConfigured)
+      end
+    end
+  end
+
+  describe ".all" do
+    before do
+      allow(Yast2::FsSnapshot).to receive(:configured?).and_return(configured)
+    end
+
+    context "when snapper is configured" do
+      let(:configured) { true }
+      let(:output) { File.read(output_path) }
+
+      before do
+        allow(Yast::SCR).to receive(:Execute)
+          .with(path(".target.bash_output"), LIST_SNAPSHOTS)
+          .and_return("stdout" => output, "exit" => 0)
+      end
+
+      context "given some snapshots exist" do
+        let(:output_path) { File.expand_path("../fixtures/snapper-list.txt", 
__FILE__) }
+
+        it "should return the snapshots and log about how many were found" do
+          expect(logger).to receive(:info).with(/Retrieving snapshots list/)
+          snapshots = described_class.all
+          expect(snapshots).to be_kind_of(Array)
+          expect(snapshots.size).to eq(5)
+        end
+      end
+
+      context "given no snapshots exist" do
+        let(:output_path) { 
File.expand_path("../fixtures/empty-snapper-list.txt", __FILE__) }
+
+        it "should return an empty array" do
+          expect(described_class.all).to eq([])
+        end
+      end
+    end
+
+    context "when snapper is not configured" do
+      let(:configured) { false }
+
+      it "raises an exception" do
+        expect { described_class.all }
+          .to raise_error(Yast2::SnapperNotConfigured)
+      end
+    end
+  end
+
+  describe ".find" do
+    before do
+      allow(Yast2::FsSnapshot).to receive(:configured?).and_return(configured)
+    end
+
+    context "when snapper is configured" do
+      let(:configured) { true }
+      let(:output) { File.read(output_path) }
+      let(:output_path) { File.expand_path("../fixtures/snapper-list.txt", 
__FILE__) }
+
+      before do
+        allow(Yast::SCR).to receive(:Execute)
+          .with(path(".target.bash_output"), LIST_SNAPSHOTS)
+          .and_return("stdout" => output, "exit" => 0)
+      end
+
+      context "when a snapshot with that number exists" do
+        it "should return the snapshot" do
+          snapshot = described_class.find(4)
+          expect(snapshot.number).to eq(4)
+          expect(snapshot.snapshot_type).to eq(:post)
+          expect(snapshot.previous_number).to eq(3)
+          expect(snapshot.timestamp).to eq(DateTime.parse("Wed 13 May 2015 
05:03:13 PM WEST"))
+          expect(snapshot.user).to eq("root")
+          expect(snapshot.cleanup_algo).to eq(:number)
+          expect(snapshot.description).to eq("zypp(zypper)")
+        end
+      end
+
+      context "when a snapshot with that number does not exists" do
+        it "should return nil" do
+          expect(described_class.find(100)).to be_nil
+        end
+      end
+    end
+
+    context "when snapper is not configured" do
+      let(:configured) { false }
+
+      it "raises an exception" do
+        expect { described_class.find(1) }
+          .to raise_error(Yast2::SnapperNotConfigured)
+      end
+    end
+  end
+
+  describe "#previous" do
+    let(:output) { File.read(output_path) }
+    let(:output_path) { File.expand_path("../fixtures/snapper-list.txt", 
__FILE__) }
+
+    before do
+      allow(Yast2::FsSnapshot).to receive(:configured?).and_return(true)
+      allow(Yast::SCR).to receive(:Execute)
+        .with(path(".target.bash_output"), LIST_SNAPSHOTS)
+        .and_return("stdout" => output, "exit" => 0)
+    end
+
+    context "given a previous snapshot" do
+      subject(:fs_snapshot) { Yast2::FsSnapshot.find(4) }
+
+      it "returns the previous snapshot" do
+        expect(fs_snapshot.previous.number).to eq(3)
+      end
+    end
+
+    context "given no previous snapshot" do
+      subject(:fs_snapshot) { Yast2::FsSnapshot.find(3) }
+
+      it "returns nil" do
+        expect(fs_snapshot.previous).to be_nil
+      end
+    end
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-3.1.123/package/yast2.changes 
new/yast2-3.1.124/package/yast2.changes
--- old/yast2-3.1.123/package/yast2.changes     2015-05-18 17:02:13.000000000 
+0200
+++ new/yast2-3.1.124/package/yast2.changes     2015-05-22 15:51:11.000000000 
+0200
@@ -1,4 +1,17 @@
 -------------------------------------------------------------------
+Fri May 22 12:32:27 UTC 2015 - [email protected]
+
+- InstExtensionImage: add block variant for loading extension
+  (needed for FATE#317900)
+- 3.1.124
+
+-------------------------------------------------------------------
+Tue May 19 04:56:13 UTC 2015 - [email protected]
+
+- Add a class FsSnapshot for managing filesystem snapshots
+  (fate#317973).
+
+-------------------------------------------------------------------
 Mon May 18 10:32:24 CEST 2015 - [email protected]
 
 - Making SuSEFirewallProposal.propose_iscsi function public
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-3.1.123/package/yast2.spec 
new/yast2-3.1.124/package/yast2.spec
--- old/yast2-3.1.123/package/yast2.spec        2015-05-18 17:02:13.000000000 
+0200
+++ new/yast2-3.1.124/package/yast2.spec        2015-05-22 15:51:11.000000000 
+0200
@@ -17,7 +17,7 @@
 
 
 Name:           yast2
-Version:        3.1.123
+Version:        3.1.124
 Release:        0
 URL:            https://github.com/yast/yast-yast2
 


Reply via email to