Saturday, March 28, 2009

Ubuntu 9.04 Install Experience

The laptop I currently use at work and home has in the past been a dual boot, XP and Ubuntu machine. I kept Windows on it mostly because we're really a windows shop at work, so I felt like I needed to have that available to me. It seems like I boot into windows maybe once every six weeks, and thats for maybe 5 minutes to check whether something works in IE. Thats about all I can stand...

So, I decided that a VM would be more than enough to cover that need, which would free up quite a bit of disk space and remove the dual boot.

I also wanted to move to having /home on its own partition, something I've been too lazy to do in the past. Thats pretty lazy, I know.

So, having a partition with XP that I no longer wanted gave me the perfect opportunity to install Ubuntu Jaunty and make sure it was OK. This being my work computer, being out of commission for a few days is not possible. So, I can install it on the XP partition, use it for a few days, copy over everything I need and then turn the partition with Ubuntu 8.10 on it into my new /home partition.

I downloaded the Jaunty beta iso last evening. Using the torrent, it came down in less than 20 minutes. Awesome. Burned it to CD and popped it into the laptop CD drive. It booted up pretty fast for a live CD, it seemed to me. I passed through a nice new GDM login page, and then came the familiar Ubuntu login sound.

Then I noticed something strange. The window list at the bottom of the screen was filling up with "Starting File Manager". It was full, and just kept getting more. Doing a search, I found a bug discussed which results in Nautilus dying and respawning over and over again.

https://bugs.launchpad.net/ubuntu/+source/nautilus/+bug/325973


I restarted XWindows several times, to no avail. At that point I was considering letting it go for another beta version, to see if it would clear up. I was concerned that it was the Live CD that was doing this, and that perhaps a real install would not. So, I figured I would install it in a Virtual Box VM, to see how it did.

The VM install worked fine. No respawning problems whatsoever. So I rebooted the Live CD, and this time there was no respawning. Weird.

So, off to the install. Its been awhile since I've done a fresh install of Ubuntu, so I hadn't used the disk partitioner in quite a while. I found it pretty easy. I just chose the ntfs partition and chose to format it as ext4 and mount it on / . The install itself took very little time, 10 or 15 minutes.

By this time it was getting pretty late in the evening, and bed was calling. I decided to update everything and go to sleep while that was happening. It was off to the races doing that, and I checked out.

This morning when I got up and checked, it was hung up while updating. It had gotten everything downloaded, but hung up while installing the updates. I had to hard reboot it. After the boot, XWindows wouldn't start. I decided to reboot into the Live CD and see if I could fix it. Did that, and chrooted myself into the jaunty partition. I tried the usual things when trying to resurrect a pooched apt db.

apt-get -r install

and then

apt-get update

These two did manage to get past most of the problems. I had to force a re-install of libtango and a couple others.

But, in the end, the weirdness didn't go away. I had to start over. Ick.

Luckily, the second time around has worked much better. No hanging, no respawning of Nautilus.

I'm not going to give a run down of new features, as you can get that elsewhere. I modified the default color-scheme and wallpaper. Here's what I have so far:


Now that I've gotten past the install issues, everything seems great so far. Fast to boot, and faster in general.

More later...

Monday, March 23, 2009

Testing a Simple Rails XML API

I have a very simple xml API for adding users to our system at work. It adds a user to our front end database, and also adds that same user to our back end billing system. It needs a refactor quite badly, so testing needs to be created to make sure that the refactor works as it should.

The xml that it accepts looks like this:


<auth_request>
<vendor_id>1</vendor_id>
<vendor_password>password</vendor_password>
<lead_source_id>217</lead_source_id>
<products>
<id>A-123</id>
</products>
<firstname>Ted</firstname>
<lastname>Tester</lastname>
<address1>123 East 123 South</address1>
<address2>Apartment 6</address2>
<city>mytown</city>
<state>ST</state>
<zip>84033</zip>
<remote_host>remotesite.com</remote_host>
<email>tedtester@isp.com</email>
<billing>
<name></name>
<address></address>
<zip></zip>
<cc_num></cc_num>
<exp></exp>
</billing>
</auth_request>

It gets submitted to the api controller of my rails app, using the index action. Here is what it returned when it's successful:


<auth_response>
<error>0</error>
<registration_code>XBZ-T-123:61111-1329</registration_code>
<debug>
</debug>
</auth_response>


Because I generated the api_controller, it provided me with a proper functional test. This is where we'll test the api.

To start, lets put together a simple static test:

api_controller_test.rb:


include REXML

def test_index
myxml = "<auth_request>
<vendor_id>vendoruser1</vendor_id>
<vendor_password>myebiz</vendor_password>
<lead_source_id>217</lead_source_id>
<products>
<id>A-123</id>
</products>
<firstname>Ted</firstname>
<lastname>Tester</lastname>
<address1>123 East 123 South</address1>
<address2>Apartment 6</address2>
<city>mytown</city>
<state>ST</state>
<zip>84033</zip>
<remote_host>ProcessAuctions.com</remote_host>
<email>tedtester@myebiz.com</email>
<billing>
<name></name>
<address></address>
<zip></zip>
<cc_num></cc_num>
<exp></exp>
</billing>
</auth_request>"

post :index, :user=>myxml
assert_response :success
xml_response = Document.new( @response.body)

puts xml_response.elements["auth_response/registration_code"].text
end


Obviously, not the complete file, just the bits I created. The generator script started me off with much more.

If I test this script:

ruby api_controller_test.rb

I get


