Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unit tests for autoyast profile validation methods #12316

Merged
merged 3 commits into from
Apr 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 40 additions & 5 deletions lib/autoyast.pm
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,42 @@ so hashes and arrays in the yaml should represent nodes in the xml file.
Generates a list of XPATH expressions based on the YAML file provided, run those
expressions and create a summary based with the errors found and all the expressions.

See function 'generate_expressions' for further info.
There are special keys to handle xml attributes for the node types, or in case
exact number of nodes has to be validated, e.g. C<_t> for the type, C<__text> for
the text value of the node, C<__count> to specify exact number of child nodes.

See 'has_properties' and 'generate_expressions' functions for the further info.

In order to validate following xml:
<profile>
<suse_register t="map">
<addons t="list">
<addon t="map">
<name>sle-module-server-applications</name>
</addon>
<addon t="map">
<arch>ppc64le</arch>
<name>sle-module-basesystem</name>
</addon>
</addons>
<do_registration t="boolean">true</do_registration>
<install_updates t="boolean">false</install_updates>
</suse_register>
</profile>

YAML example to validate given xml:
profile:
suse_register:
addons:
_t: list
__count: 2
addon:
- name: sle-module-server-applications
- name: sle-module-basesystem
do_registration:
_t: boolean
__text: 'true'


=cut
sub validate_autoyast_profile {
Expand Down Expand Up @@ -290,18 +325,18 @@ sub is_processable {

YAML:
drive:
- label:
- label:
_descendant: any
__text: root_multi_btrfs
disklabel: none
partitions:
partition:
- filesystem: btrfs
label: root_multi_btrfs
- label:
- label:
_descendant: any
__text: test_multi_btrfs
disklabel: none
disklabel: none
partitions:
partition:
- filesystem: btrfs
Expand All @@ -323,7 +358,7 @@ sub has_properties {

create_xpath_predicate($node);

Based on the properties of the node will create a predicate for the XPATH expression.
Based on the properties of the node will create a predicate for the XPATH expression.

=cut
sub create_xpath_predicate {
Expand Down
90 changes: 90 additions & 0 deletions t/06_autoyast.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use strict;
use warnings;

use File::Basename;
use Test::More;
use Test::MockModule;
use Test::Warnings;
use YAML::PP;

use autoyast;


subtest 'ns' => sub {
is autoyast::ns('node'), 'ns:node';
};

subtest 'has_properties' => sub {
ok !autoyast::has_properties('scalar'), 'Test if node is scalar';
ok !autoyast::has_properties(undef), 'Test if node is undef';
ok autoyast::has_properties({_t => 'boolean'}), 'Test if type property _t is detected';
ok autoyast::has_properties({__text => 'value'}), 'Test if text value property _text is detected';
ok autoyast::has_properties({__count => 2}), 'Test if number of children node value property __count is detected';
ok autoyast::has_properties({_descendant => 'any'}), 'Test if look for descendant node value property _descendant is detected';
ok autoyast::has_properties({_t => 'boolean', __text => 'true', __count => 2}), 'Test if multiple properties are defined';
};

subtest 'close_predicate' => sub {
is autoyast::close_predicate('/book/title'), '[/book/title]', 'Test single predicate';
is autoyast::close_predicate(('/title/lotr', '/author/tolkien')), '[/title/lotr and /author/tolkien]', 'Test multiple predicates';
};

subtest 'get_descendant' => sub {
is autoyast::get_descendant({_descendant => 'any'}), './/', 'Test when _descendant property is defined';
is autoyast::get_descendant({_descendant => undef}), '', 'Test when _descendant property is not defined';
is autoyast::get_descendant('scalar'), '', 'Test when _descendant property is scalar';
};

subtest 'get_traversable' => sub {
is autoyast::get_traversable([]), undef, 'Expect undef if is an array';
is autoyast::get_traversable(0), undef, 'Expect undef if is a scalar';
is autoyast::get_traversable({root => {node => 'value'}}), 'root', 'Expect root if child is a hash';
};

subtest 'is_processable' => sub {
ok autoyast::is_processable({__text => 'true'}), 'Test key pair node with property';
ok autoyast::is_processable('scalar'), 'Test scalar';
ok !autoyast::is_processable({name => 'test'}), 'Test simple key pair node';
ok !autoyast::is_processable([{__text => '1'}, {__text => '2'}]), 'Test array of hashes';
};

subtest 'create_xpath_predicate' => sub {
is autoyast::create_xpath_predicate('test'), "[text()='test']", 'Test simple text';
is autoyast::create_xpath_predicate(''), '[not(text())]', 'Test empty text search';
is autoyast::create_xpath_predicate({_t => 'boolean', __text => 'false'}), '[text()=\'false\' and @t=\'boolean\']', 'Test node with _t and __text properties';
is autoyast::create_xpath_predicate({__count => 2, child => [1, 2]}), '[count(ns:child)=2]', 'Test node with count defined for the child node';
};

subtest 'generate_expressions' => sub {
my @rez = autoyast::generate_expressions({node => 'value'});
is_deeply \@rez, ["/ns:node[text()='value']"];
@rez = autoyast::generate_expressions([{name => "Andy"}, {name => 'Mary'}]);
is_deeply \@rez, ["[ns:name[text()='Andy']]", "[ns:name[text()='Mary']]"];
@rez = autoyast::generate_expressions({root => {__text => 'true', _t => 'boolean'}});
is_deeply \@rez, ['/ns:root[text()=\'true\' and @t=\'boolean\']'];
@rez = autoyast::generate_expressions({names => [{name => "Andy"}, {name => 'Mary'}]});
is_deeply \@rez, ["/ns:names[ns:name[text()='Andy']]", "/ns:names[ns:name[text()='Mary']]"];
@rez = autoyast::generate_expressions({root => {__count => 2, _t => 'list', child => ['item1', 'item2']}});
is_deeply \@rez, ['/ns:root[@t=\'list\' and count(ns:child)=2]', "/ns:root/ns:child[text()='item1']", "/ns:root/ns:child[text()='item2']"];
};

subtest 'validate_autoyast_profile' => sub {
# Load autoyast profile xml
my $input_xml = dirname(__FILE__) . '/data/autoyast_profile.xml';
open my $fh, '<', $input_xml or die "error opening $input_xml: $!";
my $xml = do { local $/; <$fh> };
# Load expectations being set in yaml
my $ypp = YAML::PP->new(schema => ['Core', 'Merge']);
my $yaml = $ypp->load_file(dirname(__FILE__) . '/data/autoyast_profile.yaml');
# Mock methods which use testapi
my $autoyast_mock = Test::MockModule->new('autoyast');
# Mock method which returns xml from the SUT
$autoyast_mock->redefine("init_autoyast_profile", sub { return $xml; });
# Mock testapi call inside of validate_autoyast_profile
$autoyast_mock->redefine("record_info", sub { my ($title, $output) = @_; print("$title\n$output"); });
# Test that profile validates
eval { autoyast::validate_autoyast_profile($yaml) };
ok !$@;
};

done_testing;
17 changes: 17 additions & 0 deletions t/data/autoyast_profile.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE profile>
<profile xmlns="http://www.suse.com/1.0/yast2ns" xmlns:config="http://www.suse.com/1.0/configns">
<suse_register t="map">
<addons t="list">
<addon t="map">
<name>sle-module-server-applications</name>
</addon>
<addon t="map">
<arch>ppc64le</arch>
<name>sle-module-basesystem</name>
</addon>
</addons>
<do_registration t="boolean">true</do_registration>
<install_updates t="boolean">false</install_updates>
</suse_register>
</profile>
13 changes: 13 additions & 0 deletions t/data/autoyast_profile.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
suse_register:
addons:
_t: list
__count: 2
addon:
- name: sle-module-server-applications
- name: sle-module-basesystem
do_registration:
_t: boolean
__text: 'true'
install_updates:
_t: boolean
__text: 'false'