2012-12-29

Unattended Install of CentOS 6.3 with a USB Key

Here are the steps to create a bootable USB KEY that performs unattended installation of CentOS 6.3

Prerequisites


  • I expect that you know what you are doing. Some of the commands provided can destroy your system if they are not used wisely!
  • A USB Key with at least 512MB capacity. It will be formatted during the process. Don’t forget to set USBKEY variable correctly. This is very important that you make sure you don’t execute the commands on another disk since it can destroy the data on  your system.
  • Download CentOS-6.3-x86_64-minimal.iso (I assume you have downloaded it in ~/Downloads)
  • Make sure you have the following commands installed on your system :
    • sfdisk
    • mkfs.vfat
    • grub-install
    • sudo (or root login)
  • If you want to add driver disk to the initrd.img you will also need :
    • cpio
    • xz
    • sudo
  • This procedure have been tested on Ubuntu 12.04 LTS

Initialize the USB key

In order to be able to boot from the USB key you need to make a bootable partition of type 0xB (FAT 32 C/H/S), other types might work as well, I haven’t tried.

The quickest way to do it is using sfdisk like this :
# modify the variable to suit your situation. BEWARE this is very important, 
# if you put the wrong device it can make your system unusable.
USBKEY=/dev/sdc
printf ";;b;*\n" | sudo sfdisk  ${USBKEY}

You can use -uM with sfdisk to specify the size in megabytes. It’s not relevant here since we are creating only one partition that fills the USB key.

After repartitioning your USB key, you will format it :
sudo mkfs.vfat -F 32 -n INSTALL ${USBKEY}1

Install Grub to your USB Key

Create mount point
sudo mkdir /tmp/INSTALL

Mount your USB key
sudo mount ${USBKEY}1 /tmp/INSTALL

Install grub on your USB key
sudo grub-install --force --root-directory=/tmp/INSTALL ${USBKEY}

Create a grub.cfg file

With your favorite editor create /tmp/INSTALL/boot/grub/grub.cfg
set timeout=5
set default=0

menuentry "Install CentOS 6.3" {
 linux /vmlinuz ksdevice=eth0 ks=hd:sda1:/ks.cfg --
 initrd /initrd.img
}


Create a Kickstart file



Create the file /tmp/INSTALL/ks.cfg
This is an example. You should customize your ks.cfg to suit your needs.
Keep in mind that the first harddisk will be sdb, since sda is the usbkey when you are booting.
lang en_US
keyboard us
timezone America/Montreal

rootpw --iscrypted  $1$bZB2mB8q$msVgTjbsA.RSvwiQjmr9R0
auth  --useshadow  --enablemd5
selinux --disabled
network --bootproto=dhcp --device=eth0
firewall --disabled

install
harddrive --dir=/ --partition=sda1

# Add some repo if you want (uncomment if needed)
#repo --name="EPEL6-x86_64" --baseurl=http://fedora.mirror.nexicom.net/epel/6/x86_64/
#repo --name="PuppetLabs" --baseurl=http://yum.puppetlabs.com/el/6/products/x86_64/

url --url http://less.cogeco.net/CentOS/6.3/os/x86_64/

zerombr yes
clearpart --all --initlabel
bootloader --location=mbr

# this is VERY IMPORTANT otherwise your USBKEY will be wiped during install process!
ignoredisk --drives=sda

# I’ve added fsoptions because I’m installing CentOS on SSD drives.
part swap --size 2048 --ondisk=sdb
part / --fstype ext4 --size 4096 --ondisk=sdb --fsoptions=discard,noatime,nodiratime
part /boot --fstype ext4 --size 512 --ondisk=sdb --fsoptions=discard,noatime,nodiratime
part /var --fstype ext4 --size 2048 --grow  --ondisk=sdb --fsoptions=discard,noatime,nodiratime
text
skipx
reboot

#customize the packages you want
%packages
@base
git
wget
ntp
openssh-server
openssh-clients
screen
vim


You can change the password hash used in ks.cfg using this command :
openssl passwd -1

Copy files from the ISO

Create mount point

sudo mkdir /tmp/ISO

Mount the iso file
sudo mount -o loop ~/Downloads/CentOS-6.3-x86_64-minimal.iso  /tmp/ISO
Copy the kernel and initrd from the iso
sudo cp /tmp/ISO/isolinux/initrd.img /tmp/INSTALL/
sudo cp /tmp/ISO/isolinux/vmlinuz /tmp/INSTALL/

Copy the images directory from the iso
sudo cp -r /tmp/ISO/images/ /tmp/INSTALL/

Unmount the iso and the usb key
sudo umount /tmp/INSTALL/
sudo umount /tmp/ISO/


Your USB Key is now ready to boot and install CentOS 6.3!

OPTIONAL - Add a driver disk

If  you have specialized hardware, you probably need to add a driver disk during the installation process. The best way to add a driver disk to make an unattended installation is to add it to the root of initrd image with the name dd.img.

Anaconda will load automatically the driver disk during the installation process. Here are the steps recreate the initrd.img with the dd.img



sudo mount -o loop ~/Downloads/CentOS-6.3-x86_64-minimal.iso  /tmp/ISO
cd  /tmp/INSTALL/
# the directory should be empty if you followed the instructions. If it's not empty, make sure # you unmounted the /tmp/INSTALL directory.
ls
# decompress initrd.img
xzcat --force /tmp/ISO/isolinux/initrd.img | cpio -ivdum
cp WHERE_IS_MY_DRIVER_DISK.img dd.img
# recompress initrd.img in /tmp
find . -print |cpio -o -H newc | xz --format=lzma > /tmp/initrd.img
# clean the directory rm -rf /tmp/INSTALL/*
cd /tmp
# mount the USBKEY and copy the new initrd.img sudo mount ${USBKEY}1 /tmp/INSTALL
sudo cp  /tmp/initrd.img  /tmp/INSTALL
# unmount the CD and the USBKEY
sudo umount /tmp/INSTALL
sudo umount /tmp/ISO

2012-03-19

How to sync svn repositories

Here's a simple receipe on how to sync a svn repository using svnsync.

First, create two variables. One to specify where is the source repository, the other to specify where is the target directory

TARGET_SVN=/tmp/destsvn
SOURCE_SVN=http://mysvnhost/subversion

Prepare the target directory


mkdir $TARGET_SVN
cd $TARGET_SVN
#Create the bare svn repository
svnadmin create .
#create a dummy pre-revprop-change hook
echo '#!/bin/bash' > hooks/pre-revprop-change
chmod +x hooks/pre-revprop-change
 
#prepare the target for the sync
svnsync initialize file://$(readlink -f $TARGET_SVN) $SOURCE_SVN

readlink makes sure that the path is in a canonized form.


Synchronize!


svnsync sync file://$(readlink -f $TARGET_SVN) 

That's it!

You can repeat this part periodically to sync with the remote repository.

2012-03-17

OpenVZ Centos/RedHat templates creation

I've recently found this article which is a good start on how to start to create a OpenVZ template from RPM based distribution such as RHEL, Fedora or Centos.

I'm working with Proxmox and there was some modification to do. 

So I decided to rewrite the tutorial, but it is highly inspired from the article. I recommend you to read the article before starting the following steps.

Installation

First I've installed on a VM Centos 6 using the netinstall.iso
I've chosen only the minimum installation.
The disk partitioning was done without LVM, only two partition 1GB swap, 9GB for / (formatted as ext4)

The only packages I've installed after the installation are openssh and openssh-server.
I've also ran an yum update and yum upgrade.

I've installed the Proxmox hypervisor (2.0RC), on a different VM using the ISO.

After the installation I've connected the hard disk of the Centos VM to the Hypervisor VM.

On the hypervisor, I suggest you to make a symbolic link to /vz so that you won't have to modify most of the scripts
ln -s /var/lib/vz /vz

