Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unit tests break with millisecond last modified precision #13

Open
andredasilvapinto opened this issue Nov 6, 2013 · 0 comments
Open

Comments

@andredasilvapinto
Copy link

While running the integration tests if the requested file has a last modified date with millisecond precision, something like this happens:

org.vertx.mods.test.integration.java.WebServerHeadersTest > testEtagIfUnModifiedSince STANDARD_ERROR
    java.lang.AssertionError: expected:<200> but was:<412>
        at org.junit.Assert.fail(Assert.java:88)
        at org.junit.Assert.failNotEquals(Assert.java:743)
        at org.junit.Assert.assertEquals(Assert.java:118)
        at org.junit.Assert.assertEquals(Assert.java:555)
        at org.junit.Assert.assertEquals(Assert.java:542)
        at org.vertx.testtools.VertxAssert.assertEquals(VertxAssert.java:102)
        at org.vertx.mods.test.integration.java.WebServerHeadersTest$7$1$1.handle(WebServerHeadersTest.java:260)
        at org.vertx.mods.test.integration.java.WebServerHeadersTest$7$1$1.handle(WebServerHeadersTest.java:257)
        at org.vertx.java.core.http.impl.DefaultHttpClientRequest.handleResponse(DefaultHttpClientRequest.java:283)
        at org.vertx.java.core.http.impl.ClientConnection.handleResponse(ClientConnection.java:279)
        at org.vertx.java.core.http.impl.DefaultHttpClient$ClientHandler.doMessageReceived(DefaultHttpClient.java:672)
        at org.vertx.java.core.http.impl.DefaultHttpClient$ClientHandler.doMessageReceived(DefaultHttpClient.java:652)
        at org.vertx.java.core.http.impl.VertxHttpHandler.channelRead(VertxHttpHandler.java:60)
        at org.vertx.java.core.net.impl.VertxHandler.channelRead(VertxHandler.java:156)
        at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:337)
        at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:323)
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:173)
        at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:148)
        at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:337)
        at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:323)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:785)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:101)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:485)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:452)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:346)
        at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101)
        at java.lang.Thread.run(Thread.java:722)

org.vertx.mods.test.integration.java.WebServerHeadersTest > testEtagIfUnModifiedSince FAILED
    java.lang.AssertionError: expected:<200> but was:<412>

org.vertx.mods.test.integration.java.WebServerHeadersTest > testEtagIfModifiedSince STANDARD_OUT
    Starting test: testEtagIfModifiedSince

org.vertx.mods.test.integration.java.WebServerHeadersTest > testEtagIfModifiedSince STANDARD_ERROR
    java.lang.AssertionError: expected:<304> but was:<200>
        at org.junit.Assert.fail(Assert.java:88)
        at org.junit.Assert.failNotEquals(Assert.java:743)
        at org.junit.Assert.assertEquals(Assert.java:118)
        at org.junit.Assert.assertEquals(Assert.java:555)
        at org.junit.Assert.assertEquals(Assert.java:542)
        at org.vertx.testtools.VertxAssert.assertEquals(VertxAssert.java:102)
        at org.vertx.mods.test.integration.java.WebServerHeadersTest$6$1$1.handle(WebServerHeadersTest.java:217)
        at org.vertx.mods.test.integration.java.WebServerHeadersTest$6$1$1.handle(WebServerHeadersTest.java:214)
        at org.vertx.java.core.http.impl.DefaultHttpClientRequest.handleResponse(DefaultHttpClientRequest.java:283)
        at org.vertx.java.core.http.impl.ClientConnection.handleResponse(ClientConnection.java:279)
        at org.vertx.java.core.http.impl.DefaultHttpClient$ClientHandler.doMessageReceived(DefaultHttpClient.java:672)
        at org.vertx.java.core.http.impl.DefaultHttpClient$ClientHandler.doMessageReceived(DefaultHttpClient.java:652)
        at org.vertx.java.core.http.impl.VertxHttpHandler.channelRead(VertxHttpHandler.java:60)
        at org.vertx.java.core.net.impl.VertxHandler.channelRead(VertxHandler.java:156)
        at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:337)
        at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:323)
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:173)
        at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:148)
        at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:337)
        at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:323)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:785)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:101)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:485)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:452)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:346)
        at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101)
        at java.lang.Thread.run(Thread.java:722)

org.vertx.mods.test.integration.java.WebServerHeadersTest > testEtagIfModifiedSince FAILED
    java.lang.AssertionError: expected:<304> but was:<200>

This occurs because we are using the file system to return the file timestamp, which can have millisecond precision (at least on Windows it has), and comparing/passing it to the HTTP headers, which follow the "EEE, dd MMM yyyy HH:mm:ss zzz" format. As this format does not include milliseconds, we are losing precision during the round trip. When, on the client (e.g. the failing test methods above), we use the received "last-modified" header to enable cache behaviour (tested by "If-Modified-Since" and "If-Unmodified-Since" on the tests), we may get unexpected results (like 412 and 304 error codes produced by StaticFileHandler) if our "last-modified" header (second precision) is actually behind the real "last-modified" file timestamp (millisecond precision).

If we are not using "webserver.fileProps.modified" for anything other than caching HTTP requested resources, I would suggest a small change to the checkCacheOrFileSystem method, in order to decrease our precision to the same level as the HTTP headers format we are using. As we are only able to the get the second precision for the request, I don't see any reason why our cache should use a more accurate representation (in the case it is effectively true that the map is not being used for anything else).

  private long checkCacheOrFileSystem(String fileName) {

    if (filePropsModified.containsKey(fileName)) {
      return filePropsModified.get(fileName);
    }

    FileProps fileProps = fileSystem.propsSync(fileName);

    // HTTP headers only have second precision, not millisecond
    long lastModified = fileProps.lastModifiedTime().getTime() / 1000 * 1000;

    filePropsModified.put(fileName, lastModified);

    return lastModified;
  }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant