Skip to content

Instantly share code, notes, and snippets.

@arussel
Created July 17, 2012 09:48
Show Gist options
  • Save arussel/3128411 to your computer and use it in GitHub Desktop.
Save arussel/3128411 to your computer and use it in GitHub Desktop.
package com.getpinsights.qa
import dispatch._
import org.apache.http._
import client.methods.HttpGet
import entity.InputStreamEntity
import message.{BasicHttpResponse, BasicStatusLine}
import client.HttpClient
import org.specs2.mock.Mockito
import org.mockito.Mockito._
import java.io.{InputStream, ByteArrayInputStream}
import org.apache.commons.io.IOUtils
import org.mockito.stubbing.Answer
import org.mockito.invocation.InvocationOnMock
/**
* MockHttp allows to mock dispatch.http and to server files directly from filesystem
* without any network connection.
*
* To server files sequentially, use #getMockHttp(String) or #getMockHttp(List[String])
* To server files depending on the request URI use #getMockHttp(Map[String,String])
*
* The filename needs to start with '/'.
*/
trait MockHttp extends Mockito {
val protocolVersion = new ProtocolVersion("HTTP", 1, 1)
/**
* Returns a Http that will serve the file 'file' at each invocation
* @param file the filename starting with '/'
* @return a dispatch.Http object
*/
def getMockHttp(file: String): Http = getMockHttp(List(file))
/**
* Returns a Http that will check the uri of the request and:
* - if the uri is a key in 'choices' will return a file using the value as filname
* - if the uri is not a key in 'choices' will throw an error.
* @param choices a map of key, a uri starting by '/' and the corresponding answer as value,
* a filename starting with '/'
* @return a dispatch.Http object
*/
def getMockHttp(choices: Map[String, String]): Http = {
val httpClient = mock(manifest[HttpClient])
when(httpClient.execute(any[HttpHost], any[HttpGet])).then(new Answer[HttpResponse] {
def answer(iom: InvocationOnMock): HttpResponse = {
val args = iom.getArguments
val get = args(1).asInstanceOf[HttpGet]
val uri = get.getURI.getPath
if (choices.isDefinedAt(uri)) {
val is = getClass.getResourceAsStream(choices(uri))
val bytes = IOUtils.toByteArray(is)
val bais = new ByteArrayInputStream(bytes)
val r = new BasicHttpResponse(protocolVersion, 200, "")
r.setEntity(new InputStreamEntity(bais, bytes.length))
r
} else {
throw new Error("A response file was not provided for uri: " + uri)
}
}
})
val http = new Http with thread.Safety {
override def make_client: HttpClient = httpClient
}
http
}
/**
* Returns a Http that will serve the files 'files' sequentially. When all files
* have been served, it will serve the last one forever.
* @param files a list of filename starting with '/'
* @return a dispatch.Http object
*/
def getMockHttp(files: List[String]): Http = {
val response = mock(manifest[HttpResponse])
val entity: HttpEntity = mock(manifest[HttpEntity])
val httpClient: HttpClient = mock(manifest[HttpClient])
when(response.getEntity).thenReturn(entity)
when(response.getStatusLine).thenReturn(new BasicStatusLine(protocolVersion, 200, ""))
when(httpClient.execute(any[HttpHost], any[HttpGet])).then(new Answer[HttpResponse] {
def answer(invocation: InvocationOnMock) = response
})
class AnswerInputStream extends Answer[InputStream] {
var counter = 0
override def answer(invocation: InvocationOnMock) = {
val filename = if (counter >= files.size) files.last else files(counter)
val is = getClass.getResourceAsStream(filename)
val bytes: Array[Byte] = IOUtils.toByteArray(is)
counter += 1
new ByteArrayInputStream(bytes)
}
}
when(entity.getContent).then(new AnswerInputStream)
val http = new Http with thread.Safety {
override def make_client: HttpClient = httpClient
}
http
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment