Come fare i test sui controller con Zend Framework

Lo ammetto, pietà di me: non sono un grandissimo esperto di test. Non ne ho mai fatti troppi e probabilmente neppure troppo belli.

Nel mio ultimo progetto, iniziato da poco, ho rimesso mano alla questione e unilateralmente deciso di applicarmi meglio a farli funzionare. Il progetto è scritto in PHP ed usa Zend Framework (da qui in avanti solo ZF). Premetto che quello che segue è probabilmente inutile a chi non ha già una certa esperienza con quel framework.

ZF è sempre stato testabile predilegendo tra i vari framework PHPUnit. Questa scelta si è spinta recentemente fino ad offrire un componente (Zend_Test) che estende le classi base dei test di PHPUnit in modo da esporre ai test dei controller tutti gli oggetti di alto livello necessari per lavorare in modo estremamente pratico. Questi oggetti sono la $request e la $response, ma anche una pletora di nuovi assert() tra cui alcuni fantastici che usano le estensioni XPath e DOM per verificare il contenuto di una pagina durante un test utilizzando appunto XPath o selettori CSS.

Quando scriveremo un test per un controller di una nostra applicazione, faremo dunque derivare il nostro test dalla classe Zend_Test_PHPUnit_ControllerTestCase.

Quelli che seguono sono consigli derivati dalla mia recente esperienza e non vogliono assolutamente essere una trattazione esaustiva sui test dei quali, come innanzi confessavo, non sono un grande esperto. Ma chi non è un grande esperto di test fa fatica a trovare documentazione di base sui test con Zend Framework.. per cui eccomi qua :)

Prima di tutto risolviamo il problema più grave: PHPUnit va installato (non viene distribuito insieme a ZF).

Si può scegliere di farlo in tre modi:

  1. via PEAR
  2. installare il pacchetto della propria distribuzione GNU/Linux
  3. andarsi a prendere direttamente il pacchetto di sorgenti dal sito.

Su Ubuntu 9.04, la mia attuale distribuzione, l’unica possibilità è la 3. Infatti la versione del pacchetto che arriva con la distribuzione è troppo vecchia e Zend_Test fa uso di feature piuttosto recenti (non ci puoi fare niente: ti beccherai subito un errore riguardante il metodo sconosciuto incrementAssertionCounter(). Show stopper.). Anche la 1 non mi è parsa percorribile a causa del mio “PEAR” troppo vecchio per la versione di PhpUnit (non ho indagato moltissimo, a dire il vero).

Ho preso dunque il tgz dal sito di PhpUnit, l’ho scompattato e ho messo tutta la sua directory PHPUnit nella stessa directory dove risiede lo ZF (directory ./library, per la cronaca). In questo modo le classi di PHPUnit sono già visibili senza che sia necessario toccare gli include path, grazie agli autoloader di ZF stesso.

Ho creato una directory “tests” allo stesso livello della directory “application” della mia applicazione, dunque fuori dalla DocumentRoot.

All’interno di questa directory ho messo, per ora: un file AllTests.php che serve come entry point per eseguire tutti i test e un file TestConfiguration.php che in pratica sostituisce le operazioni da fare nell’index.php del sito.

Ecco per esempio come potrebbe essere un primo AllTests.php:

<?php
require 'TestConfiguration.php';

$suite = new PHPUnit_Framework_TestSuite();
$suite->setName('MyApp');
$suite->addTestSuite('controllers_IndexControllerTest');
$suite->addTestSuite('controllers_UsersControllerTest');

PHPUnit_TextUI_TestRunner::run($suite, array());

Ed ecco invece parte del mio TestConfiguration.php

<?php
TestConfiguration::setUp();  

class TestConfiguration
{
  static function setUp()
  {
    define('APPLICATION_ENVIRONMENT', 'test');
    define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application/'));

    set_include_path(implode(PATH_SEPARATOR, array(
      realpath(APPLICATION_PATH . '/../library'),
      realpath(APPLICATION_PATH . '/library'),
      realpath(APPLICATION_PATH . '/models'),
      realpath(APPLICATION_PATH . '/modules/default/forms'),
      get_include_path(),
    )));

    require_once 'Zend/Loader/Autoloader.php';
    $loader = Zend_Loader_Autoloader::getInstance();
    $loader->setFallbackAutoloader(true);
  }

