Pages

Showing posts with label Informatica. Show all posts
Showing posts with label Informatica. Show all posts

Tuesday, August 28, 2012

How to install System Rescue CD + rEFInd in an USB Stick for EFI systems (Macboot, UEFI PC/Laptops)

update: with further reading of rEFInd website, I could find a better way to specify more options with only one menu entry. The configuration section was subsequently updated.

This blogpost comes in handy mostly if you have an EFI system (Apple Macbook, but also some Intel based desktops and laptops), and you need a portable USB stick for emergency booting.
I've been using System Rescue CD for a long time now, it's probably one of the best  rescue tools around.
It's a live Linux distribution that can help restoring not only Linux installations, but Windows and OSX too, has gparted as a partitioning tool, can restore bootloaders (such as grub), has network support and ssh server (so you can use rsync to copy filesystem, control it remotely, browse the web to search for help if you panic) but being a live linux distro it may be used in almost every way you like. You may give a look to their homepage to see details.
It can also be installed in an USB stick, which comes quite in handy as you don't have to carry a relatively big support as a CDRom; nowadays usb sticks are cheap, small and fairly reliable, I always carry with me a SystemRescue usb stick for emergency repairs.

It might however be problematic using it if you have an EFI/UEFI based system, since SystemRescue CD doesn't actively support it.
For instance, in a macbook you can boot a system rescue cd, but not from usb stick, as the EFI system can boot usb sticks only if they contains an EFI bootloader.
Which is just annoying if you have a macbook pro, but becomes a real problem if you have a Macbook Air, as they don't have a CDROM Reader.

Another tool I've recently discovered is rEFInd Boot Manager, which is an EFI bootloader capable of discovering other EFI bootloaders. Beside being an excellent bootloader it can also be used as a rescue tool, since it might boot your system if your installed bootloader has been misconfigured.

Since rEFInd can directly boot Linux kernels too, if they're compiled using EFISTUB option (version >= 3.4), and since System Rescue CD does itself contain a 3.4 kernel, can this help us, combining both of these tools in a single USB Stick?

Of course the answer is yes!

Let's see how.

First, download System Rescue CD, and install it on the USB Stick using these  instructions.
Now download rEFInd too, just choose the CD-R Image File on their download page.
Extract rEFInd CD-R Image copying all the files into the USB Stick.
Open /EFI/boot/refind.conf and modify it as follows:

  • find the "scanfor" commented out line, and add this one (uncommented, of course):
    scanfor manual,internal,external,optical,hdbios,biosexternal,cd
  • At the end of the file, add the following lines (you may replace "it" with your favourite keymap):
menuentry "System Rescue CD x64" {
        icon /EFI/boot/icons/os_linux.icns
        loader /syslinux/altker64
        initrd /syslinux/initram.igz
        options "scandelay=5"
        submenuentry "IT Keyboard, cache" {
          add_options "setkmap=it docache add_efi_memmap"
        }
        submenuentry "IT Keyboard, cache, noapic" {
          add_options "setkmap=it docache noapic add_efi_memmap irqpoll acpi=force"
        }
        submenuentry "IT Keyboard, nocache" {
          add_options "setkmap=it"
        }
        submenuentry "IT Keyboard, nocache, noapic" {
          add_options "setkmap=it  noapic add_efi_memmap irqpoll acpi=force"
        }
        submenuentry "No EFI" {
          add_options "noefi"
        }
        submenuentry "VGA" {
          add_options "vga=791"
        }
}


And... that's it! We're done! Just try it out, rEFInd will show you the three System Rescue CD options, and the other installed operating systems.
You may of course customize kernel boot arguments with the options supported by System Recue CD.

As an optional step, since EFI is supported manily on x64 machines (that's why I've only added x64 kernel boot options) you may safetly remove the various "*ia32*" files you may see around, which should be "shellia32.efi", "refind/drivers_ia32", "refind/refind_ia32.efi", "EFI/boot/drivers_ia32", "EFI/boot/bootia32.efi".

Note: if you have one of the awful new Macbook pro/retina/air, which have serious problems booting linux, you may want to add the options "add_efi_memmap noapic" to properly boot System Rescue CD with EFI. I have already included it in one of the submenus.

Friday, July 13, 2012

Macbook pro 2012 (8.1) e Ubuntu

Apple: un passo avanti, 10 indietro (come al solito).
All'arrivo dei nuovi macbook aziendali (perchè usare un mac in azienda, poi?) mi sono meravigliato di un notevole miglioramento del sistema operativo più antipatico e chiuso del mondo: una volta ripartizionare la partizione di sistema di OSX era veramente complicato. Oggi invece è possibile farlo anche dallo stesso sistema operativo: innovazione non da poco, credo che su linux si possa fare solo con btrfs.

Ma veniamo alle rogne: provo la "solita" procedura di installazione, usando Refit perchè ok, grub "dovrebbe" supportare il boot efi nativo, ma si sa, io non mi fido mai molto...

Occhio a selezionare il "partizionamento manuale".
Come layout del disco scelgo il seguente:
  • sda1: partizione EFI di osx (già esistente).
  • sda2: partizione di sistema osx (già esistente).
  • sda3: partizione di recovery di osx (già esistente).
  • sda4: swap linux, dimensioni pari alla ram del sistema (nel mio caso, 4GB)
  • sda5: partizione root linux (non mi andava di creare mille partizioni, ed ho messo tutto sulla root, potrò sempre cambiare in seguito).
Accorgimento importante: in una delle schermate di installazione viene chiesto dove installare il boot loader (grub2). Io ho scelto la partizione root linux (quindi /dev/sda5), e a parte le rogne di OSX che descriverò in seguito la cosa è andata liscia. Un'alternativa (da testare) potrebbe essere sda1.

Il primo boot è andato senza problemi. Una cosa che però mi ha stranizzato quasi subito è stata la scomparsa di refit.
Dopo un paio di riavvii decido di riavviare osx per verificare il funzionamento di alcune periferiche. E qui iniziano i problemi.
Anzitutto, grub2 non riesce ad avviare osx. Probabile qualche incompatibilità con lion.
Cercando su google la soluzione migliore sembra essere di avviare il mac tenendo premuto il tasto "option" (che è evidentemente il modo fighetto dei mac-isti di chiamare il tasto "ALT").

