Integration testing the mail dispatching in Laravel 5.1

When using the Mail facade in Laravel it is not so easy to test the output of the parsed mail template. Like http://stackoverflow.com/questions/31120567/unittesting-laravel-5-mail-using-mock I received the error Method Mockery_0__vendor_Swift_Mailer::getTransport() does not exist on this mock object. I ended up in listening to the mailer.sending event:

    public function testRegistrationMailIsSend_afterSubmittingForm()
    {
        // flag for closure has been called
        $mailerAssertionHasBeenCalled = false;

        // receive every Event::fire method and pass the reference from the outer scope into the closure
        Event::shouldReceive('fire')->andReturnUsing(function($event, $params) use (&$mailerAssertionHasBeenCalled) {
            // filter only the mailer.sending event
            if ($event != 'mailer.sending') {
                return;
            }

            // reference will be modified
            $mailerAssertionHasBeenCalled = true;
            // Swift_Message; Illuminate\Mail\Mailer::sendSwiftMessage
            $msg = $params[0];

            $this->assertEquals('Verify your e-mail account', $msg->getSubject());
            $recipients = $msg->getTo();

            $this->assertTrue(array_key_exists('my@domain.com', $recipients));
            $verificationKey = Registration::first()->verification_key;

            // assert registration key is present in parsed template
            $this->assertContains('/registration/verify-email?key=' . $verificationKey, $msg->getBody());
        });

        // visit our registration controller
        $this->visit('/registration')
            ->submitForm('Register', ['email' => 'my@domain.com'])
            ->see('Mail has been sent');

        // make sure that our closure has been called
        $this->assertTrue($mailerAssertionHasBeenCalled);
    }

Seeding the database for integration tests in Laravel

In my last post I wrote about how to define the test environment for database integration tests. Now I want to describe, how the database can be populated with test or stam data.

First of all, every test inherited from the generated TestCase class executes the Artisan migrate command (TestCase::prepareForTests()). The trait Illuminate\Foundation\Testing\DatabaseMigrations is only required, if all tables of the schema have be dropped after the test execution. This could be necessary for system tests in which the whole schema is populated with test data. For “simple” integration tests using transactions should be sufficient.
One word about the traits DatabaseMigrations and DatabaseTransactions: Both are executed by PHPUnit before every test method. PHPUnit scans all methods in the test class for the documentation annotations @before, @after, @beforeClass and @afterClass (PHPUnit_Framework_TestCase::runBare() and PHPUnit_Util_Test::getHookMethods()). The traits both uses the @before annotation to setup the context:

trait DatabaseMigrations
{
    /**
     * ckl: this annotation advises PHPUnit to run the trait before every test case
     * @before
     */
    public function runDatabaseMigrations()
    {
        $this->artisan('migrate');

        $this->beforeApplicationDestroyed(function () {
            $this->artisan('migrate:rollback');
        });
    }
}

With this in mind the seeding of the database can be placed on two different locations. First of all, the non-working approaches. Putting the seeding inside the setUp() or prepareForTests() method does not work, because at runtime there is no active transaction:

    public function setUp() {
        parent::setUp();
        // ckl: wrong place; this method is called on startup. The seeding is outside an active transaction
        // $this->seed('QualificationsTableSeeder');
    }

    public function prepareForTests() {
        $sut = $this->app->make('\App\Services\ExperienceService');
        // ckl: wrong place; this method is called on startup. The seeding is outside an active transaction
        // $this->seed('QualificationsTableSeeder');
    }

Using a pure seeder method with @before does although not work. ReflectionClass::getMethods(), which is used by PHPUnit, returns at first all “native” / non-traited methods and after that the traited methods:

    /**
     * ckl: local methods have higher precedence than traits, so this method is called *before* the DatabaseTransactions trait has been called
     * @before
     */
    public function seedTables() {
        $this->seed('MyTableSeeder');
        $testInstance = factory('App\User')->create();
    }

By starting a transaction inside the seedTables(), we have the seeding inside a running transaction:

    /**
     * @before
     */
    public function seedTables() {
        // already start the transaction and let DatabaseTransactions only rollback the transaction. This does only work on the first test case
        DB::beginTransaction();
        $this->seed('MyTableSeeder');
    }

The rollback is done by the DatabaseTransactions trait. It is no problem having two DB::beginTransaction() calls and only one rollback. MySQL does not allow nested transactions, so Laravel starts only the transaction on the first DB::beginTransaction() call. Every other invoke only increments a counter.
Laravel only executes the rollback, if all DB::rollBack() methods have been called. The seedTables() has to look like

    /**
     * @before
     */
    public function seedTables()
    {
        DB::beginTransaction();

        $this->beforeApplicationDestroyed(function () {
            $this->app->make('db')->rollBack();
        });

        $this->seed('MyTableSeeder');
    }

A much cleaner solution is to call the seedTables() method inside every test case:

    public function seedTables() {
        $this->seed('MyTableSeeder');
    }

    public function testSeeding() {
        // ckl: transaction has been started
        $this->seedTables();

        $this->assertTrue(true);
    }

Test environments for database integration tests in Laravel 5

As far as I have read, in Laravel 4 you could define your database integration test environment by adding a testing/database.php or .env.testing.php file containing your configuiration. In Laravel 5 both ways does no longer work. To switch your environment you have two options:

  1. Put both configuration definitions (testing, dev/production) inside your config/database.php:
        'connections' => [
    
            'sqlite' => [
                'driver' => 'sqlite',
                'database' => storage_path('database.sqlite'),
                'prefix' => '',
            ],
            'mysql' => [
                'driver' => 'mysql',
                'host' => env('DB_HOST', 'localhost'),
                'database' => env('DB_DATABASE', 'schema'),
                'username' => env('DB_USERNAME', 'root'),
                'password' => env('DB_PASSWORD', 'root'),
                'charset' => 'utf8',
                'collation' => 'utf8_unicode_ci',
                'prefix' => '',
                'strict' => false,
            ],
            'mysql_testing' => [
                'driver' => 'mysql',
                'host' => env('DB_HOST_TEST', 'localhost'),
                'database' => env('DB_DATABASE_TEST', 'schema_test'),
                'username' => env('DB_USERNAME_TEST', 'root'),
                'password' => env('DB_PASSWORD_TEST', 'root'),
                'charset' => 'utf8',
                'collation' => 'utf8_unicode_ci',
                'prefix' => '',
                'strict' => false,
            ],
    

    and store the configuration defaults in your .env file by adding the configuration keys DB_HOST_TEST, DB_DATABASE_TEST and so on. Eventually you must modify your base TestCase::createApplication to use the mysql_testing connection:

        /**
         * Creates the application.
         *
         * @return \Illuminate\Foundation\Application
         */
        public function createApplication()
        {
            putenv('DB_CONNECTION', 'mysql_testing');
    
            $app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
    
            return $app;
        }
    
  2. I prefer the second solution: Copy the .env file to .env.testing, modify the settings and override the default Dotenv file .env by modifying your base TestCase::createApplication:
        public function createApplication()
        {
            $app = require __DIR__.'/../bootstrap/app.php';
            // ckl: use .env.testing in favor of .env; clear separation between configuration values and configuration definition
            $app->loadEnvironmentFrom('.env.testing');
    
            $app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
    
            return $app;
    

Using GitHub forks or local Git repositories with Composer

For two weeks I have been heavily developing a new web application based upon Laravel. Tonight I searched for an easy filtering solution like Zend_Filter so that the request strings are automagically trim’d, lowercased, and so on. Lucky me, the repository https://github.com/rmasters/filter is available with a composer.json but latest commit from 2013 is not compatible with Laravel 5.1. The compatibility fix would be trivial: editing two files in the composer.json and it is done. But how can I use my own fork on GitHub or my local cloned repository?

I learned, that I can add a repository reference to the composer.json of my application:

"repositories": [
		{
			"type": "vcs",
			"url": "http://github.com/schakko/filter"
		}
	],

Additionally, I have to specify my development branch which contains the Laravel 5.1 fix (laravel51):

    "require": {
        "php": ">=5.5.9",
        "laravel/framework": "5.1.*",
        "laracasts/flash": "~1.3",
        "cocur/slugify": "dev-master",
        "rmasters/filter": "dev-laravel51"
    },

It is important that the Git branch is named laravel51 and not dev-laravel51, otherwise you will receive an error like

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - The requested package rmasters/filter could not be found in any version, there may be a typo in the package name.

Potential causes:
 - A typo in the package name
 - The package is not available in a stable-enough version according to your minimum-stability setting
   see <https://groups.google.com/d/topic/composer-dev/_g3ASeIFlrc/discussion> for more details.

Read <https://getcomposer.org/doc/articles/troubleshooting.md> for further common problems.

Another neat feature is that Composer supports local repositories without any problems. During testing I changed my repository to

	"repositories": [
		{
			"type": "vcs",
			"url": "c:/ckl/projects/github/filter"
		}
	],

and had no longer to push my changes to the remote repository. The code has to be committed to local branch, of course.

Using Subselects with CQL in CMDBuilds “filter” type properties

CMDBuild supports the usage of SQL queries inside the “filter” options if the type is a REFERENCE.

Given:

  • A lookup table named “Software Type” [{Code: DBMS}, {Code: App}]
  • A class Application [{Code: MySQL, Type: DBMS}, {Code: PostgreSQL, Type: DBMS}, {Code: Tomcat, Type: App}]; “Type” references the lookup table “Software Type”
  • A class ApplicationRelease [{Code: “MySQL 5.0″, Application: MySQL}, {Code: “PostgreSQL 9.x”, Application “PostgreSQL”}, {Code: “Tomcat 7.0″, Application “Tomcat”}]; “Application” is a foreign key to the Application class.
  • A class DbmsInstance with a reference/foreign key to ApplicationRelease

Target:

  • By adding/modifying a DbmsInstance, only ApplicationReleases shall be shown which are of type “DBMS”.

How to solve this by using a subselect:

from ApplicationRelease where Id (/(
  SELECT "Id" FROM "ApplicationRelease" WHERE "Application" IN 
	(SELECT "Id" FROM "Application" WHERE "Type" = 
		(SELECT "Id" FROM "LookUp" WHERE "Code"='DBMS')
	)
)/)

Please note, that every referenced column must be quoted with double quotes. Every value of WHERE clause must be quoted using single quotes only!
The (/(…)/) construct introduces plain SQL.

Trying to install CMDBuild and receiving an ORMException “ORM_GENERIC_ERROR”

CMDBuild is a free (“free” as in GPL v2) ITIL solution. The installation of the 2.3.1 version has been a pain in the ass. After applying the database information in the setup wizard, I always received an org.cmdbuild.exception.ORMException: ORM_GENERIC_ERROR. CMDBuild stores its log files (cmdbuild.log, cmdbuild_dd_sql.log) in the “logs” folder of Tomcat where I could find the root cause for this issue. Our PostgreSQL instance is installed on a Windows machine and holds two database templates. template0 has UTF-8 default encoding, template1 uses WIN-1252. During the installation of the database schema of CMDBuild, the template1 is used. The WIN-1252 encoding of template1 is not compatible with the used UTF-8 encoding of CMDBuild/Java. I fixed this issue by re-creating the template1 schema with UTF-8:


DROP DATABASE template1;
CREATE DATABASE template1 WITH template = template0 ENCODING = 'UTF8';
UPDATE pg_database SET datistemplate = TRUE WHERE datname = 'template1';

The next time I hit the install button of the wizard, I received another ORM_GENERIC_ERROR. This time the log stated that the plpgsql language was missing for template1. I altered the template1 by issuing a “CREATE LANGUAGE plpgsql”. After that I was able to install CMDBuild.

Unattended installation of Windows Server 2012 R2 in VirtualBox and getting an 0x80042565 error

Today I struggled with a working configuration for an autounattend.xml for 9600.17050.WINBLUE_REFRESH.140317-1640_X64FRE_SERVER_EVAL_DE-DE-IR3_SSS_X64FREE_DE-DE_DV9.ISO (Windows Server 2012 R2, Standard, Standard Core, Datacenter and Datacenter Core). The unattended installation inside VirtualBox always failed with an error 0x80042565 or did not use the partition scheme I had previously provided.

I suppose that the problem occured in the first place because of the disabled UEFI of my VM. The usage of the following DiskConfiguration section installs Win2K12 R2 correctly:

https://gist.github.com/schakko/d5df24a2aab89e5e7ed0

Dell XPS 15, Linux and HiDPI

A few weeks ago I bought a new notebook (Dell XPS 15, 15″, 512 GByte SSD, Core i7) for my after-work work and home usage. First of all: it is an awesome fast piece of hardware. Fedora 21 boots up in 3 seconds, Eclipse (STS) starts up in around 7 seconds. But it has some disadvantages regarding the hardware:

  • Having the laptop on the lap bends the case, randomly not releasing the buttons, see http://en.community.dell.com/support-forums/laptop/f/3518/t/19601453
  • At the beginning backspace and space key felt like already used. I must admit that I am using a mechanical keyboard at work and for my standalone PC at home, so every other rubber keyboard sucks 😉
  • Return key feels slightly too small at the beginning.
  • High pitching noise, probably coming from the touchscreen. Most of the time it occurs during scrolling through long documents and having CPU load. I am not sure why this happens.

Especially the problem with the non-releasable buttons drove me crazy at first because it seemed to occur randomly. After some days working with the notebook I accepted this failure. All in all it seems to be a very nice notebook for a developer like me, but…

… The HiDPI support for Linux software just sucks. Linus Torvald statement made his statement at the end of 2012 but the current state is still bad:

  • Default Chromium package has no support for HiDPI; buttons and menus have the wrong scaling. Firefox does support HiDPI and so I set it as my default browser.
  • Scaling of some GTK input fields (radio buttons, checkbox) is wrong, see https://bugzilla.mozilla.org/show_bug.cgi?id=975919
  • Using a second display (beamer) totally screws up the X server. I can’t  get a higher resolution than 800*600 when cloning both displays. Not sure, why this happens.
  • IntelliJ (including EAP 14), Eclipse (4.4) and Netbeans (8.x) are having wrong scaled icons. See wiki discussion for Eclipse at https://wiki.eclipse.org/Bug_421383_-_Graphics_Scaling_issues_on_high_DPI_displays

For a list of workarounds, the ArchWiki is the first place to look for.

Fixing gratuitous ARP requests

Due to some internal network problems I fired up Wireshark and saw a lot of gratuitous ARP requests/broadcasts. I had never seen the sending MAC or IP before but could assign it to one the ports our switching hardware. The designated port was used for a Citrix XenServer virtualization environment, so at first I suspected a miconfiguration of one of the bonds and some looping ARP packets. This assumption was wrong: I shutted down the server and the ARP requests still came from the physical network interface, so it could only be a problem/configuration of the interface itself.

I googled for “intel gratuitious ARP” and found the answer: the Intel NIC had an IPMI module and was sending announcements but the GUI was disabled.
Fixing the problem was easy. I ssh’ed into to the Citrix XenServer and used the ipmitool to disable the ARP sending mechanism:

modprobe ipmi_devintf; modprobe ipmi_si
ipmitool -d /dev/ipmi0 lan set 1 arp generate off

Second Hackcamp Wolfsburg – December 2014

Last Saturday our second Hackcamp Wolfsburg in 2014 took place. In the run-up to the Hackcamp I had suggested to use the NeosIT office as the event location. @stevenschwenke agreed to that and so I prepared our office on Friday evening. Before the event I expected a team programming session but in the end I explained (too?) much about the Spring Framework and showed samples, use cases and technical approaches to solve different problems with the framework.

Nevertheless it was an enjoyable circle consisting of Steven, Karsten, Sven, Nikolai, Daniel, Kevin, Tobse and me. Besides the usual software development topics we talked about TV series and net political issues. For lunch time we had ordered pizza and Steven bought a lot of juice and fruit. And certainly we had a lot of Club Mate available.

I am really looking forward to the next Hackcamp in 2015 – thank you for the participation and patience 😉