  static function setUpDatabase()
  {
    // TODO
  }
}  

Nella directory tests/controllers metterò i test dei controller. Per esempio, un inizio di un test per una home page potrebbe essere:

class controllers_IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{

  public function testHomePageIsASuccessfulRequest()
  {
    $this->dispatch('/');

    // Tests there are no exceptions on the home page
    $this->assertFalse($this->response->isException());

    $this->assertController('session');
    $this->assertAction('new');

    $this->assertQueryCount('#LoginForm', 1);
  }

}

A questo punto non resta che eseguire i test. Da linea comando sarà sufficiente lanciare un php AllTests.php direttamente dalla directory tests.

Un altro punto di attenzione è dovuto al fatto che PHPUnit inizia molto presto a  scrivere in console e questo potrebbe dare fastidio a particolari operazioni di ZF. Nella fattispecie mi sto riferendo al malefico errore “Headers already sent”.

Quello che succedeva a me era che in una preDispatch() di un action plugin, a fronte di una particolare situazione, effettuavo un header(”Location …”). Questa operazione non andava a buon fine proprio per il motivo di cui sopra (e tutti i test fallivano miseramente); per cui, se la vostra applicazione ha un redirect HTTP in un plugin prima dell’effettivo dispatch, potreste incorrere in un errore del genere. La soluzione (almeno per me) è stata quella di non fare la redirect ma di modificare il controller e la action della corrente request. Stesso risultato, ed anche pienamente testabile.

Altro sabato, altro portatile

E così ieri mattina, all’improvviso, il portatile di Antonella ha reso l’anima al Dio Dei Computerini. Il monitor si è fulminato.

Il portatile, un Acer 3810T Timeline 13 pollici, era stato acquistato sabato scorso e le caratteristiche sono strepitose: ultraleggero (1.6Kg) e con una batteria clamorosa (si parla di 8 ore di autonomia). Appena arrivato a casa il portatile è stato subito de-Vistato. Al posto del buffo sistema operativo della Microsoft è stata messa una Ubuntu 9.04.

Le cose non sono andate benissimo: la scheda di rete non è compatibile ed occorre scaricarsi e compilarsi un moduletto (facile). È inoltre necessario disattivare l’AHCI del disco (da BIOS, va messo in modalità IDE). Facile.

Più difficile è stato diagnosticare il motivo per il quale, ogni tanto (una volta al giorno), il sistema operativo dichiarasse di non poter scrivere sul disco rigido. Occorreva riavviare, e sperare nel successivo fsck.

Apparentemente un aggiornamento al kernel 2.6.30 aveva sistemato anche quel problema, rendendo alla fine il portatile FULL supported, per così dire. Finché ieri… il video prima ha tremato un po’ e poi… è diventato tutto bianco. Fine.

Rimpacchettato tutto, siamo andati da MediaWorld a farcelo cambiare. Nessun problema dal punto di vista della garanzia: dopo aver tentato di accenderlo il commesso ha verificato che non si vedeva nulla (e qui non nascondo che abbiamo temuto che si potesse accorgere che sulla macchina non fosse presente NESSUN sistema operativo, magari attaccando un monitor esterno. Sono sicuro che avrebbe iniziato a dare la colpa a qualche nostro intervento software (linux!) o a un cattivo aggiornamento di qualche driver).

A questo proposito non ho ancora avuto la sfortuna di sapere se e quante storie ti fanno in fatto di garanzia se sul portatile che porti a riparare dovessero trovare un altro sistema che non sia il preinstallato Windows. Per sicurezza, nel caso dell’Acer, ci siamo fatti i DVD di “ripristino” tramite l’apposita utility del fornitore.

Questa utility crea dei DVD che fanno sì boot e, ATTENZIONE, una volta partiti chiedono se si voglia ripristinare completamente il sistema: però mentono. Infatti si aspettano di trovare un file system NTFS sul nostro hard disk (dunque il ripristino è “soft”: fanno semplicemente una copia e non aggiornano neanche l’MBR; che può andare anche bene, ma almeno dammi questa opzione!). Se così non fosse daranno il classico errore del cazzo mezzo in italiano e mezzo in inglese e si fermeranno. Per cui, se si vuol essere sicuri di non andare incontro a problemi di questo tipo, i consigli possono essere:

  1. farsi comunque i DVD di ripristino (che, tra le altre cose, si possono fare UNA volta sola. Fantastici).
  2. lasciare sempre una partizione sul disco con il Windows originale (e magari anche la partizione di ripristino). Questa operazione è possibile dal momento che con il programma gparted (usato in fase di installazione di Ubuntu oppure direttamente dal LiveCD della stessa distribuzione) è possibile fare il resize della partizione NTFS. Per portare una partizione di 350GB a 35GB ci sono voluti circa 30 minuti.
  3. formattare tutto e installare la nostra Ubuntu. In caso di necessità, occorre ripartire con un LiveCD e formattare il disco come NTFS: prima si fa la partizione con gparted e poi la si formatta con mkfs.ntfs. Ricordatevi in questo caso di usare l’opzione –fast o ci passerete una vita. A questo punto si dovrebbe usare il programmillo ms-sys (non distribuito con Ubuntu) per togliere un eventuale grub nel’MBR e ripristinare quello di Vista. Ho detto “dovrebbe”, perché per motivi che non sto qui a spiegare non sono riuscito a portare a fondo questa procedura e non posso garantire il funzionamento. Occhio che a ms-sys occorre passare il device e NON la partizione! (es: /dev/sda e NON /dev/sda1 )

OK, così siamo da MediaWorld a cambiare il portatile. Peccato che tutti i MediaWorld della zona (Bologna) avessero finito le scorte di QUEL portatile e, ancora più strano, non ne erano stati ordinati altri.

Antonella ha dunque dovuto fare buon viso a cattivo gioco e “approfittare”  di una prezzo d’occasione su un portatile appena uscito: l’HP Pavilion dv3 2020el (leggi scheda). Molto più potente dell’Acer, 50€ di differenza. Nel confronto si perde un po’ di autonomia di batteria (l’HP è comunque un 6 celle) e si guadagnano circa 600gr di peso. Per il resto, però, è un’altra storia: Core2 8600 a 2,4Ghz, scheda video Nvidia con 512MB dedicati, disco da 360GB, masterizzatore interno (l’Acer non ce l’ha) e, che non guasta, una qualità componentistica certamente superiore.

Tornati in ufficio con l’acquisto, lo spacchettiamo e iniziamo la procedura pallosissima di “masterizzazione dei DVD di ripristino”. Durata totale dell’operazione: 5 ore. Cinque ore. Cinque. Ore. Per masterizzare 3 DVD. E perché? Perché (probabilmente) l’operazione è effettuabile UNA SOLA VOLTA e allora, a scapito di 5 ore di vita di un povero mortale, la procedura occorre farla in maniera estremamente cauta e lenta… Che merde.

E cosa ci troviamo su un portatile appena acquistato? 30GB di schifezze. Trentagiga di utility assurde, programmi in versione demo, giochi che devi comprare, programmi che appena li esegui si connettono a internet senza chiederti il permesso e vanno chissà dove a dire chissà cosa. Il system tray con 10 icone di altrettanti programmi che non si sa che fanno. Gli antivirus che ogni 5 minuti appaiono e ti chiedono o di acquistare il prodotto o di far riavviare la macchina. E in tutto questo, per far partire IE7 per passare un po’ il tempo, ci vogliono svariati secondi prima di atterrare… sulla home page di AOL!?

Ma come si fa, dico,  a usare e legittimare l’uso di un sistema del genere? (e per sistema non intendo “Windows” in sé, quanto proprio questa cafonaggine da parte dei produttori).

Che roba. Bah! Chiavetta USB e dopo 30 minuti di NTFS resize e 10 minuti di installazione Ubuntu era lì pronta.

Problemi? Solo l’audio: occorre aggiornare manualmente Alsa alla versione 1.0.20.

Per ora non posso dire altro che con Ubuntu l’HP Pavilion dv3 2020el è una bomba. Con Windows è una roba ridicola e ributtante, come tutti i portatili odierni.

Click Sicuro ma non libero

I nostri parlamentari, tra una cosa e l’altra, partecipano alle commissioni di lavoro. Una di queste commissioni, quella sull’infanzia, ha promosso la nascita di un software per il controllo della navigazione dei minori.

