From: Leandro Lucarella Date: Thu, 8 Mar 2007 21:29:26 +0000 (+0000) Subject: Agregar primer boceto del probador de entregas. X-Git-Tag: 0_9~110 X-Git-Url: https://git.llucax.com/z.facultad/75.52/sercom.git/commitdiff_plain/de32d0c699858b1502f5f1e793174db8b56f9c1b?ds=sidebyside;hp=46efc3a84d19545f396bac742bef4bff4b12fbac Agregar primer boceto del probador de entregas. --- diff --git a/sercom/tester.py b/sercom/tester.py new file mode 100644 index 0000000..7638fc8 --- /dev/null +++ b/sercom/tester.py @@ -0,0 +1,263 @@ +# vim: set et sw=4 sts=4 encoding=utf-8 foldmethod=marker: + +from sercom import model as mod +import zipfile as zf +import cStringIO as sio +import shutil as shu +import datetime as dt +from os import path as osp +import os + +import logging +log = logging.getLogger('sercom.tester') + +#from Queue import Queue +#queue = Queue() + +class Error(StandardError): pass + +class ExecutionFailure(Error, RuntimeError): pass + +class RsyncError(Error, EnvironmentError): pass + +error_interno = u'\n**Error interno al preparar la entrega.**' + +def unzip(bytes, dst): # {{{ + log.debug(_(u'Intentando descomprimir en %s') % dst) + if bytes is None: + return + zfile = zf.ZipFile(sio.StringIO(bytes), 'r') + for f in zfile.namelist(): + if f.endswith(os.sep): + log.debug(_(u'Creando directorio %s') % f) + os.mkdir(osp.join(dst, f)) + else: + log.debug(_(u'Descomprimiendo archivo %s') % f) + file(osp.join(dst, f), 'w').write(zfile.read(f)) +#}}} + +class Tester(object): #{{{ + + def __init__(self, name, path, home, queue): #{{{ y properties + self.name = name + self.path = path + self.home = home + self.queue = queue + + @property + def build_path(self): + return osp.join(self.chroot, self.home, 'build') + + @property + def test_path(self): + return osp.join(self.chroot, self.home, 'test') + + @property + def chroot(self): + return osp.join(self.path, 'chroot_' + self.name) + #}}} + + @property + def orig_chroot(self): + return osp.join(self.path, 'chroot') + + def run(self): #{{{ + entrega_id = self.queue.get() # blocking + while entrega_id is not None: + entrega = mod.Entrega.get(entrega_id) + log.debug(_(u'Nueva entrega para probar en tester %s: %s') + % (self.name, entrega)) + self.test(entrega) + log.debug(_(u'Fin de pruebas de: %s') % entrega) + entrega_id = self.queue.get() # blocking + #}}} + + def test(self, entrega): #{{{ + log.debug(_(u'Tester.test(entrega=%s)') % entrega) + entrega.inicio_tareas = dt.datetime.now() + try: + try: + self.setup_chroot(entrega) + self.ejecutar_tareas_fuente(entrega) + self.ejecutar_tareas_prueba(entrega) + self.clean_chroot(entrega) + except ExecutionFailure, e: + entrega.correcta = False + log.debug(_(u'Entrega incorrecta: %s') % entrega) + except Exception, e: + entrega.observaciones += error_interno + log.exception(_(u'Hubo una excepción inesperada: %s') % e) + except: + entrega.observaciones += error_interno + log.exception(_(u'Hubo una excepción inesperada desconocida')) + else: + entrega.correcta = True + log.debug(_(u'Entrega correcta: %s') % entrega) + finally: + entrega.fin_tareas = dt.datetime.now() + #}}} + + def setup_chroot(self, entrega): #{{{ y clean_chroot() + log.debug(_(u'Tester.setup_chroot(entrega=%s)') % entrega) + rsync = 'rsync --stats --itemize-changes --human-readable --archive ' \ + '--acls --delete-during --force' # TODO config + orig_chroot = osp.join(self.orig_chroot, '') + cmd = '%s %s %s' % (rsync, orig_chroot, self.chroot) + log.debug(_(u'Ejecutando: %s') % cmd) + ret = os.system(cmd) + if ret != 0: + entrega.observaciones += error_interno + errstr = _(u'No se pudo hacer rsync al chroot para la prueba,' \ + u'falló el comando: %s (con código de error %d)') % (cmd, ret) + log.error(errstr) + raise RsyncError(errstr) + try: + unzip(entrega.archivos, self.build_path) + except zf.BadZipfile: + entrega.correcta = False + entrega.observaciones += error_interno + log.error(_(u'El archivo adjunto no está en formato ZIP')) + raise + except IOError, e: + entrega.observaciones += error_interno + log.error(_(u'Error de IO al descromprimir archivos del ZIP: %s') + % e) + raise + + def clean_chroot(self, entrega): + log.debug(_(u'Tester.clean_chroot(entrega=%s)') % entrega) + pass # Se limpia con el próximo rsync + #}}} + + def ejecutar_tareas_fuente(self, entrega): #{{{ y tareas_prueba + log.debug(_(u'Tester.ejecutar_tareas_fuente(entrega=%s)') % entrega) + tareas = [t for t in entrega.instancia.ejercicio.enunciado.tareas + if isinstance(t, mod.TareaFuente)] + for tarea in tareas: + tarea.ejecutar(self.build_path, entrega) + + def ejecutar_tareas_prueba(self, entrega): + log.debug(_(u'Tester.ejecutar_tareas_prueba(entrega=%s)') % entrega) + for caso in entrega.instancia.ejercicio.enunciado.casos_de_prueba: + caso.ejecutar(self.test_path, entrega) + #}}} + +#}}} + +def ejecutar_caso_de_prueba(self, path, entrega): #{{{ + log.debug(_(u'CasoDePrueba.ejecutar(path=%s, entrega=%s)') + % (path, entrega)) + tareas = [t for t in entrega.instancia.ejercicio.enunciado.tareas + if isinstance(t, mod.TareaPrueba)] + prueba = entrega.add_prueba(self) + try: + try: + for tarea in tareas: + tarea.ejecutar(path, prueba) + except ExecutionFailure, e: + prueba.pasada = False + if self.rechazar_si_falla: + entrega.exito = False + if self.terminar_si_falla: + raise ExecutionError(e.comando, e.tarea, prueba) + else: + prueba.pasada = True + finally: + prueba.fin = dt.datetime.now() +mod.CasoDePrueba.ejecutar = ejecutar_caso_de_prueba +#}}} + +def ejecutar_tarea_fuente(self, path, entrega): #{{{ + log.debug(_(u'TareaFuente.ejecutar(path=%s, entrega=%s)') % (path, entrega)) + try: + for cmd in self.comandos: + cmd.ejecutar(path, entrega) + except ExecutionFailure, e: + if self.rechazar_si_falla: + entrega.exito = False + if self.terminar_si_falla: + raise ExecutionError(e.comando, tarea) +mod.TareaFuente.ejecutar = ejecutar_tarea_fuente +#}}} + +def ejecutar_tarea_prueba(self, path, prueba): #{{{ + log.debug(_(u'TareaPrueba.ejecutar(path=%s, prueba=%s)') % (path, prueba)) + try: + for cmd in self.comandos: + cmd.ejecutar(path, prueba) + except ExecutionFailure, e: + if self.rechazar_si_falla: + prueba.exito = False + if self.terminar_si_falla: + raise ExecutionError(e.comando, tarea) +mod.TareaPrueba.ejecutar = ejecutar_tarea_prueba +#}}} + +def ejecutar_comando_fuente(self, path, entrega): #{{{ + log.debug(_(u'ComandoFuente.ejecutar(path=%s, entrega=%s)') + % (path, entrega)) + unzip(self.archivos_entrada, path) # TODO try/except + comando_ejecutado = entrega.add_comando_ejecutado(self) + # TODO ejecutar en chroot (path) + comando_ejecutado.fin = dt.datetime.now() +# if no_anda_ejecucion: # TODO +# comando_ejecutado.exito = False +# comando_ejecutado.observaciones += 'No anduvo xxx' # TODO mas info +# if self.rechazar_si_falla: +# entrega.exito = False +# if self.terminar_si_falla: # TODO +# raise ExecutionFailure(self) + # XXX ESTO EN REALIDAD EN COMANDOS FUENTE NO IRIA + # XXX SOLO HABRÍA QUE CAPTURAR stdout/stderr + # XXX PODRIA TENER ARCHIVOS DE SALIDA PERO SOLO PARA MOSTRAR COMO RESULTADO +# for archivo in self.archivos_salida: +# pass # TODO hacer diff +# if archivos_mal: # TODO +# comando_ejecutado.exito = False +# comando_ejecutado.observaciones += 'No anduvo xxx' # TODO mas info +# if self.rechazar_si_falla: +# entrega.exito = False +# if self.terminar_si_falla: # TODO +# raise ExecutionFailure(self) +# else: +# comando_ejecutado.exito = True +# comando_ejecutado.observaciones += 'xxx OK' # TODO + comando_ejecutado.exito = True + comando_ejecutado.observaciones += 'xxx OK' # TODO +mod.ComandoFuente.ejecutar = ejecutar_comando_fuente +#}}} + +def ejecutar_comando_prueba(self, path, prueba): #{{{ + log.debug(_(u'ComandoPrueba.ejecutar(path=%s, prueba=%s)') + % (path, prueba)) + shu.rmtree(path) + os.mkdir(path) + unzip(prueba.caso_de_prueba.archivos_entrada, path) # TODO try/except + unzip(self.archivos_entrada, path) # TODO try/except + comando_ejecutado = prueba.add_comando_ejecutado(self) + # TODO ejecutar en chroot (path) + comando_ejecutado.fin = dt.datetime.now() +# if no_anda_ejecucion: # TODO +# comando_ejecutado.exito = False +# comando_ejecutado.observaciones += 'No anduvo xxx' # TODO +# if self.rechazar_si_falla: +# entrega.exito = False +# if self.terminar_si_falla: # TODO +# raise ExecutionFailure(self) # TODO info de error +# for archivo in self.archivos_salida: +# pass # TODO hacer diff +# if archivos_mal: # TODO +# comando_ejecutado.exito = False +# comando_ejecutado.observaciones += 'No anduvo xxx' # TODO +# if self.rechazar_si_falla: +# entrega.exito = False +# if self.terminar_si_falla: # TODO +# raise ExecutionFailure(comando=self) # TODO info de error +# else: +# comando_ejecutado.exito = True +# comando_ejecutado.observaciones += 'xxx OK' # TODO + comando_ejecutado.exito = True + comando_ejecutado.observaciones += 'xxx OK' # TODO +mod.ComandoPrueba.ejecutar = ejecutar_comando_prueba +#}}} + diff --git a/testtester.py b/testtester.py new file mode 100644 index 0000000..4e7f951 --- /dev/null +++ b/testtester.py @@ -0,0 +1,28 @@ +#!/usr/bin/python +# vim: set et sw=4 sts=4 encoding=utf-8 foldmethod=marker : + +import turbogears +import turbogears.database +turbogears.update_config(configfile="dev.cfg", modulename="sercom.config") +from sercom.tester import * +from sercom import model +from Queue import Queue + +queue = Queue() + +queue.put(1) +#queue.put(5) +queue.put(None) + +tester = Tester(name='pepe', path='var', home=os.path.join('home', 'sercom'), + queue=queue) + +tester.run() + +model.hub.rollback() +#model.hub.commit() + +#model.hub.begin() +#model.Entrega.get(5).correcta = True +#model.hub.rollback() +