Transferring to OpenVZ

Create a variable to identify the container ID
CTID=110
Make sure it is well assigned
echo $CTID

The following step will erase any existing container that use the $CTID number
rm -rf /vz/private/$CTID
mkdir /vz/private/$CTID 


For the rsync part, I was working on an hypervisor installed in a VM, I decided to connect the virtual hard drive of my newly installed minimal Centos 6 installation to the hypervisor instead of invoking rsync remotely 

I've mounted the Centos VM hard disk on the hypervisor on /media/centos6 and I've used this command to copy the file to the oz machine :
rsync -arvpz --numeric-ids --exclude=/dev --exclude=/mnt --exclude=/proc --exclude=/sys --exclude=/tmp  /media/centos6/ /vz/private/$CTID/

ftab modification
echo "none /dev/pts devpts rw 0 0" >  /vz/private/$CTID/etc/fstab
echo "proc /proc proc defaults 0 0" >> /vz/private/$CTID/etc/fstab

create directories
mkdir /vz/private/$CTID/dev
mkdir /vz/private/$CTID/mnt
mkdir /vz/private/$CTID/proc
mkdir /vz/private/$CTID/sys
mkdir /vz/private/$CTID/tmp
chmod 1777 /vz/private/$CTID/tmp 

I had a problem with the MAKEDEV command, the one provided by debian 6.0.4 (Used by Proxmox Hypervisor) does not work as the one described in the original HOWTO.
mkdir /vz/private/$CTID/dev/pts
mknod -m 600 /vz/private/$CTID/dev/console c 5 1
mknod -m 666 /vz/private/$CTID/dev/tty c 5 0
mknod -m 666 /vz/private/$CTID/dev/full c 1 7
mknod -m 600 /vz/private/$CTID/dev/initctl p
mknod -m 666 /vz/private/$CTID/dev/null c 1 3
mknod -m 666 /vz/private/$CTID/dev/ptmx c 5 2 
mknod -m 666 /vz/private/$CTID/dev/random c 1 8
mknod -m 444 /vz/private/$CTID/dev/urandom c 1 9 
mknod -m 666 /vz/private/$CTID/dev/zero c 1 5
mknod -m 660 /vz/private/$CTID/dev/pts/0 c 136 0
mknod -m 660 /vz/private/$CTID/dev/pts/1 c 136 1
mknod -m 000 /vz/private/$CTID/dev/pts/ptmx c 5 2
chown root.tty /vz/private/$CTID/dev/pts/0
chown root.tty /vz/private/$CTID/dev/pts/1

If you need to, set the interfaces to ONBOOT="no"
sed -i -e 's/ONBOOT="yes"/ONBOOT="no"/g'  /vz/private/$CTID/etc/sysconfig/network-scripts/ifcfg-eth*

remove HWADDR from the interfaces files
sed -i -e 's/^\(HWADDR=.*\)$//g' /vz/private/$CTID/etc/sysconfig/network-scripts/ifcfg-eth*

Change PROMPT=yes to PROMPT=no in sysconfig/init
sed -i -e 's/PROMPT=yes/PROMPT=no/g' /vz/private/$CTID/etc/sysconfig/init

Commenting out console from rc.conf
sed -i -e 's/^\(console.*\)$/#\1/g' /vz/private/$CTID/etc/init/rc.conf 

Making a default container configuration


