| TL;DR: Setting the clock is a Bad Thing; don't do that. Adjust it gradually instead. To make Jenkins tolerate a clock change, we'd have to find a way of making all of Jenkins' "wait for a duration" code use nanotime instead of UTC. If the system "long millisecondsSince1970" clock changes, all of Java's normal "wait until" methods will return early or late. It's only code that only looks at system nanosecondsOfUptime that'll be unaffected. This (kind of) issue has bitten me many times in my career and it extends to more than just Java & Jenkins, e.g. the Windows DHCP Client doesn't cope with the clock changing either (it'll either re-request an IP early, or it'll fail to renew the lease in time, sometimes causing a brief network outage that Windows cascades into a fatal networking error that kills all current TCP connections and thus briefly disconnects the slave). Been there; done that ... and have the mental scars to prove it. The solution is fairly simple - do NOT set the clock while Jenkins (or anything else you care about) is running. If you need to tweak the clock then use the Windows Time Service (or an ntpd service) to gradually adjust the clock (by running it a bit fast or a bit slow) until it's in sync. e.g. what we do on our dynamically-provisioned slaves, before the Jenkins slave process starts, is (a) force the time service to re-sync and set the time, (b) halt & disable all services that might adjust the time (c) force Windows to renew the DHCP lease and only after the clock is correct and the network "renewed" do we then allow the Jenkins slave.jar to run, thus ensuring that no other process will adjust the clock while Jenkins is running. Going back to the original problem ... I think you need to refactor your code to make it testable by injecting in a test-controlled time source so that, during this test, the code-under-test isn't actually reading the system's real time clock at all, but is instead reading the time provided by the test harness. e.g. we declared an interface `ITimeProvider` which had a getUpimeInNanoseconds(), a getUTCInMilliseconds() and a delay(long milliseconds) method, and then had a default implementation that the code-under-test usually used unless the test harness needed to control time. |