Esempio n. 1
0
def test_scheduler_orden_distinto(db, settings):
    # Creamos 5 attachments sin identificar
    attachments = AttachmentFactory.create_batch(
        5, status=Attachment.STATUS.sin_identificar)

    c1 = CategoriaFactory(sensible=True)
    c2 = CategoriaFactory(sensible=True)
    m1 = MesaFactory(categorias=[c1])
    IdentificacionFactory(
        mesa=m1,
        status='identificada',
        source=Identificacion.SOURCES.csv,
    )
    m2 = MesaFactory(categorias=[c1, c2])
    assert MesaCategoria.objects.count() == 3
    IdentificacionFactory(
        mesa=m2,
        status='identificada',
        source=Identificacion.SOURCES.csv,
    )
    # Ambas consolidadas vía csv.

    consumir_novedades_identificacion()
    # Si hay más fotos que attachments primero se ponen las fotos,
    # hasta que haya la misma cantidad de cargas pendients.
    with override_config(COEFICIENTE_IDENTIFICACION_VS_CARGA=1):
        scheduler()
    assert ColaCargasPendientes.largo_cola() == 16

    # items = ColaCargasPendientes.objects.all().order_by('orden')
    # for i in range(16):
    #     it = items[i]
    #     print(f'{i}: ({it.orden},{it.attachment},{it.mesa_categoria})')

    # Las primeras seis tareas son de identificaciones.
    for i in range(6):
        consumir()

    assert ColaCargasPendientes.largo_cola() == 10

    # Luego vienen dos cargas...
    for i in range(2):
        consumir(False)

    assert ColaCargasPendientes.largo_cola() == 8

    # luego dos identificaciones y dos cargas, dos veces:
    for j in range(2):
        for i in range(2):
            consumir()

        for i in range(2):
            consumir(False)

    # Ya no queda nada en la cola.
    assert ColaCargasPendientes.largo_cola() == 0
    (mc, attachment) = ColaCargasPendientes.siguiente_tarea(fiscal=None)
    assert mc is None and attachment is None
Esempio n. 2
0
def test_cargar_resultados_redirige_a_parcial_si_es_necesario_con_scheduler(
        db, fiscal_client, status, parcial):
    mesa = MesaFactory()
    a = AttachmentFactory(mesa=mesa)
    c1 = CategoriaFactory(requiere_cargas_parciales=True, sensible=True)
    with override_config(ASIGNAR_MESA_EN_EL_MOMENTO_SI_NO_HAY_COLA=False):
        m1c1 = MesaCategoriaFactory(categoria=c1,
                                    coeficiente_para_orden_de_carga=0.1,
                                    status=status,
                                    mesa=mesa)
        scheduler()
        response = fiscal_client.get(reverse('siguiente-accion'))
        assert response.status_code == HTTPStatus.FOUND
        assert response.url == reverse(
            'carga-parcial' if parcial else 'carga-total', args=[m1c1.id])
Esempio n. 3
0
    def una_ronda(self, options):
        if not options['no_llamar_al_consolidador']:
            consolidador(cant_por_iteracion=options['cant_elem_consolidador'],
                         ejecutado_desde='Scheduler')
        self.ronda_consolidador += 1

        if self.ronda_consolidador == options[
                'cant_rondas_antes_de_reconstruir_la_cola']:
            self.ronda_consolidador = 0
            reconstruir_la_cola = True
        else:
            reconstruir_la_cola = False

        try:
            (cant_tareas, cant_cargas,
             cant_ident) = scheduler(reconstruir_la_cola)
            logger.debug(
                'Encolado',
                tareas=cant_tareas,
                cargas=cant_cargas,
                identificaciones=cant_ident,
                reconstruir_la_cola=reconstruir_la_cola,
            )
        except Exception as e:
            # Logueamos la excepción y continuamos.
            capture_message(f"""
                Excepción {e} en el scheduler.
                """)
            logger.error('Scheduler', error=str(e))
        time.sleep(config.PAUSA_SCHEDULER)