(change centos-6-x86_64 for whatever distro you are creating a template for)
echo OSTEMPLATE=\"centos-6-x86_64\" > /etc/vz/conf/$CTID.conf
vzctl set $CTID --save --kmemsize 256M
vzctl set $CTID --save --lockedpages 256M
vzctl set $CTID --save --privvmpages unlimited
vzctl set $CTID --save --shmpages unlimited
vzctl set $CTID --save --numproc unlimited
vzctl set $CTID --save --physpages 512M
vzctl set $CTID --save --vmguarpages 0:unlimited
vzctl set $CTID --save --oomguarpages 0:unlimited
vzctl set $CTID --save --numtcpsock unlimited
vzctl set $CTID --save --numflock unlimited
vzctl set $CTID --save --numpty unlimited
vzctl set $CTID --save --numsiginfo unlimited
vzctl set $CTID --save --tcpsndbuf  unlimited
vzctl set $CTID --save --tcprcvbuf unlimited
vzctl set $CTID --save --othersockbuf unlimited
vzctl set $CTID --save --dgramrcvbuf unlimited
vzctl set $CTID --save --numothersock unlimited
vzctl set $CTID --save --numfile unlimited
vzctl set $CTID --save --dcachesize 116M:128M
vzctl set $CTID --save --numiptent unlimited
vzctl set $CTID --save --swappages 512M

vzctl set $CTID --save --quotatime 0
vzctl set $CTID --save --diskinodes 800000:880000
vzctl set $CTID --save --diskspace 1G

Enter in your OpenVZ container for cleanup

vzctl start $CTID
vzctl enter $CTID

Theses steps needs to be done from INSIDE your OpenVZ

Fix df 

rm -f /etc/mtab
ln -s /proc/mounts /etc/mtab 

remove ssh host keys

rm -f /etc/ssh/ssh_host_*

remove boot and kernel

rm -rf /boot/*.*
for i in `rpm -q kernel`; do rpm -e --nodeps $i; done


Remove unwanted packages (tested on Centos 6.2)

Check
rpm -qa | egrep 'grub|fs|firmware|libdrm|b43-openfwwf|dracut|plymouth|qpid'
And proceed...
rpm -qa | egrep 'grub|fs|firmware|libdrm|b43-openfwwf|dracut|plymouth|qpid' | while read l; do rpm -e --nodeps $l; done

clean some other dependencies and unwanted stuff (might be centos specific)
yum remove matahari matahari-lib qpid-cpp-server

Clean rpm db :
yum clean all


Creating the template


Exit the OpenVZ container with "exit" and stop it
exit
vzctl stop $CTID 


Final cleanup


rm /vz/private/$CTID/etc/resolv.conf
touch /vz/private/$CTID/etc/resolv.conf
rm /vz/private/$CTID/etc/hostname

Go to the CTID directory

cd /vz/private/$CTID

Create the tar file

tar --numeric-owner -zcf /vz/template/cache/centos-6.2-standard-x86_64.tar.gz .

Test the template


create a sample file (or get it from elsewere)

cp /etc/pve/openvz/$CTID.conf /etc/pve/openvz/ve-testOZ.conf-sample
sed -i -e 's/^OSTEMPLATE.*//g'  /etc/pve/openvz/ve-testOZ.conf-sample

Test it!


Do it using the command line or the web based interface.
vzctl create 123456 --ostemplate  centos-6.2-standard-x86_64  --config testOZ


2011-06-22

Using maven to build a qooxdoo application

Qooxdoo is a framework to build rich Internet applications. It is very promising. The qooxdoo language use a syntax similar to javascript, but it is fully object oriented. It generates optimized javascript that runs on most populars browsers.

Qooxdoo code is compiled using python script provided with the SDK.

There are few receipe to build qooxdoo apps using maven, but I rolled up my own, and I share it with you, because I think it is hasslefree. You even don't need to install python if you want!

This is possible thanks to jspresso maven repository that hosts the latest qooxdoo-sdk releases

I'm a maven newbee, so please help me make theses pom.xml snipets simplier or standard.

Let's begin.

Repository

First you need to specify the jspresso repository.

    <repositories>
        <repository>
            <id>jspresso.org</id>
            <url>http://repository.jspresso.org/maven2/</url>
        </repository>
    </repositories>

Plugin

During the compile phase, It fetches jython (Python on the JVM)
Then extracts jython.jar and the Lib directory from the jython-installer.jar
After that, it updates jython.jar (it adds the Lib directory to the jython.jar so it contains all the necessary stuff to compile qooxdoo).

