From e1e9f2345733e606f0c508c8c1eae86d86e0333a Mon Sep 17 00:00:00 2001 From: grayTerminal-sh Date: Sat, 18 Jul 2026 11:29:56 +0200 Subject: [PATCH] feat: initialize external tools asynchronously --- Makefile | 18 +- include/core/tool_initializer.h | 237 +++++ labfy-investigation | Bin 310912 -> 328816 bytes src/core/tool_initializer.c | 1338 +++++++++++++++++++++++++ tests/test_tool_initializer | Bin 0 -> 85656 bytes tests/test_tool_initializer.c | 1647 +++++++++++++++++++++++++++++++ 6 files changed, 3238 insertions(+), 2 deletions(-) create mode 100644 include/core/tool_initializer.h create mode 100644 src/core/tool_initializer.c create mode 100755 tests/test_tool_initializer create mode 100644 tests/test_tool_initializer.c diff --git a/Makefile b/Makefile index 79e42a4..6a5adcf 100644 --- a/Makefile +++ b/Makefile @@ -46,6 +46,7 @@ TEST_TOOL_REGISTRY := tests/test_tool_registry TEST_TOOL_PROCESS := tests/test_tool_process TEST_TOOL_TASK := tests/test_tool_task TEST_TOOL_CATALOG := tests/test_tool_catalog +TEST_TOOL_INITIALIZER := tests/test_tool_initializer all: $(TARGET) @@ -179,6 +180,16 @@ $(TEST_TOOL_CATALOG): \ src/core/tool_process.c $(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS) +$(TEST_TOOL_INITIALIZER): \ + tests/test_tool_initializer.c \ + src/core/tool_initializer.c \ + src/core/task_manager.c \ + src/core/background_task.c \ + src/core/tool_registry.c \ + src/core/tool_catalog.c \ + src/core/tool_process.c + $(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS) + test: \ $(TEST_NODE) \ $(TEST_TREE_MODEL) \ @@ -196,7 +207,8 @@ test: \ $(TEST_TOOL_REGISTRY) \ $(TEST_TOOL_PROCESS) \ $(TEST_TOOL_TASK) \ - $(TEST_TOOL_CATALOG) + $(TEST_TOOL_CATALOG) \ + $(TEST_TOOL_INITIALIZER) @echo "Exécution des tests..." @./$(TEST_NODE) @./$(TEST_TREE_MODEL) @@ -215,6 +227,7 @@ test: \ @$(TEST_TOOL_PROCESS) @$(TEST_TOOL_TASK) @$(TEST_TOOL_CATALOG) + @$(TEST_TOOL_INITIALIZER) @echo "Tous les tests sont valides." %.o: %.c @@ -241,6 +254,7 @@ clean: $(TEST_TOOL_REGISTRY) \ $(TEST_TOOL_PROCESS) \ $(TEST_TOOL_TASK) \ - $(TEST_TOOL_CATALOG) + $(TEST_TOOL_CATALOG) \ + $(TEST_TOOL_INITIALIZER) .PHONY: clean run test diff --git a/include/core/tool_initializer.h b/include/core/tool_initializer.h new file mode 100644 index 0000000..411d7a2 --- /dev/null +++ b/include/core/tool_initializer.h @@ -0,0 +1,237 @@ +/****************************************************************************** + * @file tool_initializer.h + * @brief Initialisation asynchrone des outils externes. + ******************************************************************************/ + +#ifndef LABFY_INVESTIGATION_TOOL_INITIALIZER_H +#define LABFY_INVESTIGATION_TOOL_INITIALIZER_H + +#include "core/background_task.h" +#include "core/task_manager.h" +#include "core/tool_registry.h" + +#include + +G_BEGIN_DECLS + +/** + * @brief Représentation opaque de l’initialiseur d’outils. + */ +typedef struct ToolInitializer ToolInitializer; + +/** + * @brief Résumé d’une initialisation terminée avec succès. + */ +typedef struct +{ + gsize total_count; + gsize available_count; + gsize missing_count; + gsize version_detected_count; + gsize version_failed_count; +} ToolInitializationSummary; + +/** + * @brief Codes d’erreur de ToolInitializer. + */ +typedef enum +{ + /** + * Un argument transmis au module est invalide. + */ + TOOL_INITIALIZER_ERROR_INVALID_ARGUMENT, + + /** + * Une initialisation est déjà en cours. + */ + TOOL_INITIALIZER_ERROR_ALREADY_RUNNING, + + /** + * Aucune initialisation n’est actuellement en cours. + */ + TOOL_INITIALIZER_ERROR_NOT_RUNNING, + + /** + * La tâche d’arrière-plan n’a pas pu être créée. + */ + TOOL_INITIALIZER_ERROR_TASK_CREATION, + + /** + * La tâche n’a pas pu être ajoutée au TaskManager. + */ + TOOL_INITIALIZER_ERROR_TASK_REGISTRATION, + + /** + * La tâche n’a pas pu être démarrée. + */ + TOOL_INITIALIZER_ERROR_TASK_START, + + /** + * Le catalogue n’a pas pu être enregistré. + */ + TOOL_INITIALIZER_ERROR_CATALOG_REGISTRATION, + + /** + * Le registre n’a pas pu rechercher les exécutables. + */ + TOOL_INITIALIZER_ERROR_REGISTRY_REFRESH, + + /** + * L’état interne de l’initialiseur est incohérent. + */ + TOOL_INITIALIZER_ERROR_INTERNAL_STATE +} ToolInitializerError; + +/** + * @brief Domaine d’erreur du module. + */ +#define TOOL_INITIALIZER_ERROR \ + tool_initializer_error_quark() + +/** + * @brief Retourne le domaine d’erreur de ToolInitializer. + * + * @return Quark GLib du domaine d’erreur. + */ +GQuark tool_initializer_error_quark(void); + +/** + * @brief Crée un initialiseur d’outils externes. + * + * L’initialiseur : + * + * - conserve une référence empruntée vers task_manager ; + * - crée et possède son propre ToolRegistry ; + * - ne prend pas possession de task_manager. + * + * task_manager doit rester valide pendant les appels publics utilisant + * l’initialiseur. + * + * @param task_manager Gestionnaire recevant la tâche d’initialisation. + * @param error Emplacement facultatif recevant une erreur. + * + * @return Nouvel initialiseur, ou NULL en cas d’échec. + */ +ToolInitializer *tool_initializer_new( + TaskManager *task_manager, + GError **error +); + +/** + * @brief Libère la référence détenue par l’appelant. + * + * Si une initialisation est encore active, son annulation est demandée. + * La fonction ne bloque pas en attendant la fin du worker. + * + * Une référence interne conserve les ressources nécessaires jusqu’à la + * finalisation réelle de la tâche. + * + * La fonction accepte tool_initializer == NULL. + * + * @param tool_initializer Initialiseur à libérer. + */ +void tool_initializer_free( + ToolInitializer *tool_initializer +); + +/** + * @brief Retourne le registre appartenant à l’initialiseur. + * + * Le pointeur retourné est emprunté et ne doit jamais être libéré par + * l’appelant. + * + * Il ne doit plus être utilisé après tool_initializer_free(). + * + * @param tool_initializer Initialiseur consulté. + * + * @return Registre emprunté, ou NULL. + */ +ToolRegistry *tool_initializer_get_registry( + ToolInitializer *tool_initializer +); + +/** + * @brief Démarre l’initialisation en arrière-plan. + * + * La fonction : + * + * - crée une nouvelle BackgroundTask ; + * - l’ajoute au TaskManager ; + * - lance son worker ; + * - refuse un second démarrage tant qu’une tâche est active. + * + * Une nouvelle exécution peut être lancée après la fin ou l’annulation + * de la précédente. + * + * @param tool_initializer Initialiseur concerné. + * @param error Emplacement facultatif recevant une erreur. + * + * @return TRUE si la tâche a été lancée, sinon FALSE. + */ +gboolean tool_initializer_start( + ToolInitializer *tool_initializer, + GError **error +); + +/** + * @brief Demande l’annulation de l’initialisation active. + * + * L’annulation est coopérative. + * + * @param tool_initializer Initialiseur concerné. + * @param error Emplacement facultatif recevant une erreur. + * + * @return TRUE si une annulation a été demandée, sinon FALSE. + */ +gboolean tool_initializer_cancel( + ToolInitializer *tool_initializer, + GError **error +); + +/** + * @brief Indique si une initialisation est en cours. + * + * @param tool_initializer Initialiseur consulté. + * + * @return TRUE si une tâche est en attente ou en cours, sinon FALSE. + */ +gboolean tool_initializer_is_running( + const ToolInitializer *tool_initializer +); + +/** + * @brief Retourne une référence vers la tâche actuelle ou la dernière tâche. + * + * L’appelant devient propriétaire d’une référence et doit la libérer avec : + * + * @code + * background_task_unref(task); + * @endcode + * + * @param tool_initializer Initialiseur consulté. + * + * @return Nouvelle référence vers la tâche, ou NULL. + */ +BackgroundTask *tool_initializer_get_task( + const ToolInitializer *tool_initializer +); + +/** + * @brief Copie le résumé de la dernière initialisation réussie. + * + * Le résumé n’est disponible que lorsque la dernière tâche s’est terminée + * dans l’état BACKGROUND_TASK_STATE_COMPLETED. + * + * @param tool_initializer Initialiseur consulté. + * @param out_summary Structure recevant une copie du résumé. + * + * @return TRUE si un résumé est disponible, sinon FALSE. + */ +gboolean tool_initializer_get_last_summary( + const ToolInitializer *tool_initializer, + ToolInitializationSummary *out_summary +); + +G_END_DECLS + +#endif diff --git a/labfy-investigation b/labfy-investigation index 915aaec332f04f539ae54ca369a0db9d29716dd6..843eaa869a00ae82967bf45c87c782b4880ea72f 100755 GIT binary patch delta 91879 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 XbTogHzcav*cHi+1)skjm?stDB&Q zx9|}4hZ(Xl_vEe)zPaCOvtMc{hjUkZUyF!Pp?tWPyoK@~jMsVJ1#%zqq5u3_=l$pF zh+DOH$IDj2l@|3)YuzclDTfJH2mW+td7W@|5AW@)!P`v%=7Vp$JS1E#eXHodq~e<1 SRmRz__Wa}%a)9m1|Nj7|;|j9? diff --git a/src/core/tool_initializer.c b/src/core/tool_initializer.c new file mode 100644 index 0000000..0c91b60 --- /dev/null +++ b/src/core/tool_initializer.c @@ -0,0 +1,1338 @@ +/****************************************************************************** + * @file tool_initializer.c + * @brief Initialisation asynchrone des outils externes. + ******************************************************************************/ + +#include "core/tool_initializer.h" +#include "core/tool_catalog.h" + +#include +#include + +/** + * @struct ToolInitializer + * @brief État interne de l’initialiseur d’outils. + */ +struct ToolInitializer +{ + gatomicrefcount reference_count; + GMutex mutex; + + TaskManager *task_manager; + ToolRegistry *tool_registry; + + BackgroundTask *task; + + ToolInitializationSummary last_summary; + + gboolean has_last_summary; + gboolean is_running; +}; + +static gboolean tool_initializer_ensure_catalog_registered( + ToolInitializer *tool_initializer, + GError **error +); + +/** + * @brief Ajoute une référence interne à l’initialiseur. + * + * @param tool_initializer Initialiseur concerné. + * + * @return L’initialiseur fourni, ou NULL. + */ +static ToolInitializer *tool_initializer_ref_internal( + ToolInitializer *tool_initializer +) +{ + if (tool_initializer == NULL) + { + return NULL; + } + + g_atomic_ref_count_inc( + &tool_initializer->reference_count + ); + + return tool_initializer; +} + +/** + * @brief Libère une référence interne à l’initialiseur. + * + * @param tool_initializer Initialiseur concerné. + */ +static void tool_initializer_unref_internal( + ToolInitializer *tool_initializer +) +{ + BackgroundTask *task = NULL; + ToolRegistry *tool_registry = NULL; + + if (tool_initializer == NULL) + { + return; + } + + if (!g_atomic_ref_count_dec( + &tool_initializer->reference_count + )) + { + return; + } + + g_mutex_lock( + &tool_initializer->mutex + ); + + task = tool_initializer->task; + tool_registry = tool_initializer->tool_registry; + + tool_initializer->task = NULL; + tool_initializer->tool_registry = NULL; + tool_initializer->task_manager = NULL; + tool_initializer->is_running = FALSE; + + g_mutex_unlock( + &tool_initializer->mutex + ); + + background_task_unref( + task + ); + + tool_registry_free( + tool_registry + ); + + g_mutex_clear( + &tool_initializer->mutex + ); + + g_free( + tool_initializer + ); +} + +/** + * @brief Adapte tool_initializer_unref_internal() à GDestroyNotify. + * + * @param user_data Initialiseur concerné. + */ +static void tool_initializer_unref_notify( + gpointer user_data +) +{ + tool_initializer_unref_internal( + user_data + ); +} + +/** + * @brief Produit une erreur ToolInitializer à partir d’une erreur interne. + * + * @param error Emplacement recevant l’erreur. + * @param error_code Code ToolInitializer. + * @param message Message principal. + * @param cause Erreur interne facultative. + */ +static void tool_initializer_set_wrapped_error( + GError **error, + ToolInitializerError error_code, + const char *message, + const GError *cause +) +{ + if (cause != NULL) + { + g_set_error( + error, + TOOL_INITIALIZER_ERROR, + error_code, + "%s : %s", + message, + cause->message + ); + + return; + } + + g_set_error_literal( + error, + TOOL_INITIALIZER_ERROR, + error_code, + message + ); +} + +/** + * @brief Enregistre, recherche et interroge les outils externes. + */ +static gboolean tool_initializer_bootstrap_worker( + BackgroundTask *task, + GCancellable *cancellable, + gpointer worker_data, + gpointer *result, + GError **error +) +{ + ToolInitializer *tool_initializer = + worker_data; + + ToolRegistry *tool_registry = NULL; + + ToolInitializationSummary *summary = NULL; + + gsize tool_count = 0; + gsize tool_index = 0; + + GError *local_error = NULL; + + if (task == NULL || + cancellable == NULL || + tool_initializer == NULL || + result == NULL) + { + g_set_error_literal( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_INTERNAL_STATE, + "Le contexte du worker d’initialisation est invalide." + ); + + return FALSE; + } + + tool_registry = + tool_initializer->tool_registry; + + if (tool_registry == NULL) + { + g_set_error_literal( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_INTERNAL_STATE, + "Le registre interne des outils est invalide." + ); + + return FALSE; + } + + if (g_cancellable_set_error_if_cancelled( + cancellable, + error + )) + { + return FALSE; + } + + background_task_report_progress( + task, + 0.05, + "Enregistrement du catalogue des outils" + ); + + if (!tool_initializer_ensure_catalog_registered( + tool_initializer, + error + )) + { + return FALSE; + } + + if (g_cancellable_set_error_if_cancelled( + cancellable, + error + )) + { + return FALSE; + } + + background_task_report_progress( + task, + 0.15, + "Recherche des exécutables installés" + ); + + if (!tool_registry_refresh( + tool_registry, + &local_error + )) + { + tool_initializer_set_wrapped_error( + error, + TOOL_INITIALIZER_ERROR_REGISTRY_REFRESH, + "La recherche des exécutables a échoué", + local_error + ); + + g_clear_error( + &local_error + ); + + return FALSE; + } + + summary = g_new0( + ToolInitializationSummary, + 1 + ); + + tool_count = + tool_catalog_get_count(); + + summary->total_count = + tool_count; + + for (tool_index = 0; + tool_index < tool_count; + tool_index++) + { + const ToolCatalogEntry *catalog_entry = NULL; + const ToolInfo *tool_info = NULL; + + const char *identifier = NULL; + const char *display_name = NULL; + + char *detected_version = NULL; + char *status_message = NULL; + + double progress = 0.0; + + if (g_cancellable_set_error_if_cancelled( + cancellable, + error + )) + { + g_free( + summary + ); + + return FALSE; + } + + catalog_entry = + tool_catalog_get_entry( + tool_index + ); + + if (catalog_entry != NULL) + { + identifier = + tool_catalog_entry_get_identifier( + catalog_entry + ); + + display_name = + tool_catalog_entry_get_display_name( + catalog_entry + ); + } + + if (catalog_entry == NULL || + identifier == NULL || + display_name == NULL) + { + g_set_error( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_INTERNAL_STATE, + "L’entrée de catalogue numéro %" + G_GSIZE_FORMAT + " est invalide.", + tool_index + ); + + g_free( + summary + ); + + return FALSE; + } + + status_message = + g_strdup_printf( + "Vérification de %s", + display_name + ); + + progress = + 0.15 + + ( + 0.80 * + ( + (double) tool_index / + (double) tool_count + ) + ); + + background_task_report_progress( + task, + progress, + status_message + ); + + g_free( + status_message + ); + + tool_info = + tool_registry_find( + tool_registry, + identifier + ); + + if (tool_info == NULL) + { + g_set_error( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_INTERNAL_STATE, + "L’outil '%s' est absent du registre.", + identifier + ); + + g_free( + summary + ); + + return FALSE; + } + + switch (tool_info_get_availability( + tool_info + )) + { + case TOOL_AVAILABILITY_MISSING: + summary->missing_count++; + + /* + * Une nouvelle détection peut rendre absent un outil + * précédemment disponible. Sa version devient alors + * obsolète et doit être effacée. + */ + if (!tool_registry_set_version( + tool_registry, + identifier, + NULL, + &local_error + )) + { + tool_initializer_set_wrapped_error( + error, + TOOL_INITIALIZER_ERROR_INTERNAL_STATE, + "La version obsolète n’a pas pu être effacée", + local_error + ); + + g_clear_error( + &local_error + ); + + g_free( + summary + ); + + return FALSE; + } + + break; + + case TOOL_AVAILABILITY_AVAILABLE: + summary->available_count++; + + if (tool_catalog_detect_version( + tool_registry, + identifier, + cancellable, + &detected_version, + &local_error + )) + { + if (!tool_registry_set_version( + tool_registry, + identifier, + detected_version, + &local_error + )) + { + tool_initializer_set_wrapped_error( + error, + TOOL_INITIALIZER_ERROR_INTERNAL_STATE, + "La version détectée n’a pas pu être enregistrée", + local_error + ); + + g_clear_error( + &local_error + ); + + g_free( + detected_version + ); + + g_free( + summary + ); + + return FALSE; + } + + summary->version_detected_count++; + } + else + { + /* + * Une annulation arrête toute la tâche. + * + * Une erreur propre à la commande de version reste + * locale à l’outil : l’exécutable demeure disponible. + */ + if (g_error_matches( + local_error, + G_IO_ERROR, + G_IO_ERROR_CANCELLED + )) + { + g_propagate_error( + error, + local_error + ); + + g_free( + detected_version + ); + + g_free( + summary + ); + + return FALSE; + } + + g_clear_error( + &local_error + ); + + if (!tool_registry_set_version( + tool_registry, + identifier, + NULL, + &local_error + )) + { + tool_initializer_set_wrapped_error( + error, + TOOL_INITIALIZER_ERROR_INTERNAL_STATE, + "La version précédente n’a pas pu être effacée", + local_error + ); + + g_clear_error( + &local_error + ); + + g_free( + detected_version + ); + + g_free( + summary + ); + + return FALSE; + } + + summary->version_failed_count++; + } + + g_free( + detected_version + ); + + break; + + case TOOL_AVAILABILITY_UNKNOWN: + default: + g_set_error( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_INTERNAL_STATE, + "La disponibilité de l’outil '%s' est incohérente.", + identifier + ); + + g_free( + summary + ); + + return FALSE; + } + } + + if (g_cancellable_set_error_if_cancelled( + cancellable, + error + )) + { + g_free( + summary + ); + + return FALSE; + } + + { + char *summary_message = NULL; + + summary_message = + g_strdup_printf( + "Initialisation terminée : %" + G_GSIZE_FORMAT + " disponibles, %" + G_GSIZE_FORMAT + " absents, %" + G_GSIZE_FORMAT + " versions détectées, %" + G_GSIZE_FORMAT + " non détectées", + summary->available_count, + summary->missing_count, + summary->version_detected_count, + summary->version_failed_count + ); + + background_task_report_progress( + task, + 1.0, + summary_message + ); + + g_free( + summary_message + ); + } + + *result = summary; + + return TRUE; +} + +/** + * @brief Garantit que le registre contient exactement le catalogue initial. + * + * Le premier démarrage enregistre les outils. + * Les démarrages suivants réutilisent le registre existant. + * + * @param tool_initializer Initialiseur concerné. + * @param error Emplacement recevant une erreur. + * + * @return TRUE si le registre est prêt. + */ +static gboolean tool_initializer_ensure_catalog_registered( + ToolInitializer *tool_initializer, + GError **error +) +{ + ToolRegistry *tool_registry = NULL; + + gsize registry_count = 0; + gsize catalog_count = 0; + gsize entry_index = 0; + + GError *local_error = NULL; + + if (tool_initializer == NULL || + tool_initializer->tool_registry == NULL) + { + g_set_error_literal( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_INTERNAL_STATE, + "Le registre interne des outils est invalide." + ); + + return FALSE; + } + + tool_registry = + tool_initializer->tool_registry; + + registry_count = + tool_registry_get_count( + tool_registry + ); + + catalog_count = + tool_catalog_get_count(); + + if (registry_count == 0) + { + if (!tool_catalog_register_defaults( + tool_registry, + &local_error + )) + { + tool_initializer_set_wrapped_error( + error, + TOOL_INITIALIZER_ERROR_CATALOG_REGISTRATION, + "Le catalogue d’outils n’a pas pu être enregistré", + local_error + ); + + g_clear_error( + &local_error + ); + + return FALSE; + } + + return TRUE; + } + + /* + * Le registre est conservé entre deux initialisations. + * + * Un registre partiellement rempli indique une incohérence, + * car tool_catalog_register_defaults() est atomique. + */ + if (registry_count != catalog_count) + { + g_set_error( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_CATALOG_REGISTRATION, + "Le registre contient %" G_GSIZE_FORMAT + " outils alors que le catalogue en contient %" + G_GSIZE_FORMAT ".", + registry_count, + catalog_count + ); + + return FALSE; + } + + for (entry_index = 0; + entry_index < catalog_count; + entry_index++) + { + const ToolCatalogEntry *catalog_entry = NULL; + const char *identifier = NULL; + + catalog_entry = + tool_catalog_get_entry( + entry_index + ); + + + if (catalog_entry != NULL) + { + identifier = + tool_catalog_entry_get_identifier( + catalog_entry + ); + } + + if (catalog_entry == NULL || + identifier == NULL || + tool_registry_find( + tool_registry, + identifier + ) == NULL) + { + g_set_error( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_CATALOG_REGISTRATION, + "L’entrée de catalogue numéro %" + G_GSIZE_FORMAT + " est absente ou invalide.", + entry_index + ); + + return FALSE; + } + } + + return TRUE; +} + +/** + * @brief Finalise l’état de ToolInitializer sur le contexte principal. + * + * @param task Tâche terminée. + * @param user_data Initialiseur concerné. + */ +static void tool_initializer_bootstrap_completed( + BackgroundTask *task, + gpointer user_data +) +{ + ToolInitializer *tool_initializer = + user_data; + + const ToolInitializationSummary *summary = + NULL; + + if (task == NULL || + tool_initializer == NULL) + { + return; + } + + if (background_task_get_state( + task + ) == BACKGROUND_TASK_STATE_COMPLETED) + { + summary = background_task_get_result( + task + ); + } + + g_mutex_lock( + &tool_initializer->mutex + ); + + if (summary != NULL) + { + tool_initializer->last_summary = + *summary; + + tool_initializer->has_last_summary = + TRUE; + } + + tool_initializer->is_running = FALSE; + + g_mutex_unlock( + &tool_initializer->mutex + ); +} + +GQuark tool_initializer_error_quark(void) +{ + return g_quark_from_static_string( + "labfy-investigation-tool-initializer-error" + ); +} + +ToolInitializer *tool_initializer_new( + TaskManager *task_manager, + GError **error +) +{ + ToolInitializer *tool_initializer = NULL; + + g_return_val_if_fail( + error == NULL || *error == NULL, + NULL + ); + + if (task_manager == NULL) + { + g_set_error_literal( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_INVALID_ARGUMENT, + "Le gestionnaire de tâches est invalide." + ); + + return NULL; + } + + tool_initializer = g_new0( + ToolInitializer, + 1 + ); + + g_atomic_ref_count_init( + &tool_initializer->reference_count + ); + + g_mutex_init( + &tool_initializer->mutex + ); + + tool_initializer->task_manager = + task_manager; + + tool_initializer->tool_registry = + tool_registry_new(); + + tool_initializer->task = NULL; + tool_initializer->has_last_summary = FALSE; + tool_initializer->is_running = FALSE; + + return tool_initializer; +} + +void tool_initializer_free( + ToolInitializer *tool_initializer +) +{ + BackgroundTask *task = NULL; + + if (tool_initializer == NULL) + { + return; + } + + task = tool_initializer_get_task( + tool_initializer + ); + + if (task != NULL) + { + background_task_cancel( + task + ); + + background_task_unref( + task + ); + } + + tool_initializer_unref_internal( + tool_initializer + ); +} + +ToolRegistry *tool_initializer_get_registry( + ToolInitializer *tool_initializer +) +{ + if (tool_initializer == NULL) + { + return NULL; + } + + return tool_initializer->tool_registry; +} + +gboolean tool_initializer_start( + ToolInitializer *tool_initializer, + GError **error +) +{ + ToolInitializationSummary previous_summary = {0}; + gboolean previous_has_last_summary = FALSE; + BackgroundTask *new_task = NULL; + BackgroundTask *previous_task = NULL; + + ToolInitializer *worker_reference = NULL; + ToolInitializer *completion_reference = NULL; + + TaskManager *task_manager = NULL; + + GError *local_error = NULL; + + g_return_val_if_fail( + error == NULL || *error == NULL, + FALSE + ); + + if (tool_initializer == NULL) + { + g_set_error_literal( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_INVALID_ARGUMENT, + "L’initialiseur d’outils est invalide." + ); + + return FALSE; + } + + /* + * is_running sert également d’état STARTING. + * + * Cela empêche deux appels simultanés de créer chacun une tâche. + */ + g_mutex_lock( + &tool_initializer->mutex + ); + + if (tool_initializer->is_running) + { + g_mutex_unlock( + &tool_initializer->mutex + ); + + g_set_error_literal( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_ALREADY_RUNNING, + "Une initialisation des outils est déjà en cours." + ); + + return FALSE; + } + + previous_summary = + tool_initializer->last_summary; + + previous_has_last_summary = + tool_initializer->has_last_summary; + + tool_initializer->last_summary = + (ToolInitializationSummary) {0}; + + tool_initializer->has_last_summary = + FALSE; + + tool_initializer->is_running = TRUE; + task_manager = tool_initializer->task_manager; + + g_mutex_unlock( + &tool_initializer->mutex + ); + + new_task = background_task_new( + "Initialisation des outils externes" + ); + + if (new_task == NULL) + { + g_mutex_lock( + &tool_initializer->mutex + ); + + tool_initializer->is_running = FALSE; + + tool_initializer->last_summary = + previous_summary; + + tool_initializer->has_last_summary = + previous_has_last_summary; + + g_mutex_unlock( + &tool_initializer->mutex + ); + + g_set_error_literal( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_TASK_CREATION, + "La tâche d’initialisation n’a pas pu être créée." + ); + + return FALSE; + } + + if (!task_manager_add( + task_manager, + new_task, + &local_error + )) + { + g_mutex_lock( + &tool_initializer->mutex + ); + + tool_initializer->is_running = FALSE; + + g_mutex_unlock( + &tool_initializer->mutex + ); + + tool_initializer->last_summary = + previous_summary; + + tool_initializer->has_last_summary = + previous_has_last_summary; + + tool_initializer_set_wrapped_error( + error, + TOOL_INITIALIZER_ERROR_TASK_REGISTRATION, + "La tâche d’initialisation n’a pas pu être enregistrée", + local_error + ); + + g_clear_error( + &local_error + ); + + background_task_unref( + new_task + ); + + return FALSE; + } + + /* + * La référence initiale de new_task devient la référence possédée + * par ToolInitializer. + */ + g_mutex_lock( + &tool_initializer->mutex + ); + + previous_task = tool_initializer->task; + tool_initializer->task = new_task; + + g_mutex_unlock( + &tool_initializer->mutex + ); + + worker_reference = + tool_initializer_ref_internal( + tool_initializer + ); + + completion_reference = + tool_initializer_ref_internal( + tool_initializer + ); + + if (!background_task_start( + new_task, + tool_initializer_bootstrap_worker, + worker_reference, + tool_initializer_unref_notify, + g_free, + tool_initializer_bootstrap_completed, + completion_reference, + tool_initializer_unref_notify, + &local_error + )) + { + /* + * En cas d’échec, BackgroundTask ne possède ni worker_reference + * ni completion_reference. + */ + tool_initializer_unref_internal( + worker_reference + ); + + tool_initializer_unref_internal( + completion_reference + ); + + g_mutex_lock( + &tool_initializer->mutex + ); + + tool_initializer->last_summary = + previous_summary; + + tool_initializer->has_last_summary = + previous_has_last_summary; + + tool_initializer->task = + previous_task; + + tool_initializer->is_running = + FALSE; + + g_mutex_unlock( + &tool_initializer->mutex + ); + + task_manager_remove( + task_manager, + new_task + ); + + tool_initializer_set_wrapped_error( + error, + TOOL_INITIALIZER_ERROR_TASK_START, + "La tâche d’initialisation n’a pas pu être démarrée", + local_error + ); + + g_clear_error( + &local_error + ); + + g_mutex_lock( + &tool_initializer->mutex + ); + + tool_initializer->last_summary = + (ToolInitializationSummary) {0}; + + tool_initializer->has_last_summary = + FALSE; + + g_mutex_unlock( + &tool_initializer->mutex + ); + + background_task_unref( + new_task + ); + + return FALSE; + } + + /* + * L’ancienne tâche n’est plus la tâche courante. + */ + background_task_unref( + previous_task + ); + + return TRUE; +} + +gboolean tool_initializer_cancel( + ToolInitializer *tool_initializer, + GError **error +) +{ + BackgroundTask *task = NULL; + + g_return_val_if_fail( + error == NULL || *error == NULL, + FALSE + ); + + if (tool_initializer == NULL) + { + g_set_error_literal( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_INVALID_ARGUMENT, + "L’initialiseur d’outils est invalide." + ); + + return FALSE; + } + + g_mutex_lock( + &tool_initializer->mutex + ); + + if (tool_initializer->is_running && + tool_initializer->task != NULL) + { + task = background_task_ref( + tool_initializer->task + ); + } + + g_mutex_unlock( + &tool_initializer->mutex + ); + + if (task == NULL) + { + g_set_error_literal( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_NOT_RUNNING, + "Aucune initialisation des outils n’est en cours." + ); + + return FALSE; + } + + background_task_cancel( + task + ); + + background_task_unref( + task + ); + + return TRUE; +} + +gboolean tool_initializer_is_running( + const ToolInitializer *tool_initializer +) +{ + ToolInitializer *mutable_initializer = NULL; + gboolean is_running = FALSE; + + if (tool_initializer == NULL) + { + return FALSE; + } + + mutable_initializer = + (ToolInitializer *) tool_initializer; + + g_mutex_lock( + &mutable_initializer->mutex + ); + + is_running = + mutable_initializer->is_running; + + g_mutex_unlock( + &mutable_initializer->mutex + ); + + return is_running; +} + +BackgroundTask *tool_initializer_get_task( + const ToolInitializer *tool_initializer +) +{ + ToolInitializer *mutable_initializer = NULL; + BackgroundTask *task = NULL; + + if (tool_initializer == NULL) + { + return NULL; + } + + mutable_initializer = + (ToolInitializer *) tool_initializer; + + g_mutex_lock( + &mutable_initializer->mutex + ); + + if (mutable_initializer->task != NULL) + { + task = background_task_ref( + mutable_initializer->task + ); + } + + g_mutex_unlock( + &mutable_initializer->mutex + ); + + return task; +} + +gboolean tool_initializer_get_last_summary( + const ToolInitializer *tool_initializer, + ToolInitializationSummary *out_summary +) +{ + ToolInitializer *mutable_initializer = NULL; + gboolean has_last_summary = FALSE; + + if (tool_initializer == NULL || + out_summary == NULL) + { + return FALSE; + } + + mutable_initializer = + (ToolInitializer *) tool_initializer; + + g_mutex_lock( + &mutable_initializer->mutex + ); + + has_last_summary = + mutable_initializer->has_last_summary; + + if (has_last_summary) + { + *out_summary = + mutable_initializer->last_summary; + } + + g_mutex_unlock( + &mutable_initializer->mutex + ); + + return has_last_summary; +} diff --git a/tests/test_tool_initializer b/tests/test_tool_initializer new file mode 100755 index 0000000000000000000000000000000000000000..8ac05fd779be91c684a4a114a1d41c880cf45b4f GIT binary patch literal 85656 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 literal 0 HcmV?d00001 diff --git a/tests/test_tool_initializer.c b/tests/test_tool_initializer.c new file mode 100644 index 0000000..b8fd0ea --- /dev/null +++ b/tests/test_tool_initializer.c @@ -0,0 +1,1647 @@ +/****************************************************************************** + * @file test_tool_initializer.c + * @brief Tests du composant ToolInitializer. + ******************************************************************************/ + +#include "core/tool_initializer.h" +#include "core/tool_catalog.h" + +#include +#include +#include + +#define TEST_TOOL_INITIALIZER_TIMEOUT_SECONDS 3 + +static char *test_tool_initializer_directory = NULL; + +static gboolean test_tool_initializer_wait_for_progress( + ToolInitializer *tool_initializer, + double minimum_progress +) +{ + const gint64 timeout_microseconds = + 3 * G_TIME_SPAN_SECOND; + + gint64 deadline = 0; + + g_assert_nonnull( + tool_initializer + ); + + deadline = + g_get_monotonic_time() + + timeout_microseconds; + + while (g_get_monotonic_time() < deadline) + { + BackgroundTask *task = NULL; + BackgroundTaskState task_state; + double progress = 0.0; + + task = + tool_initializer_get_task( + tool_initializer + ); + + if (task != NULL) + { + task_state = + background_task_get_state( + task + ); + + progress = + background_task_get_progress( + task + ); + + background_task_unref( + task + ); + + if (progress >= minimum_progress) + { + return TRUE; + } + + if (task_state == BACKGROUND_TASK_STATE_COMPLETED || + task_state == BACKGROUND_TASK_STATE_FAILED || + task_state == BACKGROUND_TASK_STATE_CANCELLED) + { + return FALSE; + } + } + + while (g_main_context_iteration( + NULL, + FALSE + )) + { + } + + g_usleep( + 1000 + ); + } + + return FALSE; +} + +static void test_tool_initializer_reset_fake_tools(void) +{ + gsize tool_index = 0; + + for (tool_index = 0; + tool_index < tool_catalog_get_count(); + tool_index++) + { + const ToolCatalogEntry *catalog_entry = NULL; + const char *executable_name = NULL; + char *executable_path = NULL; + + catalog_entry = + tool_catalog_get_entry( + tool_index + ); + + executable_name = + tool_catalog_entry_get_executable_name( + catalog_entry + ); + + if (executable_name == NULL) + { + continue; + } + + executable_path = + g_build_filename( + test_tool_initializer_directory, + executable_name, + NULL + ); + + g_remove( + executable_path + ); + + g_free( + executable_path + ); + } +} + +static void test_tool_initializer_write_fake_tool( + const char *executable_name, + const char *script_content +) +{ + char *executable_path = NULL; + GError *error = NULL; + + g_assert_nonnull( + test_tool_initializer_directory + ); + + g_assert_nonnull( + executable_name + ); + + g_assert_nonnull( + script_content + ); + + executable_path = + g_build_filename( + test_tool_initializer_directory, + executable_name, + NULL + ); + + g_assert_true( + g_file_set_contents( + executable_path, + script_content, + -1, + &error + ) + ); + + g_assert_no_error( + error + ); + + g_assert_cmpint( + g_chmod( + executable_path, + S_IRUSR | + S_IWUSR | + S_IXUSR + ), + ==, + 0 + ); + + g_free( + executable_path + ); +} + +static gboolean test_tool_initializer_timeout( + gpointer user_data +) +{ + gboolean *timed_out = + user_data; + + g_assert_nonnull( + timed_out + ); + + *timed_out = TRUE; + + return G_SOURCE_REMOVE; +} + +static gboolean test_tool_initializer_wait_until_stopped( + ToolInitializer *tool_initializer +) +{ + gboolean timed_out = FALSE; + guint timeout_source_id = 0; + + g_assert_nonnull( + tool_initializer + ); + + timeout_source_id = + g_timeout_add_seconds( + TEST_TOOL_INITIALIZER_TIMEOUT_SECONDS, + test_tool_initializer_timeout, + &timed_out + ); + + g_assert_cmpuint( + timeout_source_id, + !=, + 0 + ); + + while (tool_initializer_is_running( + tool_initializer + ) && + !timed_out) + { + g_main_context_iteration( + NULL, + TRUE + ); + } + + if (!timed_out) + { + g_assert_true( + g_source_remove( + timeout_source_id + ) + ); + } + + return !timed_out && + !tool_initializer_is_running( + tool_initializer + ); +} + +static void test_tool_initializer_new_invalid_arguments(void) +{ + ToolInitializer *tool_initializer = NULL; + GError *error = NULL; + + tool_initializer = tool_initializer_new( + NULL, + &error + ); + + g_assert_null( + tool_initializer + ); + + g_assert_error( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_INVALID_ARGUMENT + ); + + g_clear_error( + &error + ); + + tool_initializer = tool_initializer_new( + NULL, + NULL + ); + + g_assert_null( + tool_initializer + ); +} + +static void test_tool_initializer_new_valid(void) +{ + TaskManager *task_manager = NULL; + ToolInitializer *tool_initializer = NULL; + ToolRegistry *tool_registry = NULL; + GError *error = NULL; + + task_manager = task_manager_new(); + + g_assert_nonnull( + task_manager + ); + + tool_initializer = tool_initializer_new( + task_manager, + &error + ); + + g_assert_no_error( + error + ); + + g_assert_nonnull( + tool_initializer + ); + + tool_registry = tool_initializer_get_registry( + tool_initializer + ); + + g_assert_nonnull( + tool_registry + ); + + g_assert_cmpuint( + tool_registry_get_count( + tool_registry + ), + ==, + 0 + ); + + g_assert_false( + tool_initializer_is_running( + tool_initializer + ) + ); + + g_assert_null( + tool_initializer_get_task( + tool_initializer + ) + ); + + tool_initializer_free( + tool_initializer + ); + + /* + * ToolInitializer ne possède pas le TaskManager. + */ + g_assert_cmpuint( + task_manager_get_count( + task_manager + ), + ==, + 0 + ); + + task_manager_free( + task_manager + ); +} + +static void test_tool_initializer_null_accessors(void) +{ + ToolInitializationSummary summary = {0}; + + g_assert_null( + tool_initializer_get_registry( + NULL + ) + ); + + g_assert_false( + tool_initializer_is_running( + NULL + ) + ); + + g_assert_null( + tool_initializer_get_task( + NULL + ) + ); + + g_assert_false( + tool_initializer_get_last_summary( + NULL, + &summary + ) + ); + + tool_initializer_free( + NULL + ); +} + +static void test_tool_initializer_registry_is_owned(void) +{ + TaskManager *task_manager = NULL; + + ToolInitializer *first_initializer = NULL; + ToolInitializer *second_initializer = NULL; + + ToolRegistry *first_registry = NULL; + ToolRegistry *second_registry = NULL; + + GError *error = NULL; + + task_manager = task_manager_new(); + + g_assert_nonnull( + task_manager + ); + + first_initializer = tool_initializer_new( + task_manager, + &error + ); + + g_assert_no_error( + error + ); + + second_initializer = tool_initializer_new( + task_manager, + &error + ); + + g_assert_no_error( + error + ); + + first_registry = tool_initializer_get_registry( + first_initializer + ); + + second_registry = tool_initializer_get_registry( + second_initializer + ); + + g_assert_nonnull( + first_registry + ); + + g_assert_nonnull( + second_registry + ); + + /* + * Chaque initialiseur possède son propre registre. + */ + g_assert_true( + first_registry != second_registry + ); + + tool_initializer_free( + first_initializer + ); + + tool_initializer_free( + second_initializer + ); + + task_manager_free( + task_manager + ); +} + +static void test_tool_initializer_start_invalid_arguments(void) +{ + TaskManager *task_manager = NULL; + + ToolInitializer *tool_initializer = NULL; + GError *error = NULL; + + g_assert_false( + tool_initializer_start( + NULL, + &error + ) + ); + + g_assert_error( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_INVALID_ARGUMENT + ); + + g_clear_error( + &error + ); + + task_manager = task_manager_new(); + + tool_initializer = tool_initializer_new( + task_manager, + &error + ); + + g_assert_no_error( + error + ); + + g_assert_false( + tool_initializer_cancel( + tool_initializer, + &error + ) + ); + + g_assert_error( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_NOT_RUNNING + ); + + g_clear_error( + &error + ); + + g_assert_false( + tool_initializer_cancel( + NULL, + &error + ) + ); + + g_assert_error( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_INVALID_ARGUMENT + ); + + g_clear_error( + &error + ); + + tool_initializer_free( + tool_initializer + ); + + task_manager_free( + task_manager + ); +} + +static void test_tool_initializer_start(void) +{ + test_tool_initializer_reset_fake_tools(); + + TaskManager *task_manager = NULL; + ToolInitializer *tool_initializer = NULL; + BackgroundTask *task = NULL; + + ToolInitializationSummary summary = {0}; + + GError *error = NULL; + + task_manager = task_manager_new(); + + tool_initializer = tool_initializer_new( + task_manager, + &error + ); + + g_assert_no_error( + error + ); + + g_assert_false( + tool_initializer_get_last_summary( + tool_initializer, + &summary + ) + ); + + g_assert_true( + tool_initializer_start( + tool_initializer, + &error + ) + ); + + g_assert_no_error( + error + ); + + g_assert_true( + tool_initializer_is_running( + tool_initializer + ) + ); + + g_assert_cmpuint( + task_manager_get_count( + task_manager + ), + ==, + 1 + ); + + task = tool_initializer_get_task( + tool_initializer + ); + + g_assert_nonnull( + task + ); + + g_assert_cmpstr( + background_task_get_title( + task + ), + ==, + "Initialisation des outils externes" + ); + + g_assert_true( + test_tool_initializer_wait_until_stopped( + tool_initializer + ) + ); + + g_assert_cmpint( + background_task_get_state( + task + ), + ==, + BACKGROUND_TASK_STATE_COMPLETED + ); + + g_assert_true( + tool_initializer_get_last_summary( + tool_initializer, + &summary + ) + ); + + g_assert_cmpuint( + summary.total_count, + ==, + tool_catalog_get_count() + ); + + g_assert_cmpuint( + summary.available_count, + ==, + 0 + ); + + g_assert_cmpuint( + summary.missing_count, + ==, + tool_catalog_get_count() + ); + + g_assert_cmpuint( + summary.version_detected_count, + ==, + 0 + ); + + g_assert_cmpuint( + summary.version_failed_count, + ==, + 0 + ); + + g_assert_cmpuint( + tool_registry_get_count( + tool_initializer_get_registry( + tool_initializer + ) + ), + ==, + tool_catalog_get_count() + ); + + g_assert_cmpfloat( + background_task_get_progress( + task + ), + ==, + 1.0 + ); + + background_task_unref( + task + ); + + tool_initializer_free( + tool_initializer + ); + + task_manager_free( + task_manager + ); +} + +static void test_tool_initializer_double_start(void) +{ + TaskManager *task_manager = NULL; + ToolInitializer *tool_initializer = NULL; + GError *error = NULL; + + task_manager = task_manager_new(); + + tool_initializer = tool_initializer_new( + task_manager, + &error + ); + + g_assert_no_error( + error + ); + + g_assert_true( + tool_initializer_start( + tool_initializer, + &error + ) + ); + + g_assert_no_error( + error + ); + + /* + * Le callback de fin n’a pas encore été distribué par la boucle + * principale : l’initialiseur est donc toujours considéré actif. + */ + g_assert_false( + tool_initializer_start( + tool_initializer, + &error + ) + ); + + g_assert_error( + error, + TOOL_INITIALIZER_ERROR, + TOOL_INITIALIZER_ERROR_ALREADY_RUNNING + ); + + g_clear_error( + &error + ); + + g_assert_cmpuint( + task_manager_get_count( + task_manager + ), + ==, + 1 + ); + + g_assert_true( + test_tool_initializer_wait_until_stopped( + tool_initializer + ) + ); + + tool_initializer_free( + tool_initializer + ); + + task_manager_free( + task_manager + ); +} + +static void test_tool_initializer_detect_versions(void) +{ + TaskManager *task_manager = NULL; + ToolInitializer *tool_initializer = NULL; + ToolRegistry *tool_registry = NULL; + BackgroundTask *task = NULL; + + const ToolInfo *curl_info = NULL; + const ToolInfo *openssl_info = NULL; + + ToolInitializationSummary summary = {0}; + + GError *error = NULL; + + test_tool_initializer_reset_fake_tools(); + + test_tool_initializer_write_fake_tool( + "curl", + "#!/bin/sh\n" + "printf 'Fake curl 1.2.3\\n'\n" + ); + + test_tool_initializer_write_fake_tool( + "openssl", + "#!/bin/sh\n" + "printf 'Fake OpenSSL 3.0.0\\n' >&2\n" + ); + + task_manager = + task_manager_new(); + + tool_initializer = + tool_initializer_new( + task_manager, + &error + ); + + g_assert_no_error( + error + ); + + g_assert_true( + tool_initializer_start( + tool_initializer, + &error + ) + ); + + g_assert_no_error( + error + ); + + g_assert_true( + test_tool_initializer_wait_until_stopped( + tool_initializer + ) + ); + + task = + tool_initializer_get_task( + tool_initializer + ); + + g_assert_nonnull( + task + ); + + g_assert_cmpint( + background_task_get_state( + task + ), + ==, + BACKGROUND_TASK_STATE_COMPLETED + ); + + g_assert_true( + tool_initializer_get_last_summary( + tool_initializer, + &summary + ) + ); + + g_assert_cmpuint( + summary.total_count, + ==, + 5 + ); + + g_assert_cmpuint( + summary.available_count, + ==, + 2 + ); + + g_assert_cmpuint( + summary.missing_count, + ==, + 3 + ); + + g_assert_cmpuint( + summary.version_detected_count, + ==, + 2 + ); + + g_assert_cmpuint( + summary.version_failed_count, + ==, + 0 + ); + + tool_registry = + tool_initializer_get_registry( + tool_initializer + ); + + curl_info = + tool_registry_find( + tool_registry, + "http.curl" + ); + + openssl_info = + tool_registry_find( + tool_registry, + "tls.openssl" + ); + + g_assert_nonnull( + curl_info + ); + + g_assert_nonnull( + openssl_info + ); + + g_assert_cmpstr( + tool_info_get_detected_version( + curl_info + ), + ==, + "Fake curl 1.2.3" + ); + + g_assert_cmpstr( + tool_info_get_detected_version( + openssl_info + ), + ==, + "Fake OpenSSL 3.0.0" + ); + + background_task_unref( + task + ); + + tool_initializer_free( + tool_initializer + ); + + task_manager_free( + task_manager + ); +} + +static void test_tool_initializer_version_failure_is_nonfatal(void) +{ + TaskManager *task_manager = NULL; + ToolInitializer *tool_initializer = NULL; + ToolRegistry *tool_registry = NULL; + BackgroundTask *task = NULL; + + const ToolInfo *curl_info = NULL; + const ToolInfo *openssl_info = NULL; + + ToolInitializationSummary summary = {0}; + + GError *error = NULL; + + test_tool_initializer_reset_fake_tools(); + + test_tool_initializer_write_fake_tool( + "curl", + "#!/bin/sh\n" + "printf 'Version inutilisable\\n'\n" + "exit 7\n" + ); + + test_tool_initializer_write_fake_tool( + "openssl", + "#!/bin/sh\n" + "printf 'Fake OpenSSL 4.0.0\\n'\n" + ); + + task_manager = + task_manager_new(); + + tool_initializer = + tool_initializer_new( + task_manager, + &error + ); + + g_assert_no_error( + error + ); + + g_assert_true( + tool_initializer_start( + tool_initializer, + &error + ) + ); + + g_assert_no_error( + error + ); + + g_assert_true( + test_tool_initializer_wait_until_stopped( + tool_initializer + ) + ); + + task = + tool_initializer_get_task( + tool_initializer + ); + + g_assert_nonnull( + task + ); + + g_assert_cmpint( + background_task_get_state( + task + ), + ==, + BACKGROUND_TASK_STATE_COMPLETED + ); + + g_assert_true( + tool_initializer_get_last_summary( + tool_initializer, + &summary + ) + ); + + g_assert_cmpuint( + summary.available_count, + ==, + 2 + ); + + g_assert_cmpuint( + summary.missing_count, + ==, + 3 + ); + + g_assert_cmpuint( + summary.version_detected_count, + ==, + 1 + ); + + g_assert_cmpuint( + summary.version_failed_count, + ==, + 1 + ); + + tool_registry = + tool_initializer_get_registry( + tool_initializer + ); + + curl_info = + tool_registry_find( + tool_registry, + "http.curl" + ); + + openssl_info = + tool_registry_find( + tool_registry, + "tls.openssl" + ); + + g_assert_null( + tool_info_get_detected_version( + curl_info + ) + ); + + g_assert_cmpstr( + tool_info_get_detected_version( + openssl_info + ), + ==, + "Fake OpenSSL 4.0.0" + ); + + background_task_unref( + task + ); + + tool_initializer_free( + tool_initializer + ); + + task_manager_free( + task_manager + ); +} + +static void test_tool_initializer_cancel_running(void) +{ + TaskManager *task_manager = NULL; + ToolInitializer *tool_initializer = NULL; + BackgroundTask *task = NULL; + + ToolInitializationSummary summary = {0}; + + GError *error = NULL; + + test_tool_initializer_reset_fake_tools(); + + /* + * dig est le premier outil du catalogue. + * + * Le processus reste actif suffisamment longtemps pour permettre + * de tester l’annulation de ToolProcess. + */ + test_tool_initializer_write_fake_tool( + "dig", + "#!/bin/sh\n" + "exec /bin/sleep 30\n" + ); + + task_manager = + task_manager_new(); + + tool_initializer = + tool_initializer_new( + task_manager, + &error + ); + + g_assert_no_error( + error + ); + + g_assert_true( + tool_initializer_start( + tool_initializer, + &error + ) + ); + + g_assert_no_error( + error + ); + + g_assert_true( + test_tool_initializer_wait_for_progress( + tool_initializer, + 0.15 + ) + ); + + task = + tool_initializer_get_task( + tool_initializer + ); + + g_assert_nonnull( + task + ); + + g_assert_true( + tool_initializer_cancel( + tool_initializer, + &error + ) + ); + + g_assert_no_error( + error + ); + + g_assert_true( + test_tool_initializer_wait_until_stopped( + tool_initializer + ) + ); + + g_assert_cmpint( + background_task_get_state( + task + ), + ==, + BACKGROUND_TASK_STATE_CANCELLED + ); + + /* + * Une initialisation annulée ne produit pas de résumé valide. + */ + g_assert_false( + tool_initializer_get_last_summary( + tool_initializer, + &summary + ) + ); + + background_task_unref( + task + ); + + tool_initializer_free( + tool_initializer + ); + + task_manager_free( + task_manager + ); +} + +static void test_tool_initializer_restart_after_completion(void) +{ + TaskManager *task_manager = NULL; + ToolInitializer *tool_initializer = NULL; + ToolRegistry *tool_registry = NULL; + + const ToolInfo *curl_info = NULL; + + ToolInitializationSummary summary = {0}; + + GError *error = NULL; + + test_tool_initializer_reset_fake_tools(); + + test_tool_initializer_write_fake_tool( + "curl", + "#!/bin/sh\n" + "printf 'Fake curl 1.0.0\\n'\n" + ); + + task_manager = + task_manager_new(); + + tool_initializer = + tool_initializer_new( + task_manager, + &error + ); + + g_assert_no_error( + error + ); + + g_assert_true( + tool_initializer_start( + tool_initializer, + &error + ) + ); + + g_assert_no_error( + error + ); + + g_assert_true( + test_tool_initializer_wait_until_stopped( + tool_initializer + ) + ); + + tool_registry = + tool_initializer_get_registry( + tool_initializer + ); + + curl_info = + tool_registry_find( + tool_registry, + "http.curl" + ); + + g_assert_nonnull( + curl_info + ); + + g_assert_cmpstr( + tool_info_get_detected_version( + curl_info + ), + ==, + "Fake curl 1.0.0" + ); + + test_tool_initializer_write_fake_tool( + "curl", + "#!/bin/sh\n" + "/bin/sleep 1\n" + "printf 'Fake curl 2.0.0\\n'\n" + ); + + g_assert_true( + tool_initializer_start( + tool_initializer, + &error + ) + ); + + g_assert_no_error( + error + ); + + /* + * Le résumé précédent n’est plus valide pendant cette nouvelle + * exécution. + */ + g_assert_false( + tool_initializer_get_last_summary( + tool_initializer, + &summary + ) + ); + + g_assert_true( + test_tool_initializer_wait_until_stopped( + tool_initializer + ) + ); + + curl_info = + tool_registry_find( + tool_registry, + "http.curl" + ); + + g_assert_cmpstr( + tool_info_get_detected_version( + curl_info + ), + ==, + "Fake curl 2.0.0" + ); + + g_assert_true( + tool_initializer_get_last_summary( + tool_initializer, + &summary + ) + ); + + g_assert_cmpuint( + summary.available_count, + ==, + 1 + ); + + g_assert_cmpuint( + summary.missing_count, + ==, + tool_catalog_get_count() - 1 + ); + + /* + * TaskManager conserve les deux tâches terminées. + */ + g_assert_cmpuint( + task_manager_get_count( + task_manager + ), + ==, + 2 + ); + + tool_initializer_free( + tool_initializer + ); + + task_manager_free( + task_manager + ); +} + +static void test_tool_initializer_restart_after_cancellation(void) +{ + TaskManager *task_manager = NULL; + ToolInitializer *tool_initializer = NULL; + ToolRegistry *tool_registry = NULL; + + const ToolInfo *curl_info = NULL; + + ToolInitializationSummary summary = {0}; + + GError *error = NULL; + + test_tool_initializer_reset_fake_tools(); + + test_tool_initializer_write_fake_tool( + "dig", + "#!/bin/sh\n" + "exec /bin/sleep 30\n" + ); + + task_manager = + task_manager_new(); + + tool_initializer = + tool_initializer_new( + task_manager, + &error + ); + + g_assert_no_error( + error + ); + + g_assert_true( + tool_initializer_start( + tool_initializer, + &error + ) + ); + + g_assert_true( + tool_initializer_is_running( + tool_initializer + ) + ); + + g_assert_no_error( + error + ); + + g_assert_true( + test_tool_initializer_wait_for_progress( + tool_initializer, + 0.15 + ) + ); + + g_assert_true( + tool_initializer_cancel( + tool_initializer, + &error + ) + ); + + g_assert_no_error( + error + ); + + g_assert_true( + test_tool_initializer_wait_until_stopped( + tool_initializer + ) + ); + + g_assert_false( + tool_initializer_get_last_summary( + tool_initializer, + &summary + ) + ); + + /* + * Le second démarrage utilise un environnement différent. + */ + test_tool_initializer_reset_fake_tools(); + + test_tool_initializer_write_fake_tool( + "curl", + "#!/bin/sh\n" + "printf 'Fake curl 3.0.0\\n'\n" + ); + + g_assert_true( + tool_initializer_start( + tool_initializer, + &error + ) + ); + + g_assert_no_error( + error + ); + + g_assert_true( + test_tool_initializer_wait_until_stopped( + tool_initializer + ) + ); + + g_assert_true( + tool_initializer_get_last_summary( + tool_initializer, + &summary + ) + ); + + g_assert_cmpuint( + summary.available_count, + ==, + 1 + ); + + g_assert_cmpuint( + summary.version_detected_count, + ==, + 1 + ); + + tool_registry = + tool_initializer_get_registry( + tool_initializer + ); + + curl_info = + tool_registry_find( + tool_registry, + "http.curl" + ); + + g_assert_nonnull( + curl_info + ); + + g_assert_cmpstr( + tool_info_get_detected_version( + curl_info + ), + ==, + "Fake curl 3.0.0" + ); + + g_assert_cmpuint( + task_manager_get_count( + task_manager + ), + ==, + 2 + ); + + tool_initializer_free( + tool_initializer + ); + + task_manager_free( + task_manager + ); +} + +int main( + int argc, + char **argv +) +{ + g_test_init( + &argc, + &argv, + NULL + ); + + { + GError *error = NULL; + + test_tool_initializer_directory = + g_dir_make_tmp( + "labfy-tool-initializer-XXXXXX", + &error + ); + + g_assert_no_error( + error + ); + + g_assert_nonnull( + test_tool_initializer_directory + ); + + g_assert_true( + g_setenv( + "PATH", + test_tool_initializer_directory, + TRUE + ) + ); + } + + g_test_add_func( + "/tool_initializer/detect_versions", + test_tool_initializer_detect_versions + ); + + g_test_add_func( + "/tool_initializer/version_failure_is_nonfatal", + test_tool_initializer_version_failure_is_nonfatal + ); + + g_test_add_func( + "/tool_initializer/new_invalid_arguments", + test_tool_initializer_new_invalid_arguments + ); + + g_test_add_func( + "/tool_initializer/new_valid", + test_tool_initializer_new_valid + ); + + g_test_add_func( + "/tool_initializer/null_accessors", + test_tool_initializer_null_accessors + ); + + g_test_add_func( + "/tool_initializer/registry_is_owned", + test_tool_initializer_registry_is_owned + ); + + g_test_add_func( + "/tool_initializer/start_invalid_arguments", + test_tool_initializer_start_invalid_arguments + ); + + g_test_add_func( + "/tool_initializer/start", + test_tool_initializer_start + ); + + g_test_add_func( + "/tool_initializer/double_start", + test_tool_initializer_double_start + ); + + g_test_add_func( + "/tool_initializer/cancel_running", + test_tool_initializer_cancel_running + ); + + g_test_add_func( + "/tool_initializer/restart_after_completion", + test_tool_initializer_restart_after_completion + ); + + g_test_add_func( + "/tool_initializer/restart_after_cancellation", + test_tool_initializer_restart_after_cancellation + ); + + { + int test_result = 0; + + test_result = + g_test_run(); + + test_tool_initializer_reset_fake_tools(); + + g_rmdir( + test_tool_initializer_directory + ); + + g_clear_pointer( + &test_tool_initializer_directory, + g_free + ); + + return test_result; + } +}