diff --git a/service/lib/agama/storage/config_conversions/from_model_conversions/filesystem.rb b/service/lib/agama/storage/config_conversions/from_model_conversions/filesystem.rb index 069bb613b2..d30091a985 100644 --- a/service/lib/agama/storage/config_conversions/from_model_conversions/filesystem.rb +++ b/service/lib/agama/storage/config_conversions/from_model_conversions/filesystem.rb @@ -49,7 +49,7 @@ def conversions # @return [Configs::FilesystemType, nil] def convert_type filesystem_model = model_json[:filesystem] - return if !filesystem_model || filesystem_model[:default] + return if filesystem_model.nil? FromModelConversions::FilesystemType.new(filesystem_model).convert end diff --git a/service/lib/agama/storage/config_conversions/from_model_conversions/filesystem_type.rb b/service/lib/agama/storage/config_conversions/from_model_conversions/filesystem_type.rb index d6b7466f6c..04a7565985 100644 --- a/service/lib/agama/storage/config_conversions/from_model_conversions/filesystem_type.rb +++ b/service/lib/agama/storage/config_conversions/from_model_conversions/filesystem_type.rb @@ -44,7 +44,7 @@ def default_config # @return [Hash] def conversions { - default: false, + default: filesystem_model[:default], fs_type: convert_type, btrfs: convert_btrfs } @@ -53,6 +53,8 @@ def conversions # @return [Y2Storage::Filesystems::Type, nil] def convert_type value = filesystem_model[:type] + return unless value + Y2Storage::Filesystems::Type.find(value.to_sym) end diff --git a/service/lib/agama/storage/config_conversions/from_model_conversions/size.rb b/service/lib/agama/storage/config_conversions/from_model_conversions/size.rb index 29a0859fed..9805acb0bf 100644 --- a/service/lib/agama/storage/config_conversions/from_model_conversions/size.rb +++ b/service/lib/agama/storage/config_conversions/from_model_conversions/size.rb @@ -43,7 +43,7 @@ def default_config # @return [Hash] def conversions { - default: false, + default: size_model[:default], min: convert_min_size, max: convert_max_size } @@ -57,10 +57,10 @@ def convert_min_size disk_size(value) end - # @return [Y2Storage::DiskSize, nil] + # @return [Y2Storage::DiskSize] def convert_max_size value = size_model[:max] - return unless value + return Y2Storage::DiskSize.unlimited unless value disk_size(value) end diff --git a/service/lib/agama/storage/config_conversions/from_model_conversions/with_filesystem.rb b/service/lib/agama/storage/config_conversions/from_model_conversions/with_filesystem.rb index 6eedb6093f..46853c16e1 100644 --- a/service/lib/agama/storage/config_conversions/from_model_conversions/with_filesystem.rb +++ b/service/lib/agama/storage/config_conversions/from_model_conversions/with_filesystem.rb @@ -29,6 +29,8 @@ module FromModelConversions module WithFilesystem # @return [Configs::Filesystem, nil] def convert_filesystem + return unless model_json[:mountPath] || model_json[:filesystem] + FromModelConversions::Filesystem.new(model_json).convert end end diff --git a/service/lib/agama/storage/config_conversions/from_model_conversions/with_size.rb b/service/lib/agama/storage/config_conversions/from_model_conversions/with_size.rb index 2fa8008122..23e7a3686c 100644 --- a/service/lib/agama/storage/config_conversions/from_model_conversions/with_size.rb +++ b/service/lib/agama/storage/config_conversions/from_model_conversions/with_size.rb @@ -33,7 +33,7 @@ def convert_size return Configs::Size.new_for_shrink_if_needed if model_json[:resizeIfNeeded] size_model = model_json[:size] - return if size_model.nil? || size_model[:default] + return if size_model.nil? FromModelConversions::Size.new(size_model).convert end diff --git a/service/lib/agama/storage/configs/size.rb b/service/lib/agama/storage/configs/size.rb index b584c00711..98cc1f1645 100644 --- a/service/lib/agama/storage/configs/size.rb +++ b/service/lib/agama/storage/configs/size.rb @@ -19,6 +19,8 @@ # To contact SUSE LLC about this file by physical or electronic mail, you may # find current contact information at www.suse.com. +require "y2storage/disk_size" + module Agama module Storage module Configs @@ -30,7 +32,7 @@ class Size def self.new_for_shrink_if_needed new.tap do |config| config.default = false - config.min = 0 + config.min = Y2Storage::DiskSize.zero end end diff --git a/service/test/agama/storage/config_conversions/from_model_test.rb b/service/test/agama/storage/config_conversions/from_model_test.rb new file mode 100644 index 0000000000..77141cdcd6 --- /dev/null +++ b/service/test/agama/storage/config_conversions/from_model_test.rb @@ -0,0 +1,738 @@ +# frozen_string_literal: true + +# Copyright (c) [2024] 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 SUSE LLC. +# +# To contact SUSE LLC about this file by physical or electronic mail, you may +# find current contact information at www.suse.com. + +require_relative "../../../test_helper" +require "agama/config" +require "agama/storage/config_conversions" +require "y2storage/encryption_method" +require "y2storage/filesystems/mount_by_type" +require "y2storage/filesystems/type" +require "y2storage/pbkd_function" +require "y2storage/refinements" + +using Y2Storage::Refinements::SizeCasts + +shared_examples "without alias" do |config_proc| + it "does not set #alias" do + config = config_proc.call(subject.convert) + expect(config.alias).to be_nil + end +end + +shared_examples "without filesystem" do |config_proc| + it "does not set #filesystem" do + config = config_proc.call(subject.convert) + expect(config.filesystem).to be_nil + end +end + +shared_examples "without ptableType" do |config_proc| + it "does not set #ptable_type" do + config = config_proc.call(subject.convert) + expect(config.ptable_type).to be_nil + end +end + +shared_examples "without partitions" do |config_proc| + it "sets #partitions to the expected value" do + config = config_proc.call(subject.convert) + expect(config.partitions).to eq([]) + end +end + +shared_examples "without size" do |config_proc| + it "sets #size to default size" do + config = config_proc.call(subject.convert) + expect(config.size.default?).to eq(true) + expect(config.size.min).to be_nil + expect(config.size.max).to be_nil + end +end + +shared_examples "without delete" do |config_proc| + it "sets #delete to false" do + config = config_proc.call(subject.convert) + expect(config.delete?).to eq(false) + end +end + +shared_examples "without deleteIfNeeded" do |config_proc| + it "sets #delete_if_needed to false" do + config = config_proc.call(subject.convert) + expect(config.delete_if_needed?).to eq(false) + end +end + +shared_examples "with name" do |config_proc| + let(:name) { "/dev/vda" } + + it "sets #search to the expected value" do + config = config_proc.call(subject.convert) + expect(config.search).to be_a(Agama::Storage::Configs::Search) + expect(config.search.name).to eq("/dev/vda") + expect(config.search.max).to be_nil + expect(config.search.if_not_found).to eq(:error) + end +end + +shared_examples "with alias" do |config_proc| + let(:device_alias) { "test" } + + it "sets #alias to the expected value" do + config = config_proc.call(subject.convert) + expect(config.alias).to eq("test") + end +end + +shared_examples "with mountPath" do |config_proc| + let(:mountPath) { "/test" } + + it "sets #filesystem to the expected value" do + config = config_proc.call(subject.convert) + filesystem = config.filesystem + expect(filesystem).to be_a(Agama::Storage::Configs::Filesystem) + expect(filesystem.reuse?).to eq(false) + expect(filesystem.type).to be_nil + expect(filesystem.label).to be_nil + expect(filesystem.path).to eq("/test") + expect(filesystem.mount_by).to be_nil + expect(filesystem.mkfs_options).to be_empty + expect(filesystem.mount_options).to be_empty + end +end + +shared_examples "with filesystem" do |config_proc| + context "if the filesystem is default" do + let(:filesystem) do + { + default: true, + type: type, + snapshots: true + } + end + + context "and the type is 'btrfs'" do + let(:type) { "btrfs" } + + it "sets #filesystem to the expected value" do + config = config_proc.call(subject.convert) + filesystem = config.filesystem + expect(filesystem).to be_a(Agama::Storage::Configs::Filesystem) + expect(filesystem.reuse?).to eq(false) + expect(filesystem.type.default?).to eq(true) + expect(filesystem.type.fs_type).to eq(Y2Storage::Filesystems::Type::BTRFS) + expect(filesystem.type.btrfs).to be_a(Agama::Storage::Configs::Btrfs) + expect(filesystem.type.btrfs.snapshots?).to eq(true) + expect(filesystem.label).to be_nil + expect(filesystem.path).to be_nil + expect(filesystem.mount_by).to be_nil + expect(filesystem.mkfs_options).to be_empty + expect(filesystem.mount_options).to be_empty + end + end + + context "and the type is not 'btrfs'" do + let(:type) { "xfs" } + + it "sets #filesystem to the expected value" do + config = config_proc.call(subject.convert) + filesystem = config.filesystem + expect(filesystem).to be_a(Agama::Storage::Configs::Filesystem) + expect(filesystem.reuse?).to eq(false) + expect(filesystem.type.default?).to eq(true) + expect(filesystem.type.fs_type).to eq(Y2Storage::Filesystems::Type::XFS) + expect(filesystem.type.btrfs).to be_nil + expect(filesystem.label).to be_nil + expect(filesystem.path).to be_nil + expect(filesystem.mount_by).to be_nil + expect(filesystem.mkfs_options).to be_empty + expect(filesystem.mount_options).to be_empty + end + end + end + + context "if the filesystem is not default" do + let(:filesystem) do + { + default: false, + type: type, + snapshots: true + } + end + + context "and the type is 'btrfs'" do + let(:type) { "btrfs" } + + it "sets #filesystem to the expected value" do + config = config_proc.call(subject.convert) + filesystem = config.filesystem + expect(filesystem).to be_a(Agama::Storage::Configs::Filesystem) + expect(filesystem.reuse?).to eq(false) + expect(filesystem.type.default?).to eq(false) + expect(filesystem.type.fs_type).to eq(Y2Storage::Filesystems::Type::BTRFS) + expect(filesystem.type.btrfs).to be_a(Agama::Storage::Configs::Btrfs) + expect(filesystem.type.btrfs.snapshots?).to eq(true) + expect(filesystem.label).to be_nil + expect(filesystem.path).to be_nil + expect(filesystem.mount_by).to be_nil + expect(filesystem.mkfs_options).to be_empty + expect(filesystem.mount_options).to be_empty + end + end + + context "and the type is not 'btrfs'" do + let(:type) { "xfs" } + + it "sets #filesystem to the expected value" do + config = config_proc.call(subject.convert) + filesystem = config.filesystem + expect(filesystem).to be_a(Agama::Storage::Configs::Filesystem) + expect(filesystem.reuse?).to eq(false) + expect(filesystem.type.default?).to eq(false) + expect(filesystem.type.fs_type).to eq(Y2Storage::Filesystems::Type::XFS) + expect(filesystem.type.btrfs).to be_nil + expect(filesystem.label).to be_nil + expect(filesystem.path).to be_nil + expect(filesystem.mount_by).to be_nil + expect(filesystem.mkfs_options).to be_empty + expect(filesystem.mount_options).to be_empty + end + end + end + + context "if the filesystem does not specify 'type'" do + let(:filesystem) { { default: false } } + + it "sets #filesystem to the expected value" do + config = config_proc.call(subject.convert) + filesystem = config.filesystem + expect(filesystem).to be_a(Agama::Storage::Configs::Filesystem) + expect(filesystem.reuse?).to eq(false) + expect(filesystem.type.default?).to eq(false) + expect(filesystem.type.fs_type).to be_nil + expect(filesystem.type.btrfs).to be_nil + expect(filesystem.label).to be_nil + expect(filesystem.path).to be_nil + expect(filesystem.mount_by).to be_nil + expect(filesystem.mkfs_options).to eq([]) + expect(filesystem.mount_options).to eq([]) + end + end +end + +shared_examples "with mountPath and filesystem" do |config_proc| + let(:mountPath) { "/test" } + + let(:filesystem) do + { + default: false, + type: "btrfs", + snapshots: true + } + end + + it "sets #filesystem to the expected value" do + config = config_proc.call(subject.convert) + filesystem = config.filesystem + expect(filesystem).to be_a(Agama::Storage::Configs::Filesystem) + expect(filesystem.reuse?).to eq(false) + expect(filesystem.type.default?).to eq(false) + expect(filesystem.type.fs_type).to eq(Y2Storage::Filesystems::Type::BTRFS) + expect(filesystem.type.btrfs).to be_a(Agama::Storage::Configs::Btrfs) + expect(filesystem.type.btrfs.snapshots?).to eq(true) + expect(filesystem.label).to be_nil + expect(filesystem.path).to eq("/test") + expect(filesystem.mount_by).to be_nil + expect(filesystem.mkfs_options).to be_empty + expect(filesystem.mount_options).to be_empty + end +end + +shared_examples "with ptableType" do |config_proc| + let(:ptableType) { "gpt" } + + it "sets #ptable_type to the expected value" do + config = config_proc.call(subject.convert) + expect(config.ptable_type).to eq(Y2Storage::PartitionTables::Type::GPT) + end +end + +shared_examples "with size" do |config_proc| + context "if the size is default" do + let(:size) do + { + default: true, + min: 1.GiB.to_i, + max: 10.GiB.to_i + } + end + + it "sets #size to the expected value" do + config = config_proc.call(subject.convert) + size = config.size + expect(size).to be_a(Agama::Storage::Configs::Size) + expect(size.default?).to eq(true) + expect(size.min).to eq(1.GiB) + expect(size.max).to eq(10.GiB) + end + end + + context "if the size is not default" do + let(:size) do + { + default: false, + min: 1.GiB.to_i, + max: 10.GiB.to_i + } + end + + it "sets #size to the expected value" do + config = config_proc.call(subject.convert) + size = config.size + expect(size).to be_a(Agama::Storage::Configs::Size) + expect(size.default?).to eq(false) + expect(size.min).to eq(1.GiB) + expect(size.max).to eq(10.GiB) + end + end + + context "if the size does not spicify 'max'" do + let(:size) do + { + default: false, + min: 1.GiB.to_i + } + end + + it "sets #size to the expected value" do + config = config_proc.call(subject.convert) + size = config.size + expect(size).to be_a(Agama::Storage::Configs::Size) + expect(size.default?).to eq(false) + expect(size.min).to eq(1.GiB) + expect(size.max).to eq(Y2Storage::DiskSize.unlimited) + end + end +end + +shared_examples "with resizeIfNeeded" do |config_proc| + context "if 'resizeIfNeeded' is true" do + let(:resizeIfNeeded) { true } + + it "sets #size to the expected value" do + config = config_proc.call(subject.convert) + size = config.size + expect(size).to be_a(Agama::Storage::Configs::Size) + expect(size.default?).to eq(false) + expect(size.min).to eq(Y2Storage::DiskSize.zero) + expect(size.max).to be_nil + end + end + + context "if 'resizeIfNeeded' is false" do + let(:resizeIfNeeded) { false } + + it "sets #size to the expected value" do + config = config_proc.call(subject.convert) + size = config.size + expect(size).to be_a(Agama::Storage::Configs::Size) + expect(size.default?).to eq(true) + expect(size.min).to be_nil + expect(size.max).to be_nil + end + end +end + +shared_examples "with size and resizeIfNeeded" do |config_proc| + let(:size) do + { + default: true, + min: 1.GiB.to_i, + max: 10.GiB.to_i + } + end + + context "if 'resizeIfNeeded' is true" do + let(:resizeIfNeeded) { true } + + it "sets #size to the expected value" do + config = config_proc.call(subject.convert) + size = config.size + expect(size).to be_a(Agama::Storage::Configs::Size) + expect(size.default?).to eq(false) + expect(size.min).to eq(Y2Storage::DiskSize.zero) + expect(size.max).to be_nil + end + end + + context "if 'resizeIfNeeded' is false" do + let(:resizeIfNeeded) { false } + + it "sets #size to the expected value" do + config = config_proc.call(subject.convert) + size = config.size + expect(size).to be_a(Agama::Storage::Configs::Size) + expect(size.default?).to eq(true) + expect(size.min).to eq(1.GiB) + expect(size.max).to eq(10.GiB) + end + end +end + +shared_examples "with size and resize" do |config_proc| + let(:size) do + { + default: true, + min: 1.GiB.to_i, + max: 10.GiB.to_i + } + end + + context "if 'resize' is true" do + let(:resize) { true } + + it "sets #size to the expected value" do + config = config_proc.call(subject.convert) + size = config.size + expect(size).to be_a(Agama::Storage::Configs::Size) + expect(size.default?).to eq(true) + expect(size.min).to eq(1.GiB) + expect(size.max).to eq(10.GiB) + end + end + + context "if 'size' is false" do + let(:resize) { false } + + it "sets #size to the expected value" do + config = config_proc.call(subject.convert) + size = config.size + expect(size).to be_a(Agama::Storage::Configs::Size) + expect(size.default?).to eq(true) + expect(size.min).to eq(1.GiB) + expect(size.max).to eq(10.GiB) + end + end +end + +shared_examples "with delete" do |config_proc| + it "sets #delete to true" do + config = config_proc.call(subject.convert) + expect(config.delete?).to eq(true) + end +end + +shared_examples "with deleteIfNeeded" do |config_proc| + it "sets #delete_if_needed to true" do + config = config_proc.call(subject.convert) + expect(config.delete_if_needed?).to eq(true) + end +end + +shared_examples "with partitions" do |config_proc| + let(:partitions) do + [ + partition, + { mountPath: "/test" } + ] + end + + let(:partition) { { mountPath: "/" } } + + context "with an empty list" do + let(:partitions) { [] } + + it "sets #partitions to empty" do + config = config_proc.call(subject.convert) + expect(config.partitions).to eq([]) + end + end + + context "with a list of partitions" do + it "sets #partitions to the expected value" do + config = config_proc.call(subject.convert) + partitions = config.partitions + expect(partitions.size).to eq(2) + + partition1, partition2 = partitions + expect(partition1).to be_a(Agama::Storage::Configs::Partition) + expect(partition1.filesystem.path).to eq("/") + expect(partition2).to be_a(Agama::Storage::Configs::Partition) + expect(partition2.filesystem.path).to eq("/test") + end + end + + partition_proc = proc { |c| config_proc.call(c).partitions.first } + + context "if a partition does not specify 'name'" do + let(:partition) { {} } + + it "does not set #search" do + partition = partition_proc.call(subject.convert) + expect(partition.search).to be_nil + end + end + + context "if a partition does not spicify 'alias'" do + let(:partition) { {} } + include_examples "without alias", partition_proc + end + + context "if a partition does not spicify 'id'" do + let(:partition) { {} } + + it "does not set #id" do + partition = partition_proc.call(subject.convert) + expect(partition.id).to be_nil + end + end + + context "if a partition does not spicify 'size'" do + let(:partition) { {} } + include_examples "without size", partition_proc + end + + context "if a partition does not spicify neither 'mountPath' nor 'filesystem'" do + let(:partition) { {} } + include_examples "without filesystem", partition_proc + end + + context "if a partition does not spicify 'delete'" do + let(:partition) { {} } + include_examples "without delete", partition_proc + end + + context "if a partition does not spicify 'deleteIfNeeded'" do + let(:partition) { {} } + include_examples "without deleteIfNeeded", partition_proc + end + + context "if a partition specifies 'name'" do + let(:partition) { { name: name } } + include_examples "with name", partition_proc + end + + context "if a partition specifies 'alias'" do + let(:partition) { { alias: device_alias } } + include_examples "with alias", partition_proc + end + + context "if a partition spicifies 'id'" do + let(:partition) { { id: "esp" } } + + it "sets #id to the expected value" do + partition = partition_proc.call(subject.convert) + expect(partition.id).to eq(Y2Storage::PartitionId::ESP) + end + end + + context "if a partition specifies 'mountPath'" do + let(:partition) { { mountPath: mountPath } } + include_examples "with mountPath", partition_proc + end + + context "if a partition specifies 'filesystem'" do + let(:partition) { { filesystem: filesystem } } + include_examples "with filesystem", partition_proc + end + + context "if a partition specifies both 'mountPath' and 'filesystem'" do + let(:partition) { { mountPath: mountPath, filesystem: filesystem } } + include_examples "with mountPath and filesystem", partition_proc + end + + context "if a partition spicifies 'size'" do + let(:partition) { { size: size } } + include_examples "with size", partition_proc + end + + context "if a partition spicifies 'resizeIfNeeded'" do + let(:partition) { { resizeIfNeeded: resizeIfNeeded } } + include_examples "with resizeIfNeeded", partition_proc + end + + context "if a partition spicifies both 'size' and 'resizeIfNeeded'" do + let(:partition) { { size: size, resizeIfNeeded: resizeIfNeeded } } + include_examples "with size and resizeIfNeeded", partition_proc + end + + context "if a partition spicifies both 'size' and 'resize'" do + let(:partition) { { size: size, resize: resize } } + include_examples "with size and resize", partition_proc + end + + context "if a partition specifies 'delete'" do + let(:partition) { { delete: true } } + include_examples "with delete", partition_proc + end + + context "if a partition specifies 'deleteIfNeeded'" do + let(:partition) { { deleteIfNeeded: true } } + include_examples "with deleteIfNeeded", partition_proc + end +end + +describe Agama::Storage::ConfigConversions::FromModel do + subject do + described_class.new(model_json) + end + + before do + # Speed up tests by avoding real check of TPM presence. + allow(Y2Storage::EncryptionMethod::TPM_FDE).to receive(:possible?).and_return(true) + end + + describe "#convert" do + let(:model_json) { {} } + + it "returns a storage config" do + config = subject.convert + expect(config).to be_a(Agama::Storage::Config) + end + + context "with an empty JSON" do + let(:model_json) { {} } + + it "sets #drives to the expected value" do + config = subject.convert + expect(config.drives).to be_empty + end + end + + context "with a JSON specifying 'drives'" do + let(:model_json) do + { drives: drives } + end + + let(:drives) do + [ + drive, + { name: "/dev/vdb" } + ] + end + + let(:drive) do + { name: "/dev/vda" } + end + + context "with an empty list" do + let(:drives) { [] } + + it "sets #drives to the expected value" do + config = subject.convert + expect(config.drives).to eq([]) + end + end + + context "with a list of drives" do + it "sets #drives to the expected value" do + config = subject.convert + expect(config.drives.size).to eq(2) + expect(config.drives).to all(be_a(Agama::Storage::Configs::Drive)) + + drive1, drive2 = config.drives + expect(drive1.search.name).to eq("/dev/vda") + expect(drive1.partitions).to eq([]) + expect(drive2.search.name).to eq("/dev/vdb") + expect(drive2.partitions).to eq([]) + end + end + + drive_proc = proc { |c| c.drives.first } + + context "if a drive does not specify 'name'" do + let(:drive) { {} } + + it "sets #search to the expected value" do + drive = drive_proc.call(subject.convert) + expect(drive.search).to be_a(Agama::Storage::Configs::Search) + expect(drive.search.name).to be_nil + expect(drive.search.if_not_found).to eq(:error) + end + end + + context "if a drive does not spicify 'alias'" do + let(:drive) { {} } + include_examples "without alias", drive_proc + end + + context "if a drive does not spicify neither 'mountPath' nor 'filesystem'" do + let(:drive) { {} } + include_examples "without filesystem", drive_proc + end + + context "if a drive does not spicify 'ptableType'" do + let(:drive) { {} } + include_examples "without ptableType", drive_proc + end + + context "if a drive does not spicify neither 'spacePolicy' nor 'partitions'" do + let(:drive) { {} } + include_examples "without partitions", drive_proc + end + + context "if a drive specifies 'name'" do + let(:drive) { { name: name } } + include_examples "with name", drive_proc + end + + context "if a drive specifies 'alias'" do + let(:drive) { { alias: device_alias } } + include_examples "with alias", drive_proc + end + + context "if a drive specifies 'mountPath'" do + let(:drive) { { mountPath: mountPath } } + include_examples "with mountPath", drive_proc + end + + context "if a drive specifies 'filesystem'" do + let(:drive) { { filesystem: filesystem } } + include_examples "with filesystem", drive_proc + end + + context "if a drive specifies both 'mountPath' and 'filesystem'" do + let(:drive) { { mountPath: mountPath, filesystem: filesystem } } + include_examples "with mountPath and filesystem", drive_proc + end + + context "if a drive specifies 'ptableType'" do + let(:drive) { { ptableType: ptableType } } + include_examples "with ptableType", drive_proc + end + + context "if a drive specifies 'partitions'" do + let(:drive) { { partitions: partitions } } + include_examples "with partitions", drive_proc + end + + xcontext "if a drive specifies 'spacePolicy'" do + let(:drive) { { partitions: partitions } } + include_examples "with partitions", drive_proc + end + + xcontext "if a drive specifies both 'spacePolicy' and 'partitions'" do + let(:drive) { { partitions: partitions } } + include_examples "with partitions", drive_proc + end + end + end +end