def test_siguiente_prioriza_categoria(db, settings): f = FiscalFactory() c = CategoriaFactory(prioridad=2) c2 = CategoriaFactory(prioridad=1) m1 = MesaFactory() AttachmentFactory(mesa=m1) mc1 = MesaCategoriaFactory( status=MesaCategoria.STATUS.parcial_sin_consolidar, categoria=c, mesa=m1, ) mc1.actualizar_coeficiente_para_orden_de_carga() m2 = MesaFactory() AttachmentFactory(mesa=m2) mc2 = MesaCategoriaFactory( categoria=c2, status=MesaCategoria.STATUS.parcial_sin_consolidar, mesa=m2, ) mc2.actualizar_coeficiente_para_orden_de_carga() # Se recibe la mc con categoria más prioritaria. assert MesaCategoria.objects.siguiente() == mc2 for i in range(settings.MIN_COINCIDENCIAS_CARGAS): mc2.asignar_a_fiscal() # Luego la de la categoría menos prioritaria. assert MesaCategoria.objects.siguiente() == mc1
def test_identificadas_excluye_sin_orden(db): m1 = MesaFactory() AttachmentFactory(mesa=m1) mc1 = MesaCategoriaFactory(mesa=m1) m2 = MesaFactory() AttachmentFactory(mesa=m2) mc2 = MesaCategoriaFactory(coeficiente_para_orden_de_carga=0.1, mesa=m2) assert mc1.coeficiente_para_orden_de_carga is None assert mc1 not in MesaCategoria.objects.identificadas() assert mc2 in MesaCategoria.objects.identificadas()
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)
def test_efecto_diferencia_1(db, caplog): fiscal_1 = nuevo_fiscal() fiscal_2 = nuevo_fiscal() mesa_categoria = MesaCategoriaFactory() carga_1 = nueva_carga(mesa_categoria, fiscal_1, [30, 20, 10]) carga_1.actualizar_firma() mesa_categoria.carga_testigo = carga_1 mesa_categoria.save() # incompatible carga_2 = nueva_carga(mesa_categoria, fiscal_2, [30, 20, 9]) carga_2.actualizar_firma() efecto_scoring_troll_confirmacion_carga(mesa_categoria) # hay un solo evento troll del fiscal 2, y la diferencia es 1 assert EventoScoringTroll.objects.filter( fiscal_afectado=fiscal_2).get().variacion == carga_1 - carga_2 == 1
def test_consumir_novedades_carga_tres_ok_tres_error(db, settings): # En esta variable se almacena el comportamiento que tendrá cada llamado a # la función consolidar_cargas para cada mesa_categoria a procesar. # Las mc1, mc3 y mc5 se procesarán con normalidad y sus cargas c1, c3 y c6 # quedarán marcadas como procesadas=True. # Para las mc2 y mc4 se lanzará una Exception y sus cargas c2, c4 y c5 # quedarán como procesada=False. side_effects = [ mock.DEFAULT, #comportamiento para mc1 Exception('error'), #comportamiento para mc2 mock.DEFAULT, #comportamiento para mc3 Exception('error'), #comportamiento para mc4 mock.DEFAULT #comportamiento para mc5 ] with mock.patch('adjuntos.consolidacion.consolidar_cargas', side_effect=side_effects): m1 = MesaFactory() m2 = MesaFactory() mc1 = MesaCategoriaFactory(mesa=m1) mc2 = MesaCategoriaFactory(mesa=m1) mc3 = MesaCategoriaFactory(mesa=m2) mc4 = MesaCategoriaFactory(mesa=m2) mc5 = MesaCategoriaFactory(mesa=m2) c1 = CargaFactory(mesa_categoria=mc1, tipo='parcial') c2 = CargaFactory(mesa_categoria=mc2, tipo='total') c3 = CargaFactory(mesa_categoria=mc3, tipo='total') c4 = CargaFactory(mesa_categoria=mc4, tipo='total') c5 = CargaFactory(mesa_categoria=mc4, tipo='parcial') c6 = CargaFactory(mesa_categoria=mc5, tipo='total') consumir_novedades_carga() # Chequeamos que las no procesadas son 3 no_procesadas = Carga.objects.filter(procesada=False) assert no_procesadas.count() == 3 # Chequeamos que las no procesadas son c2, c4 y c5 no_procesadas_ids = map(lambda x: x.id, no_procesadas) assert set([c2.id, c4.id, c5.id]) == set(no_procesadas_ids) # Chequeamos que las procesadas son 3 procesadas = Carga.objects.filter(procesada=True) assert procesadas.count() == 3 # # Chequeamos que las procesadas son c1, c3 y c6 procesadas_ids = map(lambda x: x.id, procesadas) assert set([c1.id, c3.id, c6.id]) == set(procesadas_ids)
def test_efecto_ignora_cargas_incompatibles(db, caplog): with override_config(SCORING_TROLL_DESCUENTO_ACCION_CORRECTA=28): fiscal_1 = nuevo_fiscal() fiscal_2 = nuevo_fiscal() mesa_categoria = MesaCategoriaFactory() carga_1 = nueva_carga(mesa_categoria, fiscal_1, [30, 20, 10]) carga_1.actualizar_firma() mesa_categoria.carga_testigo = carga_1 mesa_categoria.save() # incompatible carga_2 = nueva_carga(mesa_categoria, fiscal_2, [30, 20]) carga_2.actualizar_firma() efecto_scoring_troll_confirmacion_carga(mesa_categoria) # se ignoran las diferencias, sólo se genera evento con variación negativa para la carga testigo assert EventoScoringTroll.objects.count() == 1 assert EventoScoringTroll.objects.get().variacion == -28
def test_prioridades_mesacat_categoria_prioritaria(db, settings, proporcion, orden_de_llegada, prioridad): """ Prioridades para una MesaCategoria de una seccion standard, para una categoria prioritaria, en un circuito de 100 mesas. """ definir_prioridades_seccion_categoria(settings) mesa_categoria = MesaCategoriaFactory( categoria=categoria_pv(), mesa=mesa_en_seccion(seccion_standard())) prioridades = mapa_prioridades_para_mesa_categoria(mesa_categoria) assert(prioridades.valor_para(proporcion, orden_de_llegada)) == prioridad
def test_cargar_resultados_redirige_a_identificar(db, fiscal_client, status, parcial): mesa = MesaFactory() a = AttachmentFactory(mesa=mesa) c1 = CategoriaFactory(requiere_cargas_parciales=True) m1c1 = MesaCategoriaFactory(categoria=c1, coeficiente_para_orden_de_carga=0.1, status=status, mesa=mesa) response = fiscal_client.get(reverse('siguiente-accion')) assert response.status_code == HTTPStatus.FOUND assert response.url.startswith('/clasificar-actas/')
def agregar_mesacats(self, settings): opciones_prioritarias = ["FT", "JC"] opciones_no_prioritarias = ["CF", "FIT", "Desp"] # presidente categoria_pv = nueva_categoria( settings.SLUG_CATEGORIA_PRESI_Y_VICE, opciones_prioritarias, opciones_no_prioritarias) self.mesacats_pv_pba = [MesaCategoriaFactory( mesa=mesa, categoria=categoria_pv) for mesa in self.mesas_pba] self.mesacats_pv_caba = [MesaCategoriaFactory( mesa=mesa, categoria=categoria_pv) for mesa in self.mesas_caba] self.mesacats_pv_cat = [MesaCategoriaFactory( mesa=mesa, categoria=categoria_pv) for mesa in self.mesas_cat] # gobernador PBA categoria_gv_pba = nueva_categoria( settings.SLUG_CATEGORIA_GOB_Y_VICE_PBA, opciones_prioritarias, opciones_no_prioritarias, self.distrito_pba) self.mesacats_gv_pba = [MesaCategoriaFactory( mesa=mesa, categoria=categoria_gv_pba) for mesa in self.mesas_pba] # una categoría CABA categoria_jefe_de_gobierno_caba = nueva_categoria( "JG_CABA", opciones_prioritarias, opciones_no_prioritarias, self.distrito_caba) self.mesacats_jg_caba = [MesaCategoriaFactory( mesa=mesa, categoria=categoria_jefe_de_gobierno_caba) for mesa in self.mesas_caba] # una categoría Catamarca categoria_diputados_catamarca = nueva_categoria( "DIP_CAT", opciones_prioritarias, opciones_no_prioritarias, self.distrito_cat) self.mesacats_jg_caba = [MesaCategoriaFactory( mesa=mesa, categoria=categoria_diputados_catamarca) for mesa in self.mesas_cat]
def test_identificacion_consolidada_calcula_orden_de_prioridad(db): mc1 = MesaCategoriaFactory() mesa = mc1.mesa mc2 = MesaCategoriaFactory(mesa=mesa) assert mc1.coeficiente_para_orden_de_carga is None assert mc2.coeficiente_para_orden_de_carga is None # Emulo consolidación. i = IdentificacionFactory(status='identificada', mesa=mc1.mesa, fiscal=FiscalFactory()) AttachmentFactory(status='identificada', mesa=mesa, identificacion_testigo=i) mc1.refresh_from_db() mc2.refresh_from_db() assert mc1.coeficiente_para_orden_de_carga is not None assert mc2.coeficiente_para_orden_de_carga is not None
def test_prioridades_mesacat_seccion_con_definicion_parcial_1(db, settings, proporcion, orden_de_llegada, prioridad): """ Prioridades para una MesaCategoria de una seccion que define prioridades distintas de las standard sólo para un rango de proporciones. """ definir_prioridades_seccion_categoria(settings) seccion_parcial = SeccionFactory(nombre="Definición parcial de prioridades no standard") PrioridadSchedulingFactory(seccion=seccion_parcial, desde_proporcion=2, hasta_proporcion=5, prioridad=4) mesa_categoria = MesaCategoriaFactory( categoria=categoria_standard(), mesa=crear_mesa(seccion_parcial)) prioridades = mapa_prioridades_para_mesa_categoria(mesa_categoria) assert(prioridades.valor_para(proporcion, orden_de_llegada)) == prioridad
def test_prioridades_mesa_seccion_cuatro_prioridades_1000(db, settings, proporcion, orden_de_llegada, prioridad): """ Prioridades para una MesaCategoria de una seccion que tiene definidas cuatro niveles de prioridad en lugar de tres, para una categoria intermedia, en un circuito de 1000 mesas. La maxima prioridad para la seccion rige hasta el 2% con un minimo de 12 mesas. """ definir_prioridades_seccion_categoria(settings) mesa_categoria = MesaCategoriaFactory( categoria=categoria_gv(), mesa=mesa_en_seccion(seccion_cuatro_prioridades())) prioridades = mapa_prioridades_para_mesa_categoria(mesa_categoria) assert(prioridades.valor_para(proporcion, orden_de_llegada)) == prioridad
def test_prioridades_mesacat_standard(db, settings, proporcion, orden_de_llegada, prioridad): """ Prioridades para una MesaCategoria para la cual ni la sección ni la categoría tienen asignadas prioridades distintas a las standard """ definir_prioridades_seccion_categoria(settings) mesa_categoria = MesaCategoriaFactory( categoria=categoria_standard(), mesa=mesa_en_seccion(seccion_standard())) prioridades = mapa_prioridades_para_mesa_categoria(mesa_categoria) assert(prioridades.valor_para(proporcion,orden_de_llegada)) == prioridad
def test_prioridades_mesacat_categoria_y_seccion_prioritarias_1000(db, settings, proporcion, orden_de_llegada, prioridad): """ Prioridades para una MesaCategoria de una seccion prioritaria, para una categoria prioritaria, en un circuito de 100 mesas. La maxima prioridad para la seccion rige hasta el 2% con un minimo de 7 mesas. """ definir_prioridades_seccion_categoria(settings) mesa_categoria = MesaCategoriaFactory( categoria=categoria_pv(), mesa=mesa_en_seccion(seccion_prioritaria())) prioridades = mapa_prioridades_para_mesa_categoria(mesa_categoria) assert(prioridades.valor_para(proporcion, orden_de_llegada)) == prioridad
def test_cargar_resultados_redirige_a_parcial_si_es_necesario( db, fiscal_client, status, parcial): mesa = MesaFactory() a = AttachmentFactory(mesa=mesa) c1 = CategoriaFactory(requiere_cargas_parciales=True, sensible=True) m1c1 = MesaCategoriaFactory(categoria=c1, coeficiente_para_orden_de_carga=0.1, status=status, mesa=mesa) 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])
def test_siguiente_prioriza_seccion(db, settings): f = FiscalFactory() c = CategoriaFactory() # Si se pone # m1 = MesaFactory(circuito__seccion__prioridad_hasta_2=10000) # no funciona. # Intuyo que es porque en MesaFactory, el circuito se setea mediante un LazyAttribute, # y los seteos que van como argumentos de la Factory se estarían ejecutando antes de # que se apliquen los LazyAttribute. # Lo único que hice fue la prueba empírica de agregar "lugar_votacion__" antes, y ver que sí setea # la prioridad de la sección. No llegué a entender la documentación de factory boy en la medida necesaria. m1 = MesaFactory(lugar_votacion__circuito__seccion__prioridad_hasta_2=10000) AttachmentFactory(mesa=m1) mc1 = MesaCategoriaFactory( status=MesaCategoria.STATUS.parcial_sin_consolidar, categoria=c, mesa=m1, ) mc1.actualizar_coeficiente_para_orden_de_carga() m2 = MesaFactory(lugar_votacion__circuito__seccion__prioridad_hasta_2=42) AttachmentFactory(mesa=m2) mc2 = MesaCategoriaFactory( categoria=c, status=MesaCategoria.STATUS.parcial_sin_consolidar, mesa=m2, ) mc2.actualizar_coeficiente_para_orden_de_carga() assert mc1.percentil == 1 assert mc1.mesa.circuito.seccion.prioridad_hasta_2 == 10000 assert mc2.percentil == 1 assert mc2.mesa.circuito.seccion.prioridad_hasta_2 == 42 # Se recibe la mc de la sección más prioritaria. assert MesaCategoria.objects.siguiente() == mc2 for i in range(settings.MIN_COINCIDENCIAS_CARGAS): mc2.asignar_a_fiscal() # Luego la de la sección con prioridad menos prioritaria. assert MesaCategoria.objects.siguiente() == mc1
def test_datos_previos_desde_metadata(db): o1 = OpcionFactory(tipo=Opcion.TIPOS.metadata) o2 = OpcionFactory() cat1 = CategoriaFactory(opciones=[o1, o2]) cat1o1 = CategoriaOpcionFactory(categoria=cat1, opcion=o1, orden=1) cat1o2 = CategoriaOpcionFactory(categoria=cat1, opcion=o2, orden=2) mc = MesaCategoriaFactory(categoria=cat1, status=MesaCategoria.STATUS.total_consolidada_dc) carga = CargaFactory(mesa_categoria=mc, tipo='total') VotoMesaReportadoFactory(carga=carga, opcion=o1, votos=10) VotoMesaReportadoFactory(carga=carga, opcion=o2, votos=12) # otra categoria incluye la misma metadata. o2 = OpcionFactory() cat2 = CategoriaFactory(opciones=[o1, o2]) cat1o1 = CategoriaOpcionFactory(categoria=cat2, opcion=o1, orden=1) cat2o2 = CategoriaOpcionFactory(categoria=cat2, opcion=o2, orden=2) mc2 = MesaCategoriaFactory(categoria=cat2, mesa=mc.mesa) # esa mesa categoria incluye la metadata ya cargada en mc1 assert mc2.datos_previos('parcial') == {o1.id: 10} assert mc2.datos_previos('total') == {o1.id: 10}
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])
def test_procesar_csv_categorias_faltantes_en_archivo(db, usr_unidad_basica): CategoriaGeneralFactory() d1 = DistritoFactory(numero=1) s1 = SeccionFactory(numero=50, distrito=d1) c1 = CircuitoFactory(numero='2', seccion=s1) m = MesaFactory(numero='4012', lugar_votacion__circuito=c1, electores=100, circuito=c1) o2 = OpcionFactory(codigo='Todes') o3 = OpcionFactory(codigo='Juntos') c = CategoriaFactory(opciones=[o2, o3], nombre='Otra categoria') MesaCategoriaFactory(mesa=m, categoria=c) cant_mesas_ok, cant_mesas_parcialmente_ok, errores = CSVImporter( PATH_ARCHIVOS_TEST + 'info_resultados_negativos.csv', usr_unidad_basica).procesar() assert cant_mesas_ok == 0 assert cant_mesas_parcialmente_ok == 0 assert 'Faltan datos en el archivo de la siguiente categoría' in errores assert Carga.objects.count() == 0
def test_liberacion_vuelve_al_ruedo(db, settings): """ Este test verifica que la acción del consolidador libera mesas que nunca recibieron resultados. """ f = FiscalFactory() c = CategoriaFactory(prioridad=1) m1 = MesaFactory() AttachmentFactory(mesa=m1) mc1 = MesaCategoriaFactory( status=MesaCategoria.STATUS.parcial_sin_consolidar, categoria=c, coeficiente_para_orden_de_carga=1.0, mesa=m1 ) m3 = MesaFactory() AttachmentFactory(mesa=m3) mc3 = MesaCategoriaFactory( categoria=c, status=MesaCategoria.STATUS.total_en_conflicto, coeficiente_para_orden_de_carga=2.0, mesa=m3 ) assert MesaCategoria.objects.siguiente() == mc1 for i in range(settings.MIN_COINCIDENCIAS_CARGAS): mc1.asignar_a_fiscal() cant_asignaciones = mc1.cant_fiscales_asignados # Es como si de las varias asignaciones de la mc la última sea para el fiscal f f.asignar_mesa_categoria(mc1) # Como mc1 está muy asignada, ahora me propone mc3. assert MesaCategoria.objects.siguiente() == mc3 settings.TIMEOUT_TAREAS = 0 liberar_mesacategorias_y_attachments() # mc1 volvió al ruedo. assert MesaCategoria.objects.siguiente() == mc1 mc1.refresh_from_db() assert mc1.cant_fiscales_asignados == cant_asignaciones - 1
def test_datos_previos_parcial(db): o1 = OpcionFactory(tipo=Opcion.TIPOS.metadata) o2 = OpcionFactory() cat1 = CategoriaFactory(opciones=[o1, o2]) cat1o1 = CategoriaOpcionFactory(categoria=cat1, opcion=o1, orden=1) cat1o2 = CategoriaOpcionFactory(categoria=cat1, opcion=o2, orden=2) # tengo una consolidación parcial mc = MesaCategoriaFactory( categoria=cat1, status=MesaCategoria.STATUS.parcial_consolidada_dc) carga = CargaFactory(mesa_categoria=mc, tipo='total') VotoMesaReportadoFactory(carga=carga, opcion=o1, votos=10) VotoMesaReportadoFactory(carga=carga, opcion=o2, votos=12) mc.carga_testigo = carga mc.save() # si pedimos datos previos para realizar una carga total, los de consolidados parciales vienen assert mc.datos_previos('total') == {o1.id: 10, o2.id: 12}