15

Ho cercato di rintracciare un problema con alcuni test di unità/integrazione che ho scritto per un progetto Apache Spark.Test di integrazione fallito per Apache Spark Streaming

Quando si utilizza Spark 1.1.1 è stato superato il test. Quando ho provato ad aggiornare a 1.4.0 (anche provato 1.4.1) il test inizia a fallire.

Sono riuscito a ridurre il codice necessario per riprodurre il problema fino al test di integrazione di seguito.

È interessante notare che se commento l'annotazione @RunWith sul test, il test passa correttamente. Ovviamente non ho bisogno dell'annotazione @RunWith per questo test di riduzione, ma i veri test fanno uso di mock abbastanza estensivamente, quindi preferisco non dover cadere usando PowerMock.

package com.example; 

import org.apache.spark.SparkConf; 
import org.apache.spark.streaming.Duration; 
import org.apache.spark.streaming.api.java.JavaStreamingContext; 
import org.junit.Before; 
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.powermock.modules.junit4.PowerMockRunner; 

@RunWith(PowerMockRunner.class) 
public class SampleTest { 

    @Before 
    public void setup() throws Exception { 
     SparkConf conf = new  SparkConf(false).setMaster("local[2]").setAppName("My app"); 
     JavaStreamingContext jsc = new JavaStreamingContext(conf, new Duration(1000)); 
    } 

    @Test 
    public void exampleTest() { 
    } 
} 

Di seguito è l'eccezione che sto vedendo

java.io.IOException: failure to login 
    at org.apache.hadoop.security.UserGroupInformation.loginUserFromSubject(UserGroupInformation.java:796) 
    at org.apache.hadoop.security.UserGroupInformation.getLoginUser(UserGroupInformation.java:748) 
    at org.apache.hadoop.security.UserGroupInformation.getCurrentUser(UserGroupInformation.java:621) 
    at org.apache.spark.util.Utils$$anonfun$getCurrentUserName$1.apply(Utils.scala:2162) 
    at org.apache.spark.util.Utils$$anonfun$getCurrentUserName$1.apply(Utils.scala:2162) 
    at scala.Option.getOrElse(Option.scala:120) 
    at org.apache.spark.util.Utils$.getCurrentUserName(Utils.scala:2162) 
    at org.apache.spark.SparkContext.<init>(SparkContext.scala:301) 
    at org.apache.spark.streaming.StreamingContext$.createNewSparkContext(StreamingContext.scala:842) 
    at org.apache.spark.streaming.StreamingContext.<init>(StreamingContext.scala:80) 
    at org.apache.spark.streaming.api.java.JavaStreamingContext.<init>(JavaStreamingContext.scala:133) 
    at com.example.SampleTest.setup(SampleTest.java:19) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at org.junit.internal.runners.MethodRoadie.runBefores(MethodRoadie.java:133) 
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:96) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282) 
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87) 
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120) 
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34) 
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:122) 
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:106) 
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53) 
    at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59) 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 
Caused by: javax.security.auth.login.LoginException: Can't find user name 
    at org.apache.hadoop.security.UserGroupInformation$HadoopLoginModule.commit(UserGroupInformation.java:197) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at javax.security.auth.login.LoginContext.invoke(LoginContext.java:784) 
    at javax.security.auth.login.LoginContext.access$000(LoginContext.java:203) 
    at javax.security.auth.login.LoginContext$5.run(LoginContext.java:721) 
    at javax.security.auth.login.LoginContext$5.run(LoginContext.java:719) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at javax.security.auth.login.LoginContext.invokeCreatorPriv(LoginContext.java:718) 
    at javax.security.auth.login.LoginContext.login(LoginContext.java:591) 
    at org.apache.hadoop.security.UserGroupInformation.loginUserFromSubject(UserGroupInformation.java:771) 
    ... 38 more 

Le versioni delle varie dipendenze sono mostrate sotto

  • Hadoop-client 2.6
  • apache scintilla 1.4.0/1.4.1
  • junit 4.12
  • facile finto 3.31
  • potere finto 1.6.2

Ho provato questo con le varie versioni di Spark. La prova di cui sopra supera con le seguenti versioni di Spark

  • 1.1.1
  • 1.2.2

Si parte difettosa dal Spark 1.3.0 in poi.

Qualche idea di cosa ho bisogno di cambiare per farlo funzionare?

risposta

12

Osservando il codice sorgente per SparkContext, la riga che causa l'eccezione durante il tentativo di ottenere il nome utente corrente. In version 1.2 c'era un default fallback SparkContext.SPARK_UNKNOWN_USER e non ha richiesto currectly utente connesso:

// Set SPARK_USER for user who is running SparkContext. 
val sparkUser = Option { 
    Option(System.getenv("SPARK_USER")).getOrElse(System.getProperty("user.name")) 
    }.getOrElse { 
     SparkContext.SPARK_UNKNOWN_USER 
    } 

Questo codice introdotto nel version 1.3 non ha utente predefinito più quindi, perché non si ottiene questo errore con le versioni precedenti:

// Set SPARK_USER for user who is running SparkContext. 
val sparkUser = Utils.getCurrentUserName() 

Ciò richiede l'following code in Utils:

/** 
    * Returns the current user name. This is the currently logged in user, unless that's been 
    * overridden by the `SPARK_USER` environment variable. 
    */ 
    def getCurrentUserName(): String = { 
    Option(System.getenv("SPARK_USER")) 
     .getOrElse(UserGroupInformation.getCurrentUser().getShortUserName()) 
    } 

Se si imposta la variabile di ambiente SPARK_USER, si dovrebbe essere in grado di impedire la diramazione a UserGroupInformation che porta alla propria eccezione.

UserGroupInformation è una classe di sicurezza Hadoop e sembra che l'utilizzo di PowerMock impedisca il corretto funzionamento.

+2

Ho intenzione di accettare questa risposta perché risolve il problema. Tuttavia, impostare le variabili di ambiente in un unit test è un dolore. La risposta mi ha anche indotto a pensare al problema in un modo diverso e ho trovato una soluzione alternativa. Annotare la classe con @PowerMockIgnore ({"org.apache. *", "Akka. *"}) Risolve anche il problema (ma non ho ancora preso il tempo di vedere se ciò causa altri problemi) – Glen