Ok, osx si avvia... problema: ha sovrascritto senza pietà grub, infatti al riavvio successivo è impossibile avviare ubuntu.
Ri-ok, pazienza, proviamo a installare refit: risultato, refit NON viene mostrato (mi sa che viene sovrascritto anche lui) e in più non si avvia più neanche osx.
Ri-ri-ok: una soluzione che riesco a trovare è di installare refit su un cdrom. Questo riesce a far avviare sia osx sia linux.
Ma ovviamente bisogna metterci una pezza.
Ecco come sono riuscito a rimediare:

Al primissimo avvio di Ubuntu, in /etc/grub.d/ creare un nuovo file per inserire una entry "custom" in grado di avviare OSX.
Nel mio caso, /etc/grub.d/42_osx_chainloader
Ricordarsi di marcarlo come eseguibile (chmod a+x /etc/grub.d/42_osx_chainloader).
Il contenuto è il seguente:

#!/bin/sh
cat <<EOF
# Chainloading OSX EFI Bootloader
menuentry "OSX-Chainloader" {
        insmod part_gpt
        insmod hfsplus
        set root='(hd0,gpt2)'
        search --no-floppy --fs-uuid --set=root $( grub-probe -d /dev/sda2 -t fs_uuid)
        load_video
        set do_resume=0
        chainloader /usr/standalone/i386/boot.efi
}120
EOF

Ovviamente se OSX non fosse su /dev/sda2 bisogna modificare inserendo il dispositivo giusto (ma su una installazione di default dovrebbe andar bene).

Eseguire "sudo update-grub"
Al prossimo boot, troverete la nuova entry "OSX-Chainloader". Sceglierla per avviare osx.
Adesso il problema è evitare di far sovrascrivere grub da osx.
Io ho risolto scrivendo un file che reimposta grub come bootloader di default.
Posizione: /usr/sbin/bless_grub.sh
#!/bin/bash
mkdir -p /Volumes/efi
mount -t msdos /dev/disk0s1 /Volumes/efi

bless --folder=/Volumes/efi --file=/Volumes/efi/EFI/ubuntu/grubx64.efi --setBoot
bless --mount=/Volumes/efi --file=/Volumes/efi/EFI/ubuntu/grubx64.efi --setBoot



Anche questo file deve essere marcato come eseguibile (chmod a+x /usr/sbin/bless_grub.sh ).
Ora bisogna fare in modo di far eseguire questo file ad osx come root ad ogni avvio.
La soluzione "pulita" è usare plist, l'init di apple. Essendo abbastanza complesso da usare, ho optato per la soluzione "quick&dirty", ovvero aggiungere la riga
 /usr/sbin/bless_grub.sh
Alla fine del file /etc/rc.common.
Abbiamo finito: adesso grub2 è in grado di avviare osx, ed osx ad ogni avvio reimposta grub2 come bootloader predefinito.
Unico problema ancora aperto: nel mio caso grub2 ci mette ben 20 secondi ad avviarsi.
Idee?
Update: aggiornando a Ubuntu 12.10 beta (e quindi presumibilmente anche grub) il problema sembra sparito...
Update-bis: ho notato che a risolvere non è stato l'aggiornamento, infatti il problema si è ripresentato.   Pensandoci meglio però ho trovato la soluzione effettiva: rieseguire "grub-install", senza parametri.

Saturday, May 19, 2012

Touché 0.1.1


New minor release available for Touché, mostly for build and bug fixes.
Here's the changelog:

  • Make build more reliable.
  • Desktop file fixed for kdeinit launch error.
  • Use of kuniqueapplication in release mode (no need for multiple instances).
  • Fix crash when removing a device with configuration dialog open.
  • Microsoft Wireless Keyboard 3000: added "F-Block" key mapping.


Source tarball: http://github.com/rockman81/Touche/downloads
Arch Linux packages (AUR):

Ubuntu packages:


Wednesday, January 18, 2012

Test Driven Development, C++ e Qt: Mock Objects

Dopo aver ripulito a dovere il codice siamo pronti per aggiungere nuove funzionalità alla nostra applicazione. Chiaramente seguendo le regole del tdd, ossia aggiungendo un nuovo test prima di scrivere nuovo codice.
Prima di iniziare, ho corretto un paio di minor issue sullo script bash che lancia i test, e sulla classe c++ che li raggruppa. In questo modo i test rispondono meglio alla linea di comando, ed è possibile isolare i singoli test case. Come al solito, trovate tutto sul repository git, l'url è in fondo alla pagina.

Una prima banale funzionalità che manca alla nostra applicazione è distinguere tra l'invocazione senza parametri, che come output stampa il messaggio di help, e l'invocazione con uno o più parametri, che invece fa altro.
Testare l'invocazione senza parametri è stato piuttosto facile, ma come testiamo l'invocazione con parametri, se non sappiamo ancora esattamente cosa farà?

Ci viene in aiuto la composizione fra oggetti: assumiamo infatti che la nostra classe DownloadManagerCore avrà uno (o più) collaboratori addetti al download, in tal caso la nostra classe dovrà semplicemente dare in pasto a questi collaboratori la lista degli url da scaricare.
Dobbiamo quindi identificare questi collaboratori, dare loro un nome (e quindi una responsabilità) e scrivere la loro interfaccia. Non ci interessa implementarli davvero, lo faremo in un secondo momento nei rispettivi test unitari, ci interessa però definire la loro interfaccia in modo da poterne creare istanze "finte" da usare nel test di DownloadManagerCore.

In una prima approssimazione possiamo pensare di creare un oggetto Queue, con un metodo add(QStringList) che viene invocato se l'oggetto DownloadManagerCore riceve una lista di argomenti non vuota.
Cominciamo quindi a creare la sua interfaccia: dato che si tratterà di un'interfaccia di dominio, creiamo il suo header nella sottodirectory domain del progetto downloadmanagercore.


class Queue {
public:
    virtual void add(const QStringList &urls)=0;
};



