Test... Test... 1, 2, 3: come SnapLogic testa gli snap sulla piattaforma Apache Spark

La piattaforma di integrazione elastica SnapLogic collega i dati aziendali, le applicazioni e le API costruendo pipeline di dati drag-and-drop. Ogni pipeline è composta da Snaps, connettori intelligenti, che gli utenti trascinano su una tela e "incastrano" insieme come pezzi di un puzzle.

Una pipeline SnapLogic in fase di costruzione e configurazione
Una pipeline SnapLogic in fase di costruzione e configurazione

Queste pipeline vengono eseguite su Snaplex, un'applicazione che viene eseguita su una moltitudine di piattaforme: sull'infrastruttura del cliente, su SnapLogic cloud e, più recentemente, su Hadoop. Uno Snaplex che gira su Hadoop può eseguire pipeline in modo nativo in Spark.

La piattaforma di gestione dei dati SnapLogic è nota per la sua interfaccia self-service di facile utilizzo, resa possibile dal nostro team di ingegneri dedicati(stiamo assumendo!). Lavoriamo per applicare le migliori pratiche del settore in modo che i nostri clienti ottengano il miglior prodotto finale possibile, e i test sono fondamentali.

I test sono una parte importante del processo di sviluppo del software, ma spesso sono difficili da eseguire correttamente. Alcune delle sfide che gli sviluppatori devono affrontare durante il collaudo del software consistono nell'assicurarsi che la copertura dei test sia adeguata e nel mantenere il codice di test aggiornato con le ultime modifiche. Anche se i test esistono e sono aggiornati, è possibile che siano scritti in modo errato e che non valutino correttamente il codice. Una battuta che ha fatto il giro di Internet l'anno scorso era la seguente immagine con la didascalia: "Tutti i test passano".

Immagine: anonimo su reddit Scherzo: probabilmente Keith Smiley (@SmileyKeith) su Twitter
Immagine: anonimo su reddit
Scherzo: probabilmente Keith Smiley (@SmileyKeith) su Twitter

I test aiutano a garantire la qualità del software, ma tutto dipende da test ben scritti. Un test mal concepito dà una falsa sicurezza che l'applicazione funzioni correttamente, facendo perdere tempo e impattando sulla produzione.

Dal punto di vista dello sviluppatore, la possibilità di iterare rapidamente l'implementazione può migliorare notevolmente la produttività. Questo è particolarmente vero quando si eseguono programmi su infrastrutture distribuite con un grande overhead. Per questo motivo, nello sviluppo di un framework di test, SnapLogic ha voluto fornire ai propri ingegneri un mezzo per sviluppare uno Snap in modo rapido e sicuro, e per far sì che l'ambiente di test assomigli a come lo Snap verrebbe eseguito in produzione.

Individuare le lacune nella copertura dei test: Snaps sulla piattaforma Apache Spark

Al momento, gli Snap sono abilitati da Spark scrivendo un metodo che utilizza l'API RDD di Spark per eseguire la logica dello Snap.

badumtsss

In generale, l'API RDD contiene operazioni che lo sviluppatore chiama con una funzione. Per questo motivo, un'implementazione di Spark richiederà allo sviluppatore di ottenere l'RDD dallo Snap precedente, applicare un'operazione RDD con una funzione e quindi scrivere l'RDD nello Snap successivo. Ad esempio, il codice Java per uno Snap di filtraggio sarebbe simile a questo (anche se si tratta di una versione semplificata dell'implementazione effettiva, escludendo la logica per gestire il linguaggio di espressione):

public void sparkExec(final ExecContext execContext) {
   JavaRDD<Document> javaRDD = execContext.getRDD();
   JavaRDD<Document> filteredRDD = javaRDD.filter(new FilterDocuments(filter));
   execContext.setRDD(filteredRDD);
}

public class FilterDocuments implements Serializable, Function<Document, Boolean> {
    ...

    @Override
    public Boolean call(final Document document) throws Exception {
        return shouldFilter(filter, document);
    }
}

La classe FilterDocuments implementa la funzione utilizzata dal metodo sparkExec, che richiama il metodo Spark RDD filtro di Spark con tale funzione e l'RDD passato dall'upstream Snap.

Testare questo codice è relativamente semplice: la logica è incapsulata nella funzione, quindi l'aggiunta di test unitari che chiamano la funzione filtro dovrebbe essere sufficiente, giusto? Come si è scoperto, c'era una discreta quantità di logica all'interno dei metodi sparkExec di alcuni snap (anche se non nell'esempio precedente), per i quali non era stata implementata una copertura di test automatizzati.