Esempio n. 4
0
def test_scheduler_orden_estandar(db, settings):
    # Creamos 5 attachments sin identificar
    attachments = AttachmentFactory.create_batch(
        5, status=Attachment.STATUS.sin_identificar)

    c1 = CategoriaFactory(sensible=True)
    c2 = CategoriaFactory(sensible=True)
    m1 = MesaFactory(categorias=[c1])
    IdentificacionFactory(
        mesa=m1,
        status='identificada',
        source=Identificacion.SOURCES.csv,
    )
    m2 = MesaFactory(categorias=[c1, c2])
    assert MesaCategoria.objects.count() == 3
    IdentificacionFactory(
        mesa=m2,
        status='identificada',
        source=Identificacion.SOURCES.csv,
    )
    # Ambas consolidadas vía csv.

    consumir_novedades_identificacion()
    with override_config(COEFICIENTE_IDENTIFICACION_VS_CARGA=10):
        scheduler()
    assert ColaCargasPendientes.largo_cola() == 16

    # Las primeras seis tareas son de carga de votos.
    for i in range(6):
        consumir(False)

    assert ColaCargasPendientes.largo_cola() == 10

    # las siguientes diez son identificaciones.
    for i in range(10):
        consumir()

    assert ColaCargasPendientes.largo_cola() == 0

    # Ya no queda nada en la cola.
    (mc, attachment) = ColaCargasPendientes.siguiente_tarea(fiscal=None)
    assert mc is None and attachment is None
Esempio n. 5
0
def test_siguiente_happy_path_parcial_y_total_con_scheduler(
        db, fiscal_client, settings):
    settings.MIN_COINCIDENCIAS_CARGAS = 1
    mesa = MesaFactory()
    a = AttachmentFactory(mesa=mesa, status='identificada')
    mc1 = MesaCategoriaFactory(categoria__requiere_cargas_parciales=True,
                               coeficiente_para_orden_de_carga=1,
                               mesa=mesa)
    scheduler()
    response = fiscal_client.get(reverse('siguiente-accion'))
    assert response.status_code == HTTPStatus.FOUND
    assert response.url == reverse('carga-parcial', args=[mc1.id])

    carga = CargaFactory(mesa_categoria=mc1, tipo='parcial')
    consumir_novedades_carga()
    scheduler()
    mc1.refresh_from_db()
    assert mc1.status == MesaCategoria.STATUS.parcial_consolidada_dc
    assert mc1.carga_testigo == carga
    mc1.desasignar_a_fiscal()
    response = fiscal_client.get(reverse('siguiente-accion'))
    assert response.url == reverse('carga-total', args=[mc1.id])

    carga = CargaFactory(mesa_categoria=mc1, tipo='total')
    consumir_novedades_carga()
    scheduler()
    mc1.refresh_from_db()
    assert mc1.status == MesaCategoria.STATUS.total_consolidada_dc
    assert mc1.carga_testigo == carga
    response = fiscal_client.get(reverse('siguiente-accion'))
    # No hay actas para cargar, vuelta a empezar.
    assert response.status_code == HTTPStatus.OK
    assert 'No hay actas para cargar' in str(response.content)
Esempio n. 6
0
def test_scheduler(db, settings):
    """
    Ejecutar dos veces el scheduler sin nuevas cosas no cambia el estado.
    """

    # Creamos 5 attachments sin identificar
    attachments = AttachmentFactory.create_batch(
        5, status=Attachment.STATUS.sin_identificar)

    c1 = CategoriaFactory()
    c2 = CategoriaFactory()
    m1 = MesaFactory(categorias=[c1])
    IdentificacionFactory(
        mesa=m1,
        status=Identificacion.STATUS.identificada,
        source=Identificacion.SOURCES.web,
    )
    m2 = MesaFactory(categorias=[c1, c2])

    IdentificacionFactory(
        mesa=m2,
        status=Identificacion.STATUS.identificada,
        source=Identificacion.SOURCES.csv,
    )

    # Los cinco del principio y los dos de la identificación.
    assert Attachment.objects.count() == 7
    assert MesaCategoria.objects.count() == 3

    # Empezamos con la cola vacía.
    assert ColaCargasPendientes.largo_cola() == 0

    # Ejecutar el scheduler antes de consolidar sólo encola identificaciones:
    # 2 por cada una de las fotos no identificadas y 1 para las creadas con
    # IdentificationFactory.

    scheduler()
    assert ColaCargasPendientes.largo_cola(
    ) == 5 * settings.MIN_COINCIDENCIAS_IDENTIFICACION + 2 * (
        settings.MIN_COINCIDENCIAS_IDENTIFICACION - 1)

    # Al consumir las novedades de identificación, se consolidan las
    # categorías de la segunda mesa, así que agregamos 4 tareas.
    consumir_novedades_identificacion()
    scheduler()
    assert ColaCargasPendientes.largo_cola() == 16
    cola_primera = list(ColaCargasPendientes.objects.all())

    consumir_novedades_identificacion()
    scheduler()
    # Al volver ejecutar el scheduler sin que haya novedades se mantiene la
    # misma cantidad de tareas.
    assert ColaCargasPendientes.largo_cola() == 16
    cola_segunda = list(ColaCargasPendientes.objects.all())

    # Testeamos la igualdad de las colas con la inclusión mutua.
    for i in cola_primera:
        assert i in cola_segunda
    for i in cola_segunda:
        assert i in cola_primera
Esempio n. 7
0
def test_siguiente_manda_a_parcial_si_es_requerido_con_scheduler(
        db, fiscal_client, settings):
    settings.MIN_COINCIDENCIAS_CARGAS = 1
    m1 = MesaFactory()
    a1 = AttachmentFactory(mesa=m1, status=Identificacion.STATUS.identificada)
    m2 = MesaFactory()
    a2 = AttachmentFactory(mesa=m2, status=Identificacion.STATUS.identificada)
    mc1 = MesaCategoriaFactory(categoria__requiere_cargas_parciales=False,
                               coeficiente_para_orden_de_carga=1,
                               mesa=m1)
    mc2 = MesaCategoriaFactory(categoria__requiere_cargas_parciales=True,
                               coeficiente_para_orden_de_carga=2,
                               mesa=m2)
    scheduler()
    response = fiscal_client.get(reverse('siguiente-accion'))
    assert response.status_code == HTTPStatus.FOUND
    assert response.url == reverse('carga-total', args=[mc1.id])

    # mc1 fue asignada, ahora da mc2

    response = fiscal_client.get(reverse('siguiente-accion'))
    assert response.status_code == HTTPStatus.FOUND
    assert response.url == reverse('carga-parcial', args=[mc2.id])
Esempio n. 8
0
def test_siguiente_accion_balancea_con_scheduler(fiscal_client,
                                                 cant_attachments, cant_mcs,
                                                 coeficiente, expect):
    attachments = AttachmentFactory.create_batch(cant_attachments,
                                                 status='sin_identificar')
    mesas = MesaFactory.create_batch(cant_mcs)
    for i in range(cant_mcs):
        attachment_identificado = AttachmentFactory(mesa=mesas[i],
                                                    status='identificada')
        MesaCategoriaFactory(mesa=mesas[i],
                             coeficiente_para_orden_de_carga=1,
                             categoria__sensible=True)

    # Como la URL de identificación pasa un id no predictible
    # y no nos importa acá saber exactamente a que instancia se relaciona la acción
    # lo que evalúo es que redirija a una url que empiece así.
    beginning = reverse(expect, args=[0])[:10]

    with override_config(COEFICIENTE_IDENTIFICACION_VS_CARGA=coeficiente):
        scheduler()
        response = fiscal_client.get(reverse('siguiente-accion'))
    assert response.status_code == HTTPStatus.FOUND
    assert response.url.startswith(beginning)