On next compile, it won't do this long process again, since it checks for the existence of the file before fetching it from the Internet.


During the clean phase, it removes all the created files and directories.
As you can see, I've used maven-antrun-plugin since I'm more familiar with ant.
  
<plugin>
    <!-- we download the jython.jar from internet using ant, since it doesn't
        exists in maven repositories -->
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.6</version>
    <executions>
        <execution>
            <id>getJython</id>
            <phase>compile</phase>
            <configuration>
                        <target name="getJython">
                        <taskdef resource="net/sf/antcontrib/antcontrib.properties"
                            classpathref="maven.plugin.classpath" />
                        <if>
                            <not>
                                <available file="${project.basedir}/tools/jython.jar" />
                            </not>
                            <then>
                                <get
                                    src="http://sourceforge.net/projects/jython/files/jython/2.5.2/jython_installer-2.5.2.jar/download"
                                    dest="${project.basedir}/tools/jython_installer-2.5.2.jar"
                                    usetimestamp="true" />
                                <unzip src="${project.basedir}/tools/jython_installer-2.5.2.jar"
                                    dest="${project.basedir}/tools" overwrite="false">
                                    <patternset>
                                        <include name="jython.jar" />
                                        <include name="Lib/**" />
                                    </patternset>
                                </unzip>
                                <zip zipfile="${project.basedir}/tools/jython.jar" update="true">
                                    <fileset dir="${project.basedir}/tools/">
                                        <include name="Lib/**" />
                                    </fileset>
                                </zip>
                            </then>
                        </if>                   
                        </target>               
            </configuration>
            <goals>
                <goal>run</goal>
            </goals>
        </execution>
        <execution>
            <id>deleteJython</id>
            <phase>clean</phase>
            <configuration>
                <target>
                    <delete dir="${project.basedir}/tools/qooxdoo-sdk"/>
                    <delete file="${project.basedir}/tools/jython_installer-2.5.2.jar" />
                    <delete file="${project.basedir}/tools/jython.jar" />
                    <delete dir="${project.basedir}/tools/Lib" />
                </target>
            </configuration>
            <goals>
                <goal>run</goal>
            </goals>
        </execution>
    </executions>
   <dependencies>
      <dependency>
        <groupId>ant-contrib</groupId>
        <artifactId>ant-contrib</artifactId>
        <version>20020829</version>
      </dependency>
    </dependencies>
</plugin>

Dependencies

In the dependency part, the only needed thing is qooxdoo-sdk :

<dependencies>
        <dependency>
            <groupId>org.qooxdoo</groupId>
            <artifactId>qooxdoo-sdk</artifactId>
            <version>1.4.1</version>
            <type>zip</type>
        </dependency>
<!-- ... -->
</dependencies>


Profiles

The most interesting part is happening in the profiles.
This is where we unpack the qooxdoo-sdk, and we compile the qooxdoo code.

Qooxdoo code is compiled from src/main/qooxdoo and the compiled code will end up in
target/qooxdoo.

The pom.xml file allow two different way of invoking the qooxdoo compiler, one with "native" python. The other one using the jython we downloaded, using jython to compile is a lot slower, but it is convenient since  there is nothing more to install.

If you wish to build the qooxdoo code using native python, you need to download and install it. You will notice that it is a lot faster to compile the qooxdoo source code this way. BEWARE Python 3 is not supported, 2.5+ required.

Here is the profile to build using native python. It activates when you pass -DbuildQooxdoo=true.
You can specify where to look for the python executable if it is not in the PATH.

