]> git.llucax.com Git - z.facultad/75.52/sercom.git/commitdiff
Agregar primer boceto del probador de entregas.
authorLeandro Lucarella <llucax@gmail.com>
Thu, 8 Mar 2007 21:29:26 +0000 (21:29 +0000)
committerLeandro Lucarella <llucax@gmail.com>
Thu, 8 Mar 2007 21:29:26 +0000 (21:29 +0000)
sercom/tester.py [new file with mode: 0644]
testtester.py [new file with mode: 0644]

diff --git a/sercom/tester.py b/sercom/tester.py
new file mode 100644 (file)
index 0000000..7638fc8
--- /dev/null
@@ -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 (file)
index 0000000..4e7f951
--- /dev/null
@@ -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()
+