Il software verrà installato dal genitore sul computer del figlio o della figlia, e fungerà un po’ da firewall intelligente (dove navighi, cosa dici, a chi lo dici, eccetera) durante la navigazione sul web.

A parte l’efficacia o meno del mezzo, sulla quale non sta a me giudicare, quello che mi perplime parecchio sono due questioni:

  1. che i nostri parlamentari promuovano l’uso e l’acquisto di un software commerciale di una non meglio precisata azienda
  2. che i nostri parlamentari promuovano l’uso e l’acquisto di un software NON LIBERO.

Se avessi un figlio, mai e poi mai installerei sul suo computer un software promosso da dei politici di cui conosco bene l’insulsa predisposizione tecnologica senza avere le garanzie di indagine sullo stesso che mi può fornire un software di cui ho a disposizione i sorgenti. Chi mi garantisce che il traffico di mio figlio non venga monitorizzato e analizzato per secondi fini? Nessuno.

Il software in questione, che non linko, è acquistabile online su http://clicksicuro.it (il sito è tutto in Flash, con una bella musichetta di sottofondo).

La notizia la leggo dal Giornale, sia da parte della On. Mannucci che della On. Mussolini. http://www.ilgiornale.it/a.pic1?ID=354098 http://www.ilgiornale.it/a.pic1?ID=354107 http://www.ilgiornale.it/a.pic1?ID=354100

Aggiornamento. Tanto per dire: una delle due società che sembrano essere le creatrici del software in questione ha il dominio scaduto mentre l’altra ha un bel 404 nella pagina di download del software Click Sicuro.

Migliorare l’usabilità di OpenOffice Impress

Ultimamente mi sono trovato a lottare contro l’usabilità del programma Impress (quello per scrivere slide e presentazioni della suite OpenOffice.org). Qui di seguito voglio condividere qualche adattamento all’interfaccia utente che mi ha permesso di scrivere molte slide in un tempo decente, senza dover fare troppi chilometri con il fottuto mouse.

Quello che vedete qui sotto è il mio attuale setup. Sotto l’immagine descrivo il senso di ognuno dei pallini rossi

Cosa è evidenziato nella figura, partendo dall’alto e andando in senso antiorario:

  • Accesso diretto alle slide master tramite pulsante, senza dover andare a cercarlo nel menu. Una volta aperta l’interfaccia delle slide master, in quel punto appare la barra per aggiungerne o toglierne.
  • La palette di colori deve stare assolutamente a portata di mano. Il posto migliore secondo me è “dockarla” lì, sopra la lista delle slide
  • Il navigatore di stili e la lista delle slide master possono stare tranquillamente uno sotto l’altro, in modo da occupare una sola colonna ed essere sempre a disposizione
  • Per risparmiare spazio verticale, avendo un monitor “wide”, sicuramente fa comodo prendere la barra degli strumenti e spostarla in verticale all’estrema destra. Ovviamente, visto lo spazio ridotto, occorre togliere icone inutili

Idee da condividere?

Digital Video Frustration

Scrivo questo post per due motivi: prima di tutto per lamentarmi, che è lunedì ed è attività che mi riesce bene. L’altro motivo è per scrivere da qualche parte le frustrazioni incontrate nel tentare di fare manipolazioni e presdigitazioni su dei video usando soltanto strumenti open source (il problema non è l’open source, come vedremo).

Il problema: prendere una parte di un video pubblicato via RTMP (streaming vero, da piattaforma proprietario Adobe) e piazzare sopra lo spezzone un logo in sovraimpressione.

Semplice no?

Dettaglio tecnico: i video in questione sono codificati in H.264/MP3. Il container è l’f4v (ma questo, fortunatamente, conta poco o nulla).

L’operazione è da compiere server side per cui tutto attraverso command line e scripting (no GUI).

Che strumenti ci sono a disposizione per fare un lavoretto del genere? Ovviamente rtmpdump, ffmpeg e/o mencoder.

Spezzando diligentemente il problema principale in problemi più piccoli, il primo era: scaricarsi dallo streaming uno spezzone di un video. Il tool (unico, non ci sono alternative al momento) è appunto rtmpdump. Appena lo provo rimango subito molto contento del fatto che rtmpdump scaricasse non in “tempo reale” secondo gli FPS del filmato, ma mooolto più velocemente, praticamente in download. Peccato però che il tool non permettesse di specificare un tempo di partenza e uno di fine dello scaricamento. O tutto o niente. Un altro problema di rtmpdump è che il container del filmato scaricato è FLV, senza possibilità di intervenire su questa opzione.

