@@ -7,6 +7,9 @@ import org.slf4j.LoggerFactory
77
88import java.time.Duration
99import java.time.Instant
10+ import java.time.LocalDate
11+ import java.time.LocalDateTime
12+ import java.time.ZoneId
1013import java.time.temporal.TemporalAdjuster
1114
1215/**
@@ -23,7 +26,7 @@ import java.time.temporal.TemporalAdjuster
2326 * you change it for all running containers
2427 *
2528 */
26- class TimeMachine implements Container {
29+ class TimeMachine implements Container {
2730
2831 String containerName = " TimeMachine"
2932 String containerMainPort = null
@@ -32,7 +35,6 @@ class TimeMachine implements Container{
3235 String defaultShell = " /bin/sh"
3336
3437
35-
3638 /**
3739 * Travel back to the present
3840 * <b >NEVER EVER</b> use this class on a production docker engine <p >
@@ -42,11 +44,12 @@ class TimeMachine implements Container{
4244 * @return true after verifying success
4345 */
4446 static boolean travelToNow (String dockerHost = " " , String dockerCertPath = " " ) {
47+
4548 return setTime(System . currentTimeSeconds(), dockerHost, dockerCertPath)
4649 }
4750
4851 /**
49- * Travel X days in time
52+ * Travel X days in time from actual "Now"
5053 * <b >NEVER EVER</b> use this class on a production docker engine <p >
5154 * <b >WARNING THIS AFFECTS ALL CONTAINERS - READ CLASS DOCUMENTATION</b>
5255 * @param days Number of days to travel, can be negative (to the past) or positive (to the future)
@@ -56,12 +59,72 @@ class TimeMachine implements Container{
5659 */
5760 static boolean travelDays (int days , String dockerHost = " " , String dockerCertPath = " " ) {
5861
59- long newEpochS = System . currentTimeSeconds() + Duration . ofDays(days). toSeconds()
62+ long newEpochS = System . currentTimeSeconds() + Duration . ofDays(days). toSeconds()
6063
6164 return setTime(newEpochS, dockerHost, dockerCertPath)
6265
6366 }
6467
68+ /**
69+ * Travel X days in time relative to
70+ * <b >NEVER EVER</b> use this class on a production docker engine <p >
71+ * <b >WARNING THIS AFFECTS ALL CONTAINERS - READ CLASS DOCUMENTATION</b>
72+ * @param days Number of days to travel, can be negative (to the past) or positive (to the future)
73+ * @param dockerHost optional
74+ * @param dockerCertPath optional
75+ * @return true after verifying success
76+ */
77+ static boolean travelRelativeDays (int days , String dockerHost = " " , String dockerCertPath = " " ) {
78+
79+ long currentDockerTime = getDockerTime(dockerHost, dockerCertPath)
80+
81+ long newEpochS = currentDockerTime + Duration . ofDays(days). toSeconds()
82+
83+ return setTime(newEpochS, dockerHost, dockerCertPath)
84+
85+ }
86+
87+ /**
88+ * Set new time based on Date object
89+ * <b >NEVER EVER</b> use this class on a production docker engine <p >
90+ * <b >WARNING THIS AFFECTS ALL CONTAINERS - READ CLASS DOCUMENTATION</b>
91+ * @param date A date object to use as the new "now"
92+ * @param dockerHost optional
93+ * @param dockerCertPath optional
94+ * @return true after verifying success
95+ */
96+ static boolean setDate (Date date , String dockerHost = " " , String dockerCertPath = " " ) {
97+ return setTime(((date. toInstant(). toEpochMilli()) / 1000 ). toInteger(), dockerHost, dockerCertPath)
98+ }
99+
100+ /**
101+ * Set new time based on LocalDateTime object, uses the system default Time Zone
102+ * <b >NEVER EVER</b> use this class on a production docker engine <p >
103+ * <b >WARNING THIS AFFECTS ALL CONTAINERS - READ CLASS DOCUMENTATION</b>
104+ * @param localDateTime A LocalDateTime object to use as the new "now"
105+ * @param dockerHost optional
106+ * @param dockerCertPath optional
107+ * @return true after verifying success
108+ */
109+ static boolean setLocalDateTime (LocalDateTime localDateTime , String dockerHost = " " , String dockerCertPath = " " ) {
110+
111+ return setTime(localDateTime. toEpochSecond(ZoneId . systemDefault(). offset), dockerHost, dockerCertPath)
112+ }
113+
114+ /**
115+ * Set new time based on LocalDate object
116+ * <b >NEVER EVER</b> use this class on a production docker engine <p >
117+ * <b >WARNING THIS AFFECTS ALL CONTAINERS - READ CLASS DOCUMENTATION</b>
118+ * @param LocalDate A LocalDate object to use as the new "now"
119+ * @param dockerHost optional
120+ * @param dockerCertPath optional
121+ * @return true after verifying success
122+ */
123+ static boolean setLocalDate (LocalDate localDate , String dockerHost = " " , String dockerCertPath = " " ) {
124+
125+ return setTime(localDate. toEpochDay(), dockerHost, dockerCertPath)
126+ }
127+
65128
66129 /**
67130 * Change docker engine time <p >
@@ -79,25 +142,37 @@ class TimeMachine implements Container{
79142 log. warn(" THIS WILL AFFECT ALL CONTAINERS RUN BY THIS DOCKER ENGINE" )
80143
81144
82- assert epochS <= 9999999999 && epochS > 1000000000 : " Provide timestamp in epoch seconds"
83- ArrayList<String > cmdOut = runCmdAndRm([" nsenter" ," -t" ," 1" ," -m" ," -u" ," -n" , " -i" , " sh" , " -c" , " pkill sntpc || date -s \" @${ epochS} \" && echo Status \$ ?" ], 5000 , [] , dockerHost, dockerCertPath)
84- assert cmdOut. toString(). contains(" Status 0" ) : " Error setting time"
85-
86- cmdOut = runCmdAndRm(' date +"%s"' , 5000 , [], dockerHost, dockerCertPath )
145+ assert epochS <= 9999999999 && epochS > 1000000000 : " Provide timestamp in epoch seconds"
146+ ArrayList<String > cmdOut = runCmdAndRm([" nsenter" , " -t" , " 1" , " -m" , " -u" , " -n" , " -i" , " sh" , " -c" , " pkill sntpc || date -s \" @${ epochS} \" && echo Status \$ ?" ], 5000 , [], dockerHost, dockerCertPath)
147+ assert cmdOut. toString(). contains(" Status 0" ): " Error setting time"
87148
149+ long newTime = getDockerTime(dockerHost, dockerCertPath)
88150
89- long newTime = cmdOut. find {it. isNumber()}?. toLong() ?: 0
90- assert newTime : " Unexpected output when verifying time was change"
91- assert newTime >= epochS : " The newly set time appears incorrect: " + newTime
151+ assert newTime >= epochS: " The newly set time appears incorrect: " + newTime
92152
93153 return true
94154
95155 }
96156
157+ /**
158+ * Get current time as reported by a docker container
159+ * @param dockerHost
160+ * @param dockerCertPath
161+ * @return Epoch Seconds
162+ */
163+ static long getDockerTime (String dockerHost = " " , String dockerCertPath = " " ) {
164+
165+ ArrayList<String > cmdOut = runCmdAndRm(' date +"%s"' , 5000 , [], dockerHost, dockerCertPath)
166+ long timeStamp = cmdOut. find { it. isNumber() }?. toLong() ?: 0
167+ assert timeStamp: " Unexpected output when getting docker time"
168+
169+ return timeStamp
170+
171+ }
97172
98173
99174 @Override
100- ContainerCreateRequest customizeContainerCreateRequest (ContainerCreateRequest containerCreateRequest ){
175+ ContainerCreateRequest customizeContainerCreateRequest (ContainerCreateRequest containerCreateRequest ) {
101176
102177
103178 containerCreateRequest. hostConfig. setPrivileged(true )
0 commit comments