Esempio n. 9
0
def test_siguiente_happy_path_parcial_y_total_con_modo_ub(
        db, fiscal_client, admin_user, settings):
    # Este test no es del todo realista porque se lo ejecuta con la cantidad de cargas/identificaciones
    # necesarias para consolidar en 1, pero al menos prueba que se siga el circuito con modo_ub=True.
    settings.MIN_COINCIDENCIAS_CARGAS = 1
    settings.MIN_COINCIDENCIAS_IDENTIFICACION = 1
    modo_ub_querry_string = '?modo_ub=True'
    mesa = MesaFactory()
    from adjuntos.models import PreIdentificacion
    from scheduling.models import ColaCargasPendientes
    p = PreIdentificacion(fiscal=admin_user.fiscal,
                          distrito=mesa.circuito.seccion.distrito)
    p.save()
    a = AttachmentFactory(status='sin_identificar', pre_identificacion=p)
    scheduler()
    assert ColaCargasPendientes.largo_cola() == 1
    response = fiscal_client.get(
        reverse('siguiente-accion') + modo_ub_querry_string)

    assert response.status_code == HTTPStatus.FOUND
    # Me manda a idenficarlas con modo_ub
    assert response.url == reverse('asignar-mesa',
                                   args=[a.id]) + modo_ub_querry_string

    assert ColaCargasPendientes.largo_cola() == 0

    # La identifico.
    a.mesa = mesa
    a.status = 'identificada'
    a.save()
    mc1 = MesaCategoriaFactory(categoria__requiere_cargas_parciales=True,
                               coeficiente_para_orden_de_carga=1,
                               mesa=mesa)
    scheduler()

    assert ColaCargasPendientes.largo_cola() == 1

    response = fiscal_client.get(
        reverse('siguiente-accion') + modo_ub_querry_string)
    assert response.status_code == HTTPStatus.FOUND
    assert response.url == reverse('carga-parcial',
                                   args=[mc1.id]) + modo_ub_querry_string

    carga = CargaFactory(mesa_categoria=mc1, tipo='parcial', origen='csv')
    consumir_novedades_carga()
    scheduler()
    mc1.refresh_from_db()
    assert mc1.status == MesaCategoria.STATUS.parcial_consolidada_dc  # Porque la cant de cargas está en 1.
    assert mc1.carga_testigo == carga
    mc1.desasignar_a_fiscal()
    response = fiscal_client.get(
        reverse('siguiente-accion') + modo_ub_querry_string)
    assert response.url == reverse('carga-total',
                                   args=[mc1.id]) + modo_ub_querry_string

    carga = CargaFactory(mesa_categoria=mc1, tipo='total', origen='csv')
    consumir_novedades_carga()
    scheduler()
    mc1.refresh_from_db()
    assert mc1.status == MesaCategoria.STATUS.total_consolidada_dc  # Porque la cant de cargas está en 1.
    assert mc1.carga_testigo == carga
    response = fiscal_client.get(
        reverse('siguiente-accion') + modo_ub_querry_string)
    # No hay actas para cargar, vuelta a empezar.
    assert response.status_code == HTTPStatus.OK
    assert 'No hay actas para cargar' in str(response.content)
Esempio n. 10
0
def test_siguiente_accion_considera_cant_asignaciones_realizadas_con_scheduler(
        db, fiscal_client, settings):
    c1 = CategoriaFactory()
    c2 = CategoriaFactory()
    m1 = MesaFactory(categorias=[c1])
    IdentificacionFactory(
        mesa=m1,
        status='identificada',
        source=Identificacion.SOURCES.csv,
    )
    m2 = MesaFactory(categorias=[c1, c2])
    assert MesaCategoria.objects.count() == 3
    IdentificacionFactory(
        mesa=m2,
        status='identificada',
        source=Identificacion.SOURCES.csv,
    )
    # Ambas consolidadas vía csv.
    consumir_novedades_identificacion()
    scheduler()

    m1c1 = MesaCategoria.objects.get(mesa=m1, categoria=c1)
    for i in range(settings.MIN_COINCIDENCIAS_CARGAS):
        response = fiscal_client.get(reverse('siguiente-accion'))
        assert response.status_code == HTTPStatus.FOUND
        assert response.url == reverse('carga-total', args=[m1c1.id])
        # Fiscal devuelve.
        m1c1.desasignar_a_fiscal()

    # Como m1c1 ya fue pedida por suficientes fiscales,
    # se pasa a la siguiente mesacategoría.
    m1c1.refresh_from_db()
    assert m1c1.cant_fiscales_asignados == 0
    assert m1c1.cant_asignaciones_realizadas == settings.MIN_COINCIDENCIAS_CARGAS
    m2c1 = MesaCategoria.objects.get(mesa=m2, categoria=c1)
    assert m2c1.cant_fiscales_asignados == 0
    assert m2c1.cant_asignaciones_realizadas == 0
    for i in range(settings.MIN_COINCIDENCIAS_CARGAS):
        response = fiscal_client.get(reverse('siguiente-accion'))
        assert response.status_code == HTTPStatus.FOUND
        assert response.url == reverse('carga-total', args=[m2c1.id])
        # Fiscal devuelve.
        m2c1.desasignar_a_fiscal()

    m2c1.refresh_from_db()
    assert m2c1.cant_fiscales_asignados == 0
    assert m2c1.cant_asignaciones_realizadas == settings.MIN_COINCIDENCIAS_CARGAS

    # Ahora la tercera
    m2c2 = MesaCategoria.objects.get(mesa=m2, categoria=c2)
    for i in range(settings.MIN_COINCIDENCIAS_CARGAS):
        response = fiscal_client.get(reverse('siguiente-accion'))
        assert response.status_code == HTTPStatus.FOUND
        assert response.url == reverse('carga-total', args=[m2c2.id])
        # Fiscal devuelve.
        m2c2.desasignar_a_fiscal()

    m2c2.refresh_from_db()
    assert m2c2.cant_fiscales_asignados == 0
    assert m2c2.cant_asignaciones_realizadas == settings.MIN_COINCIDENCIAS_CARGAS

    # Ya no hay actas nuevas, se terminó.
    response = fiscal_client.get(reverse('siguiente-accion'))
    assert response.status_code == HTTPStatus.OK
