alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Play Framework/Scala example source code file (AssetsSpec.scala)

This example Play Framework source code file (AssetsSpec.scala) is included in my "Source Code Warehouse" project. The intent of this project is to help you more easily find Play Framework (and Scala) source code examples by using tags.

All credit for the original source code belongs to Play Framework; I'm just trying to make examples easier to find. (For my Scala work, see my Scala examples and tutorials.)

Play Framework tags/keywords

api, assets, fakeapplication, gmt, jan, mvc, not_found, not_modified, ok, play, play framework, some, t, test, this, utility

The AssetsSpec.scala Play Framework example source code

/*
 * Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
 */
package play.it.http.assets

import controllers.Assets
import controllers.Assets.Asset
import play.api.test._
import org.apache.commons.io.IOUtils
import java.util.zip.GZIPInputStream
import java.io.ByteArrayInputStream
import play.api.{Configuration, Mode}
import play.api.mvc.{PathBindable, Handler}
import play.utils.{UriEncoding, Threads}
import play.core.Router.ReverseRouteContext

object AssetsSpec extends PlaySpecification with WsTestClient {
  "Assets controller" should {

    val defaultCacheControl = Some("public, max-age=3600")
    val aggressiveCacheControl = Some("public, max-age=31536000")

    implicit val port: Port = testServerPort

    def withServer[T](block: => T): T = {
      import Asset._
      val routes: PartialFunction[(String, String), Handler] = {
        case (_, path) => Assets.versioned("/testassets", path)
      }
      running(TestServer(port, new FakeApplication(withRoutes = routes) {
        // setting prod mode ensures caching headers get set, gzip is turned on, etc
        override val mode = Mode.Prod
        // but we don't want to load config in prod mode
        override lazy val initialConfiguration = Threads.withContextClassLoader(classloader) {
          Configuration(Configuration.loadDev(path, Map.empty))
        }
      }))(block)
    }

    "serve an asset" in withServer {
      val result = await(wsUrl("/bar.txt").get())

      result.status must_== OK
      result.body must_== "This is a test asset."
      result.header(CONTENT_TYPE) must beSome.which(_.startsWith("text/plain"))
      result.header(ETAG) must beSome
      result.header(LAST_MODIFIED) must beSome
      result.header(VARY) must beNone
      result.header(CONTENT_ENCODING) must beNone
      result.header(CACHE_CONTROL) must_== defaultCacheControl
    }

    "serve an asset in a subdirectory" in withServer {
      val result = await(wsUrl("/subdir/baz.txt").get())

      result.status must_== OK
      result.body must_== "Content of baz.txt."
      result.header(CONTENT_TYPE) must beSome.which(_.startsWith("text/plain"))
      result.header(ETAG) must beSome
      result.header(LAST_MODIFIED) must beSome
      result.header(VARY) must beNone
      result.header(CONTENT_ENCODING) must beNone
      result.header(CACHE_CONTROL) must_== defaultCacheControl
    }

    "serve an asset with spaces in the name" in withServer {
      val result = await(wsUrl("/foo%20bar.txt").get())

      result.status must_== OK
      result.body must_== "This is a test asset with spaces."
      result.header(CONTENT_TYPE) must beSome.which(_.startsWith("text/plain"))
      result.header(ETAG) must beSome
      result.header(LAST_MODIFIED) must beSome
      result.header(VARY) must beNone
      result.header(CONTENT_ENCODING) must beNone
      result.header(CACHE_CONTROL) must_== defaultCacheControl
    }

    "serve a non gzipped asset when gzip is available but not requested" in withServer {
      val result = await(wsUrl("/foo.txt").get())

      result.body must_== "This is a test asset."
      result.header(VARY) must beSome(ACCEPT_ENCODING)
      result.header(CONTENT_ENCODING) must beNone
    }

    "serve a gzipped asset" in withServer {
      val result = await(wsUrl("/foo.txt")
        .withHeaders(ACCEPT_ENCODING -> "gzip")
        .get())

      result.header(VARY) must beSome(ACCEPT_ENCODING)
      result.header(CONTENT_ENCODING) must beSome("gzip")
      val ahcResult : com.ning.http.client.Response = result.underlying.asInstanceOf[com.ning.http.client.Response]
      val is = new GZIPInputStream(new ByteArrayInputStream(ahcResult.getResponseBodyAsBytes))
      IOUtils.toString(is) must_== "This is a test gzipped asset.\n"
      // release deflate resources
      is.close()
      success
    }

    "return not modified when etag matches" in withServer {
      val Some(etag) = await(wsUrl("/foo.txt").get()).header(ETAG)
      val result = await(wsUrl("/foo.txt")
        .withHeaders(IF_NONE_MATCH -> etag)
        get())

      result.status must_== NOT_MODIFIED
      result.body must beEmpty
      result.header(CACHE_CONTROL) must_== defaultCacheControl
      result.header(ETAG) must beSome
      result.header(LAST_MODIFIED) must beSome
    }

    "return not modified when multiple etags supply and one matches" in withServer {
      val Some(etag) = await(wsUrl("/foo.txt").get()).header(ETAG)
      val result = await(wsUrl("/foo.txt")
        .withHeaders(IF_NONE_MATCH -> ("\"foo\", " + etag + ", \"bar\""))
        .get())

      result.status must_== NOT_MODIFIED
      result.body must beEmpty
    }

    "return asset when etag doesn't match" in withServer {
      val result = await(wsUrl("/foo.txt")
        .withHeaders(IF_NONE_MATCH -> "foobar")
        .get())

      result.status must_== OK
      result.body must_== "This is a test asset."
    }

    "return not modified when not modified since" in withServer {
      val Some(timestamp) = await(wsUrl("/foo.txt").get()).header(LAST_MODIFIED)
      val result = await(wsUrl("/foo.txt")
        .withHeaders(IF_MODIFIED_SINCE -> timestamp)
        .get())

      result.status must_== NOT_MODIFIED
      result.body must beEmpty

      // I don't know why we implement this behaviour, I can't see it in the HTTP spec, but there were tests for it
      result.header(DATE) must beSome
      result.header(ETAG) must beNone
      result.header(CACHE_CONTROL) must beNone
    }

    "return asset when modified since" in withServer {
      val result = await(wsUrl("/foo.txt")
        .withHeaders(IF_MODIFIED_SINCE -> "Tue, 13 Mar 2012 13:08:36 GMT")
        .get())

      result.status must_== OK
      result.body must_== "This is a test asset."
    }

    "ignore if modified since header if if none match header is set" in withServer {
      val result = await(wsUrl("/foo.txt")
        .withHeaders(
        IF_NONE_MATCH -> "foobar",
        IF_MODIFIED_SINCE -> "Wed, 01 Jan 2113 00:00:00 GMT" // might break in 100 years, but I won't be alive, so :P
      ).get())

      result.status must_== OK
      result.body must_== "This is a test asset."
    }

    "return the asset if the if modified since header can't be parsed" in withServer {
      val result = await(wsUrl("/foo.txt")
        .withHeaders(IF_MODIFIED_SINCE -> "Not a date")
        .get())

      result.status must_== OK
      result.body must_== "This is a test asset."
    }

    "return 200 if the asset is empty" in withServer {
      val result = await(wsUrl("/empty.txt").get())

      result.status must_== OK
      result.body must beEmpty
    }

    "return 404 for files that don't exist" in withServer {
      val result = await(wsUrl("/nosuchfile.txt").get())

      result.status must_== NOT_FOUND
      result.body must beEmpty
    }

    "serve a versioned asset" in withServer {
      val result = await(wsUrl("/versioned/sub/12345678901234567890123456789012-foo.txt").get())

      result.status must_== OK
      result.body must_== "This is a test asset."
      result.header(CONTENT_TYPE) must beSome.which(_.startsWith("text/plain"))
      result.header(ETAG) must_== Some("12345678901234567890123456789012")
      result.header(LAST_MODIFIED) must beSome
      result.header(VARY) must beNone
      result.header(CONTENT_ENCODING) must beNone
      result.header(CACHE_CONTROL) must_== aggressiveCacheControl
    }
  }
}

Other Play Framework source code examples

Here is a short list of links related to this Play Framework AssetsSpec.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.