From c4d39b7a09088f980313888cf1a6eb98c8a76358 Mon Sep 17 00:00:00 2001 From: Alessandro Vullo <avullo@ebi.ac.uk> Date: Thu, 9 May 2013 15:34:20 +0000 Subject: [PATCH] [ENSCORESW-411]. Test cases asserting previous version schema plus patches equals current table.sql --- modules/t/schemaPatches.t | 247 ++++++++++++++++++++++++++++++-------- 1 file changed, 195 insertions(+), 52 deletions(-) diff --git a/modules/t/schemaPatches.t b/modules/t/schemaPatches.t index 2a7658e3f5..e90303acac 100644 --- a/modules/t/schemaPatches.t +++ b/modules/t/schemaPatches.t @@ -1,6 +1,7 @@ use strict; use warnings; +use Data::Dumper; use Test::More; use Bio::EnsEMBL::ApiVersion qw/software_version/; @@ -11,36 +12,16 @@ use File::Spec::Functions qw/updir catfile catdir/; use File::Temp qw/tempfile/; use FindBin qw/$Bin/; -#Assume if ensembl.org is down then there is no point in continuing with the tests (1 shot) -sub test_ensembl { - my $content = eval { do_GET('http://www.ensembl.org', 1); }; - my $success = 1; - if($@) { - note 'ensembl.org is unreachable. Cannot continue with tests'; - $success = 0; - } - return $success; -} - -sub get_url { - my ($url) = @_; - my $content = eval { do_GET($url, 5, 0.5); }; - return $content if defined $content; - diag $@; - fail("We do not have access to HTTP::Tiny or LWP. Cannot continue") if $@; - return; -} SKIP: { my $ensembl_ok = test_ensembl(); skip 'Cannot communicate with ensembl.org. We cannot continue with the tests', 1 unless $ensembl_ok; - #Get last DB version and download the last SQL schema + # Get last DB version and download last SQL schema my $current_release = software_version(); my $last_release = $current_release - 1; - my $cvs_url = "http://cvs.sanger.ac.uk/cgi-bin/viewvc.cgi/ensembl/sql/table.sql?root=ensembl&view=co&pathrev=branch-ensembl-${last_release}"; - my $table_sql = get_url($cvs_url); + my $last_table_sql = get_table_sql($last_release); # Get patch location my $sql_dir = catdir($Bin, updir(), updir(), 'sql'); @@ -51,50 +32,212 @@ SKIP: { } }, $sql_dir); - skip 'Skipping DB patch tests as we cannot find the SQL at URL '.$cvs_url, (scalar(@patches)+1) unless defined $table_sql; + skip "Skipping DB patch tests as we cannot find the SQL for release $last_release", (scalar(@patches)+1) + unless defined $last_table_sql; my $db = Bio::EnsEMBL::Test::MultiTestDB->new(); my $dba = $db->get_DBAdaptor('core'); my $dbc = $dba->dbc(); - my $new_db_name = $db->create_db_name('schemapatchestemp'); + # Create last release DB + my $patched_db_name = $db->create_db_name('schemapatchestemp'); + note 'Creating database ' . $patched_db_name; + $dba->dbc()->do("create database $patched_db_name"); + + # Load last release's schema my ($fh, $sql_schema_file) = tempfile(); - print $fh $table_sql; + print $fh $last_table_sql; close $fh; + my $loaded_schema = load_sql($dbc, $patched_db_name, $sql_schema_file); - #Create DB + skip 'Skipping DB patch tests as we cannot load the last release schema into a database', scalar(@patches) + unless $loaded_schema; + + # Create last release DB + my $current_table_sql = get_table_sql($current_release); + skip "Skipping DB patch tests as we cannot find the SQL for release $current_release", (scalar(@patches)+1) + unless defined $current_table_sql; + + my $current_db_name = $db->create_db_name('schematemp'); + note 'Creating database ' . $current_db_name; + $dba->dbc()->do("create database $current_db_name"); + + # Load current release's schema + ($fh, $sql_schema_file) = tempfile(); + print $fh $current_table_sql; + close $fh; + $loaded_schema = load_sql($dbc, $current_db_name, $sql_schema_file); - note 'Creating database '.$new_db_name; - $dba->dbc()->do("create database $new_db_name"); + skip 'Skipping DB patch tests as we cannot load current release schema into a database', scalar(@patches) + unless $loaded_schema; + + # Now apply all current patches + foreach my $patch (@patches) { + # Get the number of patch entries before applying next patch + my $previous_patches = get_num_patches($dbc, $patched_db_name); + + note "Applying patch $patch"; + load_sql($dbc, $patched_db_name, $patch); + check_after_patch($dbc, $patched_db_name, $previous_patches); + } + + # check the two schemas after applying the patch + compare_after_patches($dbc, $patched_db_name, $current_db_name); - # Load SQL subroutine - my $load_sql = sub { - my ($path) = @_; - my %args = ( host => $dbc->host(), port => $dbc->port(), user => $dbc->username(), password => $dbc->password()); - my $cmd_args = join(q{ }, map { "--${_}=$args{$_}" } keys %args); - my $cmd = "mysql $cmd_args $new_db_name < $path 2>&1"; - my $output = `$cmd`; - my $ec = ($? >> 8); - if($ec != 0) { - note($output); - return fail("MySQL command failed with error code '$ec'"); - } - return pass("MySQL was able to load the file $path core schema"); - }; + note 'Dropping database ' . $patched_db_name; + $dba->dbc()->do("drop database if exists $patched_db_name"); + note 'Dropping database ' . $current_db_name; + $dba->dbc()->do("drop database if exists $current_db_name"); +} + +done_testing(); + +# Compare source schema with target after a series of patches +sub compare_after_patches { + my ($dbc, $source_schema, $target_schema) = @_; + + # compare source/target schema type/version + $dbc->do("use $target_schema"); + my $sql_helper = $dbc->sql_helper; + my ($target_schema_type, $target_schema_version) = + ($sql_helper->execute_single_result(-SQL => "select meta_value from meta where meta_key='schema_type'"), + $sql_helper->execute_single_result(-SQL => "select meta_value from meta where meta_key='schema_version'")); + + $dbc->do("use $source_schema"); + my ($source_schema_type, $source_schema_version) = + ($sql_helper->execute_single_result(-SQL => "select meta_value from meta where meta_key='schema_type'"), + $sql_helper->execute_single_result(-SQL => "select meta_value from meta where meta_key='schema_version'")); + + is($source_schema_type, $target_schema_type, "Schema type after patches"); + is($source_schema_version, $target_schema_version, "Schema version after patches"); - #Load last release's schema - my $loaded_schema = $load_sql->($sql_schema_file); + # Check if the patch meta value does not contain line breaks + my $patch_meta_values_with_newlines = + $sql_helper->execute_simple(-SQL => "select meta_value from meta where meta_key='patch' and meta_value like '%\n%'"); + is(scalar @{$patch_meta_values_with_newlines}, 0, "No line breaks in patch meta values"); + + # check the two schemas contain the same tables + my $source_tables = get_table_names($dbc, $source_schema); + my $target_tables = get_table_names($dbc, $target_schema); + my $diff = (union_intersection_difference($source_tables, $target_tables))[2]; + is(scalar @{$diff}, 0, "Same table set"); - skip 'Skipping DB patch tests as we cannot load the last release schema into a database', scalar(@patches) unless $loaded_schema; + # check each table has the same definition in both schemas + map { is(get_create_table($dbc, $source_schema, $_), + get_create_table($dbc, $target_schema, $_), + "Table $_ definition")} + @{$source_tables}; + +} + +# Get the name of all tables of a certain schema +sub get_table_names { + my ($dbc, $schema_name) = @_; + $dbc->do("use $schema_name"); + + return + $dbc->sql_helper->execute_simple(-SQL => 'show tables'); +} + +# Get the create table SQL statement +sub get_create_table { + my ($dbc, $schema_name, $table_name) = @_; + $dbc->do("use $schema_name"); + my $sql_helper = $dbc->sql_helper; + + my $create_table = $sql_helper->execute( + -SQL => "show create table $table_name", + -CALLBACK => sub { + return (shift @_)->[1]; + } + )->[0]; - #Now apply all current patches - foreach my $patch (@patches) { - note "Applying patch $patch"; - $load_sql->($patch); + # stripping AUTOINCREMENT=? definitions in the way since + # they are allowed to be different + $create_table =~ s/AUTO_INCREMENT=\d+?//; + + return $create_table; +} + +# Check source schema after applying one patch +sub check_after_patch { + my ($dbc, $source_schema, $num_previous_patches) = @_; + + # see if after patch we gain a meta key corresponding to the applied patch + my $num_current_patches = get_num_patches($dbc, $source_schema); + is($num_current_patches, $num_previous_patches + 1, "Source schema gains patch meta key after patch"); +} + +# Get the number of patches applied +sub get_num_patches { + my ($dbc, $schema) = @_; + $dbc->do("use $schema"); + my $sql_helper = $dbc->sql_helper; + + return + $sql_helper->execute_single_result(-SQL => "select count(*) from meta where meta_key='patch' and species_id is NULL"); +} + +# Load SQL subroutine +sub load_sql { + my ($dbc, $dbname, $path) = @_; + my %args = ( host => $dbc->host(), port => $dbc->port(), user => $dbc->username(), password => $dbc->password()); + my $cmd_args = join(q{ }, map { "--${_}=$args{$_}" } keys %args); + my $cmd = "mysql $cmd_args $dbname < $path 2>&1"; + my $output = `$cmd`; + my $ec = ($? >> 8); + if($ec != 0) { + note($output); + return fail("MySQL command failed with error code '$ec'"); } + return pass("MySQL was able to load the file $path core schema"); +} + +# Get table.sql for a given Ensembl release +sub get_table_sql { + my $release = shift; + $release = $release == software_version()?'HEAD':"branch-ensembl-${release}"; - note 'Dropping database '.$new_db_name; - $dba->dbc()->do("drop database if exists $new_db_name"); + my $cvs_url = "http://cvs.sanger.ac.uk/cgi-bin/viewvc.cgi/ensembl/sql/table.sql?root=ensembl&view=co&pathrev=${release}"; + + return get_url($cvs_url); } -done_testing(); \ No newline at end of file +# Assume if ensembl.org is down then there is no point in continuing with the tests (1 shot) +sub test_ensembl { + my $content = eval { do_GET('http://www.ensembl.org', 1); }; + my $success = 1; + if($@) { + note 'ensembl.org is unreachable. Cannot continue with tests'; + $success = 0; + } + return $success; +} + +sub get_url { + my ($url) = @_; + my $content = eval { do_GET($url, 5, 0.5); }; + return $content if defined $content; + diag $@; + fail("We do not have access to HTTP::Tiny or LWP. Cannot continue") if $@; + return; +} + +# Computing Union, Intersection, or Difference of Unique Lists +sub union_intersection_difference { + my ($a, $b) = @_; + + my (@union, @isect, @diff); + my %count = (); + foreach my $e (@$a, @$b) { $count{$e}++ } + + foreach my $e (keys %count) { + push(@union, $e); + if ($count{$e} == 2) { + push @isect, $e; + } else { + push @diff, $e; + } + } + return (\@union, \@isect, \@diff); +} -- GitLab