Jasmine-Matchers – Adding more common matchers to Jasmine.

Jasmine-Matchers is a library of test assertion matchers for a range of common use-cases, to improve the readability of tests written using the Jasmine testing framework.

Installation

Install the package

npm install karma-jasmine-matchers --save-dev

And configure it in karma.conf in the frameworks section

frameworks: ['jasmine', 'jasmine-matchers’],

To use the additional matchers also in protractor e2e, protractor should be configured to import the ‘jasmine-expect’ module before the tests run. That can be done in the protractor.conf.js like this:

onPrepare: function () {
// Import additional jasmine matchers
require('jasmine-expect’);
}

Usage

The list of additional matchers is available here https://github.com/JamieMason/Jasmine-Matchers#matchers

Examples

Examples of unit test refactors using new matchers

toBeArrayOfSize
– expect(clients.length).toBe(2);
+ expect(clients).toBeArrayOfSize(2);

and instead of failing like this
Expected 1 to be 2.
when it fails, the new matcher look like this:
Expected [ Object({ id: ‘client-id’, name: ‘A Client’ }) ] to be array of size 2.

toBeEmptyString
– expect(vm.getCategory({})).toBe(‘’);
Expected ‘Test’ to be ‘’
+ expect(vm.getCategory({})).toBeEmptyString();
Expected ‘Test’ to be empty string.

– expect(vm.projectsFilter.name).toEqual(‘’);
Expected ‘Test’ to be ‘’
+ expect(vm.projectsFilter.name).toBeEmptyString();;
Expected ‘Test’ to be empty string.

toBeEmptyObject
– expect(data).toEqual({});
Expected Object({ location: ‘ftp.mysite.com’, username: ‘username’, password: ‘password’, directory: ‘test’ }) to equal Object({ }).
+ expect(data).toBeEmptyObject();
Expected Object({ location: ‘ftp.mysite.com’, username: ‘username’, password: ‘password’, directory: ‘test’ }) to be empty object.

toBeTrue
– expect(vm.showHelp).toBe(true);
Expected false to be true.
+ expect(vm.showHelp).toBeTrue();
Expected false to be true.

Documentation

https://github.com/JamieMason/Jasmine-Matchers
https://www.npmjs.com/package/karma-jasmine-matchers
https://blog.pivotal.io/labs/labs/writing-beautiful-specs-jasmine-custom-matchers
https://github.com/JamieMason/Jasmine-Matchers/issues/60

Adding a Swagger Validator Badge to you project README

The Swagger Validator project can be used to show a “valid swagger” badge on your site or github README file.

captura-de-pantalla-2016-11-06-a-las-7-23-54

To generate a badge image for the validation of your swagger json or yaml file against OpenAPI 2.0 spec use

<img src="http://online.swagger.io/validator?url={YOUR_URL}">

Or using markdown

[![swagger-api validator-badge]({YOUR_URL/api_spec.yaml}task-list-api-swagger-definition.yaml)](./api_spec.yaml)

Links:
https://github.com/swagger-api/validator-badge
https://github.com/swagger-api/validator-badge/issues/77

Decorating Angular $httpBackend service.

An example of how to ​decorate the angular $httpBackend mock server with custom logic. In this example, I log to console the request method and URL.

// Configure the Mock HTTP Backend
angular
    .module('my-app')
    .config(['$provide', function ($provide) {
        $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
    }]);

// Decorate Mock HTTP Backend to log requests
angular
    .module('my-app')
    .config(function ($provide) {
        $provide.decorator('$httpBackend', function ($delegate) {
            let decoratedHttpBackend = function (method, url, data, callback, headers, timeout, withCredentials, responseType) {
                console.log(method + ' ' + url);

                return $delegate.call(this, method, url, data, callback, headers, timeout, withCredentials, responseType);
            };

            for (var key in $delegate) {
                if ($delegate.hasOwnProperty(key)) {
                    decoratedHttpBackend[key] = $delegate[key];
                }
            }

            return decoratedHttpBackend;
        });
    });

Solve CORS Cross-origin issue in Development Environment

Developing a front-end application, let’s say an Angular app, you could run into CORS Cross-origin issues performing requests to back-end services.

XMLHttpRequest cannot load http://my-service/api/my-resource. Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:8000&#8217; is therefore not allowed access.

In production is something that should be configured in the server adding the following header to its response:

Access-Control-Allow-Origin: *

And the same can be done in your local dev machine if you are serving the fron-end and also the back-end. But what happens if your service is in another machine or port?

We can solve this problem with a local reverse proxy, or using apps like Burp Suite. But a really quick workaround is to use the Google Chrome Allow-Control-Allow-Origin plugin.

Don’t forget to configure properly the filters to intercept only the URLs to the services that you use:

http://my-service/api/my-resource/*

CORS_chrome_plugin

Another hacky and quick way to solve this is opening chrome with the web security disabled:

open /Applications/Google\ Chrome.app/ --args --disable-web-security

but It could be really dangerous to use that all the time.

To know more about CORS read http://www.html5rocks.com/en/tutorials/cors/.

Bower Guideline – Always Ignore the files that you don’t want to publish

The bower.json defines several options, one of those is the ignore option:

ignore [array]: An array of paths not needed in production that you want Bower to ignore when installing your package.

It is really important to use it when you are defining a bower.json of a package that is meant to be used from other apps or modules.

Why?
When a consumer installs your package via Bower, it will download your project’s entire git repository into their project. But in most of the cases, we don’t want to distribute everything. The consumer app doesn’t need things like​ tests, configuration files, tasks, etc. Only the original and minified versions of the component and the documentation. That will save time downloading the module and disk space.

Guideline
The rule of thumb is to use the ignore attribute to define the list of files and directories that we don’t want to publish.

For example:

"ignore": [
"gulp",
".bowerrc",
".gitignore",
"gulpfile.js",
"package.json",
"README.md"
],

Angular-ui-grid enable filtering from grid menu

In Angular ui-grid it is possible to configure the grid with filtering using the enableFiltering option.

vm.gridOptions = {enableFiltering: true};

I wanted to allow the user to hide/show the filter clicking a button.
There is an example of that in http://ui-grid.info/docs/#/tutorial/103_filtering, but I wanted to add that action to the grid menu itself.

angular-ui-grid-enable-filtering-grid-menu-01

angular-ui-grid-enable-filtering-grid-menu-02

Here is the code of my solution:

            vm.gridOptions.gridMenuCustomItems = [
                {
                    title: 'Hide filter',
                    icon: 'glyphicons filter failure',
                    leaveOpen: true,
                    order: 0,
                    action: function ($event) {
                        this.grid.options.enableFiltering = !this.grid.options.enableFiltering;
                        this.grid.api.core.notifyDataChange(uiGridConstants.dataChange.COLUMN);
                    },
                    shown: function () {
                        return this.grid.options.enableFiltering;
                    }
                },
                {
                    title: 'Show filter',
                    icon: 'glyphicons filter success',
                    leaveOpen: true,
                    order: 0,
                    action: function ($event) {
                        this.grid.options.enableFiltering = !this.grid.options.enableFiltering;
                        this.grid.api.core.notifyDataChange(uiGridConstants.dataChange.COLUMN);
                    },
                    shown: function () {
                        return !this.grid.options.enableFiltering;
                    }
                }
            ];

You can see that doesn’t need to expose the grid to scope in a onRegisterApi block.

Documentation:
http://ui-grid.info/docs/#/tutorial/103_filtering
http://ui-grid.info/docs/#/tutorial/121_grid_menu

MailServer con Postfix + Dovecot + Mysql + Roundcube

MailServer con Postfix + Dovecot + Mysql + Roundcube

Hace unos días monté un servidor de correo para una pequeña empresa. Querían una solución basada en software libre, que pudiera trabajar con multiples buzones virtuales y utilizando IMAP de forma segura.

Despues de ver y comparar diferentes opciones me decidí por la tupla Postfix + Dovecot, el primero servidor de transporte SMTP y el segundo servidor IMAP y POP3 para obtener los correos. Hasta donde he leído y probado me han parecido más seguros y rápidos que otras opciones como Sendmail, Exim, Courier, etc.

Los dominios y usuarios virtuales los tendré en una BD MySql, ayudandome de la pequeña utilidad php Virtual Mail Manager para gestionarlos.

Y por último ofrezco también a los usuarios la opción de consultar sus buzones con un WebMail, en mi caso me he decantado por útilizar Roundcubemail.

roundcubemail_listing

A continuación dejo algunas indicaciones de como lo instalé, pero esto ni es una guia ni mucho menos un manual. Os recomiendo por completo que sigais esta gúia de workaround, en la que me base yo en mi instalación. Es de lo mejorcito que podeis encontrar para instalar lo que os comento sobre Debian.

Instalo Debian Lenny 5.0 con la selección de paquetes de sistema base, sin nada mas.

Añadimos al sources.list el repositorio non-free:

deb http://ftp.es.debian.org/debian/ lenny main non-free
deb-src http://ftp.es.debian.org/debian/ lenny main non-free


aptitude update
aptitude upgrade
aptitude install ssh vim

Instalación
Instalamos los paquetes necesarios para el mailserver:


aptitude install postfix-mysql mysql-server-5.0 phpmyadmin
aptitude install dovecot-pop3d dovecot-imapd openssl
aptitude install amavisd-new libclass-dbi-mysql-perl
aptitude install spamassassin clamav-daemon cpio arj zoo nomarch lzop cabextract pax lha unrar

Configuración

Refinar la configuración de Posfix

# dpkg-reconfigure postfix

He dejado el tamaño máximo de los buzones a 500 MB (524288000).

– MySQL

En nuestro servidor MySQL crearemos una nueva bdd llamada mailserver, con acceso para el usuario mailuser. Y creamos 3 tablas: virtual_domains, virtual_users, virtual_aliases y 2 vistas: view_users, view_aliases.

# mysqladmin -p

mysql>

CREATE DATABASE mailserver ;

GRANT SELECT ON mailserver.*
TO mailuser@localhost
IDENTIFIED BY 'mailuserPASSWORD';

USE mailserver ;

CREATE TABLE `virtual_domains` (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL
) ENGINE = InnoDB;

CREATE TABLE `virtual_users` (
id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
domain_id INT(11) NOT NULL,
user VARCHAR(40) NOT NULL,
password VARCHAR(32) NOT NULL,
CONSTRAINT UNIQUE_EMAIL UNIQUE (domain_id,user),
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
) ENGINE = InnoDB;

CREATE TABLE `virtual_aliases` (
id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
domain_id INT(11) NOT NULL,
source VARCHAR(40) NOT NULL,
destination VARCHAR(80) NOT NULL,
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
) ENGINE = InnoDB;

CREATE VIEW view_users AS
SELECT CONCAT(virtual_users.user, '@', virtual_domains.name) AS email,
virtual_users.password
FROM virtual_users
LEFT JOIN virtual_domains ON virtual_users.domain_id=virtual_domains.id;

CREATE VIEW view_aliases AS
SELECT CONCAT(virtual_aliases.source, '@', virtual_domains.name) AS email,
destination
FROM virtual_aliases
LEFT JOIN virtual_domains ON virtual_aliases.domain_id=virtual_domains.id;

Creamos los mapping-files:

# vi /etc/postfix/mysql-virtual-mailbox-domains.cf

user = mailuser
password = miP@ss
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_domains WHERE name='%s'


# vi /etc/postfix/mysql-virtual-mailbox-maps.cf

user = mailuser
password = miP@ss
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM view_users WHERE email='%s'


# vi /etc/postfix/mysql-virtual-alias-maps.cf

user = mailuser
password = miP@ss
hosts = 127.0.0.1
dbname = mailserver
query = SELECT destination FROM view_aliases WHERE email='%s'


# vi /etc/postfix/mysql-email2email.cf

user = mailuser
password = miP@ss
hosts = 127.0.0.1
dbname = mailserver
query = SELECT email FROM view_users WHERE email='%s'

Tras esto configuramos postfix con estos mapeos

# postconf -e virtual_mailbox_domains=mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
# groupadd -g 5000 vmail
# useradd -g vmail -u 5000 vmail -d /home/vmail -m
# postconf -e virtual_uid_maps=static:5000
# postconf -e virtual_gid_maps=static:5000
# postconf -e virtual_mailbox_maps=mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
# postconf -e virtual_alias_maps=mysql:/etc/postfix/mysql-virtual-alias-maps.cf,mysql:/etc/postfix/mysql-email2email.cf
# chgrp postfix /etc/postfix/mysql-*.cf
# chmod u=rw,g=r,o= /etc/postfix/mysql-*.cf

PENDIENTE

Documentación:
http://workaround.org/articles/ispmail-etch/
http://workaround.org/ispmail/lenny/amavis-filtering-spam-and-viruses