<profile>
    <id>qooxdoo-building</id>
    <properties>
        <pythonExecutable>python</pythonExecutable>           
    </properties>
    <activation>
        <property>
            <name>buildQooxdoo</name>
            <value>true</value>
        </property>
    </activation>
   
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2</version>
                <executions>
                    <execution>
                        <id>compile-js</id>
                        <goals>
                            <goal>exec</goal>
                        </goals>
                        <phase>compile</phase>
                    </execution>
                </executions>
        <configuration>
                  <executable>${pythonExecutable}</executable>
                  <workingDirectory>${project.basedir}</workingDirectory>
                  <arguments>
                     <argument>${project.basedir}/tools/qooxdoo-sdk/tool/bin/generator.py</argument>
                     <argument>build</argument>
                     <argument>--macro=QOOXDOO_PATH:${project.basedir}/tools/qooxdoo-sdk</argument>
                <argument>--macro=BUILD_PATH:${project.build.directory}/qooxdoo</argument>
                     <argument>--config=${project.basedir}/src/main/qooxdoo/config.json</argument>
                  </arguments>
              </configuration>
            </plugin>
        </plugins>
    </build>
</profile>



Here is the profile to build using jython. It activates when you pass -DbuildQooxdooJython=true.

<profile>
    <id>qooxdoo-building-jython</id>
    <activation>
        <property>
            <name>buildQooxdooJython</name>
            <value>true</value>
        </property>
    </activation>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2</version>
                <executions>
                    <execution>
                        <id>compile-js</id>
                        <goals>
                            <goal>exec</goal>
                        </goals>
                        <phase>compile</phase>
                    </execution>
                </executions>
                <configuration>
                    <executable>${java.home}/bin/java</executable>
                    <workingDirectory>${project.basedir}</workingDirectory>
                    <arguments>
                        <argument>-Dpython.home=${project.build.directory}</argument>
                        <argument>-classpath</argument>
                        <argument>${project.basedir}/tools/jython.jar</argument>
                        <argument>org.python.util.jython</argument>
                        <argument>${project.basedir}/tools/qooxdoo-sdk/tool/bin/generator.py</argument>
                        <argument>-v</argument>
                        <argument>build</argument>
                        <argument>--macro=QOOXDOO_PATH:${project.basedir}/tools/qooxdoo-sdk</argument>
                        <argument>--macro=BUILD_PATH:${project.build.directory}/qooxdoo</argument>
                        <argument>--config=${project.basedir}/src/main/qooxdoo/config.json</argument>
                    </arguments>
                </configuration>
            </plugin>
        </plugins>
    </build>
</profile>

Here is the profile to unpack qooxdoo-sdk, it activates when tools/qooxdoo-sdk is missing.

        <profile>
            <id>qooxdoo-unpacking</id>
            <activation>
                <file>
                    <missing>tools/qooxdoo-sdk</missing>
                </file>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-dependency-plugin</artifactId>
                        <version>2.2</version>
                        <executions>
                            <!--Import qooxdoo sdk and add it to target directory -->
                            <execution>
                                <id>extract-qooxdoo-sdk</id>
                                <phase>process-resources</phase>
                                <goals>
                                    <goal>unpack-dependencies</goal>
                                </goals>
                                <configuration>
                                    <includeArtifactIds>qooxdoo-sdk</includeArtifactIds>
                                    <outputDirectory>tools/qooxdoo-sdk</outputDirectory>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>


Using this pom.xml snipets you should be up and running in a minute!

As I write this post, I notice that I could do better by invoking getJython in the qooxdoo-building-jython profile only. This is one improvement I  see, but you will probably spot more than one!

Happy Qooxdooing!

2011-02-28

FreeFileSync : A free tool to synchronize folders

I recently wanted to synchronize few folders of a Windows machine.
I had some experience with DeltaCopy which is a front end to rsync (cygwin).
It was OK, but I had problems synchronizing some Cyrillic files, and honestly I don't think it is the easiest tool to use...

I wanted something simpler.

I ended up to play with FreeFileSync, an open source application hosted on SourceForge.
I was amazed by the quality of this tool. It is quite efficient and easy to use.

The interface is available in many languages, it is intuitive and has very interesting options. The help is very comprehensive. The tool is well polished and has professional features.

It supports larges files, it has a 64 bits version, it supports synchronization of a huge amount of files and it supports very deep paths. You can use it to backup folders on a network drive. You can mirror, update, and customize the way you want to synchronize folders. The synchronization operation is very fast. You can compare files using the combination of timestamp and size or by content. (I guess md5 is used to compare).  If you wish, you can save your sync configuration and use it later.


