Scala 可变。缓冲区不适用于类型安全API的烫伤性作业测试

Scala 可变。缓冲区不适用于类型安全API的烫伤性作业测试,scala,hadoop,integration-testing,cascading,scalding,Scala,Hadoop,Integration Testing,Cascading,Scalding,我几乎完成了我的滚烫项目,它使用类型安全API而不是字段API。在整个项目设置中留给我的最后一个问题是整个工作本身的集成测试(我已经完成了类型安全外部操作模式的单元测试!)。这意味着运行完整的作业并测试作业的各个接收器的输出 然而,一些非常奇怪的事情正在发生。在我的 typedSink { scala.collection.mutable.Buffer[] => Unit } 似乎我的程序没有看到缓冲区,也没有对缓冲区做任何事情,所以集成测试总是通过,即使它不应该通过。以下是作业本身和测

我几乎完成了我的滚烫项目,它使用类型安全API而不是字段API。在整个项目设置中留给我的最后一个问题是整个工作本身的集成测试(我已经完成了类型安全外部操作模式的单元测试!)。这意味着运行完整的作业并测试作业的各个接收器的输出

然而,一些非常奇怪的事情正在发生。在我的

typedSink { scala.collection.mutable.Buffer[] => Unit }
似乎我的程序没有看到缓冲区,也没有对缓冲区做任何事情,所以集成测试总是通过,即使它不应该通过。以下是作业本身和测试,以帮助说明正在发生的事情:

object MyJob {
  val inputArgPath = "input"
  val validOutputArgPath = "validOutput"
  val invalidOutputArgPath = "invalidOutput"
}

class MyJob(args: Args) extends Job(args) {

  import OperationWrappers._

  implicit lazy val uId: Some[UniqueID] = Some(UniqueID.getIDFor(flowDef))

  val inputPath: String = args(MyJob.inputArgPath)
  val validOutputPath: String = args(MyJob.validOutputArgPath)
  val invalidOutputPath: String = args(MyJob.invalidOutputArgPath)

  val eventInput: TypedPipe[(LongWritable, Text)] = this.mode match {
    case m: HadoopMode => TypedPipe.from(WritableSequenceFile[LongWritable, Text](inputPath))
    case _ => TypedPipe.from(TypedTsv[(LongWritable, Text)](inputPath))
  }

  def returnOutputPipe(outputString: String): FixedPathSource with TypedSink[(LongWritable, Text)] with TypedSource[(LongWritable, Text)] = {
    val eventOutput: FixedPathSource with TypedSink[(LongWritable, Text)] with TypedSource[(LongWritable, Text)] = this.mode match {
      case m: HadoopMode => WritableSequenceFile[LongWritable, Text](outputString)
      case _ => TypedTsv[(LongWritable, Text)](outputString)
    }
    eventOutput
  }

  val validatedEvents: TypedPipe[(LongWritable, Either[Text, Event])] = eventInput.convertJsonToEither.forceToDisk

  validatedEvents.removeInvalidTuples.removeEitherWrapper.write(returnOutputPipe(invalidOutputPath))
  validatedEvents.keepValidTuples.removeEitherWrapper.write(returnOutputPipe(validOutputPath))

  override protected def handleStats(statsData: CascadingStats) = {
    //This is code to handle counters.
  }
}
以下是集成测试:

class MyJobTest extends FlatSpec with Matchers {
  private val LOG = LoggerFactory.getLogger(classOf[MyJobTest])

  val validEvents: List[(LongWritable, Text)] = scala.io.Source.fromInputStream(getClass.getResourceAsStream("/validEvents.txt")).getLines().toList.map(s => {
    val eventText = new Text
    val typedFields = s.split(Constants.TAB)
    eventText.set(typedFields(1))
    (new LongWritable(typedFields(0).toLong), eventText)
  })

  "Integrate-Test: My Job" should "run test" in {

    LOG.info("Before Job Test starts.")
    JobTest(classOf[MyJob].getName)
      .arg(MyJob.inputArgPath, "input")
      .arg(MyJob.invalidOutputArgPath, "invalidOutput")
      .arg(MyJob.validOutputArgPath, "validOutput")
      .source(TypedTsv[(LongWritable, Text)]("input"), validEvents)
      .typedSink[(LongWritable, Text)](TypedTsv[(LongWritable, Text)]("invalidOutput")) {
      (buffer: mutable.Buffer[(LongWritable, Text)]) => {
        LOG.info("This is inside the buffer1.")
        buffer.size should equal(1000000)
      }
    }
      .typedSink[(LongWritable, Text)](TypedTsv[(LongWritable, Text)]("validOutput")) {
      (buffer: mutable.Buffer[(LongWritable, Text)]) => {
        LOG.info("This is inside the buffer2.")
        buffer.size should equal(1000000000)
      }
    }
      .run
      .finish
  }
}
最后,输出:

