Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 20,820,001 milliseconds ago. The last packet sent successfully to the server was 20,820,002 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.
at sun.reflect.GeneratedConstructorAccessor29.newInstance(Unknown Source) ~[na:na]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.7.0_51]
at java.lang.reflect.Constructor.newInstance(Constructor.java:526) ~[na:1.7.0_51]
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411) ~[mysql-connector-java-5.1.29.jar:na]
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1129) ~[mysql-connector-java-5.1.29.jar:na]
at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3988) ~[mysql-connector-java-5.1.29.jar:na]
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2598) ~[mysql-connector-java-5.1.29.jar:na]
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2778) ~[mysql-connector-java-5.1.29.jar:na]
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2828) ~[mysql-connector-java-5.1.29.jar:na]
at com.mysql.jdbc.ConnectionImpl.setAutoCommit(ConnectionImpl.java:5372) ~[mysql-connector-java-5.1.29.jar:na]
at com.mchange.v2.c3p0.impl.NewProxyConnection.setAutoCommit(NewProxyConnection.java:881) ~[c3p0-0.9.1.1.jar:0.9.1.1]
at org.quartz.impl.jdbcjobstore.AttributeRestoringConnectionInvocationHandler.setAutoCommit(AttributeRestoringConnectionInvocationHandler.java:98) ~[quartz-2.2.1.jar:na]
注:本文试验环境为Red Hat Enterprise Linux AS release 4 (Nahant Update 5),shell为/bin/bash,不同的OS和shell可能命令有些不一样。例如AIX的ksh,没有disown,但是可以使用nohup -p PID来获得disown同样的效果。
4. disown
如果我们未加任何处理就已经提交了命令,这时想加 nohup 或者 setsid 已经为时已晚,只能通过作业调度和 disown 来解决这个问题了。让我们来看一下 disown 的帮助信息:
disown [-ar] [-h] [jobspec …]
Without options, each jobspec is removed from the table of
active jobs. If the -h option is given, each jobspec is not
removed from the table, but is marked so that SIGHUP is not
sent to the job if the shell receives a SIGHUP. If no jobspec
is present, and neither the -a nor the -r option is supplied,
the current job is used. If no jobspec is supplied, the -a
option means to remove or mark all jobs; the -r option without
a jobspec argument restricts operation to running jobs. The
return value is 0 unless a jobspec does not specify a valid
job.
可以看出,我们可以用如下方式来达成我们的目的。
a. 用disown -h jobspec 来使某个作业忽略HUP信号。
b. 用disown -ah 来使所有的作业都忽略HUP信号。
c. 用disown -rh 来使正在运行的作业忽略HUP信号。
需要注意的是,当使用过 disown 之后,会将把目标作业从作业列表中移除,我们将不能再使用jobs来查看它,但是依然能够用ps -ef查找到它。
但是还有一个问题,这种方法的操作对象是作业,如果我们在运行命令时在结尾加了”&”来使它成为一个作业并在后台运行,那么就万事大吉了,我们可以通过jobs命令来得到所有作业的列表。但是如果并没有把当前命令作为作业来运行,如何才能得到它的作业号呢?答案就是用 CTRL-z(按住Ctrl键的同时按住z键)了!
CTRL-z 的用途就是将当前进程挂起(Suspend),然后我们就可以用jobs命令来查询它的作业号,再用bg jobspec 来将它放入后台并继续运行。需要注意的是,如果挂起会影响当前进程的运行结果,慎用此方法。
示例:
root@ubuntu-server:/mnt/ftp# jobs
[1]+ Running ./sync_mirror.sh &
root@ubuntu-server:/mnt/ftp# disown -h %1
root@ubuntu-server:/mnt/ftp# ps -ef|grep sync_mirror.sh
root 8650 22271 0 15:08 pts/0 00:00:00 grep sync_mirror.sh
root 16748 22271 0 Mar31 pts/0 00:00:00 /bin/sh -e ./sync_mirror.sh
Update: Things are all change in Zend Framework 1.8, so this may require some adaptation in that version.
If you’ve followed the Zend Framework quickstart tutorial like me, you may be wondering how to perform unit testing using it. The tutorial does set up the bootstrap file to allow for unit testing, but does not cover unit testing itself. The aim of this post is to provide a quick guide to unit testing using the quickstart application, which will hopefully come in useful for a few people and myself when I inevitably forget this later on.
Step 0: Before Starting
First, you should download and set up the guestbook application from the Zend Framework website. Make sure you place the Zend library in the library folder and enable the read/write permissions for the sqlite database and the db directory for access by the web server.
You will also want to install pear and, with it, install PHPUnit:
pear channel-discover pear.phpunit.de
pear install phpunit/PHPUnit
Step 1: Create Test Folders
Create a folder called “tests” in the root folder of the application. Inside that create a folder called “controllers” and “models”. The directory structure should be as follows:
zendquickstart
|-- application
|-- data
|-- library
|-- public
|-- scripts
`--tests
|-- controllers
`-- models
All your controller tests should go in the controllers folder, all your model tests should go in the models folder.
Step 2: Create Test Configuration
Create the file TestConfiguration.php in the tests folder. This file will initially set up the testing configuration, inside place the following code:
<?php// Gets called when this file is included/required
TestConfiguration::setUp();classTestConfiguration{/**
* Sets the environment up for testing
*/staticfunctionsetUp(){// Set the environment constant to testing which will load the testing
// configuration in app.ini by the bootstrap
define('APPLICATION_ENVIRONMENT','testing');// Set the include path for locating the Zend library
set_include_path(realpath(dirname(__FILE__)).'/../library'.PATH_SEPARATOR.get_include_path());// Use Autoload so that we don't have to include/require every class
require_once"Zend/Loader.php";Zend_Loader::registerAutoload();}staticfunctionsetUpDatabase(){require'../application/bootstrap.php';$db=Zend_Registry::get('configuration')->database->params->dbname;// delete any pre-existing databases
if(file_exists($db))unlink($db);// run the database set up script to recreate the database
require'../scripts/load.sqlite.php';}}?>
The setUp() function in this class will get called when the file is included or required. The APPLICATION_ENVIRONMENT constant is set to ‘testing’ so that the testing section of the app.ini file is read in the bootstrap, and the testing database is used. A testing database should be used so that testing does not interfere with the production or development databases, and no important data is lost. The next step is to set the include path, which should contain the location of the Zend Framework library. The final step is to enable the Zend autoloader so that we don’t have to explicitly require/include the Zend libraries.
The setUpDatabase() function resets the database to a known state. When the tests are run we may wish to insert data to the database and this should be removed before every new test. We require the bootstrap file so we can get the database configuration and delete the database file, which is an easy way to reset an SQLite database. A different method will be necessary for other databases like MySQL or PostgreSQL. Finally, the setUpDatabase() function uses a script which comes with the quick start application to (re)create the database.
Step 3: Creating Controller Tests
To test the IndexController, create the file IndexControllerTest.php in the tests/controller directory. The following is a simple example:
<?php// Set up the testing environment
require'TestConfiguration.php';classcontrollers_IndexControllerTestextendsZend_Test_PHPUnit_ControllerTestCase{// Bootstraps the application
public$bootstrap='../application/bootstrap.php';publicfunctiontestHomePageIsASuccessfulRequest(){// Runs the test on /, the homepage
$this->dispatch('/');// Tests there are no exceptions on the home page
$this->assertFalse($this->response->isException());// Tests for redirection to the error handler
$this->assertNotRedirect();}publicfunctiontestHomePageDisplaysCorrectContent(){// Runs the test on /
$this->dispatch('/');// Tests the page title is present
$this->assertQueryContentContains('div#header-logo','ZF Quickstart Application');// Tests the guestbook link is present
$this->assertQueryContentContains('a','Guestbook');}}?>
This is a very basic controller test. First note that you should extend Zend_Test_PHPUnit_ControllerTestCase for controller tests. This class extends PHPUnit_Framework_TestCase itself, but adds some assertions and other things specific to Zend Framework.
The bootstrap instance variable must be set in order to test the controller, and in this case it points to the location of the bootstrap file.
The testHomePageIsASuccessfulRequest() test is used to test that the homepage functions correctly; it should not contain any exceptions or redirect to the error controller. If it does then there is a problem somewhere and the test fails. The testHomePageDisplaysCorrectContent() is used to test that the page title and the link to the guestbook is present.
Step 4: Creating Model Tests
To test the GuestBook model, create the file GuestBookTest.php in tests/models.
<?phprequire'TestConfiguration.php';require'../application/models/GuestBook.php';classmodels_GuestBookTestextendsPHPUnit_Framework_TestCase{publicfunctionsetUp(){// Reset database state
TestConfiguration::setUpDatabase();}publicfunctiontestFetchEntries(){// Instantiate the GuestBook model
$guestBook=newModel_GuestBook();// Get all entries from the database
$entries=$guestBook->fetchEntries();// Test that there are 2 entries in the guestbook
$this->assertSame(2,count($entries));}}?>
Again, this is very basic. The setUp() function gets called by PHPUnit before the test is run, and it will reset the database. The testFetchEntries() function tests the fetchEntries() function in the model. Two rows in the guestbook table should be present, therefore there should be two elements in the array returned by fetchEntries().
Step 5: Edit load.sqlite.php
You may find it annoying to have to wait 5 seconds between model tests when the database is recreated. I worked around this problem by making a small change to the PHP script which loads the database schema:
1
2
3
4
5
6
7
8
9
<?phpif(APPLICATION_ENVIRONMENT!='testing'){echo'Writing Database Guestbook in (control-c to cancel): '.PHP_EOL;for($x=5;$x>0;$x--){echo$x."\r";sleep(1);}}?>
If the application environment is not testing then the timeout should not be displayed. You may prefer to simply remove the timeout altogether. Additionally, you will need to change the lines that locate the SQL files to include dirname(FILE):
To run the tests, navigate to the tests directory in a terminal/CMD, and type phpunit controllers_IndexControllerTest and models_GuestBookTest to test the IndexController and GuestBook model, respectively.
phpunit controllers_IndexControllerTest
PHPUnit 3.3.14 by Sebastian Bergmann.
..
Time: 0 seconds
OK (2 tests, 4 assertions)
phpunit models_GuestBookTest
PHPUnit 3.3.14 by Sebastian Bergmann.
Database Created
Data Loaded.
.
Time: 0 seconds
OK (1 test, 1 assertion)
Conclusion
There you have it. This isn’t necessarily the only way or the best way to perform unit testing, this is merely the way I got it to work with the quickstart application having had no prior experience with PHPUnit. Any suggestions or improvements are welcome.