Ora possiamo scrivere una sua implementazione Fake (nel progetto UnitTests) su cui faremo delle asserzioni.
Gli oggetti Fake, detti anche Mock Objects, sono degli utili strumenti per verificare come gli oggetti interagiscono fra loro.
In realtà alcuni autori suggeriscono varie differenze tra mock objects, fake e stub, sopratutto legate alla loro programmabilità. Per semplicità al momento assumeremo equivalenti mock e fake, la rete è comunque piena di approfondimenti.
Vale la pena di specificare che in C++ è indispensabile che un oggetto abbia dei metodi virtual per poter essere correttamente mockato.
Un buon design fa comunicare fra loro le classi sopratutto tramite interfacce piuttosto che tramite oggetti   concreti, questo facilita molto la creazione di mock object adeguati.

Tornando alla classe FakeQueue, per poter fare delle asserzioni un field addWasCalled di tipo bool, e un field di tipo QStringList chiamato receivedUrls. Nel nuovo test verificheremo quindi che addWasCalled venga settato a true, e che receivedUrls sia uguale alla lista degli url ricevuti da DownloadManagerCore.
Questo tipo di oggetto permette di testare l'interazione tra la classe sotto test (DownloadManagerCore) ed i suoi collaboratori.

  • header *
class FakeQueue : public Queue
{
    Q_OBJECT
public:
    explicit FakeQueue(QObject *parent = 0);

    bool addWasCalled;
    QStringList receivedUrls;

    void add(const QStringList &urls);   
};


  • implementazione

FakeQueue::FakeQueue(QObject *parent) :
    Queue(parent), addWasCalled(false), receivedUrls(QStringList())
{
}

void FakeQueue::add(const QStringList &urls)
{
    addWasCalled=true;
    receivedUrls=urls;
}



Aggiungiamo il nuovo test case, che verifica che la chiamata add viene invocata istanziando DownloadManagerCore con almeno un argomento.



void DownloadManagerCoreTest::itShouldQueueUrlsWhenCalledWithArguments()
{
    QStringList urlList = QStringList() << "first url" << "second url";
    QString output;
    QTextStream outputStream(&output);
    FakeQueue queue;
    DownloadManagerCore *lib = new DownloadManagerCore(&outputStream, urlList, &queue, this);
    lib->start();
    QCOMPARE(queue.receivedUrls, urlList);
    QCOMPARE(output, QString() );
    QVERIFY2(queue.addWasCalled, "Add method should be called on queue");
}



In questo momento il test non compila neanche, questo perchè DownloadManagerCore non accetta ancora un puntatore a Queue in costruzione; come prima cosa quindi modifichiamo la firma del costruttore di DownloadManagerCore.

    
    DownloadManagerCore(QTextStream *output, const QStringList &arguments, Queue *queue, QObject *parent = 0);



Naturalmente dovremo sistemare anche gli altri test, che adesso avranno bisogno di Queue istanziando DownloadManagerCore.
Adesso vediamo finalmente il test fallire come ci aspettiamo: ci dice che si aspetta una QStringList di due stringe, e ne trova una vuota. Dobbiamo quindi far si che DownloadManagerCore accodi i parametri. Ma se invochiamo il metodo add su queue, il test fallisce perchè si aspetta che l'output (il messaggio di help) non venga scritto. Dobbiamo quindi aggiungere della logica di controllo dei parametri.


class DownloadManagerCorePrivate {
public:
    DownloadManagerCorePrivate(QTextStream *output, const QStringList &arguments, Queue *queue);
    QTextStream *output;
    QStringList arguments;
    Queue *queue;
    void printHelpMessage();
};


void DownloadManagerCore::start()
{
    Q_D(DownloadManagerCore);
    if(d->arguments.isEmpty()) {
        d->printHelpMessage();
        emit finished();
        return;
    }
    d->queue->add(d->arguments);
}



Adesso abbiamo bisogno di un'implementazione vera di Queue, in modo da poter anche compilare l'eseguibile principale. Questa classe deve:

  • ricevere la lista dei parametri
  • memorizzarla in una lista di url
  • effettuare validazioni
  • avviare il download
Sappiamo già che la classe Queue dovrà collaborare in qualche modo con QNetworkAccessManager, la classe di Qt addetta alle comunicazioni http.
Dovremo inoltre farla collaborare con un'altra entità, un FileWriter, che a fronte della ricezione di dati scrive il tutto su filesystem. Normalmente per testare questa classe è meglio far ricorso agli IntegrationTests, che però affronteremo più avanti. Se invece volessimo testare unitariamente una classe che collabora con alcune classi, come QNetworkAccessManager, di cui non possiamo creare implementazioni mock, come potremmo fare?
Purtroppo non c'è una risposta semplice, ed è proprio per questo che in questi casi si preferiscono di gran lunga i test di integrazione; tuttavia come esercizio proviamo ad elaborare una strategia.
Quella forse più efficace è di incapsulare le classi Qt da mockare in oggetti decorator, che implementeranno un'interfaccia che sarà la base del nostro mock object. In questo modo possiamo facilmente mockare i decorator, che saranno sufficientemente "stupidi" da non richiedere ulteriori test. Il decorator avrà anche il vantaggio di esporre solo i metodi che ci serviranno davvero, ripulendo l'interfaccia pubblica della classe decorata.
Per semplicità al momento ci occuperemo solo di testare la funzionalità di avvio e accodamento downlod.
Le classi che dovremo decorare saranno principalmente due:

  • QNetworkAccessManager, che diventerà NetworkAccess
  • QNetworkReply, che diventerà NetworkReply.

Chiaramente i test sono fatti apposta per evolversi man mano che le funzionalità vengono aggiunte, intanto però possiamo fare una lista dei metodi dell'interfaccia pubblica che avrà la classe NetworkAccess:
  • NetworkReply * get ( const QNetworkRequest & request)
  • [signal] void finished ( NetworkReply * reply )
Ecco invece l'interfaccia di NetworkReply:
  • [signal] void QIODevice::readyRead ()
  • QByteArray QIODevice::readAll ()
Quello che dovremo testare, in sintesi, è che l'implementazione HttpQueue dell'interfaccia Queue dovrà dire a NetworkReply di cominciare il download, fermandosi appena raggiunto un limite, accodando le richieste successive una volta finito uno dei download in corso.
Il codice risultante è un po' lunghetto da pubblicare qui, rimando quindi direttamente al branch github per questa puntata. In ogni caso, per quanto un po' tedioso, il test ha comunque fatto il suo dovere, permettendoci di sviluppare una funzionalità molto legata alla rete senza di fatto avviare alcuna connessione.


* normalmente è uno smell avere in una classe dei field pubblici. È però vero che questa è una classe non applicativa, che esiste solo nei test e che non ha vere responsabilità se non memorizzare il valore di quei field e fornirlo a chi li testa.


Tuesday, January 17, 2012

Test Driven Development, C++ e Qt: refactoring, ottimizzazioni, d-pointer

Nel precedente post abbiamo dato una messa a punto ai file del progetto. Potrebbe essere il caso di fare qualcosina anche per il codice sorgente...
In questa puntata vedremo alcuni passi di refactoring che ci aiuteranno ad implementare funzionalità future, e renderanno il codice più robusto. Vedremo ad esempio come applicare il meccanismo di Signal e Slot di Qt, particolarmente indicato per la programmazione "ad eventi", e in cosa consiste il pattern d-pointer che in alcuni ambienti (ad esempio nella programmazione per KDE) è divenuto uno standard praticamente obbligatorio

Sunday, January 8, 2012

Test Driven Development, C++ e Qt: ottimizzazioni layout progetti

Nella puntata precedente abbiamo creato un primo "vero" test di dominio perfettamente funzionante; il ciclo del TDD prevede a questo punto di effettuare un po' di refactoring, se necessario, prima di iniziare la nuova funzionalità.
In questo capitolo ci occuperemo non tanto di refactoring relativi al design (qualcosa si può fare, ma avendo scritto pochissimo codice è davvero poca roba), quanto piuttosto di trasformare quello che adesso è codice "sperimentale" in qualcosa di più professionale, usando layout di progetto, ottimizzazioni e convenzioni che sono da favorire in progetti pronti per la produzione.
Ma che problemi ha il nostro progettino?
In realtà un bel po', cominciamo dalle cose più evidenti: la prima è che i progetti sono collegati tra loro piuttosto malamente.
Sappiamo che il progetto DownloadManager deve usare DownloadManagerCore, ma al momento non c'è nessun riferimento ad esso. Sappiamo anche che il progetto UnitTests deve fare, e in realtà fa già, la stessa cosa. Ma per farlo abbiamo dovuto aggiungere la riga:

    LIBS += -L../DownloadManagerCore-build-desktop/ -lDownloadManagerCore

e di certo non vorremo tenerla così: quando infatti dovremo compilare in modalità release sarebbe necessario modificare manualmente il file di progetto (tanto nel progetto UnitTests quanto in DownloadManager), e non è sicuramente il massimo!
Ma anche nel codice sorgente c'è qualcosina che non va: in downloadmanagercoretest.cpp vediamo la riga

    #include "../DownloadManagerCore/downloadmanagercore.h"

che dovremmo ripetere per ogni futuro test case. Non va bene!

Per fortuna qmake ci viene in aiuto con alcune funzioni interessanti.
Aggiungendo al file di progetto la riga

    INCLUDEPATH += ../DownloadManagerCore

rendiamo disponibli tutti gli header di DownloadManagerCore al progetto UnitTests, trasformando quindi la riga precedente in

    #include "downloadmanagercore.h"

Applichiamo questa modifica anche al progetto DownloadManager.

Per distinguere invece tra debug e release, usando anche un path migliore per la direttiva LIBS dobbiamo invece usare una funzionalità un po' più avanzata di qmake.
L'idea alla base è di compilare DownloadManagerCore, installarlo in una directory comune (con suffisso -debug o -release a seconda di come l'abbiamo compilata) e far puntare gli altri progetti a quella directory.
Per far questo dobbiamo aggiungere questa sezione a tutti i file di progetto (quindi DownloadManagerCore, DownloadManager e UnitTests):


win32 {
    build_pass:CONFIG(debug, debug|release)   { COMPILE_MODE='debug'   }
    else:build_pass                           { COMPILE_MODE='release' }
} else {
    CONFIG(debug, debug|release)   { COMPILE_MODE='debug' }
    else                           { COMPILE_MODE='release' }
}


Brevemente, viene assegnata una variabile COMPILE_MODE con un valore dipendente da come si compila il progetto corrente.
win32 viene gestito a parte perchè ho notato che COMPILE_MODE rimane vuota con la sintassi specificata nel ramo else.
Probabilmente dipende dal tipo di compilatore in uso, la sezione nel ramo win32 è stata testata su visual c++ 2010, probabilmente usando invece mingw non è ncessaria.
In ogni caso, provate a vedere se COMPILE_MODE viene popolata o meno usando l'istruzione


message("Using compile mode: $$COMPILE_MODE")



Adesso che abbiamo definito la variabile, proviamo ad usarla.
Nel progetto DownloadManagerCore aggiungiamo il path per l'installazione.



target.path='../static-libraries.bin/$$COMPILE_MODE'
INSTALLS += target


Questo farà in modo che eseguendo make install la libreria verrà copiata nella directory static-libraries.bin/debug (o release).
È consigliabile anche modificare i profili del progetto in qt creator: in "projects->build settings", tra i build steps, aggiungiamo al passo make l'argomento install. Questo per tutti i profili di DownloadManagerCore.
In questo modo, ad ogni build, la libreria statica verrà installata automaticamente.
Ora nei progetti DownloadManager e UnitTests andiamo ad usare questa nuova funzionalità. Molto semplicemente, la riga "LIBS+= ....." vista in precedenza, diventerà:


LIBS += -L../static-libraries.bin/$$COMPILE_MODE -lDownloadManagerCore

aggiungendola a DownloadManager dove non esisteva ancora.
Il modo migliore per verificare il risultato di quello che abbiamo fatto è cancellare tutte le directory di build, ricompilare da capo il progetto UnitTests (e naturalmente la sua dipendenza, DownloadManagerCore) e verificare che i test passino ancora.