[INFO] --- maven-surefire-plugin:2.7:test (default-test) @ MyJob ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- scalatest-maven-plugin:1.0:test (test) @ MyJob ---
Discovery starting.
16/01/28 10:06:42 INFO jobs.MyJobTest: Before Job Test starts.
16/01/28 10:06:42 INFO property.AppProps: using app.id: A98C9B84C79348F8A7784D8247410C13
16/01/28 10:06:42 INFO util.Version: Concurrent, Inc - Cascading 2.6.1
16/01/28 10:06:42 INFO flow.Flow: [com.myCompany.myProject.c...] starting
16/01/28 10:06:42 INFO flow.Flow: [com.myCompany.myProject.c...]  source: MemoryTap["NullScheme"]["0.2996348736498404"]
16/01/28 10:06:42 INFO flow.Flow: [com.myCompany.myProject.c...]  sink: MemoryTap["NullScheme"]["0.8393418014297485"]
16/01/28 10:06:42 INFO flow.Flow: [com.myCompany.myProject.c...]  sink: MemoryTap["NullScheme"]["0.20643450953780684"]
16/01/28 10:06:42 INFO flow.Flow: [com.myCompany.myProject.c...]  parallel execution is enabled: true
16/01/28 10:06:42 INFO flow.Flow: [com.myCompany.myProject.c...]  starting jobs: 1
16/01/28 10:06:42 INFO flow.Flow: [com.myCompany.myProject.c...]  allocating threads: 1
16/01/28 10:06:42 INFO flow.FlowStep: [com.myCompany.myProject.c...] starting step: local
16/01/28 10:06:42 INFO util.Version: HV000001: Hibernate Validator 5.0.3.Final
Dumping custom counters:
rawEvent    6
validEvent  6
16/01/28 10:06:42 INFO jobs.MyJob: RawEvents: 6
16/01/28 10:06:42 INFO jobs.MyJob: ValidEvents: 6
16/01/28 10:06:42 INFO jobs.MyJob: InvalidEvents: 0
16/01/28 10:06:42 INFO jobs.MyJob: Job has valid counters and is exiting successfully.

如您所见,日志记录器记录“作业测试开始前”,但typedSink部件内部没有发生任何事情。这是令人沮丧的,因为我的代码看起来像我看到的所有其他代码,但它不工作。它应该没有通过测试,但一切都成功运行。此外,typedSink内部的记录器从不输出。最后,如果您查看输出,您会发现它正确地处理了计数器,因此它正在运行作业直至完成。我花了很多时间尝试新事物,但似乎什么都不管用。希望社区能够帮助我。谢谢

所以,虽然我对这篇文章没有很好的答案,但我有适合我的答案。基本上,我的问题是,我使用ScalaTest从以下链接运行我的大量作业:。这在我的操作单元测试中效果很好,但在将ScalaTest与JobTest一起使用时,这导致了奇怪。在与狂热的开发人员交谈并最终承认我的团队在JUnitRunner方面取得了成功后,我决定接受这一点。我更改了POM以支持JUnitRunner,并在测试中添加了
@RunWith(classOf[JUnitRunner])
注释。一切都正常工作,表现得像我想要的一样。

尝试取消
模式
检查以进行实验,看看是否有帮助。我不记得它是如何运行的,但是如果
JobTest
在Hadoop模式下运行,我也不会感到惊讶。我的团队一直在使用Fields API,而且他们在模式检查方面没有遇到任何问题。不过,我现在就试试这个。谢谢你的建议!我尝试了您的建议,但收到了此异常:原因:com.twitter.sporthing.ModeException:com.twitter.sporthing.WritableSequenceFileWrappedArray(输入)不支持级联本地模式,这表明JobTest使用级联本地模式。确定,然后我不知道:)是时候启动调试器了?你能把你发现的作为一个答案吗?我很想看看。