Il 100% di copertura dei test è bello in teoria, ma in pratica può portare a problemi di manutenzione. Un modo potenziale per ridurre la manutenzione dei test è quello di saltare i tipi di codice boilerplate, come la maggior parte dei metodi sparkExec. Questa lacuna nella nostra copertura è stata scoperta da ulteriori test, ma è più conveniente catturare i bug prima nel ciclo di sviluppo.

Fonte: Ricerca scientifica sui sistemi IBM
Fonte: Ricerca scientifica sui sistemi IBM

Colmare le lacune

A prima vista, questo problema presenta alcune potenziali soluzioni:

Prendete in giro il framework Spark

Un'opzione potrebbe essere quella di prendere in giro il framework Spark, ottenendo così la possibilità di sviluppare rapidamente e automatizzare i test. Tuttavia, il codice mock nei test può essere fragile e fastidioso da mantenere; inoltre, questo non raggiungerebbe il secondo obiettivo di dare la certezza che il codice verrà eseguito allo stesso modo in modalità distribuita.

Eseguire su cluster

All'estremo opposto, il framework potrebbe richiedere che lo sviluppatore abbia accesso a un cluster Spark per eseguire i test, ma questo sarebbe operativamente costoso da configurare e mantenere, oltre a rallentare il ciclo di sviluppo.

Il meglio dei due mondi: test in modalità locale di Spark

La nostra soluzione è una via di mezzo che sfrutta la modalità locale di Spark. Un programma Spark può essere scritto per essere eseguito su una singola macchina, in modo simile a come un programma Spark viene eseguito su un cluster, ma senza l'overhead. Il modo in cui ciò avviene è fornire un metodo di utilità che restituisca un contesto Spark, che viene eseguito in questo modo.

public class SparkTestUtil {

   private static final SparkConf SPARK_CONF = new SparkConf()
           .setMaster("local")
           .setAppName("unit test")
           .set("spark.driver.allowMultipleContexts","true");
   private static final JavaSparkContext JAVA_SPARK_CONTEXT = 
           new JavaSparkContext(SPARK_CONF);

   public static JavaSparkContext getSparkContext() {
       return JAVA_SPARK_CONTEXT;
   }
...
}

Questo contesto viene utilizzato dal nostro normale framework di test Snap, che può già configurare ed eseguire gli Snap in modalità normale, per costruire un ExecContext. Quindi, il framework è in grado di chiamare il metodo sparkExec dello Snap con l'ExecContext, che viene reso accessibile anche al test dello sviluppatore per verificare che l'output sia corretto.

Ecco un esempio di caso di test che utilizza questo framework con i miglioramenti di Spark:

@TestFixture(snap = CSVParser.class,
       input = "data/csv_parser/test_input_1.json",
       outputs = "out1",
       properties = "data/csv_parser/property_data_1.json",
       runSparkMode = true)
public void testParse(TestResult testResult) throws Exception {
   // Verify Standard mode result
   assertEquals(ImmutableMap.of(
           "First", "Test",
           "Last", "Mike",
           "Phone", "123-456-7890"
   ), testResult.getOutputViews().get(0).getRecordedData());

   // Verify Spark mode result
   ExecContext execContext = testResult.getExecContext();
   assertEquals(ImmutableMap.of(
           "First", "Test",
           "Last", "Mike",
           "Phone", "123-456-7890"
   ), execContext.getRDD("out1").collect().get(0));

L'annotazione @TestFixture consente allo sviluppatore di Snap di configurare le proprietà, gli ingressi e le uscite del test e viene utilizzata per testare gli Snap in modalità normale e in modalità Spark. Impostando runSparkMode a true il test può essere eseguito sia in modalità normale che in modalità Spark, consentendo il riutilizzo dei casi di test.

In definitiva, il framework di testing consente agli sviluppatori di Snap di costruire e testare il proprio codice in modo più rapido ed efficace, riducendo i tempi di sviluppo di Snap e aumentando la qualità del prodotto.

 

Per saperne di più sul processo di sviluppo di Snap, consultate il sito developer.snaplogic.com che illustra i passaggi necessari per sviluppare Snap per SnapLogic Elastic Integration Platform.

Categoria: Prodotto
Argomenti: Sviluppo Snaplex Snaps

Stiamo assumendo!

Scoprite la vostra prossima grande opportunità di carriera.