Skip to content

Commit

Permalink
JENKINS-21687: Add ability to retrieve the current time from the /tim…
Browse files Browse the repository at this point in the history
…estamps URL
  • Loading branch information
StevenGBrown committed Jan 22, 2017
1 parent 4b4a28a commit 820a9ad
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 151 deletions.
Expand Up @@ -39,6 +39,8 @@
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;

import hudson.model.Run;
import hudson.plugins.timestamper.Timestamp;
Expand Down Expand Up @@ -75,6 +77,9 @@
* many lines back from the end.</li>
* <li>"locale": Select the locale to use when displaying the system clock time.
* </li>
* <li>"currentTime": Display the current time instead of reading time-stamps
* from the build.
* <li>
* </ul>
*
* @author Steven G. Brown
Expand All @@ -89,14 +94,32 @@ public class TimestampsActionOutput {
* @return a {@link BufferedReader}
*/
public static BufferedReader open(Run<?, ?> build, TimestampsActionQuery query) {
TimestampsReader timestampsReader = new TimestampsReader(build);
LogFileReader logFileReader = new LogFileReader(build);
Supplier<TimestampsReader> timestampsReaderSupplier = Suppliers
.ofInstance(new TimestampsReader(build));
Supplier<LogFileReader> logFileReaderSupplier = Suppliers.ofInstance(new LogFileReader(build));

return open(timestampsReader, logFileReader, query);
long buildStartTime = build.getStartTimeInMillis();
long millisSinceEpoch = System.currentTimeMillis();
Timestamp currentTimestamp = new Timestamp(millisSinceEpoch - buildStartTime, millisSinceEpoch);

return open(timestampsReaderSupplier, logFileReaderSupplier, query, currentTimestamp);
}

static BufferedReader open(final TimestampsReader timestampsReader,
final LogFileReader logFileReader, final TimestampsActionQuery query) {
static BufferedReader open(Supplier<TimestampsReader> timestampsReaderSupplier,
Supplier<LogFileReader> logFileReaderSupplier, final TimestampsActionQuery query,
Timestamp currentTimestamp) {
if (query.currentTime) {
List<String> parts = new ArrayList<String>();
for (Function<Timestamp, String> format : query.timestampFormats) {
parts.add(format.apply(currentTimestamp));
}
String result = Joiner.on(' ').join(parts) + "\n";
return new BufferedReader(new StringReader(result));
}

final TimestampsReader timestampsReader = timestampsReaderSupplier.get();
final LogFileReader logFileReader = logFileReaderSupplier.get();

final StringBuilder buffer = new StringBuilder();

Reader reader = new Reader() {
Expand Down
Expand Up @@ -63,6 +63,7 @@ public static TimestampsActionQuery create(String query) {
Optional<Integer> endLine = Optional.absent();
List<Function<Timestamp, String>> timestampFormats = new ArrayList<Function<Timestamp, String>>();
boolean appendLogLine = false;
boolean currentTime = false;

List<QueryParameter> queryParameters = readQueryString(query);

Expand All @@ -87,6 +88,8 @@ public static TimestampsActionQuery create(String query) {
timestampFormats.add(new PrecisionTimestampFormat(precision));
} else if (parameter.name.equalsIgnoreCase("appendLog")) {
appendLogLine = (parameter.value.isEmpty() || Boolean.parseBoolean(parameter.value));
} else if (parameter.name.equalsIgnoreCase("currentTime")) {
currentTime = (parameter.value.isEmpty() || Boolean.parseBoolean(parameter.value));
} else if (parameter.name.equalsIgnoreCase("startLine")) {
startLine = Integer.parseInt(parameter.value);
} else if (parameter.name.equalsIgnoreCase("endLine")) {
Expand All @@ -99,7 +102,8 @@ public static TimestampsActionQuery create(String query) {
timestampFormats.add(new PrecisionTimestampFormat(3));
}

return new TimestampsActionQuery(startLine, endLine, timestampFormats, appendLogLine);
return new TimestampsActionQuery(startLine, endLine, timestampFormats, appendLogLine,
currentTime);
}

private static List<QueryParameter> readQueryString(String query) {
Expand Down Expand Up @@ -169,20 +173,24 @@ public String toString() {

final boolean appendLogLine;

final boolean currentTime;

TimestampsActionQuery(int startLine, Optional<Integer> endLine,
List<? extends Function<Timestamp, String>> timestampFormats, boolean appendLogLine) {
List<? extends Function<Timestamp, String>> timestampFormats, boolean appendLogLine,
boolean currentTime) {
this.startLine = startLine;
this.endLine = checkNotNull(endLine);
this.timestampFormats = ImmutableList.copyOf(timestampFormats);
this.appendLogLine = appendLogLine;
this.currentTime = currentTime;
}

/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return Objects.hash(startLine, endLine, timestampFormats, appendLogLine);
return Objects.hash(startLine, endLine, timestampFormats, appendLogLine, currentTime);
}

/**
Expand All @@ -193,8 +201,8 @@ public boolean equals(Object obj) {
if (obj instanceof TimestampsActionQuery) {
TimestampsActionQuery other = (TimestampsActionQuery) obj;
return startLine == other.startLine && endLine.equals(other.endLine)
&& timestampFormats.equals(other.timestampFormats)
&& appendLogLine == other.appendLogLine;
&& timestampFormats.equals(other.timestampFormats) && appendLogLine == other.appendLogLine
&& currentTime == other.currentTime;
}
return false;
}
Expand All @@ -204,9 +212,8 @@ public boolean equals(Object obj) {
*/
@Override
public String toString() {
return new ToStringBuilder(this).append("startLine", startLine)
.append("endLine", endLine)
.append("timestampFormats", timestampFormats)
.append("appendLogLine", appendLogLine).toString();
return new ToStringBuilder(this).append("startLine", startLine).append("endLine", endLine)
.append("timestampFormats", timestampFormats).append("appendLogLine", appendLogLine)
.append("currentTime", currentTime).toString();
}
}
Expand Up @@ -25,6 +25,7 @@

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assume.assumeThat;
import static org.mockito.Mockito.atMost;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
Expand All @@ -50,6 +51,7 @@

import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;

Expand Down Expand Up @@ -101,86 +103,72 @@ public String apply(@Nonnull Timestamp timestamp) {
public static Collection<Object[]> data() {
List<Object[]> testCases = new ArrayList<Object[]>();

testCases
.addAll(
Arrays.asList(new Object[][] {
{ "format",
new TimestampsActionQuery(0, NO_ENDLINE, Collections.singletonList(FORMAT),
false),
Arrays.asList("1", "2", "3", "4", "5", "6") },
{ "format + elapsed_format",
new TimestampsActionQuery(0, NO_ENDLINE,
ImmutableList.of(FORMAT, ELAPSED_FORMAT), false),
Arrays.asList("1 0", "2 1", "3 10", "4 100", "5 1000", "6 10000") },
{ "appendLogLine",
new TimestampsActionQuery(0, NO_ENDLINE, Collections.singletonList(FORMAT),
true),
Arrays.asList("1 line1", "2 line2", "3 line3", "4 line4", "5 line5",
"6 line6") } }));
testCases.add(new Object[] { "format",
new TimestampsActionQuery(0, NO_ENDLINE, Collections.singletonList(FORMAT), false, false),
Arrays.asList("1", "2", "3", "4", "5", "6") });

testCases.add(new Object[] {
"format + elapsed_format", new TimestampsActionQuery(0, NO_ENDLINE,
ImmutableList.of(FORMAT, ELAPSED_FORMAT), false, false),
Arrays.asList("1 0", "2 1", "3 10", "4 100", "5 1000", "6 10000") });

testCases.add(new Object[] { "appendLogLine",
new TimestampsActionQuery(0, NO_ENDLINE, Collections.singletonList(FORMAT), true, false),
Arrays.asList("1 line1", "2 line2", "3 line3", "4 line4", "5 line5", "6 line6") });

testCases.add(new Object[] { "currentTime",
new TimestampsActionQuery(0, NO_ENDLINE, ImmutableList.of(FORMAT, ELAPSED_FORMAT), false, true),
Arrays.asList("1 42") });

// start line
testCases
.addAll(
Arrays.asList(new Object[][] {
{ "start 2",
new TimestampsActionQuery(2, NO_ENDLINE, Collections.singletonList(FORMAT),
true),
Arrays.asList("2 line2", "3 line3", "4 line4", "5 line5", "6 line6") },
{ "start 1",
new TimestampsActionQuery(1, NO_ENDLINE,
Collections.singletonList(FORMAT), true),
Arrays.asList("1 line1", "2 line2", "3 line3", "4 line4", "5 line5",
"6 line6") },
{ "start -1",
new TimestampsActionQuery(-1, NO_ENDLINE, Collections.singletonList(FORMAT),
true),
Arrays.asList("6 line6") },
{ "start -2", new TimestampsActionQuery(-2, NO_ENDLINE,
Collections.singletonList(FORMAT), true),
Arrays.asList("5 line5", "6 line6") } }));
testCases.add(new Object[] { "start 2",
new TimestampsActionQuery(2, NO_ENDLINE, Collections.singletonList(FORMAT), true, false),
Arrays.asList("2 line2", "3 line3", "4 line4", "5 line5", "6 line6") });
testCases.add(new Object[] { "start 1",
new TimestampsActionQuery(1, NO_ENDLINE, Collections.singletonList(FORMAT), true, false),
Arrays.asList("1 line1", "2 line2", "3 line3", "4 line4", "5 line5", "6 line6") });
testCases.add(new Object[] { "start -1",
new TimestampsActionQuery(-1, NO_ENDLINE, Collections.singletonList(FORMAT), true, false),
Arrays.asList("6 line6") });
testCases.add(new Object[] { "start -2",
new TimestampsActionQuery(-2, NO_ENDLINE, Collections.singletonList(FORMAT), true, false),
Arrays.asList("5 line5", "6 line6") });

// end line
testCases
.addAll(Arrays.asList(new Object[][] {
{ "end 2",
new TimestampsActionQuery(0, Optional.of(2), Collections.singletonList(FORMAT),
true),
Arrays.asList("1 line1", "2 line2") },
{ "end 1",
new TimestampsActionQuery(0, Optional.of(1), Collections.singletonList(FORMAT),
true),
Arrays.asList("1 line1") },
{ "end 0",
new TimestampsActionQuery(0, Optional.of(0), Collections.singletonList(FORMAT),
true),
Collections.emptyList() },
{ "end -1",
new TimestampsActionQuery(0, Optional.of(-1), Collections.singletonList(FORMAT),
true),
Arrays.asList("1 line1", "2 line2", "3 line3", "4 line4", "5 line5",
"6 line6") },
{ "end -2",
new TimestampsActionQuery(0, Optional.of(-2), Collections.singletonList(FORMAT),
true),
Arrays.asList("1 line1", "2 line2", "3 line3", "4 line4", "5 line5") }, }));
.add(
new Object[] {
"end 2", new TimestampsActionQuery(0, Optional.of(2),
Collections.singletonList(FORMAT), true, false),
Arrays.asList("1 line1", "2 line2") });
testCases.add(new Object[] { "end 1", new TimestampsActionQuery(0, Optional.of(1),
Collections.singletonList(FORMAT), true, false), Arrays.asList("1 line1") });
testCases.add(new Object[] { "end 0", new TimestampsActionQuery(0, Optional.of(0),
Collections.singletonList(FORMAT), true, false), Collections.emptyList() });
testCases.add(new Object[] { "end -1",
new TimestampsActionQuery(0, Optional.of(-1), Collections.singletonList(FORMAT), true,
false),
Arrays.asList("1 line1", "2 line2", "3 line3", "4 line4", "5 line5", "6 line6") });
testCases.add(new Object[] {
"end -2", new TimestampsActionQuery(0, Optional.of(-2), Collections.singletonList(FORMAT),
true, false),
Arrays.asList("1 line1", "2 line2", "3 line3", "4 line4", "5 line5") });

// start line and end line
testCases
.addAll(Arrays.asList(new Object[][] {
{ "start 2, end -2",
new TimestampsActionQuery(2, Optional.of(-2), Collections.singletonList(FORMAT),
true),
Arrays.asList("2 line2", "3 line3", "4 line4", "5 line5") },
{ "start 2, end 5",
new TimestampsActionQuery(2, Optional.of(5), Collections.singletonList(FORMAT),
true),
Arrays.asList("2 line2", "3 line3", "4 line4", "5 line5") },
{ "start -4, end -2",
new TimestampsActionQuery(-4, Optional.of(-2), Collections.singletonList(FORMAT),
true),
Arrays.asList("3 line3", "4 line4", "5 line5") },
{ "start 4, end -4", new TimestampsActionQuery(4, Optional.of(-4),
Collections.singletonList(FORMAT), true), Collections.emptyList() } }));
testCases.add(new Object[] {
"start 2, end -2", new TimestampsActionQuery(2, Optional.of(-2),
Collections.singletonList(FORMAT), true, false),
Arrays.asList("2 line2", "3 line3", "4 line4", "5 line5") });
testCases.add(new Object[] {
"start 2, end 5", new TimestampsActionQuery(2, Optional.of(5),
Collections.singletonList(FORMAT), true, false),
Arrays.asList("2 line2", "3 line3", "4 line4", "5 line5") });
testCases.add(new Object[] {
"start -4, end -2", new TimestampsActionQuery(-4, Optional.of(-2),
Collections.singletonList(FORMAT), true, false),
Arrays.asList("3 line3", "4 line4", "5 line5") });
testCases.add(new Object[] { "start 4, end -4", new TimestampsActionQuery(4, Optional.of(-4),
Collections.singletonList(FORMAT), true, false), Collections.emptyList() });

return testCases;
}
Expand Down Expand Up @@ -234,7 +222,8 @@ public void setUp() throws Exception {
nextLineStubbing.thenReturn(Optional.<Line>absent());
when(logFileReader.lineCount()).thenReturn(6);

reader = TimestampsActionOutput.open(timestampsReader, logFileReader, query);
reader = TimestampsActionOutput.open(Suppliers.ofInstance(timestampsReader),
Suppliers.ofInstance(logFileReader), query, new Timestamp(42, 1));
}

/**
Expand Down Expand Up @@ -275,6 +264,8 @@ public void testRead_allAtOnce() throws Exception {
*/
@Test
public void testRead_noTimestamps() throws Exception {
assumeThat(query.currentTime, is(false));

// Remove formatted timestamps from expected result
if (query.appendLogLine) {
expectedLines = Lists.transform(expectedLines, new Function<String, String>() {
Expand Down Expand Up @@ -339,6 +330,8 @@ public String apply(@Nonnull String input) {
*/
@Test
public void testRead_noTimestampsAndNoLogFile() throws Exception {
assumeThat(query.currentTime, is(false));

when(timestampsReader.read()).thenReturn(Optional.<Timestamp>absent());
when(logFileReader.nextLine()).thenReturn(Optional.<Line>absent());
assertThat(readLines(), is(Collections.<String>emptyList()));
Expand Down

0 comments on commit 820a9ad

Please sign in to comment.