dmoulton@xerxes:~/dev/auth/test/functional$ ruby api_controller_test.rb
Loaded suite api_controller_test
Started
EBX-T-123:45555-1425
.
Finished in 1.120767 seconds.

1 tests, 1 assertions, 0 failures, 0 errors


Obviously, the puts statement is not that useful. Let's replace it with a test:


assert_not_equal(0, xml_response.elements["auth_response/registration_code"].text.length, "A proper activation code was not returned" )



This will tell us if the api doesn't return a valid activation code.

Next we need to get rid of that static xml and build it on the fly from some fixtures. I'd like to be able to test a large number of scenarios that might happen, including failures and malicious usage.

Here's what my yaml file looks like:


1:
vendor_id: vendoruser1
vendor_password: vpw
lead_source_id: 217
products: 123,67
firstname: Ted
lastname: Tester
address1: 123 East 456 South
address2: Apt 2
city: slc
state: UT
zip: 84043
remote_host: myhost
email: tedtester@company.com
billing_name: ted tester
billing_address: 123 East 456 South Lehi UT
billing_zip: 84043
cc_num: 4111111111111111
cc_exp: 10/2010

2:
vendor_id: vendoruser2
vendor_password: mpw
lead_source_id: 219
products: 123
firstname: Teddy
lastname: Tester2
address1: 123 East 456 South
address2: Apt 5
city: Lehi
state: UT
zip: 84043
remote_host: myhost
email: tedtester@company.com
billing_name: ted tester2
billing_address: 123 East 456 South Lehi UT
billing_zip: 84043
cc_num: 4111111111111111
cc_exp: 10/2010


To read this in, I'll create a method in test_helper.rb:


def make_api_xml_request(info)
userxml = REXML::Document.new
products = info['products'].split(",")
userxml = REXML::Document.new
root = REXML::Element.new('auth_request')
userxml.add_element(root)
root.add_element('vendor_id').add_text(info['vendor_id'])
root.add_element('vendor_password').add_text(info['vendor_password'])
root.add_element('lead_source_id').add_text(info['lead_source_id'].to_s)

prod = REXML::Element.new('products')

products.each do |p|
prod.add_element('id').add_text(p)
end
root.add_element(prod)
root.add_element('firstname').add_text(info['firstname'])
root.add_element('lastname').add_text(info['lastname'])
root.add_element('address1').add_text(info['address1'])
root.add_element('address2').add_text(info['address2'])
root.add_element('city').add_text(info['city'])
root.add_element('state').add_text(info['state'])
root.add_element('zip').add_text(info['zip'].to_s)
root.add_element('remote_host').add_text(info['remote_host'])
root.add_element('email').add_text(info['email'])
billing = REXML::Element.new('billing')
billing.add_element('name').add_text(info['billing_name'])
billing.add_element('address').add_text(info['billing_address'])
billing.add_element('zip').add_text(info['billing_zip'].to_s)
billing.add_element('cc_num').add_text(info['cc_num'].to_s)
billing.add_element('exp').add_text(info['cc_exp'])

root.add_element(billing)
userxml
end



Then, back in api_controller_test.rb, we can call the helper app for each user we find in the yaml file. Make sure that you are requiring the yaml library.


require 'yaml'


Here's the loop to read in users from the yaml and test them:


user = load_from_yaml(RAILS_ROOT + '/test/fixtures/xml_api_users_should_pass.yml')
user.each do |tmp,info|
userxml = make_api_xml_request(info)
post :index, :user=>userxml.to_s
assert_response :success
xml_response = Document.new( @response.body)
assert_equal('0',xml_response.elements["auth_response/error"].text)
assert_not_equal(0, xml_response.elements["auth_response/registration_code"].text.length, "A proper activation code was not returned" )
end


Now our output is:


dmoulton@xerxes:~/dev/auth/test/functional$ ruby api_controller_test.rb
Loaded suite api_controller_test
Started
..
Finished in 611.141555 seconds.

2 tests, 12 assertions, 0 failures, 0 errors


We can then create multiple yaml files, each containing users that will test the api in one way or another. One might make sure that vendors with invalid usernames or passwords can't log in. Another might try to use sql injection to trash the database. Use your imagination.

Friday, February 27, 2009

2009 Mtn West Ruby Conference

I am attending the Mtn West Ruby Conference in Salt Lake City on March 13 and 14. I am looking forward to several of the presentations.

Friday, January 02, 2009

New Web Store

My son and I have launched a new joint online venture, selling skateboarding equipment. The new site is at http://www.skatebordz.com. Its hosted by shopify, which means its a rails app, which is what attracted me to it in the first place. It has a nice API, nice admin tool, and looks pretty good.

I've started to write a tool which will integrate the supplier I am using a little closer with Shopify. What I intend to do is make it easier to keep up the inventory numbers between my supplier and my store. That involves some good old fashioned screen scraping. Hpricot is handy for that. Easy to learn, even for a marginally dumb programmer such as myself ;) . My supplier does provide a datafeed for a $100 fee, which I am not prepared to pay until there is a revenue stream from the store.

While building the store I've come across some great Rails tools and sites. This probably means I've had my head under a rock the past several months, but hey, thats normally true.

I'm really excited to be uisng Heroku. At first blush, this appears to be extremely useful way to quickly deploy rails apps. Quickly is an understatement, to be sure.

I'm also using synctobase. I haven't quite yet gotten the hang of that one, but I hope to soon.

There's still lots to learn about shopify and all the tools I might need. Sounds like fun.