Un' ultima ottimizzazione: risulta spesso utile in molti progetti avere una directory dove inserire script per automatizzare i task più frequenti, che spesso richiederebbero una serie di operazioni manuali non proprio comode. Creiamo quindi una directory "scripts". Che script possiamo scrivere per inaugurarla?
Beh, un primo task noioso e facilmente automatizzabile è la compilazione ed esecuzione automatica dei test: vogliamo uno script che sia in grado di compilare anzitutto il progetto DownloadManagerCore, installarlo nella directory static-libraries.bin, quindi compilare ed eseguire automaticamente i tests.

#!/bin/bash
set -e

PROJECTS="UnitTests"
COLORIZE_CMD="ccze -A"

MAIN_PROJECT="DownloadManagerCore"

BASE_DIRECTORY="$PWD/$( dirname $0)/.."
COMPILE_BUILD_PREFIX="$BASE_DIRECTORY/.build-"


if test "x$TERM" != "xxterm" || test "x$( which $( echo $COLORIZE_CMD | cut -d " " -f 1 ) )" == "x"; then #TODO add other terminals supported by ccze here
        COLORIZE_CMD="cat"
fi

if test "x$1" == "x--help"; then
        echo "Usage: $0 [Test-Project-Name [test-method-name]]"
        echo "It runs every project configured in the PROJECTS variable, or can select from parameters"
        echo "The variable MODE can be used to choose between debug and release compilation"
        echo "Currently supported test projects: $PROJECTS"
        exit 0
fi

if test "x$1" != "x"; then
        PROJECTS="$1"
        [ -f $PROJECTS ] && PROJECTS="$( basename "$( dirname "$PROJECTS")" )"
        echo "**** Project: $PROJECTS"
        shift
fi

BUILD_MODE="${MODE-debug}"

function buildProject() {
        project="$1"
        shift
        make_args="$1"
        shift
        #rm -rf "$project.build"
        mkdir -p "${COMPILE_BUILD_PREFIX}$project"
        cd "${COMPILE_BUILD_PREFIX}$project"
        qmake "CONFIG+=$BUILD_MODE silent" "DEFINES += QT_NO_DEBUG_OUTPUT" "$@" "../$project"
        make $make_args > /dev/null
        cd ..
}


function runTests() {
        suitename="$1"
        shift
        echo -e "Running suite $suitename\n"
        cd "${COMPILE_BUILD_PREFIX}$suitename"
        binary="./$suitename" 
        $binary $@ | while read line; do echo "$line" | $COLORIZE_CMD ; done
        ERRORS=${PIPESTATUS[0]}
        cd ..
        if test "x$ERRORS" == "x0"; then
                echo -e "\nSuite $suitename completed without errors\n"
        else
                echo -e "Suite $suitename finished with errors!\n"
                exit $ERRORS
        fi
}


buildProject $MAIN_PROJECT "all install"
for project in $PROJECTS; do
        buildProject $project "clean all" "LIBS+=-L../${COMPILE_BUILD_PREFIX}$MAIN_PROJECT" 
        runTests $project $@
done


Come al solito, i sorgenti per questa puntata sono disponibili sul mio account github.



Nella prossima puntata ci occuperemo invece di refactoring e ottimizzazioni del codice vero e proprio.

Friday, January 6, 2012

Test Driven Development, C++ e Qt: primi passi (e test)

Dopo aver creato la struttura del progetto nella prima parte, cominciamo adesso ad implementare l'applicazione.
Guardiamo l'esempio di Qt da cui stiamo prendendo spunto: il main prende in ingresso la lista di downloads (usando QCoreApplication, che li converte automaticamente in una comoda QStringList), e, se la lista è vuota stampa le informazioni di utilizzo, uscendo.
Potremmo andare avanti ad analizzare le successive funzionalità, certo l'applicazione non si limita a far questo, ma il tdd ci impone di creare un primo test (che inizialmente fallisce), ed implementare la funzionalità facendo passare il test prima di procedere troppo oltre. In una applicazione così semplice, è meglio semplificare anche l'approccio evitando di pensar troppo al futuro.
L'esempio mette il messaggio di errore nel main. Così facendo però non potremmo testarlo. D'altro canto è proprio il main che costruisce la lista di argomenti. Un buon compromesso quindi è di creare un metodo download(const QStringList &arguments)* nella classe DownloadManagerCore che come risultato stampi le informazioni di utilizzo, usando gli argomenti creati da QCoreApplication.
Può inoltre aiutare molto far estendere QObject alla classe DownloadManagerCore; in questo modo si ottimizza la memoria (c++ non ha garbage collector, però ogni classe che estende QObject verrà automaticamente distrutta quando viene distrutta la classe parent) e si migliora l'iterazione con le classi che  verranno usate, le quali saranno infatti a loro volta derivate da QObject.
Nel main.cpp invocheremo QCoreApplication per estrarre gli argomenti, e invocheremo DownloadManagerCore::download(arguments).

Proviamo quindi a scrivere il primo test. In particolare asseriremo che il metodo download stamperà su standard output (o meglio, su un output stream testabile), se la lista degli argomenti è vuota, la seguente stringa:
Usage: downloadmanager url1 [url2... urlN]
Downloads the URLs passed in the command-line to the local directory.If the target file already exists, a .0, .1, .2, etc. is appended to differentiate.

Creiamo quindi il test case itShouldPrintHelpMessageWithNoArguments.

void DownloadManagerCoreTest::itShouldPrintHelpMessageWithNoArguments()
{
    QString output;
    QTextStream outputStream(&output);
    DownloadManagerCore *lib = new DownloadManagerCore(&outputStream, this);
    lib->start(QStringList());
    QString expected("Usage: downloadmanager url1 [url2... urlN]\n");
    expected.append("Downloads the URLs passed in the command-line to the local directory.");
    expected.append(" If the target file already exists, a .0, .1, .2, etc. is appended to differentiate.\n");
    QCOMPARE(output, expected);
}

Al di là della funzionalità, di per se banale, notiamo un po' di cose importanti su come il test stia definendo in maniera molto precisa il design della classe:

  • Abbiamo bisogno di testare l'output. È quindi da evitare che la classe stampi direttamente l'output su schermo. Definiamo invece un costruttore che prende in ingresso un puntatore a QTextStream e facciamo delle asserzioni su quello. Lo stream di test, in particolare, sarà uno stream che scrive su una stringa anzichè su stdout.
  • Abbiamo anche bisogno di una entry point che riceva in ingresso gli argomenti. Definiamo quindi il metodo "start" nella classe DownloadManagerCore, il cui header diventerà quindi questo:
#ifndef DOWNLOADMANAGERCORE_H
#define DOWNLOADMANAGERCORE_H
#include <QObject>

class QTextStream;
class DownloadManagerCore : public QObject {
    Q_OBJECT
public:
    DownloadManagerCore(QTextStream *output);
    void start(const QStringList &arguments);
private:
    QTextStream *output;
};

#endif // DOWNLOADMANAGERCORE_H

Ho anche fatto estendere QObject a QDownloadManagerCore, in questo modo si potrà usare il meccanismo di auto-delete di Qt: se le classi del nostro progetto estendono QObject, e si assegna loro una classe "parent", le classi saranno automaticamente cancellate quando sarà cancellata la loro classe parent, senza nessun bisogno di cancellarle manualmente. In questo modo è possibile ridurre al minimo i rischi di memory leak, potendo assegnare alle classi uno scope ben preciso. Maggiori dettagli qui.

Naturalmente il nostro test non può ancora passare: abbiamo definito l'interfaccia della nostra classe, ma non l'implementazione.
Per avere un primo test verde basta usare lo stream per stampare in output l'help message, senza preoccuparci degli argomenti, dato che per il momento nessun test ne verifica l'utilizzo.

#include "downloadmanagercore.h"
#include <QTextStream>

DownloadManagerCore::DownloadManagerCore(QTextStream *output, QObject *parent)
    : QObject(parent), output(output)
{
}

void DownloadManagerCore::start(const QStringList &arguments)
{
    *output << "Usage: downloadmanager url1 [url2... urlN]" << endl;
    *output << "Downloads the URLs passed in the command-line to the local directory.";
    *output << " If the target file already exists, a .0, .1, .2, etc. is appended to differentiate." << endl;
}

E finalmente, barra verde!

********* Start testing of DownloadManagerCoreTest ********* 
Config: Using QTest library 4.7.4, Qt 4.7.4 
PASS   : DownloadManagerCoreTest::initTestCase() 
PASS   : DownloadManagerCoreTest::itShouldLinkToStaticLibrary() 
PASS   : DownloadManagerCoreTest::itShouldPrintHelpMessageWithNoArguments() 
PASS   : DownloadManagerCoreTest::cleanupTestCase() 
Totals: 4 passed, 0 failed, 0 skipped 
********* Finished testing of DownloadManagerCoreTest ********* 

La prossima volta vedremo di ottimizzare il nostro codice prima di aggiungere nuove funzionalità: refactoring, ma anche migliorie del layout del progetto e ottimizzazioni varie.
Qui il codice sorgente per questa puntata.




* la sintassi "const QString &arg" o "const QStringList &arg" è del tutto equivalente a specificare "QString arg". In genere però è molto meglio specificare il "const" e la "&", per ottimizzare le chiamate. In questo modo infatti i parametri saranno immutabili e passati esplicitamente per riferimento, anzichè ricopiate nel metodo, (occupando quindi più memoria e tempo cpu). Sono piccoli accorgimenti da memorizzare ed usare con costanza, che possono però migliorare di molto le prestazioni del proprio codice.

Sunday, December 11, 2011

Test Driven Development, C++ e Qt: setup e layout progetto

I metodi agili cominciano a prendere piede anche in italia, e con essi quello che è probabilmente il loro più conosciuto cavallo di battaglia: il TDD, ossia Test Driven Development. Uno dei linguaggi in cui il TDD viene più spesso è applicato è java: non solo perchè è uno dei più diffusi, ma probabilmente perchè offre allo sviluppatore degli strumenti veramente potenti: da JUnit, scritto proprio da Kent Beck, ad Eclipse, che oltre ad integrare un perfetto supporto a JUnit offre anche dei potentissimi strumenti per il refactoring, che è parte integrante di questa tecnica.
Ma per quanto riguarda altri linguaggi, come il vetusto ma sempre attuale C++? Come si può conciliare la "dinamicità" di un processo come il TDD alla macchinosità di un linguaggio che prevede costante sincronizzazione header-implementazione, build system non sempre amichevoli e pochissimi tool di refactoring?
In questa guida cercherò di offrire uno dei possibili approcci. Dovendo scegliere un IDE e un toolkit ho optato per Qt di Nokia (originariamente di Trolltech) e il suo IDE Qt Creator.
Ovviamente ognuno avrà le sue preferenze, il mondo del C++ è fin troppo ricco. Per quanto mi riguarda, da utente e sviluppatore KDE, conosco Qt da molti anni, lo trovo piuttosto semplice e intuitivo, e altrettanto può dirsi di Qt Creator, sicuramente non un IDE potente e pieno di strumenti come Eclipse, ma che ha dalla sua una notevole leggerezza, nonchè l'essere studiato proprio per Qt.
Qt offre un ambiente molto omogeneo, includendo anche un modulo per i test unitari. Sicuramente ci sono framework di testi anche migliori, ma per continuare sulla via della semplicità ho preferito usare QTest. Ha anche il non indifferente vantaggio di essere orientato al cross platform, il che vuol dire che un'applicazione o libreria creata con Qt girerà sui principali sistemi operativi (Windows, Mac, Linux) senza modificare (o quasi) il codice, ma solo ricompilando per i sistemi desiderati.

Disclaimer: non oso definirmi nè un esperto di C++ nè tantomeno di Qt. Ho imparato entrambi amatorialmente, e sono un po' arrugginito dai molti anni lavorativi in cui ho utilizzato quasi esclusivamente Java.


Come progetto di esempio prenderò spunto dal Download Manager presente nella documentazione di Qt. Si tratta di un eseguibile da riga di comando, senza GUI, anche molto semplice da realizzare.

Andiamo a creare il layout del nostro progetto.
Da QtCreator sceglieremo l'opzione "New Project", scegliendo tra i vari template disponibili "Qt C++ Project << Qt Console Application". Lo chiameremo "DownloadManager", e lo creeremo nella directory "$HOME/qt".
Il progetto verrà a trovarsi quindi in "DownloadManager", avrà un main pressochè vuoto.