Riprendendo in mano le mie conoscenze arrugginitissime di C++, modifico il programma in modo da poter specificare un offset di partenza e un tempo massimo di scaricamento. Tutto OK, senonché il filmato finale riporterà comunque la durata complessiva del filmato originale.

Mentre lavoro su questo problemino, il giorno stesso Adobe fa chiudere il sito di rtmpdump per contravvenzione al DMCA (nota che Adobe dichiarava simpaticamente di voler aprire il protocollo). Per adesso, dunque, sospendo la questione rtmpdump.

Mi trovo dunque tra le mani un video H.264/MP3. Problema successivo: stamparci sopra un logo per tutta la durata dello stesso.

L’unico modo per farlo (talvolta è bello sapere di aver un’unica possibilità, talvolta meno), è usare l’opzione “vhook” di ffmpeg. In pratica è possibile eseguire del codice - una sorta di sistema a plugin - durante la codifica del video. Uno di questi plguin si chiama, pensa un po’, “watermark” e fa esattamente quello che mi serve.

Però. Però si dà il fatto che questo sistema di “plugin” sia stato misconosciuto dagli sviluppatori di ffmpeg (”fa cagare”) e per questo prima deprecato (nella versione 0.5) e poi direttamente tolto (versione SVN attuale)… il sistema sarà sostituito (notare il tempo al futuro) da un framework molto più elegante chiamato libavfilter.

La versione che arriva con la mia Ubuntu è la 0.5 (meno male!) ma è compilata con il simpatico –disable-vhook (merda!). Ergo, se voglio usare -vhook devo ricompilarmi ffmpeg, ma la versione 0.5, non la versione SVN. Nota a latere: se chiedi supporto agli sviluppatori (mailing list o canale IRC), questi vogliono che tu faccia i test solo con la versione SVN… che non supporta vhook… OK, capito?

Faccio le mie prove e sembra andare tutto bene… il logo in sovraimpressione fa la sua sporca figura ma… ma l’audio è desincronizzato! Dopo qualche secondo, l’audio rallenta e dopo un po’ le immagini sembrano quelle di un filmato di Enrico Ghezzi.

Il problema sembra essere il decoder MP3 usato da ffmpeg, al quale non piace troppo l’Mp3 della traccia audio del filmato. Probabilmente è colpa del coder usato, ma alla fine sembra che devo trovare un’altra soluzione. Qualcuno attento potrebbe obiettare “Ma perché per un H264 viene usata una traccia audio Mp3 e non AAC?”. Osservazione più che corretta. Il problema è che questi video sono prodotti in codifica “real time” da alcune squadre di produzione. Il software utilizzato per questa codifica è Adobe Live Encoder il quale, “bontà sua”, non supporta out-of-the-box AAC. Occorre acquistare un plugin che costa circa 250€ (ogni commento è superfluo). Per questo motivo il cliente ha preferito per adesso usare Mp3 con l’encoder marcio di Adobe.

Quanti decoder Mp3 ci sono Open Source? Due. Uno è libavcodec, fornito ed usato da ffmpeg e l’altro è libmad. È possibile usare libmad con ffmpeg? No.

A questo punto occorre tirare fuori dal cassetto degli attrezzi mencoder, che invece può usare come decoder libmad, e provare. (qualcuno sa come e se si può usare libmp3lame per decodificare gli mp3 di ffmpeg?)

Incredibilmente, funziona. Mencoder + libmad riesce a ricodificare il video tenendo sincronizzato audio e video.

L’idea dunque sarebbe: passo lo spezzone originale da mencoder per crearne una versione digeribile da ffmpeg, usando come video codec “copy”, in modo da non dover ricodificare il video perdendo di qualità. Poi il video viene passato a ffmpeg per il watermarking del logo.

Già. Peccato che il video prodotto da mencoder con questa procedura sia “sminchiato”, come dicono a Milano… pieno di artefatti e con grossi problemi nelle immagini in movimento (bpyramid? bframes? Boh…).

E così continuo le mie prove, sinceramente frustrato e con poche speranze…