There are binaries available for Ubuntu 10.04, however I haven't tried this version yet.


It is a matter of minutes to get used to the tool and to get your job done.

If you need to synchronize folders in a few clicks, and you want a software that is easy to understand FreeFileSync is the tool you need!

Happy syncing! 

2011-02-03

Mockito Recipes

Last year I met a very interesting framework : Mockito.

Mockito is a mock framework for Java. It helps the developer to create mock objects for unit testing.  If you are new to mocking, I suggest you to read Martin Fowler's "Mocks Aren't Stubs".

There are many mock frameworks in Java. I tried JMock before, however I found that Mockito was easier to use. With JMock you must specify all the invocations that occurs on the mock object. If you don't do it, your test will fail. Mockito is more permissive in this way. With Mockito, if you really need to verify an invocation, you just specify it.

Of course, if you practice Test Driven Development, I think it’s better to use JMock’s style. But it’s good to know that you can use Mockito in the JMock’s way, by telling Mockito to verify all the invocations. For this reason, I think Mockito is a more versatile framework for mocking objects.

When you verify the interactions with a mock object, you make sure that it doesn’t make unplanned interactions with an unrelated object. There's an interesting post on the subject by J.B. Rainsberger on his blog.

However, I don't want to spark a debate on mocking techniques, the goal of this post is to get you started with Mockito.

So to start with Mockito :

Add JUnit’s and Mockito’s static imports. It helps the readability of the code.

import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;

Now you are ready to do some mocking!

Here are some Mockito recipes :

List<String> list = mock(List.class);

list.add("Test");
list.clear();

// verification
verify(list, times(1)).add("Test");
verify(list, times(1)).clear();

list.add("Test");
list.clear();
list.contains("Test");

//in order verification
InOrder inOrder = inOrder(list);
inOrder.verify(list).add("Test");
inOrder.verify(list).clear();
try {
// verify that there is no more interaction with the object
 verifyNoMoreInteractions(list);
 fail();
} catch (NoInteractionsWanted e) {
 // Expected
}

// thenThrow pattern
when(list.add(eq("Test"))).thenThrow(
  new RuntimeException("Major failure"));
try {
 list.add("Test");
 fail();
} catch (Exception e) {
 // Expected
}

// thenReturn pattern + chaining
when(list.contains(anyObject())).thenReturn(false).thenReturn(true);
assertFalse(list.contains("Test")); // first thenReturn
assertTrue(list.contains("Test")); // second thenReturn

// thenAnswer pattern
when(list.contains(any(String.class))).thenAnswer(
  new Answer<Boolean>() {
   @Override
   public Boolean answer(InvocationOnMock invocation_)
     throws Throwable {
    // do some stuff here (during the invocation,

    // you could play with the invocation parameters for
    // example)

    return ((String) invocation_.getArguments()[0])
      .startsWith("T");
   }
  });

assertTrue(list.contains("Test"));
assertFalse(list.contains("Best"));

// this boolean is used only for showing
// that the    code in the     answer object
// is really invocated
final AtomicBoolean invocated = new AtomicBoolean();

// mock of a void method call
doAnswer(new Answer<Object>() {
 @Override
 public Object answer(InvocationOnMock invocation_) throws
Throwable {
  // do something useful if it make sense :)
  invocated.set(true);
  return null;
 }
}).when(list).clear();

assertFalse(invocated.get());
list.clear();
// assert that the code in the Answer has been executed.
assertTrue(invocated.get());


// spy on an instance
// lets make a dummy class.
class TestSpy {
 private String _name;

 public void setName(String name_) {
  _name = name_;
 }

 public String getName() {
  return _name;
 }
}
;
// spy on it.
// (be sure to read the javadoc of the spy method prior using it)
TestSpy t = spy(new TestSpy());
t.setName("will");
assertEquals("will", t.getName());

