Hello community, here is the log from the commit of package yast2-storage for openSUSE:Factory checked in at 2016-11-07 13:24:54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/yast2-storage (Old) and /work/SRC/openSUSE:Factory/.yast2-storage.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "yast2-storage" Changes: -------- --- /work/SRC/openSUSE:Factory/yast2-storage/yast2-storage.changes 2016-10-28 10:43:36.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.yast2-storage.new/yast2-storage.changes 2016-11-07 13:24:57.000000000 +0100 @@ -1,0 +2,13 @@ +Mon Oct 31 13:11:04 UTC 2016 - igonzalezs...@suse.com + +- Improve support to redefine/detect the Btrfs default subvolume + name (FATE#320342 and FATE#317775) using AutoYaST. +- 3.2.0 + +------------------------------------------------------------------- +Thu Oct 27 14:26:49 CEST 2016 - shundham...@suse.de + +- Make subvolumes configurable in control.xml (fate#321737) +- 3.1.105 + +------------------------------------------------------------------- @@ -6 +18,0 @@ -- 3.1.105 Old: ---- yast2-storage-3.1.105.tar.bz2 New: ---- yast2-storage-3.2.0.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ yast2-storage.spec ++++++ --- /var/tmp/diff_new_pack.8DjMI4/_old 2016-11-07 13:24:59.000000000 +0100 +++ /var/tmp/diff_new_pack.8DjMI4/_new 2016-11-07 13:24:59.000000000 +0100 @@ -17,7 +17,7 @@ Name: yast2-storage -Version: 3.1.105 +Version: 3.2.0 Release: 0 BuildRoot: %{_tmppath}/%{name}-%{version}-build ++++++ yast2-storage-3.1.105.tar.bz2 -> yast2-storage-3.2.0.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/.travis.yml new/yast2-storage-3.2.0/.travis.yml --- old/yast2-storage-3.1.105/.travis.yml 2016-10-24 14:04:09.000000000 +0200 +++ new/yast2-storage-3.2.0/.travis.yml 2016-11-04 17:06:56.000000000 +0100 @@ -5,7 +5,7 @@ # disable rvm, use system Ruby - rvm reset - wget https://raw.githubusercontent.com/yast/yast-devtools/master/travis-tools/travis_setup.sh - - sh ./travis_setup.sh -p "rake yast2-core-dev yast2 yast2-devtools doxygen yast2-testsuite libstorage5-dev libstorage5-ruby ruby-dbus" -g "rspec:3.3.0 yast-rake gettext" + - sh ./travis_setup.sh -p "rake yast2-core-dev yast2 yast2-devtools doxygen yast2-testsuite libstorage5-dev libstorage5-ruby ruby-dbus" -g "rspec:3.3.0 yast-rake gettext cheetah abstract_method" script: - rake check:syntax - rake check:pot diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/package/yast2-storage.changes new/yast2-storage-3.2.0/package/yast2-storage.changes --- old/yast2-storage-3.1.105/package/yast2-storage.changes 2016-10-24 14:04:09.000000000 +0200 +++ new/yast2-storage-3.2.0/package/yast2-storage.changes 2016-11-04 17:06:56.000000000 +0100 @@ -1,9 +1,21 @@ ------------------------------------------------------------------- +Mon Oct 31 13:11:04 UTC 2016 - igonzalezs...@suse.com + +- Improve support to redefine/detect the Btrfs default subvolume + name (FATE#320342 and FATE#317775) using AutoYaST. +- 3.2.0 + +------------------------------------------------------------------- +Thu Oct 27 14:26:49 CEST 2016 - shundham...@suse.de + +- Make subvolumes configurable in control.xml (fate#321737) +- 3.1.105 + +------------------------------------------------------------------- Mon Oct 24 13:53:10 CEST 2016 - aschn...@suse.com - fixed installing required storage packages for unmounted filesystems (bsc#907331) -- 3.1.105 ------------------------------------------------------------------- Thu Sep 29 12:19:20 CEST 2016 - aschn...@suse.com diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/package/yast2-storage.spec new/yast2-storage-3.2.0/package/yast2-storage.spec --- old/yast2-storage-3.1.105/package/yast2-storage.spec 2016-10-24 14:04:09.000000000 +0200 +++ new/yast2-storage-3.2.0/package/yast2-storage.spec 2016-11-04 17:06:56.000000000 +0100 @@ -17,7 +17,7 @@ Name: yast2-storage -Version: 3.1.105 +Version: 3.2.0 Release: 0 BuildRoot: %{_tmppath}/%{name}-%{version}-build diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/src/Makefile.am new/yast2-storage-3.2.0/src/Makefile.am --- old/yast2-storage-3.1.105/src/Makefile.am 2016-10-24 14:04:09.000000000 +0200 +++ new/yast2-storage-3.2.0/src/Makefile.am 2016-11-04 17:06:56.000000000 +0100 @@ -91,7 +91,8 @@ lib/storage/target_map_formatter.rb \ lib/storage/used_storage_features.rb \ lib/storage/shadowed_vol_list.rb \ - lib/storage/shadowed_vol_helper.rb + lib/storage/shadowed_vol_helper.rb \ + lib/storage/subvol.rb scrconf_DATA = \ scrconf/proc_partitions.scr \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/src/lib/storage/subvol.rb new/yast2-storage-3.2.0/src/lib/storage/subvol.rb --- old/yast2-storage-3.1.105/src/lib/storage/subvol.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-storage-3.2.0/src/lib/storage/subvol.rb 2016-11-04 17:06:56.000000000 +0100 @@ -0,0 +1,173 @@ +# encoding: utf-8 + +# Copyright (c) [2012-2016] Novell, Inc. +# +# 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. + +require "yast" +require "storage" +Yast.import "Arch" + +module Yast + class StorageClass < Module + + # Helper class to represent a subvolume as defined in control.xml + # + class Subvol + include Yast::Logger + + attr_accessor :path, :copy_on_write, :archs + + COW_SUBVOL_PATHS = [ + "home", + "opt", + "srv", + "tmp", + "usr/local", + "var/cache", + "var/crash", + "var/lib/machines", + "var/lib/mailman", + "var/lib/named", + "var/log", + "var/opt", + "var/spool", + "var/tmp" + ] + + # No Copy On Write for SQL databases and libvirt virtual disks to + # minimize performance impact + NO_COW_SUBVOL_PATHS = [ + "var/lib/libvirt/images", + "var/lib/mariadb", + "var/lib/mysql", + "var/lib/pgsql" + ] + + def initialize(path, copy_on_write: true, archs: nil) + @path = path + @copy_on_write = copy_on_write + @archs = archs + end + + def to_s + text = "Subvol #{@path}" + text += " (NoCOW)" unless @copy_on_write + text += " (archs: #{@archs})" if arch_specific? + text + end + + def arch_specific? + !archs.nil? + end + + def cow? + @copy_on_write + end + + def no_cow? + !@copy_on_write + end + + # Comparison operator for sorting + # + def <=>(other) + path <=> other.path + end + + # Check if this subvolume should be used for the current architecture. + # A subvolume is used if its archs contain the current arch. + # It is not used if its archs contain the current arch negated + # (e.g. "!ppc"). + # + # @return [Boolean] true if this subvolume matches the current architecture + # + def current_arch? + matches_arch? { |arch| Arch.respond_to?(arch.to_sym) && Arch.send(arch.to_sym) } + end + + # Check if this subvolume should be used for an architecture. + # + # If a block is given, the block is called as the matcher with the + # architecture to be tested as its argument. + # + # If no block is given (and only then), the 'target_arch' parameter is + # used to check against. + # + # @return [Boolean] true if this subvolume matches + # + def matches_arch?(target_arch = nil, &block) + return true unless arch_specific? + use_subvol = false + archs.each do |a| + arch = a.dup + negate = arch.start_with?("!") + arch[0] = "" if negate # remove leading "!" + if block_given? + match = block.call(arch) + else + match = arch == target_arch + end + if match && negate + log.info("Not using #{self} for explicitly excluded arch #{arch}") + return false + end + use_subvol ||= match + end + log.info("Using arch specific #{self}: #{use_subvol}") + use_subvol + end + + # Factory method: Create one Subvol from XML data stored as a map. + # + # @return Subvol or nil if error + # + def self.create_from_xml(xml) + return nil unless xml.key?("path") + path = xml["path"] + cow = true + if xml.key?("copy_on_write") + cow = xml["copy_on_write"] + end + archs = nil + if xml.key?("archs") + archs = xml["archs"].gsub(/\s+/, "").split(",") + end + subvol = Subvol.new(path, copy_on_write: cow, archs: archs) + log.info("Creating from XML: #{subvol}") + subvol + end + + # Create a fallback list of Subvols. This is useful if nothing is + # specified in the control.xml file. + # + # @return List<Subvol> + # + def self.fallback_list + subvols = [] + COW_SUBVOL_PATHS.each { |path| subvols << Subvol.new(path) } + NO_COW_SUBVOL_PATHS.each { |path| subvols << Subvol.new(path, copy_on_write: false) } + subvols << Subvol.new("boot/grub2/i386-pc", archs: ["i386", "x86_64"]) + subvols << Subvol.new("boot/grub2/x86_64-efi", archs: ["x86_64"]) + subvols << Subvol.new("boot/grub2/powerpc-ieee1275", archs: ["ppc", "!board_powernv"]) + subvols << Subvol.new("boot/grub2/s390x-emu", archs: ["s390"]) + subvols.select { |s| s.current_arch? }.sort + end + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/src/modules/FileSystems.rb new/yast2-storage-3.2.0/src/modules/FileSystems.rb --- old/yast2-storage-3.1.105/src/modules/FileSystems.rb 2016-10-24 14:04:09.000000000 +0200 +++ new/yast2-storage-3.2.0/src/modules/FileSystems.rb 2016-11-04 17:06:56.000000000 +0100 @@ -31,9 +31,18 @@ # $Id$ require "storage" require "yast" +require "yast2/execute" module Yast class FileSystemsClass < Module + include Yast::Logger + + # @return [Array<String>] Supported default subvolume names + SUPPORTED_DEFAULT_SUBVOLUME_NAMES = ["", "@"].freeze + + # @return [String] Default subvolume name. + attr_reader :default_subvol + def main textdomain "storage" @@ -44,6 +53,7 @@ Yast.import "Encoding" Yast.import "Stage" Yast.import "StorageInit" + Yast.import "ProductFeatures" @conv_fs = { "def_sym" => :unknown, @@ -74,7 +84,8 @@ @possible_root_fs = [:ext2, :ext3, :ext4, :btrfs, :reiser, :xfs] @swap_m_points = ["swap"] @tmp_m_points = ["/tmp", "/var/tmp"] - @default_subvol = "UNDEFINED" + self.default_subvol = ProductFeatures.GetStringFeature("partitioning", "btrfs_default_subvolume") + @suggest_m_points = [] @suggest_tmp_points = [] @@ -1439,7 +1450,7 @@ def InitSlib(value) @sint = value if @sint != nil - @default_subvol = @sint.getDefaultSubvolName() + @sint.setDefaultSubvolName(@default_subvol) Builtins.y2milestone( "InitSlib used default_subvol:\"%1\"", @default_subvol @@ -2030,14 +2041,86 @@ ret end + # Set the default subvolume name + # + # @param [String] Default subvolume name. Only "" and "@" are supported. + # @return [Boolean] True if subvolume was changed; false otherwise. + def default_subvol=(name) + if SUPPORTED_DEFAULT_SUBVOLUME_NAMES.include?(name) + @default_subvol = name + @sint.setDefaultSubvolName(name) unless @sint.nil? + true + else + log.warn "Unsupported default subvolume name='#{name}'. Ignoring." + false + end + end + + # Try to find the default subvolume name in the target system + # + # * Root partition takes precedence + # * Not supported: more than 1 Btrfs filesystems, one using + # a '@' default subvolume and the other using ''. In that case, + # default_subvolume is set to product's default. + # + # @return [String,nil] Default subvolume from the target system + def default_subvol_from_target + Yast.import "Storage" + parts = Storage.GetTargetMap.map { |_k, d| d.fetch("partitions") }.flatten.compact + btrfs_parts = parts.select { |p| p["used_fs"] == :btrfs } + default_subvol_names = btrfs_parts.reduce({}) do |memo, part| + memo[part["mount"]] = btrfs_subvol_name_for(part["mount"]) unless part["mount"].nil? + memo + end + + # Root takes precedence + return default_subvol_names["/"] if default_subvol_names.has_key?("/") + + # If all has the same default subvolume name + found_names = default_subvol_names.values.uniq + return found_names.first if found_names.size == 1 + + # If there are different values, fallback to product's default + default_subvol_from_product + end + + # Default subvol name from product + # + # @return [String] Default subvolume name + def default_subvol_from_product + ProductFeatures.GetStringFeature("partitioning", "btrfs_default_subvolume") + end + + # Read the default subvolume from the filesystem and stores the value + # + # @return [String,nil] Default subvolume from the target system + # @see default_subvol_from_target + def read_default_subvol_from_target + self.default_subvol = default_subvol_from_target + end + + protected + + # Find the default subvolume name + # + # Only "" and "@" are supported. + # + # @param mount [String] Mount point. + # @return ["@", ""] Default subvolume name for the given mount point. + def btrfs_subvol_name_for(mount) + ret = Yast::Execute.on_target("btrfs", "subvol", "list", mount, stdout: :capture) + ret.split("\n").first =~ /.+ @\z/ ? "@" : "" + end + publish :variable => :conv_fs, :type => "map <string, any>" publish :variable => :possible_root_fs, :type => "const list <symbol>" publish :function => :system_m_points, :type => "list <string> ()" publish :function => :crypt_m_points, :type => "list <string> ()" publish :variable => :swap_m_points, :type => "const list <string>" publish :variable => :tmp_m_points, :type => "const list <string>" - publish :variable => :default_subvol, :type => "string" publish :variable => :nchars, :type => "string" + publish :function => :default_subvol, :type => "string ()" + publish :function => :default_subvol=, :type => "string (string)" publish :function => :SuggestMPoints, :type => "list <string> ()" publish :function => :SuggestTmpfsMPoints, :type => "list <string> ()" publish :function => :GetGeneralFstabOptions, :type => "list <map <symbol, any>> ()" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/src/modules/Storage.rb new/yast2-storage-3.2.0/src/modules/Storage.rb --- old/yast2-storage-3.1.105/src/modules/Storage.rb 2016-10-24 14:04:09.000000000 +0200 +++ new/yast2-storage-3.2.0/src/modules/Storage.rb 2016-11-04 17:06:56.000000000 +0100 @@ -25,6 +25,7 @@ require "storage/target_map_formatter" require "storage/used_storage_features" require "storage/shadowed_vol_helper" +require "storage/subvol" module Yast class StorageClass < Module @@ -338,10 +339,6 @@ StorageClients.InstallCallbacks(@sint) - btrfs_default_subvolume = ProductFeatures.GetStringFeature("partitioning", - "btrfs_default_subvolume") - @sint.setDefaultSubvolName(btrfs_default_subvolume) if btrfs_default_subvolume - if Stage.initial @sint.setDetectMountedVolumes(false) @sint.setRootPrefix(Installation.destdir) @@ -374,7 +371,7 @@ def default_subvolume_name() - return @sint.getDefaultSubvolName() + FileSystems.default_subvol end @@ -5011,6 +5008,24 @@ ret end + # Create a list of Subvols from the <subvolumes> part of control.xml. + # The map may be empty if there is a <subvolumes> section, but it's empty. + # + # This function does not do much error handling or reporting; it is assumed + # that control.xml is validated against its schema. + # + # @param subvolumes_xml list of XML <subvolume> entries + # @return Subvolumes map or nil + # + def ReadSubvolsFromXml(subvolumes_xml) + return nil if subvolumes_xml.nil? + return nil unless subvolumes_xml.respond_to?(:map) + + all_subvols = subvolumes_xml.map { |xml| Subvol.create_from_xml(xml) } + all_subvols.compact! # Remove nil subvols due to XML parse errors + relevant_subvols = all_subvols.select { |s| s.current_arch? } + relevant_subvols.sort + end # Adds the list of subvolumes to a partition meant to be used as root (/) # @@ -5019,53 +5034,9 @@ def AddSubvolRoot(part) part = deep_copy(part) - subvol_names = [ - "home", - "opt", - "srv", - "tmp", - "usr/local", - "var/cache", - "var/crash", - "var/lib/libvirt/images", - "var/lib/machines", - "var/lib/mailman", - "var/lib/mariadb", - "var/lib/mysql", - "var/lib/named", - "var/lib/pgsql", - "var/log", - "var/opt", - "var/spool", - "var/tmp" - ] - - # No Copy On Write for SQL databases and libvirt virtual disks to - # minimize performance impact - nocow_subvols = [ - "var/lib/libvirt/images", - "var/lib/mariadb", - "var/lib/mysql", - "var/lib/pgsql" - ] - - if Arch.i386 || Arch.x86_64 - subvol_names.push("boot/grub2/i386-pc") - end - - if Arch.x86_64 - subvol_names.push("boot/grub2/x86_64-efi") - end - - if Arch.ppc and !Arch.board_powernv - subvol_names.push("boot/grub2/powerpc-ieee1275") - end - - if Arch.s390 - subvol_names.push("boot/grub2/s390x-emu") - end - - subvol_names.sort!() + xml = ProductFeatures.GetSection("partitioning") + subvols = ReadSubvolsFromXml(xml["subvolumes"]) || Subvol.fallback_list + subvols.each { |s| log.info("Initial #{s}") } subvol_prepend = "" part["subvol"] ||= [] @@ -5073,27 +5044,27 @@ if FileSystems.default_subvol != "" subvol_prepend = FileSystems.default_subvol+"/" end - fmt = part.fetch("format",false) + fmt = part["format"] || false names = [] if !fmt names = part["subvol"].select { |s| !s.fetch("delete", false) }.each { |s| s.fetch("name", "") } else part["subvol"] = [] end - Builtins.y2milestone("AddSubvolRoot subvol names: %1 subvol: %2", names, part["subvol"]) - subvol_names.each do |subvol| - subvol_full_name = subvol_prepend + subvol + log.info("AddSubvolRoot subvol names: #{names} subvol: #{part['subvol']}") + subvols.each do |subvol| + subvol_full_name = subvol_prepend + subvol.path if !names.include?( subvol_full_name ) subvol_entry = { "create" => true, "name" => subvol_full_name } - if nocow_subvols.include?( subvol ) + if subvol.no_cow? subvol_entry["nocow"] = true - Builtins.y2milestone("AddSubvolRoot: NoCOW for %1", subvol_full_name) + log.info("AddSubvolRoot: NoCOW for #{subvol_full_name}") end part["subvol"].push(subvol_entry) end end - Builtins.y2milestone("AddSubvolRoot subvol:\n%1", format_target_map(part["subvol"])) - Builtins.y2milestone("AddSubvolRoot part: \n%1", format_target_map(part)) + log.info("AddSubvolRoot subvol:\n#{format_target_map(part['subvol'])}") + log.info("AddSubvolRoot part: \n#{format_target_map(part)}") part end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/test/Makefile.am new/yast2-storage-3.2.0/test/Makefile.am --- old/yast2-storage-3.1.105/test/Makefile.am 2016-10-24 14:04:10.000000000 +0200 +++ new/yast2-storage-3.2.0/test/Makefile.am 2016-11-04 17:06:56.000000000 +0100 @@ -8,7 +8,8 @@ storage_get_disk_partition.rb \ storage_boot_on_raid1.rb \ partitions_test.rb \ - include/partitioning_custom_part_check_generated_include_test.rb\ + include/partitioning_custom_part_check_generated_include_test.rb \ + subvol_test.rb \ ro_text_test.rb TEST_EXTENSIONS = .rb diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/test/filesystems_test.rb new/yast2-storage-3.2.0/test/filesystems_test.rb --- old/yast2-storage-3.1.105/test/filesystems_test.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-storage-3.2.0/test/filesystems_test.rb 2016-11-04 17:06:56.000000000 +0100 @@ -0,0 +1,103 @@ +#!/usr/bin/env rspec + +require_relative "spec_helper" + +Yast.import "FileSystems" +Yast.import "Storage" + +describe Yast::FileSystems do + subject { Yast::FileSystems } + + def btrfs_list_fixture(name) + fixture_name = "btrfs_list_#{name}.out" + File.read(File.join(FIXTURES_PATH, fixture_name)) + end + + let(:default_subvol) { "@" } + let(:libstorage) do + double("libstorage", getDefaultSubvolName: default_subvol, setDefaultSubvolName: default_subvol) + end + + before do + subject.InitSlib(libstorage) + end + + describe "#default_subvol_from_target" do + before do + allow(Yast::Storage).to receive(:GetTargetMap).and_return(target_map) + allow(Yast::ProductFeatures).to receive(:GetStringFeature) + .with("partitioning", "btrfs_default_subvolume").and_return(default_subvol) + end + + context "when root partition uses the default subvolume name (@)" do + let(:target_map) { YAML.load_file(File.join(FIXTURES_PATH, "subvolumes.yml")) } + + before do + allow(Yast::Execute).to receive(:on_target).with("btrfs", "subvol", "list", "/", anything) + .and_return(btrfs_list_fixture("root")) + allow(Yast::Execute).to receive(:on_target).with("btrfs", "subvol", "list", "/srv", anything) + .and_return(btrfs_list_fixture("root_no_at")) + end + + it "returns the default subvolume name" do + expect(subject.default_subvol_from_target).to eq(default_subvol) + end + end + + context "when root partitions does not use btrfs" do + let(:target_map) { YAML.load_file(File.join(FIXTURES_PATH, "subvolumes-no-root.yml")) } + + before do + allow(Yast::Execute).to receive(:on_target).with("btrfs", "subvol", "list", "/", anything) + .and_return(btrfs_list_fixture("root_no_at")) + end + + context "but all btrfs partitions uses the same subvolume name" do + before do + allow(Yast::Execute).to receive(:on_target).with("btrfs", "subvol", "list", "/srv", anything) + .and_return(btrfs_list_fixture("srv_no_at")) + allow(Yast::Execute).to receive(:on_target).with("btrfs", "subvol", "list", "/data", anything) + .and_return(btrfs_list_fixture("data_no_at")) + end + + it "returns the used name ('' in this case)" do + expect(subject.default_subvol_from_target).to eq("") + end + end + + context "and btrfs partitions uses different subvolume names" do + before do + allow(Yast::Execute).to receive(:on_target).with("btrfs", "subvol", "list", "/srv", anything) + .and_return(btrfs_list_fixture("srv")) + allow(Yast::Execute).to receive(:on_target).with("btrfs", "subvol", "list", "/data", anything) + .and_return(btrfs_list_fixture("data_no_at")) + end + + it "returns the distribution default" do + expect(subject.default_subvol_from_target).to eq(default_subvol) + end + end + end + end + + describe "#read_default_subvol_from_target" do + it "sets the default_subvol using the value from target" do + subject.default_subvol = "" + expect(subject).to receive(:default_subvol_from_target).and_return("@") + expect { subject.read_default_subvol_from_target }.to change { subject.default_subvol } + .from("").to("@") + end + end + + describe "#default_subvol=" do + it "sets the default_subvol if a valid value is given" do + expect(libstorage).to receive(:setDefaultSubvolName).with("@") + subject.default_subvol = "@" + end + + it "refuses to set default_subvol if an invalid value is given" do + expect(libstorage).to_not receive(:setDefaultSubvolName) + subject.default_subvol = "UNDEFINED" + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/test/fixtures/btrfs_list_data_no_at.out new/yast2-storage-3.2.0/test/fixtures/btrfs_list_data_no_at.out --- old/yast2-storage-3.1.105/test/fixtures/btrfs_list_data_no_at.out 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-storage-3.2.0/test/fixtures/btrfs_list_data_no_at.out 2016-11-04 17:06:56.000000000 +0100 @@ -0,0 +1,3 @@ +ID 257 gen 16 top level 5 path shared +ID 258 gen 16 top level 5 path private + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/test/fixtures/btrfs_list_root.out new/yast2-storage-3.2.0/test/fixtures/btrfs_list_root.out --- old/yast2-storage-3.1.105/test/fixtures/btrfs_list_root.out 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-storage-3.2.0/test/fixtures/btrfs_list_root.out 2016-11-04 17:06:56.000000000 +0100 @@ -0,0 +1,28 @@ +ID 257 gen 34 top level 5 path @ +ID 258 gen 51 top level 257 path @/.snapshots +ID 259 gen 88 top level 258 path @/.snapshots/1/snapshot +ID 260 gen 44 top level 257 path @/boot/grub2/i386-pc +ID 261 gen 15 top level 257 path @/boot/grub2/x86_64-efi +ID 262 gen 44 top level 257 path @/home +ID 263 gen 51 top level 257 path @/opt +ID 264 gen 50 top level 257 path @/srv +ID 265 gen 88 top level 257 path @/tmp +ID 266 gen 64 top level 257 path @/usr/local +ID 267 gen 38 top level 257 path @/var/crash +ID 268 gen 22 top level 257 path @/var/lib/mailman +ID 269 gen 88 top level 257 path @/var/lib/named +ID 270 gen 24 top level 257 path @/var/lib/pgsql +ID 271 gen 88 top level 257 path @/var/log +ID 272 gen 38 top level 257 path @/var/opt +ID 273 gen 84 top level 257 path @/var/spool +ID 274 gen 51 top level 257 path @/var/tmp +ID 275 gen 30 top level 257 path @/mysubvol +ID 276 gen 47 top level 275 path @/mysubvol/mysubsubvol +ID 277 gen 32 top level 257 path @/myothersubvol +ID 278 gen 47 top level 277 path @/myothersubvol/myothersubsubvol +ID 279 gen 33 top level 257 path @/nocow +ID 280 gen 35 top level 257 path @/myvol +ID 282 gen 40 top level 259 path var/lib/machines +ID 283 gen 48 top level 258 path @/.snapshots/2/snapshot +ID 284 gen 49 top level 258 path @/.snapshots/3/snapshot +ID 285 gen 50 top level 258 path @/.snapshots/4/snapshot diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/test/fixtures/btrfs_list_root_no_at.out new/yast2-storage-3.2.0/test/fixtures/btrfs_list_root_no_at.out --- old/yast2-storage-3.1.105/test/fixtures/btrfs_list_root_no_at.out 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-storage-3.2.0/test/fixtures/btrfs_list_root_no_at.out 2016-11-04 17:06:56.000000000 +0100 @@ -0,0 +1,27 @@ +ID 257 gen 48 top level 5 path .snapshots +ID 258 gen 92 top level 257 path .snapshots/1/snapshot +ID 259 gen 41 top level 5 path boot/grub2/i386-pc +ID 260 gen 12 top level 5 path boot/grub2/x86_64-efi +ID 261 gen 41 top level 5 path home +ID 262 gen 49 top level 5 path opt +ID 263 gen 47 top level 5 path srv +ID 264 gen 91 top level 5 path tmp +ID 265 gen 61 top level 5 path usr/local +ID 266 gen 35 top level 5 path var/crash +ID 267 gen 19 top level 5 path var/lib/mailman +ID 268 gen 89 top level 5 path var/lib/named +ID 269 gen 21 top level 5 path var/lib/pgsql +ID 270 gen 90 top level 5 path var/log +ID 271 gen 35 top level 5 path var/opt +ID 272 gen 91 top level 5 path var/spool +ID 273 gen 48 top level 5 path var/tmp +ID 274 gen 27 top level 5 path mysubvol +ID 275 gen 44 top level 274 path mysubvol/mysubsubvol +ID 276 gen 29 top level 5 path @/myothersubvol +ID 277 gen 44 top level 276 path @/myothersubvol/myothersubsubvol +ID 278 gen 30 top level 5 path nocow +ID 279 gen 32 top level 5 path myvol +ID 281 gen 37 top level 258 path var/lib/machines +ID 282 gen 45 top level 257 path .snapshots/2/snapshot +ID 283 gen 46 top level 257 path .snapshots/3/snapshot +ID 284 gen 47 top level 257 path .snapshots/4/snapshot diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/test/fixtures/btrfs_list_srv.out new/yast2-storage-3.2.0/test/fixtures/btrfs_list_srv.out --- old/yast2-storage-3.1.105/test/fixtures/btrfs_list_srv.out 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-storage-3.2.0/test/fixtures/btrfs_list_srv.out 2016-11-04 17:06:56.000000000 +0100 @@ -0,0 +1,5 @@ +ID 257 gen 16 top level 5 path @ +ID 258 gen 16 top level 257 path www +ID 259 gen 16 top level 257 path mirror +ID 260 gen 16 top level 257 path ftp +ID 261 gen 16 top level 257 path tftpboot diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/test/fixtures/btrfs_list_srv_no_at.out new/yast2-storage-3.2.0/test/fixtures/btrfs_list_srv_no_at.out --- old/yast2-storage-3.1.105/test/fixtures/btrfs_list_srv_no_at.out 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-storage-3.2.0/test/fixtures/btrfs_list_srv_no_at.out 2016-11-04 17:06:56.000000000 +0100 @@ -0,0 +1,5 @@ +ID 257 gen 16 top level 5 path www +ID 258 gen 16 top level 5 path mirror +ID 259 gen 16 top level 5 path ftp +ID 260 gen 16 top level 5 path tftpboot + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/test/fixtures/subvolumes-no-root.yml new/yast2-storage-3.2.0/test/fixtures/subvolumes-no-root.yml --- old/yast2-storage-3.1.105/test/fixtures/subvolumes-no-root.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-storage-3.2.0/test/fixtures/subvolumes-no-root.yml 2016-11-04 17:06:56.000000000 +0100 @@ -0,0 +1,180 @@ +--- +"/dev/vda": + unique: KSbE.Fxp0d3BezAE + bus: None + device: "/dev/vda" + bios_id: '0x80' + driver: virtio-pci + driver_module: virtio_pci + partitions: + - device: "/dev/vda1" + name: vda1 + used_by_type: :UB_NONE + used_by_device: '' + size_k: 264192 + used_fs: :swap + detected_fs: :swap + mount: swap + mountby: :uuid + fstopt: defaults + uuid: 559e2279-4012-4174-a746-e4664031851d + nr: 1 + fsid: 130 + fstype: Linux swap + region: + - 0 + - 34 + type: :primary + - device: "/dev/vda2" + name: vda2 + used_by_type: :UB_NONE + used_by_device: '' + size_k: 5244928 + used_fs: :ext4 + detected_fs: :ext4 + mount: "/" + mountby: :uuid + fstopt: acl,user_xattr + uuid: 323a8681-4229-4e3f-ac67-c0b70b148ecd + nr: 2 + fsid: 131 + fstype: Linux native + region: + - 33 + - 653 + type: :primary + boot: true + - device: "/dev/vda3" + name: vda3 + used_by: + - type: :UB_BTRFS + device: e71f8bec-08b6-441c-a2d0-b25cc7bc856a + used_by_type: :UB_BTRFS + used_by_device: e71f8bec-08b6-441c-a2d0-b25cc7bc856a + size_k: 2618368 + used_fs: :btrfs + detected_fs: :btrfs + fstopt: defaults + nr: 3 + fsid: 131 + fstype: Linux native + region: + - 685 + - 327 + type: :primary + subvol: + - name: "@/www" + - name: "@/ftp" + - name: "@/mirror" + uuid: e71f8bec-08b6-441c-a2d0-b25cc7bc856a + mount: "/srv" + mountby: :uuid + - device: "/dev/vda4" + name: vda4 + used_by: + - type: :UB_BTRFS + device: aa2af2cd-d43e-44b1-8025-e3d119070d47 + used_by_type: :UB_BTRFS + used_by_device: aa2af2cd-d43e-44b1-8025-e3d119070d47 + size_k: 2357248 + used_fs: :btrfs + detected_fs: :btrfs + fstopt: defaults + nr: 4 + fsid: 131 + fstype: Linux native + region: + - 1011 + - 294 + type: :primary + uuid: aa2af2cd-d43e-44b1-8025-e3d119070d47 + mount: "/data" + mountby: :uuid + size_k: 10485760 + cyl_size: 8225280 + cyl_count: 1305 + sector_size: 512 + label: msdos + name: vda + max_logical: 255 + max_primary: 4 + type: :CT_DISK + transport: :unknown + used_by_type: :UB_NONE + used_by_device: '' + dasd_format: 0 + dasd_type: 0 +"/dev/btrfs": + device: "/dev/btrfs" + name: btrfs + used_by_type: :UB_NONE + used_by_device: '' + type: :CT_BTRFS + partitions: [] +"/dev/tmpfs": + device: "/dev/tmpfs" + name: tmpfs + used_by_type: :UB_NONE + used_by_device: '' + type: :CT_TMPFS + partitions: + - device: tmpfs + name: none + used_by_type: :UB_NONE + used_by_device: '' + size_k: 507800 + used_fs: :tmpfs + detected_fs: :tmpfs + mount: "/dev/shm" + mountby: :uuid + ignore_fstab: true + type: :tmpfs + fstype: TMPFS + - device: tmpfs + name: none + used_by_type: :UB_NONE + used_by_device: '' + size_k: 507800 + used_fs: :tmpfs + detected_fs: :tmpfs + mount: "/run" + mountby: :uuid + ignore_fstab: true + type: :tmpfs + fstype: TMPFS + - device: tmpfs + name: none + used_by_type: :UB_NONE + used_by_device: '' + size_k: 507800 + used_fs: :tmpfs + detected_fs: :tmpfs + mount: "/sys/fs/cgroup" + mountby: :uuid + ignore_fstab: true + type: :tmpfs + fstype: TMPFS + - device: tmpfs + name: none + used_by_type: :UB_NONE + used_by_device: '' + size_k: 101564 + used_fs: :tmpfs + detected_fs: :tmpfs + mount: "/run/user/483" + mountby: :uuid + ignore_fstab: true + type: :tmpfs + fstype: TMPFS + - device: tmpfs + name: none + used_by_type: :UB_NONE + used_by_device: '' + size_k: 101564 + used_fs: :tmpfs + detected_fs: :tmpfs + mount: "/run/user/0" + mountby: :uuid + ignore_fstab: true + type: :tmpfs + fstype: TMPFS diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/test/fixtures/subvolumes.yml new/yast2-storage-3.2.0/test/fixtures/subvolumes.yml --- old/yast2-storage-3.1.105/test/fixtures/subvolumes.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-storage-3.2.0/test/fixtures/subvolumes.yml 2016-11-04 17:06:56.000000000 +0100 @@ -0,0 +1,185 @@ +--- +"/dev/vda": + unique: KSbE.Fxp0d3BezAE + bus: None + device: "/dev/vda" + bios_id: '0x80' + driver: virtio-pci + driver_module: virtio_pci + partitions: + - device: "/dev/vda1" + name: vda1 + used_by: + - type: :UB_BTRFS + device: 8e6e04a4-758f-4d43-bab8-6b3dca3d31e2 + used_by_type: :UB_BTRFS + used_by_device: 8e6e04a4-758f-4d43-bab8-6b3dca3d31e2 + size_k: 13925376 + used_fs: :btrfs + detected_fs: :btrfs + fstopt: defaults + nr: 2 + fsid: 131 + fstype: Linux native + region: + - 93 + - 1734 + type: :primary + boot: true + subvol: + - name: "@" + - name: "@/.snapshots" + - name: "@/.snapshots/1/snapshot" + - name: "@/home" + - name: "@/var/log" + - name: "@/var/lib/pgsql" + - name: "@/myvol" + nocow: true + - name: "@/.snapshots/1/snapshot/var/lib/machines" + - name: "@/.snapshots/2/snapshot" + - name: "@/.snapshots/3/snapshot" + - name: "@/.snapshots/4/snapshot" + uuid: 8e6e04a4-758f-4d43-bab8-6b3dca3d31e2 + mount: "/" + mountby: :uuid + size_k: 14680064 + cyl_size: 8225280 + cyl_count: 1827 + sector_size: 512 + label: msdos + name: vda + max_logical: 255 + max_primary: 4 + type: :CT_DISK + transport: :unknown + used_by_type: :UB_NONE + used_by_device: '' + dasd_format: 0 + dasd_type: 0 +"/dev/vdb": + unique: KSbE.Fxp0d3BezAE + bus: None + device: "/dev/vdb" + bios_id: '0x80' + driver: virtio-pci + driver_module: virtio_pci + partitions: + - device: "/dev/vdb1" + name: vdb1 + used_by_type: :UB_NONE + used_by_device: '' + size_k: 753664 + used_fs: :swap + detected_fs: :swap + mount: swap + mountby: :uuid + fstopt: defaults + uuid: 3fc06e37-d6b6-4411-baf3-2920cdf19fa4 + nr: 1 + fsid: 130 + fstype: Linux swap + region: + - 0 + - 94 + type: :primary + - device: "/dev/vdb2" + name: vdb2 + used_by: + - type: :UB_BTRFS + device: 862e2cbf-0501-48a1-85a3-142bfe3ab51b + used_by_type: :UB_BTRFS + used_by_device: 862e2cbf-0501-48a1-85a3-142bfe3ab51b + size_k: 13925376 + used_fs: :btrfs + detected_fs: :btrfs + fstopt: defaults + nr: 2 + fsid: 131 + fstype: Linux native + region: + - 93 + - 1734 + type: :primary + boot: true + subvol: + - name: shared + - name: www + uuid: 862e2cbf-0501-48a1-85a3-142bfe3ab51b + mount: "/srv" + mountby: :uuid + size_k: 14680064 + cyl_size: 8225280 + cyl_count: 1827 + sector_size: 512 + label: msdos + name: vdb + max_logical: 255 + max_primary: 4 + type: :CT_DISK + transport: :unknown + used_by_type: :UB_NONE + used_by_device: '' + dasd_format: 0 + dasd_type: 0 +"/dev/btrfs": + device: "/dev/btrfs" + name: btrfs + used_by_type: :UB_NONE + used_by_device: '' + type: :CT_BTRFS + partitions: [] +"/dev/tmpfs": + device: "/dev/tmpfs" + name: tmpfs + used_by_type: :UB_NONE + used_by_device: '' + type: :CT_TMPFS + partitions: + - device: tmpfs + name: none + used_by_type: :UB_NONE + used_by_device: '' + size_k: 233312 + used_fs: :tmpfs + detected_fs: :tmpfs + mount: "/dev/shm" + mountby: :uuid + ignore_fstab: true + type: :tmpfs + fstype: TMPFS + - device: tmpfs + name: none + used_by_type: :UB_NONE + used_by_device: '' + size_k: 233312 + used_fs: :tmpfs + detected_fs: :tmpfs + mount: "/run" + mountby: :uuid + ignore_fstab: true + type: :tmpfs + fstype: TMPFS + - device: tmpfs + name: none + used_by_type: :UB_NONE + used_by_device: '' + size_k: 233312 + used_fs: :tmpfs + detected_fs: :tmpfs + mount: "/sys/fs/cgroup" + mountby: :uuid + ignore_fstab: true + type: :tmpfs + fstype: TMPFS + - device: tmpfs + name: none + used_by_type: :UB_NONE + used_by_device: '' + size_k: 46664 + used_fs: :tmpfs + detected_fs: :tmpfs + mount: "/run/user/0" + mountby: :uuid + ignore_fstab: true + type: :tmpfs + fstype: TMPFS \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/test/storage_test.rb new/yast2-storage-3.2.0/test/storage_test.rb --- old/yast2-storage-3.1.105/test/storage_test.rb 2016-10-24 14:04:10.000000000 +0200 +++ new/yast2-storage-3.2.0/test/storage_test.rb 2016-11-04 17:06:56.000000000 +0100 @@ -8,14 +8,23 @@ Yast.import "StorageInit" describe "Yast::Storage" do + subject { Yast::Storage } + before do - Yast::Storage.InitLibstorage(false) + subject.InitLibstorage(false) end describe "#SetUserdata" do it "sets given user data for a given device" do # non-zero error for device that does not exist - expect(Yast::Storage.SetUserdata("/dev/ice/does/not/exist", { "/" => "snapshots" })).not_to eq(0) + expect(subject.SetUserdata("/dev/ice/does/not/exist", { "/" => "snapshots" })).not_to eq(0) + end + end + + describe "#default_subvolume_name" do + it "returns the default subvolume name according to FileSystems" do + expect(Yast::FileSystems).to receive(:default_subvol).and_return("SOME-VALUE") + expect(subject.default_subvolume_name).to eq("SOME-VALUE") end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-storage-3.1.105/test/subvol_test.rb new/yast2-storage-3.2.0/test/subvol_test.rb --- old/yast2-storage-3.1.105/test/subvol_test.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-storage-3.2.0/test/subvol_test.rb 2016-11-04 17:06:56.000000000 +0100 @@ -0,0 +1,190 @@ +#!/usr/bin/env rspec + +require_relative "spec_helper" +require "storage/subvol" +Yast.import "Arch" + + +describe Yast::StorageClass::Subvol do + + context "#new" do + let(:current_arch) { Yast::Arch.arch_short } + + describe "Simple subvol with defaults" do + subject { Yast::StorageClass::Subvol.new("var/spool") } + + it "has the correct path" do + expect(subject.path).to be == "var/spool" + end + + it "is COW" do + expect(subject.cow?).to be true + end + + it "is not arch-specific" do + expect(subject.arch_specific?).to be false + end + + it "matches arch 'fake'" do + expect(subject.matches_arch?("fake")).to be true + end + end + + describe "NoCOW subvol" do + subject { Yast::StorageClass::Subvol.new("var/lib/mysql", copy_on_write: false) } + + it "is NoCOW" do + expect(subject.no_cow?).to be true + end + + it "is not arch-specific" do + expect(subject.arch_specific?).to be false + end + end + + describe "simple arch-specific subvol" do + subject { Yast::StorageClass::Subvol.new("boot/grub2/fake-arch", archs: ["fake-arch"]) } + + it "is arch specific" do + expect(subject.arch_specific?).to be true + end + + it "does not match the current arch" do + expect(subject.current_arch?).to be false + end + end + + describe "arch-specific subvol for current arch" do + subject { Yast::StorageClass::Subvol.new("boot/grub2/fake-arch", archs: ["fake-arch", current_arch]) } + + it "is arch specific" do + expect(subject.arch_specific?).to be true + end + + it "matches the current arch" do + expect(subject.current_arch?).to be true + end + end + + describe "arch-specific subvol for everything except the current arch" do + subject { Yast::StorageClass::Subvol.new("boot/grub2/fake-arch", archs: ["!#{current_arch}"]) } + + it "does not match the current arch" do + expect(subject.current_arch?).to be false + end + end + end + + context ".create_from_xml" do + describe "Fully specified subvol" do + subject do + xml = { "path" => "var/fake", "copy_on_write" => false, "archs" => "fake, ppc, ! foo" } + Yast::StorageClass::Subvol.create_from_xml( xml ) + end + + it "has the correct path" do + expect(subject.path).to be == "var/fake" + end + + it "is NoCOW" do + expect(subject.no_cow?).to be true + end + + it "is tolerant against whitespace in the archs list" do + expect(subject.archs).to be == ["fake", "ppc", "!foo"] + end + + it "matches arch 'fake'" do + expect(subject.matches_arch?("fake")).to be true + end + + it "matches arch 'ppc'" do + expect(subject.matches_arch?("ppc")).to be true + end + + it "does not match arch 'foo'" do + expect(subject.matches_arch?("foo")).to be false + end + + it "does not match arch 'bar'" do + expect(subject.matches_arch?("bar")).to be false + end + + end + + describe "Minimalistic subvol" do + subject do + xml = { "path" => "var/fake" } + Yast::StorageClass::Subvol.create_from_xml( xml ) + end + + it "has the correct path" do + expect(subject.path).to be == "var/fake" + end + + it "is COW" do + expect(subject.cow?).to be true + end + + it "is not arch-specific" do + expect(subject.arch_specific?).to be false + end + + it "matches arch 'fake'" do + expect(subject.matches_arch?("fake")).to be true + end + end + end + + context "#<=>" do + let(:a) { Yast::StorageClass::Subvol.new("aaa") } + let(:b) { Yast::StorageClass::Subvol.new("bbb") } + let(:c) { Yast::StorageClass::Subvol.new("ccc") } + + describe "Sorting subvol arrays" do + subject { [b, c, a].sort } + it "sorts by path" do + expect(subject[0].path).to be == "aaa" + expect(subject[1].path).to be == "bbb" + expect(subject[2].path).to be == "ccc" + end + end + end + + context ".fallback_list" do + let(:fallbacks) { Yast::StorageClass::Subvol.fallback_list } + + describe "var/cache subvolume" do + subject { fallbacks.find { |subvol| subvol.path == "var/cache" } } + + it "is in the fallback list" do + expect(subject).not_to be_nil + end + + it "is COW" do + expect(subject.cow?).to be true + end + + it "is not arch-specific" do + expect(subject.arch_specific?).to be false + end + end + + describe "var/lib/mariadb subvolume" do + subject { fallbacks.find { |subvol| subvol.path == "var/lib/mariadb" } } + + it "is in the fallback list" do + expect(subject).not_to be_nil + end + + it "is NoCOW" do + expect(subject.no_cow?).to be true + end + + it "is not arch-specific" do + expect(subject.arch_specific?).to be false + end + end + end + +end