I used the same SD card I had used in one of my Raspberry pis in a different Raspberry Pi board, and after rebooting it did not show up on the network.
Hooking up an HDMI cable an monitor showed that "eth0" device was not found.
It turned out that a rules file is generated based on the MAC address, and since this board had a different MAC address it created a new rules entry for eth1 for this MAC address.
Solution is to edit the file: /etc/udev/rules.d/70-persistent-net.rules and assicoate the new MAC address with eth0.
See here: http://www.raspberrypi.org/forums/viewtopic.php?f=28&t=90319
Saturday, March 14, 2015
Wednesday, August 6, 2014
Install NodeJS & NPM on PogoPlug/Dockstar (Debian Wheezy)
Prerequisites:
My Pogoplug is running Debian Wheezy with a custom 3.14 Kernel (see other posts in this blog for install instructions).
NodeJS is now part of the wheezy-backports repository, so this installation is pretty straightforward.
1. edit /etc/apt/sources.list, add the following line:
deb http://http.debian.net/debian wheezy-backports main contrib non-free
2. Install the package
apt-get install nodejs
3. check version:
nodejs -v
NOTE: the debian binary is called "nodejs" and not "node" because of a naming conflict with an existing package called "node" (HAM radio related).
This can lead to issues down the road (e.g with the npm install)
One work-around is to create a symbolic link:
as root:
ln -s /usr/bin/nodejs /usr/local/bin/node
as non-root :
ln -s /usr/bin/nodejs ~/bin/node
Unfortunately, npm is not backported to wheezy, so we build from scratch.
Some more info: Install Node.js & NPM on Debian Wheezy
1. make sure SSL certificates are installed
apt-get install ca-certificates
2. get the npm install shell script
cd /tmp
wget https://www.npmjs.org/install.sh --no-check-certificates
(NOTE: I had to add the --no-check-certificates option even though I had the latest ca-certificates installed)
3. edit the install.sh script (if necessary)
I had to add the -k parameter to all the instances where "curl" was called to bypass the certificate checking.
4. run the NPM install script
sh install.sh
You should get a message like "It worked".
5. verify version
npm -v
My Pogoplug is running Debian Wheezy with a custom 3.14 Kernel (see other posts in this blog for install instructions).
Installing NodeJS
NodeJS is now part of the wheezy-backports repository, so this installation is pretty straightforward.
1. edit /etc/apt/sources.list, add the following line:
deb http://http.debian.net/debian wheezy-backports main contrib non-free
2. Install the package
apt-get install nodejs
3. check version:
nodejs -v
NOTE: the debian binary is called "nodejs" and not "node" because of a naming conflict with an existing package called "node" (HAM radio related).
This can lead to issues down the road (e.g with the npm install)
One work-around is to create a symbolic link:
as root:
ln -s /usr/bin/nodejs /usr/local/bin/node
as non-root :
ln -s /usr/bin/nodejs ~/bin/node
Installing NPM
Unfortunately, npm is not backported to wheezy, so we build from scratch.
Some more info: Install Node.js & NPM on Debian Wheezy
1. make sure SSL certificates are installed
apt-get install ca-certificates
2. get the npm install shell script
cd /tmp
wget https://www.npmjs.org/install.sh --no-check-certificates
(NOTE: I had to add the --no-check-certificates option even though I had the latest ca-certificates installed)
3. edit the install.sh script (if necessary)
I had to add the -k parameter to all the instances where "curl" was called to bypass the certificate checking.
4. run the NPM install script
sh install.sh
You should get a message like "It worked".
5. verify version
npm -v
Sunday, January 19, 2014
PogoPlug as external event logger for MicasaVerde VeraLite
Recently I set up a VeraLite z-wave home automation controller from MiCasaVerde.
My main goals are to use this for home energy monitoring and climate control (AC/heat).
- Energy monitoring is done with an Aeon Labs Home Energy Monitor (DSB28-ZWUS).
- AC is controlled by a Trane Z-Wave thermostat
There is a plugin for the VeraLite called "DataMine" which can do graphing of energy usage, but it runs on the VeraLite itself.
I wanted to have the flexibility to record the data on a separate server in order to have additional options for storage, processing and presentation.
The MIOS OS running on the VeraLite has the option to specify an external event logger, which will be used to implement this.
I basically followed the instructions from the excellent MiCasaVerde forum:
Re: HOWTO: Event logging to database
1. set up a web server with PHP and MySQL that supports HTTPS. Configuration is described in my previous post: Install Lighttpd/PHP5/MySQL on PogoPlug or Dockstar running Debian
2. create the database and database tables for logging the VeraLite events, for example:
mysql> create database vera;
mysql> create user 'vera'@'localhost' identified by 'vera';
mysql> grant all privileges on vera.* to 'vera'@'localhost';
mysql> flush privileges;
mysql> quit;
$
$ mysql -uvera -pvera vera < alert.sql
$
3. deploy the alert.php file on the web server
- needs to be accessible at the root of the web server as /alert (use url rewrite)
- adjust the db name/username/password if necessary
4. configure VeraLite/MIOS to use the alternate event logger
http://[YOUR-VERA-IP-ADDRESS] :3480/data_request?id=variableset&Variable=AltEventServer&Value=[YOUR-WEBSERVER-IP-ADDRESS]
5. configure notifications as needed on the VeraLite through the MIOS UI
My main goals are to use this for home energy monitoring and climate control (AC/heat).
- Energy monitoring is done with an Aeon Labs Home Energy Monitor (DSB28-ZWUS).
- AC is controlled by a Trane Z-Wave thermostat
There is a plugin for the VeraLite called "DataMine" which can do graphing of energy usage, but it runs on the VeraLite itself.
I wanted to have the flexibility to record the data on a separate server in order to have additional options for storage, processing and presentation.
The MIOS OS running on the VeraLite has the option to specify an external event logger, which will be used to implement this.
I basically followed the instructions from the excellent MiCasaVerde forum:
Re: HOWTO: Event logging to database
1. set up a web server with PHP and MySQL that supports HTTPS. Configuration is described in my previous post: Install Lighttpd/PHP5/MySQL on PogoPlug or Dockstar running Debian
2. create the database and database tables for logging the VeraLite events, for example:
mysql> create database vera;
mysql> create user 'vera'@'localhost' identified by 'vera';
mysql> grant all privileges on vera.* to 'vera'@'localhost';
mysql> flush privileges;
mysql> quit;
$
$ mysql -uvera -pvera vera < alert.sql
$
3. deploy the alert.php file on the web server
- needs to be accessible at the root of the web server as /alert (use url rewrite)
- adjust the db name/username/password if necessary
4. configure VeraLite/MIOS to use the alternate event logger
http://[YOUR-VERA-IP-ADDRESS]
5. configure notifications as needed on the VeraLite through the MIOS UI
Install Lighttpd/PHP5/MySQL on PogoPlug or Dockstar running Debian
I wanted to set up a PogoPlug with an HTTP(S) server, PHP support and MySQL so I can use it for logging my home automation data (e.g. energy usage).
I had already installed Debian Wheezy on the PogoPlog E02 (See my previous post).
Since the Seagate Dockstar has the same CPU as the PogoPlug E02, these instructions should also work for the Dockstar.
For the most part I followed the instructions here: Installing Lighttpd With PHP5 (PHP-FPM) And MySQL Support On Debian Wheezy
1. install MySQL
apt-get install mysql-server mysql-clientNote:
Probably a good idea to enter a root password for MySQL when asked.
Note2:
Unfortunately, this install hung on the message "InnoDB: using native Linux AIO".
I had to reboot the server and then run
dpkg --configure -a to finish the installation, which went fine after that.2. install lighttpd
apt-get install lighttpd3. install PHP5, PHP5 FPM (FastCGI Process Manager) and related PHP modules
apt-get install php5 php5-fpm php5-mysql php5-cli php5-xcache4. configure lighttpd to use fastcgi and php5-fpm (more details: http://www.howtoforge.com/installing-lighttpd-with-php5-php-fpm-and-mysql-support-on-debian-wheezy)
- edit the /etc/lighttpd/conf-enabled/15-fastcgi-php.conf file to use the FPM (replace the existing content which uses php-cgi with this):
## Start an FastCGI server for php (needs the php5-cgi package)
fastcgi.server += ( ".php" =>
((
"socket" => "/var/run/php5-fpm.sock",
"broken-scriptfilename" => "enable"
))
)
- enable the modules
lighttpd-enable-mod fastcgi lighttpd-enable-mod fastcgi-php - reload lighttpd
/etc/init.d/lighttpd force-reload
- edit the /etc/php5/fpm/php.ini file, uncomment the line:
cgi.fix_pathinfo=1
- reload FPM
/etc/init.d/php5-fpm reload
5. configure URL rewriting for lighttpd
- edit /etc/lighttpd/lighttpd.conf to add the url.rewrite section based on your needs
6. configure SSL for lighttpd
- create a self-signed certificate
apt-get install openssl
mkdir /etc/lighttpd/cert
cd /etc/lighttpd/cert
openssl req -new -x509 -keyout midnightcoding.pem -out midnightcoding.pem -days 365 -nodes
chmod 600 /etc/lighttpd/cert
lighttpd-enable-mod ssl- edit the ssl configuration file
vi /etc/lighttpd/onf-available/10-ssl.conf- change the line with ssl.pemfile to point to the path /etc/lighttpd/cert/midnightcoding.pem
apt-get install phpmyadmin(select lighted as the web server for phpMyAdmin)
8. get phpmyadmin and other url rewrite rules to play nice
- url.rewrite overwrites the alias.url used by phpmyadmin in /etc/lighttpd/conf-enabled
-> need to add a special rule to pass along phpmyadmin urls "as-is"
url.rewrite-if-not-file = ( "^/(phpmyadmin)/(.*)" => "$0",
"^/([^?]*)(\?.*)?$" => "/$1.php$2"
)
Now you should be able to access your server at:
https://[YOUR-SERVER-IP]/phpmyadminTuesday, January 7, 2014
Seagate Dockstar - use a digital photo frame as display
I wanted to put a cheap display on my Seagate Dockstar that I am currently using as Internet Radio and AirPlay receiver (using mpd and mpc).
After some research, I found some recommended suitable displays. The displays I bought are based on the "AppoTech AX206" chip and are supported by LCD4Linux, but the display firmware needs to be "hacked" first to allow it to be used from Linux.
I got a lot of information from this post: Digital Picture Frame as a router status display and the OpenWRT forum. See here for more info and supported devices.
I got the display to work on the Raspberry Pi successfully, now onto the next device.
Some Dockstar instructions are here (in German): LCD Display an DockStar
Installation on the Dockstar:
Unfortunately the LCD4Linux version installable with "apt-get install lcd4linux" is too old and does not include the needed DPF drivers. So we need to rebuild LCD4Linux.
0. Hack the LCD firmware, please refer to the links above for this.
1.install necessary dependency packages
2. install SVN and other dependencies to be able to build lcd4linux
(Note: these files might take up quite a lot of space, about 40+ MB on my system. They are only necessary to successfully compile LCD4Linux)
3. make a folder where to put the LCD4Linux files, e.g. /home/root/dpf
4. get (checkout) the LCD4Linux files (currently this is revision 1200):
5. build the DPF version of LCD4Linux
6. install the LCD4Linux package
On success you should get:
Notes:
- checkinstall will ask for a name, I used "LCD4Linux with DPF"
- checkinstall will complain aboput the version number, so I used "0.11.0-1200" since 1200 was the SVN revision that was used
- as noted in the success message, the installed package can be removed with "dpkg -r lcd4linux"
7. create or adjust your LCD4Linux configuration file
- the file needs to be located in /etc and called lcd4linux.conf
or get an example file from here:
Note: the permissions on the lcd4linux.conf file need to be set as:
8. start/restart LCD4Linux
Success:
9. Adjust lcd4linux.conf file according to your needs
After some research, I found some recommended suitable displays. The displays I bought are based on the "AppoTech AX206" chip and are supported by LCD4Linux, but the display firmware needs to be "hacked" first to allow it to be used from Linux.
I got a lot of information from this post: Digital Picture Frame as a router status display and the OpenWRT forum. See here for more info and supported devices.
I got the display to work on the Raspberry Pi successfully, now onto the next device.
Some Dockstar instructions are here (in German): LCD Display an DockStar
Installation on the Dockstar:
Unfortunately the LCD4Linux version installable with "apt-get install lcd4linux" is too old and does not include the needed DPF drivers. So we need to rebuild LCD4Linux.
0. Hack the LCD firmware, please refer to the links above for this.
1.install necessary dependency packages
apt-get install libgd2-noxpm2. install SVN and other dependencies to be able to build lcd4linux
apt-get install subversion
apt-get install pkg-config automake autoconf make checkinstallapt-get install libtool libusb-dev
(Note: these files might take up quite a lot of space, about 40+ MB on my system. They are only necessary to successfully compile LCD4Linux)
3. make a folder where to put the LCD4Linux files, e.g. /home/root/dpf
cd /home/root
mkdir dpf
4. get (checkout) the LCD4Linux files (currently this is revision 1200):
svn co https://ssl.bulix.org/svn/lcd4linux/trunk lcd4linux5. build the DPF version of LCD4Linux
cd lcd4linux
./bootstrap
./configure --with-drivers='DPF' --with-plugins='all,!dbus'6. install the LCD4Linux package
checkinstall -D
On success you should get:
**********************************************************************
Done. The new package has been installed and saved to
/home/root/dpf/lcd4linux/lcd4linux_0.11.0-1200-1_armel.deb
You can remove it from your system anytime using:
dpkg -r lcd4linux
**********************************************************************
Notes:
- checkinstall will ask for a name, I used "LCD4Linux with DPF"
- checkinstall will complain aboput the version number, so I used "0.11.0-1200" since 1200 was the SVN revision that was used
- as noted in the success message, the installed package can be removed with "dpkg -r lcd4linux"
7. create or adjust your LCD4Linux configuration file
- the file needs to be located in /etc and called lcd4linux.conf
or get an example file from here:
wget http://pkern.at/wp-content/uploads/lcd4linux/lcd4linux.confNote: the permissions on the lcd4linux.conf file need to be set as:
chmod 600 lcd4linux.conf8. start/restart LCD4Linux
kill lcd4linux && sleep 1 && lcd4linuxSuccess:
9. Adjust lcd4linux.conf file according to your needs
Monday, December 23, 2013
PogoPlug E02 - configure LEDs
Make the following modifications to turn the front LED green when the boot process is completed and turn the LED off when it's save to unplug the PogoPlug.
1. Install a kernel with LED support onto the PogoPlug.
Instructions here: Linux Kernel 3.12.0 Kirkwood package ...
I installed Kernel 3.12.0, which is the latest at the moment.
2. edit /etc/rc.local
add these lines:
echo none > sys/class/leds/status\:orange\:fault/trigger
echo default-on > sys/class/leds/status\:green\:health/trigger
* this will turn off the orange LED and turn on the green LED
2a. to show network traffic by blinking the orange LED:
#Set up orange LED to blink on incoming TCP traffic iptables -A INPUT -p tcp -j LED --led-trigger-id tcpin --led-delay 100 echo netfilter-tcpin > /sys/class/leds/status\:orange\:fault/trigger
(Note: might have to install iptables with apt-get install iptables)
3. edit /etc/init.d/halt
add this line BEFORE "halt -d -f $netdown ...":
echo none > sys/class/leds/status\:green\:health/trigger
(Note: in the instructions here it says to add the line AFTER the "halt" line but that did not work for me. It seems execution stops at the "halt" line an dsubsequent code is not executed.)
(Note2: if you see an LED called "status:blue:health" in /sys/class/leds then your PogoPlug is not properly recognized and the machine is running as a SheevaPlug. You might need to set the environment:
fw_setenv machid dd6
details are here.
1. Install a kernel with LED support onto the PogoPlug.
Instructions here: Linux Kernel 3.12.0 Kirkwood package ...
I installed Kernel 3.12.0, which is the latest at the moment.
2. edit /etc/rc.local
add these lines:
echo none > sys/class/leds/status\:orange\:fault/trigger
echo default-on > sys/class/leds/status\:green\:health/trigger
* this will turn off the orange LED and turn on the green LED
2a. to show network traffic by blinking the orange LED:
#Set up orange LED to blink on incoming TCP traffic iptables -A INPUT -p tcp -j LED --led-trigger-id tcpin --led-delay 100 echo netfilter-tcpin > /sys/class/leds/status\:orange\:fault/trigger
(Note: might have to install iptables with apt-get install iptables)
3. edit /etc/init.d/halt
add this line BEFORE "halt -d -f $netdown ...":
echo none > sys/class/leds/status\:green\:health/trigger
(Note: in the instructions here it says to add the line AFTER the "halt" line but that did not work for me. It seems execution stops at the "halt" line an dsubsequent code is not executed.)
(Note2: if you see an LED called "status:blue:health" in /sys/class/leds then your PogoPlug is not properly recognized and the machine is running as a SheevaPlug. You might need to set the environment:
fw_setenv machid dd6
details are here.
Saturday, December 21, 2013
PogoPlug E02 - move Debian to larger USB drive
USB drives are getting bigger and cheaper. Here are the steps I used ot move my Debian Wheezy installation from a 4GB USB drive to an 8GB USB drive.
1. partition the new drive the same way the existing one is partitioned
* use fdisk for this step
* this can be done on the PogoPlug or on another Linux computer
* e.g. 3.5GB root partition (ext2) and 500MB swap partition
* Note: this could have been done with GParted as well
2. on another Linux computer format the new USB drive partitions as ext2 and linux-swap respectively
* I used GParted for this
3. on another Linux computer, copy the old drive to the new drive using rsync
* plug in both drives into your Linux machine
* mount both drives
* as root in a terminal window:
rsync -av /media/USBCurrent/ /media/USBNew/
(make sure to use the correct mount folders, careful to list the SOURCE first)
* unmount both drives
4. check installation
* plug new USB drive into PogoPlug
* power on PogoPlug
* wait for system to boot, should show up under the same name/IP as the old one
5. expand the root partition to the larger size
* shut down PogoPlug
* unplug new USB drive
* plug new USB drive into Linux computer
* with GParted move the swap partition to the end of the drive and resize the root partition as needed
6.Boot up PogoPlug
* plug new USB drive back into the PogoPlug and power on PogoPlug
7. The UUID for the swap partition might have changed since using GParted to move/resize the swap partition.
If you issue the "top" command and under "KiB Swap" it shows 0, you have to fix this:
List the known UUIDs:
blkid -c /dev/null
Check fstab:
cat /etc/fstab
If the UUID in fstab for the line containing the swap partition does not match the UUID from the blkid output do this:
- edit fstab to change the swap partition line to the correct UUID, then save fstab
- swapon -a to enable the swap partition
check if the change worked, issue the "top" command and check at the top under "KiB Swap".
1. partition the new drive the same way the existing one is partitioned
* use fdisk for this step
* this can be done on the PogoPlug or on another Linux computer
* e.g. 3.5GB root partition (ext2) and 500MB swap partition
* Note: this could have been done with GParted as well
2. on another Linux computer format the new USB drive partitions as ext2 and linux-swap respectively
* I used GParted for this
3. on another Linux computer, copy the old drive to the new drive using rsync
* plug in both drives into your Linux machine
* mount both drives
* as root in a terminal window:
rsync -av /media/USBCurrent/ /media/USBNew/
(make sure to use the correct mount folders, careful to list the SOURCE first)
* unmount both drives
4. check installation
* plug new USB drive into PogoPlug
* power on PogoPlug
* wait for system to boot, should show up under the same name/IP as the old one
5. expand the root partition to the larger size
* shut down PogoPlug
* unplug new USB drive
* plug new USB drive into Linux computer
* with GParted move the swap partition to the end of the drive and resize the root partition as needed
6.Boot up PogoPlug
* plug new USB drive back into the PogoPlug and power on PogoPlug
7. The UUID for the swap partition might have changed since using GParted to move/resize the swap partition.
If you issue the "top" command and under "KiB Swap" it shows 0, you have to fix this:
List the known UUIDs:
blkid -c /dev/null
Check fstab:
cat /etc/fstab
If the UUID in fstab for the line containing the swap partition does not match the UUID from the blkid output do this:
- edit fstab to change the swap partition line to the correct UUID, then save fstab
- swapon -a to enable the swap partition
check if the change worked, issue the "top" command and check at the top under "KiB Swap".
Friday, December 20, 2013
PogoPlug E02 - Install Debian
I got myself another cheap PogoPlug E02 from Adorama . It is sold as a model P21, but I actually got the E02, which is nicer (better processor, more RAM).
Steps to install Debian Linux on the PogoPlug
0. start up the PogoPlug, no drives attached
1. SSH into the PogoPlug (default password: ceadmin)
2. Disable the PogoPlug Service
killall hbwd
3. install newer UBOOT as per instructions here: http://projects.doozan.com/uboot/
- select to disable the PogoPlug service
- set the arcNumber to 3542 as per here: http://archlinuxarm.org/forum/viewtopic.php?t=2780
/usr/sbin/fw_setenv arcNumber 3542
4. plug in USB drive
5. partition the USB drive with fdisk
- if fdisk gives "command not found" execute directly from /usr/sbin (this might also be in /sbin)
cd /usr/sbin
./fdisk /dev/sda
- fdisk usage
6. DOES NOT WORK: Install Debian Wheezy (7.0)
- Follow instructions from Jeff Doozan's site: http://projects.doozan.com/debian/ use Debian 7.0 (Wheezy)
cd /tmp
wget http://projects.doozan.com/debian/kirkwood.debian-wheezy.sh
chmod +x kirkwood.debian-wheezy.sh
export PATH=$PATH:/usr/sbin:/sbin
./kirkwood.debian-wheezy.sh
wait ...... (this may take some time)
Major Complications: I ran into the following error:
FATAL: Kernel too old in debootstrap
- tried to install rescue system, but you cannot install that from the device itself, needs to be booted from USB
- created USB boot drive with rescue system 3.0 (http://forum.doozan.com/read.php?4,8277) .. BUT from there you CANNOT seem to install the rescue system V2 into NAND - it says uBoot is outdated even though it's the latest version
After a lot of unsuccessful attempts went the following route:
1. install Debian Squeeze
Follow the instructions here: https://sites.google.com/site/leiqincwru/pogoplus/install-debian-squeeze-on-pogoplug-e02
(The regular instructions are here, but the above link has additional commands to be executed for the PogoPlug).
This is important for PogoPlug:
2. install rescue system 2.8.2
* link: http://forum.doozan.com/read.php?4,7915
* copied files to the debian system installed under #1
* install mtd-utils if flash_eraseall is not found (apt-get install mtd-utils)
* manual install
3. upgrade from Squeeze to Wheezy - described here (http://blog.vinnymac.org/?p=11)
Finally. Success.
4. Optional:
* update to a newer 3.x kernel from the following link: http://forum.doozan.com/read.php?2,12096
Note: apt-get upgrade might complain about half-installed packages because we manually installed the new kernel. In that case manually edit /var/lib/dpkg/status file and change "half-configured" to "installed". See here: http://ubuntuforums.org/showthread.php?t=1547998
Note2: after that there was still an error message about a "Configured-Version for package with inappropriate Status" - there was a line in the status file called "Config-Version". After it deleted that line the error went away.
5. Change the sources to the proper wheezy sources
vim /etc/apt/sources.list
add these lines, comment the others:
deb http://http.debian.net/debian wheezy main contrib non-free
deb http://http.debian.net/debian wheezy-updates main contrib non-free
6. Update your system
apt-get update
apt-get upgrade
7. Configure timezone
dpkg-reconfigure tzdata
Steps to install Debian Linux on the PogoPlug
0. start up the PogoPlug, no drives attached
1. SSH into the PogoPlug (default password: ceadmin)
2. Disable the PogoPlug Service
killall hbwd
3. install newer UBOOT as per instructions here: http://projects.doozan.com/uboot/
- select to disable the PogoPlug service
- set the arcNumber to 3542 as per here: http://archlinuxarm.org/forum/viewtopic.php?t=2780
/usr/sbin/fw_setenv arcNumber 3542
4. plug in USB drive
5. partition the USB drive with fdisk
- if fdisk gives "command not found" execute directly from /usr/sbin (this might also be in /sbin)
cd /usr/sbin
./fdisk /dev/sda
- fdisk usage
- p to show your current partitions
- d 1 to delete your first partition, and if necessary d 2, d 3, and so on
- p again to make sure there are no partitions left
- n for new partition, p for primary, 1 for partition 1, enter to accept the default starting point, and then +(size)M to size it. I used a 2 GB drive, so I put +1536M for 1.5 GB
- n, p, 2, enter, enter to create a swap partition out of the rest. Ideally you won't need a swap partition at all (we're going to try to avoid it), but better safe than sorry.
- t to change filesystem types, 2 for the second partition, and 82 for swap.
- a, 1 to set partition 1 as active/bootable
- p one last time to make sure everything looks okay. Once again, fdisk hasn't done anything to the drive yet, so if you see a mistake, you can either start over or fix it if you know what needs to be done.
- And finally, w to write the partition table to disk and exit.
6. DOES NOT WORK: Install Debian Wheezy (7.0)
- Follow instructions from Jeff Doozan's site: http://projects.doozan.com/debian/ use Debian 7.0 (Wheezy)
cd /tmp
wget http://projects.doozan.com/debian/kirkwood.debian-wheezy.sh
chmod +x kirkwood.debian-wheezy.sh
export PATH=$PATH:/usr/sbin:/sbin
./kirkwood.debian-wheezy.sh
wait ...... (this may take some time)
Major Complications: I ran into the following error:
FATAL: Kernel too old in debootstrap
- tried to install rescue system, but you cannot install that from the device itself, needs to be booted from USB
- created USB boot drive with rescue system 3.0 (http://forum.doozan.com/read.php?4,8277) .. BUT from there you CANNOT seem to install the rescue system V2 into NAND - it says uBoot is outdated even though it's the latest version
After a lot of unsuccessful attempts went the following route:
1. install Debian Squeeze
Follow the instructions here: https://sites.google.com/site/leiqincwru/pogoplus/install-debian-squeeze-on-pogoplug-e02
(The regular instructions are here, but the above link has additional commands to be executed for the PogoPlug).
This is important for PogoPlug:
./mkimage -A arm -O linux -T kernel -C none -a 0x00008000 -e
0x00008000 -n Linux-2.6.32-5-kirkwood -d
../../boot/vmlinuz-2.6.32-5-kirkwood ../../boot/uImage
./mkimage
-A arm -O linux -T ramdisk -C gzip -a 0x00000000 -e 0x00000000 -n
initramfs-2.6.32-5-kirkwood -d ../../boot/initrd.img-2.6.32-5-kirkwood
../../boot/uInitrd
2. install rescue system 2.8.2
* link: http://forum.doozan.com/read.php?4,7915
* copied files to the debian system installed under #1
* install mtd-utils if flash_eraseall is not found (apt-get install mtd-utils)
* manual install
flash_eraseall /dev/mtd1 nandwrite /dev/mtd1 uImage-mtd1.img flash_eraseall /dev/mtd2 ubiformat /dev/mtd2 -s 512 -f rootfs-mtd2.img -y fw_setenv set_bootargs_rescue 'setenv bootargs console=$console ubi.mtd=2 root=ubi0:rootfs ro rootfstype=ubifs $mtdparts' fw_setenv bootcmd_rescue 'run set_bootargs_rescue; nand read.e 0x800000 0x100000 0x400000; bootm 0x800000' fw_setenv bootcmd_pogo 'run bootcmd_rescue' fw_setenv rescue_installed 1
3. upgrade from Squeeze to Wheezy - described here (http://blog.vinnymac.org/?p=11)
Finally. Success.
4. Optional:
* update to a newer 3.x kernel from the following link: http://forum.doozan.com/read.php?2,12096
Note: apt-get upgrade might complain about half-installed packages because we manually installed the new kernel. In that case manually edit /var/lib/dpkg/status file and change "half-configured" to "installed". See here: http://ubuntuforums.org/showthread.php?t=1547998
Note2: after that there was still an error message about a "Configured-Version for package with inappropriate Status" - there was a line in the status file called "Config-Version". After it deleted that line the error went away.
5. Change the sources to the proper wheezy sources
vim /etc/apt/sources.list
add these lines, comment the others:
deb http://http.debian.net/debian wheezy main contrib non-free
deb http://http.debian.net/debian wheezy-updates main contrib non-free
6. Update your system
apt-get update
apt-get upgrade
7. Configure timezone
dpkg-reconfigure tzdata
Wednesday, December 1, 2010
Seagate Dockstar - Install Debian Linux
Step 1: Disable the Pogoplug services
- SSH into the DockStar
- command: "killall hbwd"
Step 2: Attach and configure the USB device
- use fdisk (instructions here)
- create 2 partitions: 1st partition type 83 (Linux), second partition type 82 (Linux Swap)
- mark partition 1 as bootable
Step 3: Install Debian Linux
- use instructions here
- this will take a while, after it is finished it will ask you to reboot
- log back in using SSH (PuTTY)
- change the host name by editing the file "/etc/hostname" using vi or nano
- set the timezone by using "dpkg-reconfigure tzdata"
- optionally, install an updated Kernel from here
Step 4: Additional Configuration
- install nano editor "apt-get install nano"
- install sudo with "apt-get install sudo"
- add additional users with "adduser"
- install other packages for internet radio, samba, I2C etc. (will be covered in later posts)
Step 5: make a copy/backup of your system
If you have the system configured and running, you can make a backup copy onto another USB stick with the following command:
This assumes that the boot USB drive is /dev/sda and the traget drive is /dev/sdb
ALL DATA ON /dev/sdb WILL BE ERASED!
Related links:
DIY Audio - hackable linux (openWRT) ethernet board
http://www.mikrocontroller.net/articles/Dockstar
http://ahsoftware.de/dockstar/
http://www.rudiswiki.de/wiki/DockStarDebian
Ten(ish) steps to setting up a Seagate Dockstar
http://anwendungsentwickler.ws/dockstar_freeagent_bekommt_zuwachs/entry/316/
- SSH into the DockStar
- command: "killall hbwd"
Step 2: Attach and configure the USB device
- use fdisk (instructions here)
- create 2 partitions: 1st partition type 83 (Linux), second partition type 82 (Linux Swap)
- mark partition 1 as bootable
Step 3: Install Debian Linux
- use instructions here
- this will take a while, after it is finished it will ask you to reboot
- log back in using SSH (PuTTY)
- If the device does not boot into your new Debian install, you maye have a USB stick that is not suitable for booting from it. Try a "warm boot" by using a pen to push the "Reset" button on the right side of the DockStar.).
- The device may have a different IP address now (check that using your router)
- to troubleshoot you can use netconsole as described here
- change the host name by editing the file "/etc/hostname" using vi or nano
- set the timezone by using "dpkg-reconfigure tzdata"
- optionally, install an updated Kernel from here
Step 4: Additional Configuration
- install nano editor "apt-get install nano"
- install sudo with "apt-get install sudo"
- add additional users with "adduser"
- install other packages for internet radio, samba, I2C etc. (will be covered in later posts)
Step 5: make a copy/backup of your system
If you have the system configured and running, you can make a backup copy onto another USB stick with the following command:
dd if=/dev/sda of=/dev/sdb
This assumes that the boot USB drive is /dev/sda and the traget drive is /dev/sdb
ALL DATA ON /dev/sdb WILL BE ERASED!
Related links:
DIY Audio - hackable linux (openWRT) ethernet board
http://www.mikrocontroller.net/articles/Dockstar
http://ahsoftware.de/dockstar/
http://www.rudiswiki.de/wiki/DockStarDebian
Ten(ish) steps to setting up a Seagate Dockstar
http://anwendungsentwickler.ws/dockstar_freeagent_bekommt_zuwachs/entry/316/
Tuesday, December 16, 2008
VB.Net and Optional Parameters - watch out!
I read somewhere recently that C# 4.0 will also have optional parameters, like VB6 and VB.Net had all along.
When moving to .Net I decided not to use optional parameters in VB.net since they were kind of looked at as a remnant of VB6, not CLR compliant, not available in C# etc.
And the "preferred way" was to use overloads instead of Optional Parameters.
So now after I read that C# 4.0 will have optional parameters (and the fact that I am kind of "over" the many overloads that are sometimes necessary, especially if you have logging methods etc.) I was thinking of going back to using Optional Parameters.
I always assumed that the compiler for VB.Net would just created the overloads in the background, substituting it with the default values given to the Optional Parameters.
But that is not the case. The compile hard-compiles the default values into the CALLING method/object and not as an overload into the called method.
Joel On Software
VB.NET Optional parameters
Optional Parameters (VB.NET)
Now this was a big red flag for me, because that means each time you change the value of one of the default parameters, you would need to recompile ALL the CALLING classes as well (if they call with some of the optional parameters omitted).
So if you have a live enterprise system with multiple DLLs and you need to deploy hotfixes as individual DLLs then you'd have to deploy the changed DLL and all the DLLs that call it. Otherwise the "old" DLLs will still call your method with the "old" default value and this could introduce some hard-to-find side effects.
One might argue how often do you really need to change the default value of an Optional Parameter and that that indicates a deeper design issue.
But still, for complex system or legacy code that you are refactoring this might be a real possibility.
Furthermore in VB.Net 3.5 you cannot use Nullable types as optional parameters, i.e. you cannot do this:
Public Sub DoStuff(Optional ByVal intEntityID As Nullable(Of Integer) = Nothing)
End Sub
So my conclusion at this point is to stick with overloads instead of Optional Parameters. More predictable and less things to remember as possible pitfalls. :)
I got enough other stuff to cram into my head ...
When moving to .Net I decided not to use optional parameters in VB.net since they were kind of looked at as a remnant of VB6, not CLR compliant, not available in C# etc.
And the "preferred way" was to use overloads instead of Optional Parameters.
So now after I read that C# 4.0 will have optional parameters (and the fact that I am kind of "over" the many overloads that are sometimes necessary, especially if you have logging methods etc.) I was thinking of going back to using Optional Parameters.
I always assumed that the compiler for VB.Net would just created the overloads in the background, substituting it with the default values given to the Optional Parameters.
But that is not the case. The compile hard-compiles the default values into the CALLING method/object and not as an overload into the called method.
Joel On Software
VB.NET Optional parameters
Optional Parameters (VB.NET)
Now this was a big red flag for me, because that means each time you change the value of one of the default parameters, you would need to recompile ALL the CALLING classes as well (if they call with some of the optional parameters omitted).
So if you have a live enterprise system with multiple DLLs and you need to deploy hotfixes as individual DLLs then you'd have to deploy the changed DLL and all the DLLs that call it. Otherwise the "old" DLLs will still call your method with the "old" default value and this could introduce some hard-to-find side effects.
One might argue how often do you really need to change the default value of an Optional Parameter and that that indicates a deeper design issue.
But still, for complex system or legacy code that you are refactoring this might be a real possibility.
Furthermore in VB.Net 3.5 you cannot use Nullable types as optional parameters, i.e. you cannot do this:
Public Sub DoStuff(Optional ByVal intEntityID As Nullable(Of Integer) = Nothing)
End Sub
So my conclusion at this point is to stick with overloads instead of Optional Parameters. More predictable and less things to remember as possible pitfalls. :)
I got enough other stuff to cram into my head ...
Thursday, November 13, 2008
HTTP concurrent connections from IE - AJAX
I have been stumbling across articles about the two-concurrent-connection limit of IE7 recently.
Tools like the Visual Round Trip Analyzer from Microsoft also mention this in the set of criteria they evaluate against.
It seems that in IE8 the limit of 2 connections is increased to 6 as per here:
AJAX - Connectivity Enhancements in Internet Explorer 8
But it can also be tweaked in IE7 and below as decsribed in the KB article:
http://support.microsoft.com/kb/183110
Other links:
12 Steps To Faster Web Pages With Visual Round Trip Analyzer
Case Study: Much ado about Browser's HTTP connection
Tools like the Visual Round Trip Analyzer from Microsoft also mention this in the set of criteria they evaluate against.
It seems that in IE8 the limit of 2 connections is increased to 6 as per here:
AJAX - Connectivity Enhancements in Internet Explorer 8
But it can also be tweaked in IE7 and below as decsribed in the KB article:
http://support.microsoft.com/kb/183110
Other links:
12 Steps To Faster Web Pages With Visual Round Trip Analyzer
Case Study: Much ado about Browser's HTTP connection
Friday, November 7, 2008
Nested JOINS (mix of inner and outer joins in SQL)
I just ran into this today:
Be Careful When Mixing INNER and OUTER Joins
It's not rocket science, but it can be somewhat counter-intuitive. How to tell the SQL server query engine what you want as an inner join vs an outer join.
I ended up using the nested join syntax by the way, seems cleanest to me and is not relying on the position of the JOIN line in the query.
Basically:
Be Careful When Mixing INNER and OUTER Joins
It's not rocket science, but it can be somewhat counter-intuitive. How to tell the SQL server query engine what you want as an inner join vs an outer join.
I ended up using the nested join syntax by the way, seems cleanest to me and is not relying on the position of the JOIN line in the query.
Basically:
select People.PersonName, Pets.PetName, PetTypes.PetType
from People
left outer join
(Pets inner join PetTypes on Pets.PetTypeID = PetTypes.PetTypeID)
on Pets.OwnerID = People.PersonID
Monday, November 3, 2008
Stored Procedures - Best Practices
Excellent post where Aaron Bertrand shares his best practices for developing stored procedures covering both coding style as well as some coding best practices (good use of NOCOUNT etc).
http://sqlblog.com/blogs/aaron_bertrand/archive/2008/10/30/my-stored-procedure-best-practices-checklist.aspx
http://sqlblog.com/blogs/aaron_bertrand/archive/2008/10/30/my-stored-procedure-best-practices-checklist.aspx
Windows Azure - behold the cloud
A lot of buzz is being generated at the moment about the Microsoft Azure Services platform. Here is a brief collection of links to get started on it.
Microsoft’s official Azure site, containing links to the key parts of the platform and documentation:
http://www.microsoft.com/azure/default.mspx
Microsoft's official press release:
http://www.microsoft.com/presspass/press/2008/oct08/10-27PDCDay1PR.mspx
Overview blog post by Paul Gielens:
http://weblogs.asp.net/pgielens/archive/2008/10/27/a-lap-around-windows-azure.aspx
Some details on how the Windows Azure back end infrastructure is laid out:
http://blogs.msdn.com/domgreen/archive/2008/10/30/windows-azure-back-end.aspx
Getting Started with Windows Azure - The Cloud Computing Tools Team has a nice post gathering together the downloads, tools and some information about the tools and SDK:
http://blogs.msdn.com/cloud/archive/2008/10/27/getting-started-windows-azure-tools-for-microsoft-visual-studio.aspx
Here's a tutorial on the process of storing information in Azure with plenty of screenshots and code samples included in the post:
http://blogs.msdn.com/jnak/archive/2008/10/29/walkthrough-simple-blob-storage-sample.aspx
A tutorial on the process of getting up and running with Azure, from setting up the development environment to publishing your first application:
http://blogs.msdn.com/olavt/archive/2008/10/30/how-to-create-and-publish-your-first-windows-azure-application.aspx
Clemens Vasters blogs about the Microsoft .Net ServiceBus that is part of the Azure platform:
http://vasters.com/clemensv/PermaLink,guid,92d78bee-2cfd-4a29-95ab-c5abb9b905e7.aspx
Microsoft’s official Azure site, containing links to the key parts of the platform and documentation:
http://www.microsoft.com/azure/default.mspx
Microsoft's official press release:
http://www.microsoft.com/presspass/press/2008/oct08/10-27PDCDay1PR.mspx
Overview blog post by Paul Gielens:
http://weblogs.asp.net/pgielens/archive/2008/10/27/a-lap-around-windows-azure.aspx
Some details on how the Windows Azure back end infrastructure is laid out:
http://blogs.msdn.com/domgreen/archive/2008/10/30/windows-azure-back-end.aspx
Getting Started with Windows Azure - The Cloud Computing Tools Team has a nice post gathering together the downloads, tools and some information about the tools and SDK:
http://blogs.msdn.com/cloud/archive/2008/10/27/getting-started-windows-azure-tools-for-microsoft-visual-studio.aspx
Here's a tutorial on the process of storing information in Azure with plenty of screenshots and code samples included in the post:
http://blogs.msdn.com/jnak/archive/2008/10/29/walkthrough-simple-blob-storage-sample.aspx
A tutorial on the process of getting up and running with Azure, from setting up the development environment to publishing your first application:
http://blogs.msdn.com/olavt/archive/2008/10/30/how-to-create-and-publish-your-first-windows-azure-application.aspx
Clemens Vasters blogs about the Microsoft .Net ServiceBus that is part of the Azure platform:
http://vasters.com/clemensv/PermaLink,guid,92d78bee-2cfd-4a29-95ab-c5abb9b905e7.aspx
Tuesday, August 5, 2008
Copy data between 2 SQL servers - Take 2
Alright, so one of the issues my previous post did not address was the treatment of Identity columns when using BCP and BULK import.
By default, identity column data is not part of a BCP export, so when doing a BULK IMPORT SQL server will assign new values to the identity Column .
Fortunately, that is relatively easy to address, as decribed here:
http://msdn.microsoft.com/en-us/library/ms186335.aspx
Basically when doing a BCP export, add the "-E" parameter.
Example:
bcp Northwind.dbo.Authors out C:\Temp\DataExport.dat -n -E -T -S MPDESKTOP\SQL2005
And when importing, use the KEEPIDENTITY parameter in the BULK INSERT like this:
USE Northwind
GO
BULK INSERT Authors
FROM 'G:\Transfer\Tempfiles\DataExport.dat'
WITH (KEEPIDENTITY, DATAFILETYPE='native');
GO
This will preserve the values of identity columns when copying data between 2 servers/databases. Keep in mind that there still might be issue with referential integrity constraints etc. that you need to address when moving data between databases.
By default, identity column data is not part of a BCP export, so when doing a BULK IMPORT SQL server will assign new values to the identity Column .
Fortunately, that is relatively easy to address, as decribed here:
http://msdn.microsoft.com/en-us/library/ms186335.aspx
Basically when doing a BCP export, add the "-E" parameter.
Example:
bcp Northwind.dbo.Authors out C:\Temp\DataExport.dat -n -E -T -S MPDESKTOP\SQL2005
And when importing, use the KEEPIDENTITY parameter in the BULK INSERT like this:
USE Northwind
GO
BULK INSERT Authors
FROM 'G:\Transfer\Tempfiles\DataExport.dat'
WITH (KEEPIDENTITY, DATAFILETYPE='native');
GO
This will preserve the values of identity columns when copying data between 2 servers/databases. Keep in mind that there still might be issue with referential integrity constraints etc. that you need to address when moving data between databases.
Tuesday, June 10, 2008
Updating the Main UI from a different thread
As you probably know, the availability of threading in .Net can lead to all kinds of little surprises, together of course with the power to write much more responsive applications.
For instance if you have a WinForms app that spawns a worker thread, and then that worker thread needs to update any UI elements on the main form, it will not work, since you can only update UI elements from the same thread they are created on.
I specifically ran into this when using a custom NUnit TestRunner (see previous post). It turns out, the TestRunner runs the test fixtures on a different thread, so you can't just do a frmMain.txtMessage.Text = "New Text from Test Fixture". Would have been too easy.
In addition, VB.Net also has the concept of default form instances, so when you do the above "frmMain.txtMessage" from a different thread than the main UI thread, VB.Net actually instantiates a new form, and then discards it when you are done. Thus there will be no exception raised for the above code, and putting in a brekpoint in the work thread shows the text properly updated. But in the UI the textbox will be empty.
It is much better explained in this post.
But the gist of it is this:
1. You have to use My.Application.OpenForms to get the correct UI thread instance of your form that you want to update
2. you have to use Invoke/BeginInvoke together with delegates to properly update the controls on the Main UI thread from a different thread.
3. The Control base class has a neat little method called InvokeRequired that will return True if the method is called from a different thread. This way you can write a generic function that works both on the UI thread and from other threads. Something like this:
Public Class frmMain
'some magic voodo that needs to be done here to allow updating of the text box from a different thread
Private Delegate Sub PostMessageDelegate(ByVal strNewMessage As String)
'this is part 2 of the magic voodo: this is a public method that will be called on this form from the
'outside, from different threads, so the text box can be updated
Public Sub PostMessage(ByVal strMessage As String)
If txtMessages.InvokeRequired Then
'this method is called form a different thread, so we need to use BeginInvoke to update the UI
txtMessages.BeginInvoke(New PostMessageDelegate(AddressOf PostMessage), New Object() {strMessage})
Else
txtMessages.Text &= Environment.NewLine & strMessage
End If
End Sub
...
End Class
For instance if you have a WinForms app that spawns a worker thread, and then that worker thread needs to update any UI elements on the main form, it will not work, since you can only update UI elements from the same thread they are created on.
I specifically ran into this when using a custom NUnit TestRunner (see previous post). It turns out, the TestRunner runs the test fixtures on a different thread, so you can't just do a frmMain.txtMessage.Text = "New Text from Test Fixture". Would have been too easy.
In addition, VB.Net also has the concept of default form instances, so when you do the above "frmMain.txtMessage" from a different thread than the main UI thread, VB.Net actually instantiates a new form, and then discards it when you are done. Thus there will be no exception raised for the above code, and putting in a brekpoint in the work thread shows the text properly updated. But in the UI the textbox will be empty.
It is much better explained in this post.
But the gist of it is this:
1. You have to use My.Application.OpenForms to get the correct UI thread instance of your form that you want to update
2. you have to use Invoke/BeginInvoke together with delegates to properly update the controls on the Main UI thread from a different thread.
3. The Control base class has a neat little method called InvokeRequired that will return True if the method is called from a different thread. This way you can write a generic function that works both on the UI thread and from other threads. Something like this:
Public Class frmMain
'some magic voodo that needs to be done here to allow updating of the text box from a different thread
Private Delegate Sub PostMessageDelegate(ByVal strNewMessage As String)
'this is part 2 of the magic voodo: this is a public method that will be called on this form from the
'outside, from different threads, so the text box can be updated
Public Sub PostMessage(ByVal strMessage As String)
If txtMessages.InvokeRequired Then
'this method is called form a different thread, so we need to use BeginInvoke to update the UI
txtMessages.BeginInvoke(New PostMessageDelegate(AddressOf PostMessage), New Object() {strMessage})
Else
txtMessages.Text &= Environment.NewLine & strMessage
End If
End Sub
...
End Class
Implement your own NUnit TestRunner - Part 2
After I blogged about creating a basic NUnit TestRunner in Part 1 of this series, this is the follow-up that shows how to extract and display the test results in a simple fashion.
Basically the TestResult object that is being returned from the Run method of the TestRunner contains probably most of the information you need.
Here is the Code:
Imports System.Text
Imports System.Xml
Imports System.IO
Imports System.Reflection
Imports System.Resources
Imports NUnit.Core
Imports NUnit.Util
Public Class Form1
Private Sub btnRunTests_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRunTests.Click
Dim objTestRunner As TestRunner = Nothing
objTestRunner = New RemoteTestRunner()
Dim strMyFileName As String = Assembly.GetExecutingAssembly().Location
Dim objPackage As TestPackage = New TestPackage(strMyFileName)
objTestRunner.Load(objPackage)
'run the test and create the result
Dim objTestResult As TestResult = objTestRunner.Run(New NullListener)
'get the result summary in XML format
Dim strResultSummary As String = CreateXmlOutput(objTestResult)
'now transform the XML into more display-friendly code using the default style sheet
Dim sbResultSummary As New StringBuilder
Dim objXFormReader As XmlTextReader = GetTransformReader(Nothing)
Dim objXMLXform As XmlResultTransform = New XmlResultTransform(objXFormReader)
objXMLXform.Transform(New StringReader(strResultSummary), New StringWriter(sbResultSummary))
txtResults.Text = sbResultSummary.ToString()
End Sub
Private Shared Function CreateXmlOutput(ByVal objResult As TestResult) As String
Dim sbXML As New StringBuilder()
Dim objResultVisitor As New XmlResultVisitor(New StringWriter(sbXML), objResult)
objResult.Accept(objResultVisitor)
objResultVisitor.Write()
Return sbXML.ToString()
End Function 'CreateXmlOutput
Private Shared Function GetTransformReader(ByVal strXSLFileName As String) As XmlTextReader
Dim objXMLReader As XmlTextReader = Nothing
If String.IsNullOrEmpty(strXSLFileName) Then
Dim objNUnitAssembly As Assembly = Assembly.GetAssembly(GetType(XmlResultVisitor))
Dim objResourceMgr As New ResourceManager("NUnit.Util.Transform", objNUnitAssembly)
Dim strXmlData As String = CStr(objResourceMgr.GetObject("Summary.xslt"))
objXMLReader = New XmlTextReader(New StringReader(strXmlData))
Else
Dim objXsltInfo As New FileInfo(strXSLFileName)
If Not objXsltInfo.Exists Then
Throw New FileNotFoundException("Transform file: {0} does not exist", objXsltInfo.FullName)
objXMLReader = Nothing
Else
objXMLReader = New XmlTextReader(objXsltInfo.FullName)
End If
End If
Return objXMLReader
End Function 'GetTransformReader
End Class
this will then show the results in a user-friendly form in the text box txtResults.
Where this comes in handy is if you have a WinForms App and you want to run your Unit tests as part of the WinForms app without having to launch the NUnit GUI (or Console).
This is admittedly a very simple implementation, does not have a lot of the bells and whistles of a more graphical UI, but it tells you which tests failed and how long they took and where they failed.
Basically the TestResult object that is being returned from the Run method of the TestRunner contains probably most of the information you need.
Here is the Code:
Imports System.Text
Imports System.Xml
Imports System.IO
Imports System.Reflection
Imports System.Resources
Imports NUnit.Core
Imports NUnit.Util
Public Class Form1
Private Sub btnRunTests_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRunTests.Click
Dim objTestRunner As TestRunner = Nothing
objTestRunner = New RemoteTestRunner()
Dim strMyFileName As String = Assembly.GetExecutingAssembly().Location
Dim objPackage As TestPackage = New TestPackage(strMyFileName)
objTestRunner.Load(objPackage)
'run the test and create the result
Dim objTestResult As TestResult = objTestRunner.Run(New NullListener)
'get the result summary in XML format
Dim strResultSummary As String = CreateXmlOutput(objTestResult)
'now transform the XML into more display-friendly code using the default style sheet
Dim sbResultSummary As New StringBuilder
Dim objXFormReader As XmlTextReader = GetTransformReader(Nothing)
Dim objXMLXform As XmlResultTransform = New XmlResultTransform(objXFormReader)
objXMLXform.Transform(New StringReader(strResultSummary), New StringWriter(sbResultSummary))
txtResults.Text = sbResultSummary.ToString()
End Sub
Private Shared Function CreateXmlOutput(ByVal objResult As TestResult) As String
Dim sbXML As New StringBuilder()
Dim objResultVisitor As New XmlResultVisitor(New StringWriter(sbXML), objResult)
objResult.Accept(objResultVisitor)
objResultVisitor.Write()
Return sbXML.ToString()
End Function 'CreateXmlOutput
Private Shared Function GetTransformReader(ByVal strXSLFileName As String) As XmlTextReader
Dim objXMLReader As XmlTextReader = Nothing
If String.IsNullOrEmpty(strXSLFileName) Then
Dim objNUnitAssembly As Assembly = Assembly.GetAssembly(GetType(XmlResultVisitor))
Dim objResourceMgr As New ResourceManager("NUnit.Util.Transform", objNUnitAssembly)
Dim strXmlData As String = CStr(objResourceMgr.GetObject("Summary.xslt"))
objXMLReader = New XmlTextReader(New StringReader(strXmlData))
Else
Dim objXsltInfo As New FileInfo(strXSLFileName)
If Not objXsltInfo.Exists Then
Throw New FileNotFoundException("Transform file: {0} does not exist", objXsltInfo.FullName)
objXMLReader = Nothing
Else
objXMLReader = New XmlTextReader(objXsltInfo.FullName)
End If
End If
Return objXMLReader
End Function 'GetTransformReader
End Class
this will then show the results in a user-friendly form in the text box txtResults.
Where this comes in handy is if you have a WinForms App and you want to run your Unit tests as part of the WinForms app without having to launch the NUnit GUI (or Console).
This is admittedly a very simple implementation, does not have a lot of the bells and whistles of a more graphical UI, but it tells you which tests failed and how long they took and where they failed.
Implement your own NUnit TestRunner - Part 1
I wanted to be able to run NUnit unit tests from my own test runner within a WinForms App. Easier said than done, not a lot of examples out there. I looked through the NUnit-Console code and the NUnit-Gui code and pieced together bits and pieces. Then I also stumbled across this blog post from a fellow german which helped with the last stumbling block:
http://achblah.blogspot.com/2007/04/monocov-and-my-contribution-to-it.html
The end result is this piece of VB.net code that will run any tests within your current EXE:
Imports System.Reflection
Imports NUnit.Core
Imports NUnit.Util
Public Class Form1
Private Sub btnRunTests_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRunTests.Click
Dim objTestRunner As TestRunner = Nothing
objTestRunner = New RemoteTestRunner()
Dim strMyFileName As String = Assembly.GetExecutingAssembly().Location
Dim objPackage As TestPackage = New TestPackage(strMyFileName)
objTestRunner.Load(objPackage)
objTestRunner.Run(New NullListener)
End Sub
End Class
Of course this does not show any test results or exceptions because of using the "NullListener". In Part 2 I will fix that.
http://achblah.blogspot.com/2007/04/monocov-and-my-contribution-to-it.html
The end result is this piece of VB.net code that will run any tests within your current EXE:
Imports System.Reflection
Imports NUnit.Core
Imports NUnit.Util
Public Class Form1
Private Sub btnRunTests_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRunTests.Click
Dim objTestRunner As TestRunner = Nothing
objTestRunner = New RemoteTestRunner()
Dim strMyFileName As String = Assembly.GetExecutingAssembly().Location
Dim objPackage As TestPackage = New TestPackage(strMyFileName)
objTestRunner.Load(objPackage)
objTestRunner.Run(New NullListener)
End Sub
End Class
Of course this does not show any test results or exceptions because of using the "NullListener". In Part 2 I will fix that.
Friday, April 18, 2008
Life Cycle of static variables in ASP.Net
Have you ever wondered about the scope and life time of static (Shared in VB.Net) variables in ASP.Net?
- Do they get destroyed after each requests?
- Do they get destroyed after the IIS services is restarted?
- multiple apps run in the same Application Pool, do they all get the same copy (and value) of static variables?
- Does a Singleton make sense in ASP.Net
Here is what I could gather from doing some research on the web:
- static variables work in ASP.Net the same way they work in a Windows app: they are global across the whole .Net AppDomain
- each ASP.Net application gets their own AppDomain, even if they are hosted in the same application pool (same w3wp.exe or aspnet_wp.exe)
- so even if you have multiple ASP.Net applications per Application Pool, they would still get their own AppDomains, and thus the singletons/shared variables would be isolated from each other
Some people encourage initializing the singletons/static variables in the Application_Startup event, just to make sure that all the ASP.Net infrastructure.
Here are some supporting links:
http://weblogs.asp.net/jeff/archive/2007/09/21/how-do-you-get-a-true-singleton-in-an-asp-net-app.aspx
http://www.odetocode.com/Articles/305.aspx
http://blogs.msdn.com/david.wang/archive/2005/09/01/HOWTO-Provision-ASP-dotNet-AppDomains-and-IIS6-Application-Pools.aspx
http://www.vzyl.co.za/post/2008/04/Singleton-Design-Pattern-amp3b-Lifetime-of-a-static-variable-in-ASPNET-20.aspx
http://www.yoda.arachsys.com/csharp/singleton.html
- Do they get destroyed after each requests?
- Do they get destroyed after the IIS services is restarted?
- multiple apps run in the same Application Pool, do they all get the same copy (and value) of static variables?
- Does a Singleton make sense in ASP.Net
Here is what I could gather from doing some research on the web:
- static variables work in ASP.Net the same way they work in a Windows app: they are global across the whole .Net AppDomain
- each ASP.Net application gets their own AppDomain, even if they are hosted in the same application pool (same w3wp.exe or aspnet_wp.exe)
- so even if you have multiple ASP.Net applications per Application Pool, they would still get their own AppDomains, and thus the singletons/shared variables would be isolated from each other
Some people encourage initializing the singletons/static variables in the Application_Startup event, just to make sure that all the ASP.Net infrastructure.
Here are some supporting links:
http://weblogs.asp.net/jeff/archive/2007/09/21/how-do-you-get-a-true-singleton-in-an-asp-net-app.aspx
http://www.odetocode.com/Articles/305.aspx
http://blogs.msdn.com/david.wang/archive/2005/09/01/HOWTO-Provision-ASP-dotNet-AppDomains-and-IIS6-Application-Pools.aspx
http://www.vzyl.co.za/post/2008/04/Singleton-Design-Pattern-amp3b-Lifetime-of-a-static-variable-in-ASPNET-20.aspx
http://www.yoda.arachsys.com/csharp/singleton.html
Friday, November 16, 2007
BLowery Compression module and Visual Studio Webserver (Cassini)
We have been using the HTTPCompress module (BLowery), and when running your web site in development mode using the built-in web server in Visual Studio 2005 you can get the error "Server cannot append header after HTTP headers have been sent." in cases where you want to do a Response.Flush (e.g. for downloading a file to the client).
Now the HTTPCompress module can be configured to exclude certain pages by using the "excludedPaths" tag in the web.config file. But this did not seem to work.
The cause was this:
This is the line in the HTTPCompress Module that is supposed to chop off the absolute portion of the path:
string realPath = app.Request.Path.Remove(0, app.Request.ApplicationPath.Length+1);
This works fine if your web application is not at the root. But in the Visual Studio Development Web Server (formerly Cassini), the Request.ApplicationPath always comes back as "/". In that case the above code will actually chop off the first character of the relative path.
I.e. "/WebResource.axd" will become "ebResource.axd".
The Solution:
This is ugly, but when you do development using the Visual Studio built-in web server you need to add both paths to the web.config file.
<excludedPaths>
<add path="ebresource.axd"/>
<add path="WebResource.axd"/>
</excludedPaths>
Of course another option is to modify the HTTPCompress source code and fix this.
Now the HTTPCompress module can be configured to exclude certain pages by using the "excludedPaths" tag in the web.config file. But this did not seem to work.
The cause was this:
This is the line in the HTTPCompress Module that is supposed to chop off the absolute portion of the path:
string realPath = app.Request.Path.Remove(0, app.Request.ApplicationPath.Length+1);
This works fine if your web application is not at the root. But in the Visual Studio Development Web Server (formerly Cassini), the Request.ApplicationPath always comes back as "/". In that case the above code will actually chop off the first character of the relative path.
I.e. "/WebResource.axd" will become "ebResource.axd".
The Solution:
This is ugly, but when you do development using the Visual Studio built-in web server you need to add both paths to the web.config file.
<excludedPaths>
<add path="ebresource.axd"/>
<add path="WebResource.axd"/>
</excludedPaths>
Of course another option is to modify the HTTPCompress source code and fix this.
Subscribe to:
Posts (Atom)