2010-07-07

在Gentoo里调试新软件包

最近又开始研究web测试的技术,迷上了西门子开发的robot framework。不过服务器用的Gentoo上还没有这东西,只好自力更生。所以先记录一下给Gentoo添加新软件包的过程,下次也好照抄,以后再说robot framework有多好。

Gentoo的包管理器叫做Portage,描述文件叫Portfile。现在的portage很讲究目录结构,就是Gentoo里的PORTDIR structure,所谓category。robot framework是用python开发的,照例是在dev-python下的某个目录中。没想到的是,现在ebuild对目录的检查很严格,即使在调试时安装本地的portfile也要遵循该结构:
mkdir -p dev-python/robotframework
mv robotframework-2.5.ebuild dev-python/robotframework/
cd dev-python/robotframework


然后利用底层的ebuild包管理命令,对本地包生成数字摘要、测试安装和部署:
sudo ebuild robotframework-2.5.ebuild digest
sudo ebuild robotframework-2.5.ebuild install
sudo ebuild robotframework-2.5.ebuild qmerge

digest是最近新增加的指令?有这个命令省事多了,调试起来很happy。

调试过程需要反复修改,得删除已经用qmerge安装到系统目录中的文件,以及portfile的缓存:
sudo emerge -C robotframework-2.5
sudo rm -rf /var/tmp/portage/dev-python/robotframework-2.5/


把dev-python/robotframework和dev-python/robotframework-seleniumlibrary向Gentoo提交了,不知道审核要多久。

完。

2009-04-26

请,给点提示吧,bitten

一直在用bitten做集成测试,效果挺好,现在天天离不了它。不过最近被它搞的很郁闷,因为bitten-slave吐出一行神秘的错误信息:
[DEBUG   ] Sending POST request to 'https://mytrac.com/build/5632/steps/'
[WARNING ] Server returned error 403: Forbidden
[ERROR ] HTTP Error 403: Forbidden

起因是因为最近升级了bitten,顺便想把以前的单个进程拆成多个,加快一下bitten的执行速度。人家说,一个和尚有水吃,两个和尚抬水吃,三个和尚没水吃,没想到软件也是这样。两个slave一块跑起来,就有了问题:有时这个出错,有时那个出错,提示都是神秘的403。观察了一下,出现错误的时候,都是某slave A先执行,B稍后也开始执行,然后A再次向服务器POST数据就会出错。猜测可能用户之间有冲突,试过了几种方式,使用各自独立的用户名,在不同目录执行,在不同机器执行,但问题依旧。今天费了些力气,把bitten的代码跟踪了半天,发现程序调用了这个函数
    def reset_orphaned_builds(self):
"""Reset all in-progress builds to ``PENDING`` state if they've been
running so long that the configured timeout has been reached.

This is used to cleanup after slaves that have unexpectedly cancelled
a build without notifying the master, or are for some other reason not
reporting back status updates.
"""

幸亏代码里有注释,这才恍然大悟,原来是timeout参数在作怪。进入trac管理界面,把timeout从10秒调高到500秒,总算解决了问题。

实际上,在bitten描述客户端协议的文档中,已经指出了这一问题:
To handle the case of build slaves going away at some point between having created a build and completing the build, the build master should have a configurable timeout. All in-progress builds would be checked against this timeout; if there has been no activity on the build for an amount of time exceeding the timeout, the master should cancel the build, resetting it the PENDING state. If a slave later does decide to come back to life and post results, it would get 404 (Not Found) or 409 (Conflict) errors, and should cancel the build on its side, too.

但由于未明的原因,bitten的实现用403代替了404、409,并且没有给出进一步的提示信息。要是bitten-slave能打印一条附加信息,告诉我403的原因可能跟timeout设置有关系,那该多好呀。

这个故事告诉我们,别嫌提示信息废话太多,能多写一点是一点,不定什么时候它就会节省自己和别人的若干时间。折腾了三天以后,我现在太喜欢话唠的软件啦。

2007-11-30

用于django中的缓存decorator

myproject/decorators.py代码:
from django.core.cache import cache

def cached(cache_key='', timeout_seconds=1800):
def _cached(func):
def do_cache(*args, **kws):
if isinstance(cache_key, str):
key = cache_key % locals()
elif callable(cache_key):
key = cache_key(*args, **kws)
data = cache.get(key)
if data: return data
data = func(*args, **kws)
cache.set(key, data, timeout_seconds)
return data
return do_cache
return _cached
只能用于静态数据的缓存,如果需要对connection.cursor等对象进行缓存,那需要函数本身做更多的处理,不是这个decorator要解决的问题。

使用范例1,简单的cache key:
from myproject.decorators import cached

class MenuItem(models.Model):
@classmethod
@cached('menu_root')
def get_root(self):
return MenuItem.objects.get(pk=1)

使用范例2,cache key需要根据调用参数来决定:
@cached(lambda u: 'user_privileges_%s' % u.username, 3600)
def get_user_privileges(user):
#...

使用范例3,需要只对直接调用者做缓存,递归的调用不需要,那么把要递归函数独立出来:
class MenuItem(models.Model):
@cached(lambda s,u: 'user_menu_%s_%s' % (u.username, s.id), 3600)
def permit_menu_items(self, user):
return self._permit_menu_items(user)

def _permit_menu_items(self, user):
items = []
for mi in self.children():
items += [n for n in mi._permit_menu_items(user)]
return items

使用范例4,返回结果中部分需要做缓存的,首先把要缓存的部分extract出来,然后对其应用缓存机制:
class Report:
def get_summary(self, day, path='', sort='path', type='daily'):
data = self._get_summary(day, path, type)
# sort ...
return data

@cached(lambda s,d,p,t:'summary_%s_%s_%s'%(d,p,t), 3600*24)
def _get_summary(self, day, path='', type='daily'):
#...

2007-11-16

人们研究android的热情高涨

短短一天时间,又有很多新情况发生。

首先,有人测试了汉字的显示,发现可以支持。我也在模拟器里试了一下,确实很容易。系统内带了几种字体,其中有一款支持CJK字符。

其次,有人成功编译了c版本的hello world,并执行成功。使用的是arm的编译器。而且还编译了全功能的busybox,可以安装到模拟器的系统中。

另外,已经有人成功编译linux放入android模拟器中运行。

邮件列表里很多人都在打听、讨论能不能用C/C++/Python/Ruby之类的语言代替java来开发。今天去jython的项目主页看了看,惊奇的发现项目复苏了,jython 2.2已经正式发布。期待高手把jython打包集成进android吧。

2007-11-15

Django+Cheetah

最近在用Django做东西,考虑到现在的流行程度,用Django在稳定性、bug修正速度、参考资料等方面很有优势。但它的模板系统很被一些人诟病,很多用python开发者第一次使用Django都会对它发点牢骚。Python语言的魅力之一就是它的开发,甚至对象实例在运行中都可以随时被改变。但Django因为一些考虑,人为的限制了模板系统的功能,不允许它过于强大。作为一种设计思想,增加限制可以简化问题的复杂程度、提高效率和代码安全性等等,好处不少。但我们是Python程序员,不受拘束、流畅而连贯的书写代码是我们的一贯风格(或说是追求目标),反正我可不愿被当孩子一样限制不许做这、不许做那。用最快的速度,写出糟糕但是能运行的代码,也是程序员应该争取的一个权利--有了可以跑的代码,才能有生存的机会,才能有后续的优化。所以我要寻找一种Django模板的替换方案。

从编写者的舒适角度来看,zpt等类似php的语法写起来感觉都恩罗唆,逻辑之外要码的累赘字符太多了,不够爽快。类似webpyCheetah的模板用起来更简单,而且有着类似python的语法风格,个人比较喜欢。据测试,Cheetah的速度也非常快,历史又很悠久,社区活跃,使用起来基本没有后顾之忧。所以我选择Cheetah。参考了Eric Florenzano的文章,在Django中使用Cheetah非常简单。首先要在settings.py中配置模板目录:
TEMPLATE_DIRS = (
'/path/to/myproject/templates',
)

然后编写一个使用Cheetah模板的render_to_response函数,用来代替Django自带的:
import os.path
from Cheetah.Template import Template
from django.conf import settings
from django.http import HttpResponse

def render_to_response(template_name, context=None, **kwargs):
for template_dir in settings.TEMPLATE_DIRS:
path = os.path.join(template_dir, template_name)
if os.path.exists(path):
template = Template(file = path, searchList = (context,))
return HttpResponse(unicode(str(template), 'utf-8'), **kwargs)
raise ValueError, 'Could not find template for %s' % template_name

我是把上面这段代码放在myproject/shortcuts.py文件中。使用起来是这样子:
from myproject.shortcuts import render_to_response
def index(request):
return render_to_response('index.tmpl', {'title': 'index')