Esempio n. 11
0
def test_siguiente_accion_redirige_a_cargar_resultados_con_scheduler(
        db, settings, client, setup_groups):
    c1 = CategoriaFactory()
    c2 = CategoriaFactory()
    m1 = MesaFactory(categorias=[c1])
    IdentificacionFactory(
        mesa=m1,
        status='identificada',
        source=Identificacion.SOURCES.csv,
    )
    m2 = MesaFactory(categorias=[c1, c2])
    assert MesaCategoria.objects.count() == 3
    IdentificacionFactory(
        mesa=m2,
        status='identificada',
        source=Identificacion.SOURCES.csv,
    )
    # Ambas consolidadas vía csv.
    consumir_novedades_identificacion()
    scheduler()

    # Los fiscales que voy a usar.
    fiscales = FiscalFactory.create_batch(20)
    indice_fiscal = 0

    m1c1 = MesaCategoria.objects.get(mesa=m1, categoria=c1)
    for i in range(settings.MIN_COINCIDENCIAS_CARGAS):
        fiscal_client = fiscal_client_from_fiscal(client,
                                                  fiscales[indice_fiscal])
        indice_fiscal += 1
        response = fiscal_client.get(reverse('siguiente-accion'))
        assert response.status_code == HTTPStatus.FOUND
        assert response.url == reverse('carga-total', args=[m1c1.id])
        # Cerramos la sesión para que el client pueda reutilizarse sin que nos diga
        # que ya estamos logueados.
        fiscal_client.logout()

    # Como m1c1 ya fue pedida por suficientes fiscales,
    # se pasa a la siguiente mesacategoría.
    m2c1 = MesaCategoria.objects.get(mesa=m2, categoria=c1)
    for i in range(settings.MIN_COINCIDENCIAS_CARGAS):
        fiscal_client = fiscal_client_from_fiscal(client,
                                                  fiscales[indice_fiscal])
        indice_fiscal += 1
        response = fiscal_client.get(reverse('siguiente-accion'))
        assert response.status_code == HTTPStatus.FOUND
        assert response.url == reverse('carga-total', args=[m2c1.id])
        fiscal_client.logout()

    # Ahora la tercera.
    m2c2 = MesaCategoria.objects.get(mesa=m2, categoria=c2)
    for i in range(settings.MIN_COINCIDENCIAS_CARGAS):
        fiscal_client = fiscal_client_from_fiscal(client,
                                                  fiscales[indice_fiscal])
        indice_fiscal += 1
        response = fiscal_client.get(reverse('siguiente-accion'))
        assert response.status_code == HTTPStatus.FOUND
        assert response.url == reverse('carga-total', args=[m2c2.id])
        fiscal_client.logout()

    # Ya no hay actas nuevas, vacío.
    fiscal_client = fiscal_client_from_fiscal(client, fiscales[indice_fiscal])
    indice_fiscal += 1
    response = fiscal_client.get(reverse('siguiente-accion'))
    assert response.status_code == HTTPStatus.OK
    fiscal_client.logout()