Echelon 2010 - over and out
Posted 3 months, 1 week ago
Posted 3 months, 4 weeks ago
MacVim, by default has this ugly setting to display vertical bar. They appear on both sides when using :vs. Because I want to keep my screen clean while coding (fullscreen too. shift + cmd + f), some digging revealed this:
- set guioptions+=LlRrb
- set guioptions-=LlRrb
Put these two lines in the config file and the bars go away. Yeah, I noticed the anomaly too. Don't ask why.
Category: sparks
Leave a CommentPosted 4 months, 2 weeks ago

I've recently stumbled upon the ethical need to write a test for the password reset page on one of our webapps. After upgrading Django to 1.2 beta (yeah, we track the SVN trunk), the password reset page was giving 403 errors, due to missing CSRF protection.
Some googling revealed that Django changed some parts of the csrf module
and, for safety, all the contrib apps got a @csrf_protect
decorator.
Tests written and ran. WTF? They pass? Can't be right. Digging in the csrf middleware revealed that Django skips this step for the test client. Quote from the comment in their source:
Mechanism to turn off CSRF checks for test suite. It comes after the creation of CSRF cookies, so that everything else continues to work exactly the same (e.g. cookies are sent etc), but before the any branches that call reject()
I've wrote a custom test client, that forces the csrf check, all fine. The sun raises again. Oh wait, this custom client doesn't mean that I won't forget to add the {% csrf_token %} template tag to my template. Shitz!
Final solution: check if the csrfmiddlewaretoken hidden input appears in the template. Kinda superficial. Better suggestions are welcome.
Category: Django
Leave a CommentPosted 5 months ago
One of the puzzles of testing in Django are models who have an ImageField(). In Odeon we use ImageKit (with some custom spec handling), so tests should cover all the other images derived from the original uploaded one.
- #models.py
- class ProfileAvatar(IKImage):
- original_image = models.ImageField(upload_to=AVATAR_PATH)
- class IKOptions:
- spec_module = 'mymodule.specs'
- cache_dir = MY_CACHE_PATH
- image_field = 'original_image'
- #forms.py
- class AjaxAvatarForm(forms.Form):
- image = forms.ImageField()
- #views.py
- def upload(request):
- form = UploadImageForm(request.POST, request.FILES)
- if not form.is_valid():
- #Return some error
- image = form.cleaned_data.get('image')
- ProfileAvatar.objects.create(image = image)
First of all, using a separate folder for testing prevents from mixing test content with production content.
- from django.test import TestCase
- class UserprofileTest(TestCase):
- def test_upload(self):
- count = ProfileAvatar.objects.count()
- image_path = settings.MEDIA_ROOT + 'testdata/image.png'
- f = open(image_path, "r")
- resp = self.client.post(url, {'image': f})
- f.close()
- self.assertEquals(count, 1)
Second of all, check that all the image specs are generated successfully. _ik.specs is an generated list of all these specs, each spec having a .name() method which returns the actual spec name.
- # check validity
- avatar = ProfileAvatar.objects.all()[0]
- for spec in avatar._ik.specs:
- spec_name = spec.name()
- img_url = getattr(avatar, spec_name).url
- self.assertTrue(img_url.find('_' + spec_name) > -1)
Last step: Your mom was right to say "Clean your room!", so remove test data.
- # clean images
- avatar.delete()
- self.assertEquals(count, 0)
The end result is less headache and chasing after faulty images. If, for some rare reason, one image can't be converted, put it in /testdata/ and run the test with it, tweaking your logic to cater for that.
Category: Django
Leave a CommentPosted 5 months, 2 weeks ago
The iPhone app store has surely brought a new light on how software is sold. The solid and long approval process can be a positive decision. This Big Brother approach has raised the quality of the products and that can only be a good thing, but full control can be a heavy sword to carry, even for Apple. There’s one missing part, which is essential for building quality apps: ability to get market feedback.
How can one answer such a question if the app has been rejected from the app store? Instead of spending thinking and development time on building an app that might get rejected for more or less stupid reasons, I suggest developing your idea fast and easy, which incorporates as much as possible from the iPhone/iPad experience. There’s another hurdle to jump over in the path to building a solid app: the language. Objective-C doesn’t have many supporters, despite the fact that it exploded after the app store was launched and the community keeps growing because of the iPad. Frameworks like PhoneGap and Titatium have solved the language problem, but they have their cons too. Even so, it’s a pretty expensive and risky road, especially for smaller start-ups, which might be fighting to identify themselves. For big companies sending 50K USD down the drain when their app can’t make it to the market place might not seem much, but I won’t get into that story now.
As Eric Ries emphasizes in many of his talks, getting market feedback is essential on evolving your business. So what if you think that your app about puppies is awesome? The UI might be clunky, people might not want to pay you 50 cents for puppy pictures. Without the ability to get these metrics, your development time spent so far is in the risk of being useless. That is not lean!
Let’s build a web-app! Even tough the full experience of a native app can’t be transposed in a web-app, great progress has been made on discovering what Mobile Safari can do. jQTouch is a great example and the extensions (here and here) proved that GeoLocation, multi-touch, gestures, animations, full-screen, skins are do-able and they provide a great experience, very close to a native app. This settles the front-end, but the need for a flexible back-end arises. This back-end can provide the metrics, which are vital to the marketing geeks. This is where behavior tracking of the mainstream user or early adopters can be seen. The iPod Touch, iPhone and iPad can benefit from this approach.
3 CommentsPosted 6 months, 1 week ago
Snow Leopard comes built-in with Python 2.6.1 which does not satisfy my ego, so I grabbed 2.6.4 from Mac Ports. All is fine, until I stumble upon a Python package that is not available as a port, yet appears in Python's official package index.
This makes pretty obvious that simply calling easy_install will not work. MacPort's Python doesn't look in the same path as Apple's Python.
sudo port installed tells me that py26-setuptools for MacPorts' Python is installed, so it should have it's own easy_install. After some snooping around I found it here:
/opt/local/bin/easy_install-2.6
Case solved, let the coding continue.
1 CommentPosted 6 months, 2 weeks ago
Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.Leave a Comment
Brian W. Kernighan, co-author of The C Programming Language and the "K" in "AWK"
Posted 6 months, 2 weeks ago
This can be used to make forms easier to fill in. Bulletize will convert a <select> into a list of bullets, each bullet representing an <option> inside the <select>.
Events can still be binded to the <select>, for example .change(). I have used the change() event on one of our projects to load trough AJAX a different section of the page, based on what option has been selected.
By default each bullet will display the label of each option ( the text between <option></option> ). There are 2 ways to control the display:
Comments and improvements can be added here.
I have tested on
IE 7 and 8, Opera 10, Firefox 3.5 and 3.6, Safari 4, Chrome. It
would run smoothly on all major web browsers, although there are some
minor rendering issues with Opera, but I will update the code soon. Yes, the round corners are CSS3.
Posted 6 months, 3 weeks ago
These are the main comments which tell the story of a test case:
# create a generic user
# add this user to the business group, this he becomes a business owner
# create an organisation
# set permision for organisation group
# the owner becomes part of the organisation group
# get PointType, since we have fixtures
# define contest start and end date for the contest
# create a contest and check if it was saved ( URL check )
# check if appears in organisation admin, check URL
# score a point as the contest owner
# gotcha! The owner of the book, and implicitly of the contest, can't score a points
# John signs up
# John tries to score
# no luck. The contest is not live yet
# now make the contest live
# John scores 3 times, trough the AJAX URL
# Mary is playing too
# Susan want's to play, but the contest is over so her point isn't saved
# John, being a simple-minded user, shouldn't have access to the contest list page (URL permissions check)
# check the new contest creation URL
# create a new contest, with a budget
Posted 6 months, 3 weeks ago
Last week I had to setup a contest platform for one of our projects. As many of the things we do in Odeon, it was something new. This project is one of our most important and the specs weren't clear from the start. All the features evolve trough short ( sometimes intense, othertimes silly ) discussions. AGILE baby! Changes can break already existing code, so I took advantage of this opportunity to evolve my unit-test writing skills and bend some Django rules.
Main types of tests were:
Unit testing in Django is close to trivial, but takes time, nonetheless. These tests helped me define an lean way to score points in the contest and organize the all the methods under the proper classes.
Example: A user can score a point only if he is logged in, there is a contest running, he is not the contest owner and the players limit hasn't been reached. In the first iteration, I wasn't even aware of all these requirements so I had one 'if' for each check. After thinking a about some real-life scenarios, my code ended up as only one line that actually called the .score() method, while all these checks are cleanly inside the appropriate class. The coder that might change or maintain my code would just use the .score() method wherever needed.
"Regression testing focuses on finding defects after a major code change has occurred. Specifically, it seeks to uncover software regressions, or old bugs that have come back. Such regressions occur whenever software functionality that was previously working correctly stops working as intended. Typically, regressions occur as an unintended consequence of program changes, when the newly developed part of the software collides with the previously existing code." Wikipedia.
These tests include: creation of models, creation of users and user profiles, checking various actions a user can do ( score different types of points ). It's important to check what a user can do AND what a user can't do in as many scenarios as possible.
Every time I added new fields to the models, I wrote tests to cover both new and old scenarios. Is there a need to say that it's important that all tests pass ?
This was by far the funnest part. Given the fact that all tests until now passed, I can actually make some requests to see what the results should be. The previous tests were pretty low level, testing object creation and logic.
Who cares about low level ? The client or user surely doesn't. That's why the integrations tests needed to be high-level, black-box style, without knowing internal implementations.
Django's Test Client is a powerful tool, which acts like a dummy web browser. It can make GET and POST requests to your URLs and returns status codes, templates and rendered HTML.
I've setup a few URLs, some of them should be accessed trough AJAX. By making POST requests with POST data, the tests checked the forms for contest creation. I emphasize again the need to check when a form is submitted successfully and when not.
Tip: Django has a problem when reporting possible template or view errors, which might be misleading. If the URL tests doesn't explain the error, try a test which calls the view associated to the URL.
Example:
View test:
- from userprofile.views import ajax_login_status
- email = "jim.morrison@is.awesome.com"
- u, p, password = Profile.objects.create_user_and_profile(email)
- # create a fake request object, because it needs the .user property
- class ReqObj:
- user = u
- request = ReqObj()
- output = ajax_login_status( request )
- self.assertEquals( output, "{'is_authenticated': false}" )
URL test:
- client.login(username = u.username, password = password)
- response = client.get( '/users/ajax/check/login_status/', follow = True )
- self.assertEquals( response.status_code, 200 )
I strongly advise to write URL tests for every URL defined within the project.
Contest system is up. The next coder who wants to check if it's working properly or if he broke some code only needs to run ./manage.py test contest, wait for 3.7s and rest assured that no bugs crawled in.
Did I mention that during this time my Firefox was closed? After all the tests passed I browsed the app trough Firefox and it magically worked.
What no, pretty pages? Selenium to the rescue, but I'll cover that on the next occasion.
http://en.wikipedia.org/wiki/Software_testing
http://docs.djangoproject.com/en/dev/topics/testing/
We are an agile software development team.
Keep it simple, iterate fast and release often. Our iterative development strategy is based on practical, scrum, XP and agile methodologies.
No unnecessary documentation, a focus on working, operating software and an eye for core deliverables, business objectives. It is all about software development that works.
Our professional blogs offer visitors a window to the way we think about business, about technology and about the art and science of application development:
Odeon Consulting Group »
Calvin Cheng »
Tudor Munteanu »
Stefan Talpalaru »
Liviu Chiributa »
Horia Dragomir »
Bogdan Nistor »
Andy Tan »
Drop us a note or leave a comment on our blogs.
Getting things done and building your custom application can start with a simple dialogue with us. Today.
If email or a phone conversation is more your cup of tea, drop us your contact number via:
Copyright ©2010 Odeon Consulting Group.