tag 746125 patch
thanks

On Thu, Sep 04, 2014 at 11:35:58PM +0100, Dominic Hargreaves wrote:

> Unhandled error: [DBD::SQLite::st execute failed: attempt to write a readonly 
> database at /usr/share/perl5/Wiki/Toolkit/Store/Database.pm line 567.

This can be reduced to the attached script, which succeeds for me on
wheezy but fails on sid. I think it's a bug in the tests, which first
make a database connection and then remove the database file from
underneath it.

Older combinations of SQLite / DBD::SQLite are apparently more
tolerant. From the SQLite 3.8.3 changelog:

 Add SQLITE_READONLY_DBMOVED error code, returned at the beginning of
 a transaction, to indicate that the underlying database file has been
 renamed or moved out from under SQLite.

This is what shines through in the above message.

It's a bit surprising that this ever worked. It looks like the new
DBI->connect for a different database handle somehow used to reset the
behaviour for the first handle too. If I omit the second DBI->connect
in the test script, I get 
  DBD::SQLite::db do failed: disk I/O error
on wheezy, which matches my expectations better.

Now, the fix for openguides is to call OpenGuides::Test::refresh_db()
before OpenGuides->new(), which connects to the database and caches the
connection handle. Patch attached, this makes the test suite pass for me.
-- 
Niko Tyni   nt...@debian.org
#!/usr/bin/perl -w
use strict;
use DBI;

my $dbh = DBI->connect("dbi:SQLite:dbname=t.db", { PrintError => 1, RaiseError => 1})
    or die("connect failed");

$dbh->do('create table t (name varchar)')
    or die("create failed");

$dbh->do("INSERT INTO t (name) VALUES ('old');")
    or die("insert old failed");

unlink 't.db'
    or die("unlink failed");

my $dbh2 = DBI->connect("dbi:SQLite:dbname=t.db", { PrintError => 1, RaiseError => 1})
    or die("second connect failed");

$dbh->do("INSERT INTO t (name) VALUES ('new');")
    or die("insert new failed");

print "finished successfully\n";
>From b36e14a8df59fb13f066d68230a00d29991daa41 Mon Sep 17 00:00:00 2001
From: Niko Tyni <nt...@debian.org>
Date: Sun, 14 Sep 2014 19:37:40 +0300
Subject: [PATCH] Refresh the database before caching a connection handle to it

OpenGuides->new() caches a connection to the SQLite database.  When
OpenGuides::Test::refresh_db() is called, it removes the database file
and reconnects to it. If that happens after OpenGuides->new(), the cached
handle becomes read-only as of SQLite 3.8.3. From its changelog:

 Add SQLITE_READONLY_DBMOVED error code, returned at the beginning of
 a transaction, to indicate that the underlying database file has been
 renamed or moved out from under SQLite.

This causes test failures with error messages like

Unhandled error: [DBD::SQLite::st execute failed: attempt to write a readonly database at /usr/share/perl5/Wiki/Toolkit/Store/Database.pm line 567.
] at /usr/share/perl5/Wiki/Toolkit.pm line 849.

Moving the refresh_db() call earlier fixes these failures.
---
 t/109_autocreate.t                  | 6 +++---
 t/802_stylesheet.t                  | 6 +++---
 t/809_recent_changes_ip_addr.t      | 6 +++---
 t/900_css_category_locale_classes.t | 6 +++---
 t/901_username_in_templates.t       | 6 +++---
 t/902_node_name_from_cgi_obj.t      | 6 +++---
 t/903_redirect_without_spaces.t     | 6 +++---
 t/904_leaflet.t                     | 6 +++---
 t/905_multiple_index.t              | 6 +++---
 t/907_auto_map_link.t               | 6 +++---
 t/908_custom_node_location_search.t | 6 +++---
 t/909_external_class_metadata.t     | 6 +++---
 12 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/t/109_autocreate.t b/t/109_autocreate.t
index 7c44f18..b9a1f19 100644
--- a/t/109_autocreate.t
+++ b/t/109_autocreate.t
@@ -14,6 +14,9 @@ if ( $@ ) {
 
 plan tests => 13;
 
+# Clear out the database from any previous runs.
+OpenGuides::Test::refresh_db();
+
 my $config = OpenGuides::Test->make_basic_config;
 $config->custom_template_path( cwd . "/t/templates/" );
 my $guide = OpenGuides->new( config => $config );
@@ -21,9 +24,6 @@ my $wiki = $guide->wiki;
 my $categoriser = Wiki::Toolkit::Plugin::Categoriser->new;
 $wiki->register_plugin( plugin => $categoriser );
 
-# Clear out the database from any previous runs.
-OpenGuides::Test::refresh_db();
-
 # Check that unwelcome characters are stripped from autocreated cats/locales.
 # Double spaces:
 OpenGuides::Test->write_data(
diff --git a/t/802_stylesheet.t b/t/802_stylesheet.t
index 9a76518..5bda3bb 100644
--- a/t/802_stylesheet.t
+++ b/t/802_stylesheet.t
@@ -18,13 +18,13 @@ if ( $@ ) {
 
 plan tests => 3;
 
+# Clear out the database from any previous runs.
+OpenGuides::Test::refresh_db();
+
 my $config = OpenGuides::Test->make_basic_config;
 my $guide = OpenGuides->new( config => $config );
 my $wiki = $guide->wiki;
 
-# Clear out the database from any previous runs.
-OpenGuides::Test::refresh_db();
-
 # Write a node.
 OpenGuides::Test->write_data( guide => $guide, node => "Red Lion",
                               return_output => 1 );
diff --git a/t/809_recent_changes_ip_addr.t b/t/809_recent_changes_ip_addr.t
index a1ad33a..e2ba127 100644
--- a/t/809_recent_changes_ip_addr.t
+++ b/t/809_recent_changes_ip_addr.t
@@ -14,13 +14,13 @@ if ( $@ ) {
 
 plan tests => 10;
 
+# Clear out the database from any previous runs.
+OpenGuides::Test::refresh_db();
+
 my $config = OpenGuides::Test->make_basic_config;
 my $guide = OpenGuides->new( config => $config );
 my $wiki = $guide->wiki;
 
-# Clear out the database from any previous runs.
-OpenGuides::Test::refresh_db();
-
 # First we need to make sure that the preferences are accessible
 # from the recent changes view.  Can't test this using return_tt_vars
 # because the prefs TT var is set in OpenGuides::Template->output(),
diff --git a/t/900_css_category_locale_classes.t b/t/900_css_category_locale_classes.t
index 00bfc01..13ab74c 100644
--- a/t/900_css_category_locale_classes.t
+++ b/t/900_css_category_locale_classes.t
@@ -18,13 +18,13 @@ if ( $@ ) {
 
 plan tests => 3;
 
+# Clear out the database from any previous runs.
+OpenGuides::Test::refresh_db();
+
 my $config = OpenGuides::Test->make_basic_config;
 $config->custom_template_path( cwd . "/t/templates/" );
 my $guide = OpenGuides->new( config => $config );
 
-# Clear out the database from any previous runs.
-OpenGuides::Test::refresh_db();
-
 # Check that a node in one locale and one category has CSS classes for both.
 OpenGuides::Test->write_data(
                               guide => $guide,
diff --git a/t/901_username_in_templates.t b/t/901_username_in_templates.t
index 2ae32bb..128ec16 100644
--- a/t/901_username_in_templates.t
+++ b/t/901_username_in_templates.t
@@ -14,13 +14,13 @@ if ( $@ ) {
 
 plan tests => 2;
 
+# Clear out the database from any previous runs.
+OpenGuides::Test::refresh_db();
+
 my $config = OpenGuides::Test->make_basic_config;
 $config->custom_template_path( cwd . "/t/templates/tmp/" );
 my $guide = OpenGuides->new( config => $config );
 
-# Clear out the database from any previous runs.
-OpenGuides::Test::refresh_db();
-
 # Write a node.
 OpenGuides::Test->write_data(
                               guide => $guide,
diff --git a/t/902_node_name_from_cgi_obj.t b/t/902_node_name_from_cgi_obj.t
index acb1d4a..431664a 100644
--- a/t/902_node_name_from_cgi_obj.t
+++ b/t/902_node_name_from_cgi_obj.t
@@ -13,13 +13,13 @@ if ( $@ ) {
 
 plan tests => 18;
 
+# Clear out the database from any previous runs.
+OpenGuides::Test::refresh_db();
+
 my $config = OpenGuides::Test->make_basic_config;
 my $guide = OpenGuides->new( config => $config );
 my $wiki = $guide->wiki;
 
-# Clear out the database from any previous runs.
-OpenGuides::Test::refresh_db();
-
 # Write a node.
 OpenGuides::Test->write_data(
                               guide => $guide,
diff --git a/t/903_redirect_without_spaces.t b/t/903_redirect_without_spaces.t
index a3b40c4..72fe398 100644
--- a/t/903_redirect_without_spaces.t
+++ b/t/903_redirect_without_spaces.t
@@ -13,13 +13,13 @@ if ( $@ ) {
 
 plan tests => 27;
 
+# Clear out the database from any previous runs.
+OpenGuides::Test::refresh_db();
+
 my $config = OpenGuides::Test->make_basic_config;
 my $guide = OpenGuides->new( config => $config );
 my $wiki = $guide->wiki;
 
-# Clear out the database from any previous runs.
-OpenGuides::Test::refresh_db();
-
 # Write a couple of nodes, one with a single-word name, one with multiple.
 OpenGuides::Test->write_data(
                               guide => $guide,
diff --git a/t/904_leaflet.t b/t/904_leaflet.t
index 71732a0..a7d83b8 100644
--- a/t/904_leaflet.t
+++ b/t/904_leaflet.t
@@ -16,14 +16,14 @@ my $thc = $@ ? 0 : 1;
 
 plan tests => 25;
 
+# Clear out the database from any previous runs.
+OpenGuides::Test::refresh_db();
+
 my $config = OpenGuides::Test->make_basic_config;
 $config->static_url( "http://example.com/static"; );
 my $guide = OpenGuides->new( config => $config );
 my $wiki = $guide->wiki;
 
-# Clear out the database from any previous runs.
-OpenGuides::Test::refresh_db();
-
 # Write a couple of nodes, two with legitimate geodata, another with
 # broken geodata, another with no geodata.
 OpenGuides::Test->write_data(
diff --git a/t/905_multiple_index.t b/t/905_multiple_index.t
index 2900b22..ccfa450 100644
--- a/t/905_multiple_index.t
+++ b/t/905_multiple_index.t
@@ -19,13 +19,13 @@ if ( $@ ) {
 
 plan tests => 18;
 
+# Clear out the database from any previous runs.
+OpenGuides::Test::refresh_db();
+
 my $config = OpenGuides::Test->make_basic_config;
 my $guide = OpenGuides->new( config => $config );
 my $wiki = $guide->wiki;
 
-# Clear out the database from any previous runs.
-OpenGuides::Test::refresh_db();
-
 # Write some nodes.
 OpenGuides::Test->write_data(
                               guide         => $guide,
diff --git a/t/907_auto_map_link.t b/t/907_auto_map_link.t
index f356544..db72c2f 100644
--- a/t/907_auto_map_link.t
+++ b/t/907_auto_map_link.t
@@ -14,14 +14,14 @@ if ( $@ ) {
 
 plan tests => 10;
 
+# Clear out the database from any previous runs.
+OpenGuides::Test::refresh_db();
+
 my $config = OpenGuides::Test->make_basic_config;
 $config->custom_template_path( cwd . "/t/templates/tmp/" );
 my $guide = OpenGuides->new( config => $config );
 my $wiki = $guide->wiki;
 
-# Clear out the database from any previous runs.
-OpenGuides::Test::refresh_db();
-
 # Write a couple of nodes, one with a map link and another
 # without; also with/without address
 # NOTE: the node with neither address nor map link 
diff --git a/t/908_custom_node_location_search.t b/t/908_custom_node_location_search.t
index a2c02a6..2cc004f 100644
--- a/t/908_custom_node_location_search.t
+++ b/t/908_custom_node_location_search.t
@@ -14,14 +14,14 @@ if ( $@ ) {
 
 plan tests => 3;
 
+# Clear out the database from any previous runs.
+OpenGuides::Test::refresh_db();
+
 my $config = OpenGuides::Test->make_basic_config;
 $config->custom_template_path( cwd . "/t/templates/tmp/" );
 my $guide = OpenGuides->new( config => $config );
 my $wiki = $guide->wiki;
 
-# Clear out the database from any previous runs.
-OpenGuides::Test::refresh_db();
-
 # Write a couple of nodes, one with a map link and another
 # without; also with/without address
 # NOTE: the node with neither address nor map link 
diff --git a/t/909_external_class_metadata.t b/t/909_external_class_metadata.t
index ed14703..d3e3df9 100644
--- a/t/909_external_class_metadata.t
+++ b/t/909_external_class_metadata.t
@@ -14,13 +14,13 @@ if ( $@ ) {
 
 plan tests => 2;
 
+# Clear out the database from any previous runs.
+OpenGuides::Test::refresh_db();
+
 my $config = OpenGuides::Test->make_basic_config;
 my $guide = OpenGuides->new( config => $config );
 my $wiki = $guide->wiki;
 
-# Clear out the database from any previous runs.
-OpenGuides::Test::refresh_db();
-
 # Write out a node with a map link and external website
 OpenGuides::Test->write_data(
                               guide         => $guide,
-- 
2.1.0

Reply via email to