// change the behavior of the getName() method
when(t.getName()).thenReturn("bob");
assertEquals("bob", t.getName());


Happy mocking!

2011-01-08

keepass in a console

Recently I needed to access my keepass database file from a console.  Keepass is a wonderful tool to store passwords. It's Linux counterpart keepassX is available in most major distributions.

However, keepassX is a graphical tool and I was booting from a console based distro with a very limited set of libraries. I said to myself, that it would be cool to be able to open keepass files from the console.

After some Google searches, I've found the ckpass project on sourceforge that does exactly what I wanted.
It depends on ncurses, openssl and libkpass.

I wanted to compile that all statically, so I could put it on my usbkey / dropbox and use it in case of emergency.

Here's a recipe I've made to compile ckpass-0.1 statically (32bit ELF) on Ubuntu 10.04 64bit.
(I needed a 32bit version so it can run on most small Linux distro available)

First of all create a work directory where you are going to download everything. (e.g /tmp/work)

mkdir /tmp/work
cd /tmp/work
wget http://ftp.gnu.org/pub/gnu/ncurses/ncurses-5.7.tar.gz

wget http://mirror.switch.ch/ftp/mirror/openssl/source/openssl-1.0.0c.tar.gz
wget http://downloads.sourceforge.net/project/ckpass/ckpass-0.1.tar.gz
wget http://downloads.sourceforge.net/project/libkpass/libkpass-3/libkpass-3.tar.gz

tar xzf ncurses-5.7.tar.gz
tar xzf openssl-1.0.0c.tar.gz
tar xzf ckpass-0.1.tar.gz
tar xzf libkpass-3.tar.gz

you might need to get the package install libc6-dev-i386
sudo apt-get install libc6-dev-i386


BASEDIR=/tmp/work
PREFIX=${BASEDIR}/install/

OPENSSL_HOME=${BASEDIR}/openssl-1.0.0c
LIBKPASS_HOME=${BASEDIR}/libkpass-3
CKPASS_HOME=${BASEDIR}/ckpass-0.1
NCURSES_HOME=${BASEDIR}/ncurses-5.7

cd ${OPENSSL_HOME}
make clean;./Configure linux-elf -m32  no-dso no-shared --prefix=${PREFIX}  && make install

cd ${LIBKPASS_HOME}
make clean;./configure --prefix=${PREFIX} --disable-shared  LDFLAGS="-L${OPENSSL_HOME} -m32" CFLAGS="-m32 -I${OPENSSL_HOME}/include" && make install

cd ${NCURSES_HOME}
make clean;./configure --prefix=${PREFIX}  --without-cxx  --disable-shared LDFLAGS="-L${OPENSSL_HOME} -m32" CFLAGS="-m32 -I${OPENSSL_HOME}/include" && make install

cd ${CKPASS_HOME}
make clean; ./configure LDFLAGS="-static -L${OPENSSL_HOME}  -L ${LIBKPASS_HOME}/.libs -m32 $(${PREFIX}/bin/ncurses5-config --libs)" CFLAGS="-m32 -I${OPENSSL_HOME}/include -I${LIBKPASS_HOME}/src $(${PREFIX}/bin/ncurses5-config --cflags)" LIBS="-lssl -lcrypto -lkpass -lncurses" && make && strip ckpass

After everything is done  "file ckpass" should output this :

ckpass: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, for GNU/Linux 2.6.15, stripped


I recommend to build every library one by one (do not copy & paste the whole thing). If you have an error during the execution of configure, check config.log, it contains precious informations to help you debug.

If you want to try it yourself and you have some problems doing it, feel free to post a comment, I will try to help you out.

For your convenience, I've uploaded the binary here


UPDATE
If you have a problem when starting ckpass (error opening terminal)

Don't forget to export the TERMINFO before executing ckpass.

export TERMINFO=/usr/share/terminfo/

on some distribution you will have to do :

export TERMINFO=/lib/terminfo/