Adesso cominciamo a creare le prime classi? Sbagliato. In realtà il progetto "DownloadManager" è praticamente già finito. Tutto il nostro codice andrà invece in una libreria statica: questo perchè dovrà essere accessibile anche dai test. Una libreria statica è molto diversa da una dinamica: essa non verrà infatti "esportata" come una dipendenza, ma viene inglobata dall'eseguibile, avendo però il vantaggio di poter condividere le proprie classi anche con i test che creeremo.
Quindi, nuovo progetto, con tipo "Other Project << C++ Library". Scegliamo nel wizard "Statically Linked Library", assegnamo come nome "DownloadManagerCore" e lo creiamo sempre nella posizione "$HOME/qt". Nella pagina successiva scegliamo di aggiungere i moduli "QtCore" e "QtNetwork". Il wizard creerà anche una classe principale (che potremo usare come un main) DownloadManagerCore.

Adesso è ora di creare il progetto (o come vedremo, i progetti) per i test, cominciando dagli unit: sempre dal menù nuovo progetto, scegliamo nuovamente "Other Project << Qt Console Application", con nome "UnitTests" e solita posizione, "$HOME/qt". Nel file UnitTests.pro creato dal wizard cambiamo la riga

   QT       += core
in
   QT       += core testlib



Col tasto destro sul progetto selezioniamo "Add New...", quindi scegliamo "C++ Class".
Diamo nome alla classe: "DownloadManagerCoreTest", base class "QObject".
Modifichiamo lo header creando un primo test come private slot:

#ifndef DOWNLOADMANAGERCORETEST_H
#define DOWNLOADMANAGERCORETEST_H

#include <QObject>

class DownloadManagerCoreTest : public QObject
{
    Q_OBJECT
public:
    explicit DownloadManagerCoreTest(QObject *parent = 0);

private slots:
    void itShouldLinkToStaticLibrary();

};

#endif // DOWNLOADMANAGERCORETEST_H


e anche la sua implementazione:

#include <QTest>

#include "downloadmanagercoretest.h"
#include "../DownloadManagerCore/downloadmanagercore.h"

DownloadManagerCoreTest::DownloadManagerCoreTest(QObject *parent) :
    QObject(parent)
{
}

void DownloadManagerCoreTest::itShouldLinkToStaticLibrary() {
    DownloadManagerCore *lib = new DownloadManagerCore();
    QVERIFY2(lib != NULL, "Library should not be null");
}

QVERIFY è una semplice asserzione che verifica il valore booleano passato come parametro.
QVERIFY2 aggiunge la possibilità di specificare un messaggio.
Questi sono un po' i "mattoncini base" per le asserzioni; ne esistono altre, ed è anche possibile implementarne di personalizzate.
Modificare anche il main.cpp come segue:

#include <QtCore/QString>
#include <QtTest/QTest>
#include <QList>

#include "downloadmanagercoretest.h"

class UnitTests : public QObject
{
    Q_OBJECT
private:
    int argc;
    char **argv;

public:
    UnitTests(int argc, char *argv[]);
    int runAll();
private:
    QList<QObject*> tests;
};

UnitTests::UnitTests(int argc, char *argv[])
    : argc(argc), argv(argv)
{
    tests << new DownloadManagerCoreTest(this);
}

int UnitTests::runAll() {
    int testResults=0;
    foreach(QObject *currentTest, tests) {
        testResults += QTest::qExec(currentTest, argc, argv);
    }
    return testResults;
}


int main(int argc, char *argv[])
{
    UnitTests testSuite(argc, argv);
    return testSuite.runAll();
}

#include "main.moc"


Aggiungere nuovi test alla suite è semplice, basta creare dei metodi (void) come "private slots" nelle classi di test.
Se vorremo aggiungere nuove classi di test alla test suite, basterà invece creare nuove classi del tutto simili a DownloadManagerCoreTest: molto semplicemente devono estendere QObject e tutti i metodi dichiarati "private slot" verranno automaticamente usati come test case.
Si deve poi includere lo header corretto nel main.cpp ed aggiungere una riga uguale all'esistente nel costruttore di UnitTests per aggiungere la classe di test alla suite.
Infine, le altre suite di test, come gli integration test e gli acceptance test, possono essere creati esattamente nello stesso modo del progetto UnitTests.

Ma che succede se proviamo ad eseguire il nostro primo test unitario?
Non compila nulla.. o per meglio dire, il link fallisce: questo perchè il nostro progetto di test non "vede" ancora il progetto contenente la classe "DownloadManagerCore". Come Fare?
Beh, basta aprire nuovamente il file "UnitTests.pro" ed aggiungere alla fine del file la riga


   LIBS += -L../DownloadManagerCore-build-desktop/ -lDownloadManagerCore



Visto che anche l'applicazione "DownloadManager" richiederà la libreria può essere utile aggiungere questa riga anche nel suo file .pro.
Può anche essere utile andare nel tab "Projects" di Qt Creator, e nei progetti "DownloadManager" e "UnitTests" selezionare come dipendenza (tab Dependencies) il progetto "DownloadManagerCore".

Adesso basta compilare il tutto per avere la suite di test funzionante:
********* Start testing of DownloadManagerCoreTest *********
Config: Using QTest library 4.7.4, Qt 4.7.4
PASS   : DownloadManagerCoreTest::initTestCase() 
PASS   : DownloadManagerCoreTest::itShouldLinkToStaticLibrary()
PASS   : DownloadManagerCoreTest::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped
********* Finished testing of DownloadManagerCoreTest *********
Alla prossima puntata!

p.s.: i sorgenti per questa versione del progetto potete trovarmi sul mio account github.

Saturday, November 26, 2011

Leggibilità: meglio fuori che dentro

Un argomento di cui recentemente si discute non poco nel nostro team è l'argomento leggibilità.
Premesso che la leggibilità è sempre un soggetto altamente personale, ciò che per me può essere perfettamente leggibile può non esserlo per altri, la mia opinione è che, dovendo scegliere, è sempre meglio preferire la leggibilità esterna di una classe, piuttosto che quella interna.

"Meglio fuori che dentro, dico sempre io"
Difatti, in teoria (specie se si vuole rispettare OCP), una classe dovrebbe essere modificata il meno possibile, e se scriviamo del buon design ben orientato agli oggetti è probabile che la classe stessa non sarà modificata mai, ma verranno solo aggiunte nuove implementazioni di interfacce a fronte di nuove funzionalità.
La leggibilità interna ha quindi un valore abbastanza relativo, basta cioè che sia sufficientemente leggibile da rispettare principi come avere metodi corti e ben definiti, pochi (meglio niente) cicli for e if statement innestati in cascata (ma piuttosto estratti in metodi),  nessuna ambiguità su ingressi e uscite, meglio ancora se con un forte controllo sui tipi (per quanto in java i generics siano molto verbosi, preferisco usarli sempre e comunque quando servono, perchè offrono forti garanzie sulla correttezza dei tipi in uso).

Un esempio concreto: la classe sottostante effettivamente ha una leggibilità interna sufficiente, ma non esaltante.
Le classi inner e l'uso pesante di reflection (purtroppo inevitabile, dato lo scopo di questa classe) sicuramente confondono molto, e anche la gestione delle eccezioni ci mette il suo zampino.
E' anche vero però che la classe principale ha un costruttore privato, e l'unico modo di istanziarla è usando l'unico metodo pubblico disponibile: il metodo "search(enumClass)". Da lì, navigando il codice seguendo lo stack delle chiamate, è possibile seguire il flusso senza perdersi troppo, dato che le biforcazioni non sono molte.
Inoltre i metodi (così come le inner class) sono abbastanza compatti e focalizzati.
Si riesce a capire cosa fa questa classe? (in basso la risposta...)

package com.gmail.gulino.marco.utils;

import static com.google.common.collect.Iterables.find;
import static com.google.common.collect.Lists.newArrayList;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

import com.google.common.base.Predicate;

@SuppressWarnings("unchecked")
public class SmartEnums<EnumType extends Enum<EnumType>> {

        public static <EnumType extends Enum<EnumType>> SmartEnums<EnumType> search(Class<EnumType> enumClass) {
                return new SmartEnums<EnumType>(enumClass);
        }

        private List<EnumType> allValues;

        private SmartEnums(Class<EnumType> enumClass) {
                try {
                        Method valuesMethod = enumClass.getMethod("values");
                        this.allValues = newArrayList((EnumType[]) valuesMethod.invoke(enumClass));
                } catch (Exception e) {
                        throw new RuntimeException("Are you trying to apply SmartEnums to a non enum class?");
                }
        }

        public MemberSearch byField(final String fieldName) {
                return new MemberSearch() {

                        @Override
                        protected Object findValueOn(EnumType enumType) throws Exception {
                                Field field = enumType.getClass().getDeclaredField(fieldName);
                                field.setAccessible(true);
                                return field.get(enumType);
                        }
                };
        }

        public MemberSearch byMethod(final String methodName) {
                return new MemberSearch() {

                        protected Object findValueOn(EnumType enumType) throws Exception {
                                Method method = enumType.getClass().getDeclaredMethod(methodName);
                                method.setAccessible(true);
                                return method.invoke(enumType);
                        }

                };
        }

        public abstract class MemberSearch {

                public EnumType havingValue(Object value) {
                        try {
                                return find(allValues, valueFinderPredicate(value));
                        } catch (Exception e) {
                                throw new RuntimeException(e);
                        }
                }

                protected abstract Object findValueOn(EnumType enumType) throws Exception;

                protected Predicate<EnumType> valueFinderPredicate(final Object value) {
                        return new Predicate<EnumType>() {
                                @Override
                                public boolean apply(EnumType enumType) {
                                        try {
                                                return value.equals(findValueOn(enumType));
                                        } catch (Exception e) {
                                                throw new RuntimeException(e);
                                        }
                                }
                        };
                }

        }
}

Certo, come ho già scritto prima la leggibilità interna non è esaltante...
Ma vediamo come viene utilizzata esternamente questa classe, nella fattispecie il suo unit test::

package com.gmail.gulino.marco.utils;

import static com.gmail.gulino.marco.utils.SmartEnums.search;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;

import org.junit.Test;

public class SmartEnumsTest {
        @Test
        public void itShouldRetrieveEnumByField() throws Exception {
                assertThat(search(AnExampleEnum.class).byField("enumFieldToSearchFor").havingValue("first"), equalTo(AnExampleEnum.firstElement));
                assertThat(search(AnExampleEnum.class).byField("enumFieldToSearchFor").havingValue("second"), equalTo(AnExampleEnum.secondElement));
        }
        @Test
        public void itShouldRetrieveEnumByMethods() throws Exception {
                assertThat(search(AnExampleEnum.class).byMethod("enumMethodToSearchFor").havingValue("first"), equalTo(AnExampleEnum.firstElement));
                assertThat(search(AnExampleEnum.class).byMethod("enumMethodToSearchFor").havingValue("second"), equalTo(AnExampleEnum.secondElement));
        }

        public enum AnExampleEnum {
                firstElement("first"), secondElement("second");
                private final String enumFieldToSearchFor;

                private AnExampleEnum(String value) {
                        this.enumFieldToSearchFor = value;
                }

                public String enumMethodToSearchFor() {
                        return enumFieldToSearchFor;
                }

        }
}

Le assert sono chiare: traducendo letteralmente dall'inglese, abbiamo, mettendo tra parentesi le parole sottointese:
Asserisci (che la) ricerca (di) AnExampleEnum per field "enumFieldToSearchFor" avente valore "first" (sia) uguale a AnExampleEnum.firstElement
Le parole sottointese sono ben poche, è quindi evidente che fa la classe:
Ricerca una enum per field "nome del field" avente valore "valore da ricercare".
o, nella seconda delle due interfacce disponibili:
Ricerca una enum per metodo "nome del metodo" avente valore "valore da ricercare".
Ora, il vantaggio evidente è che gli utilizzatori di questa classe non dovranno scervellarsi troppo nel capirla, in effetti non avranno proprio alcun bisogno di aprire l'implementazione e leggerla. Basta solo leggere il suo test (o un eventuale altro utilizzo) per capire cosa fa e come va invocata.