/*
* Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.glowroot.agent.it.harness.impl;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import com.google.common.base.Joiner;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import org.immutables.value.Value;
import org.glowroot.wire.api.model.CollectorServiceOuterClass.LogEvent;
import org.glowroot.wire.api.model.TraceOuterClass.Trace;
import static java.util.concurrent.TimeUnit.SECONDS;
class TraceCollector {
private volatile @Nullable Trace trace;
private final List<ExpectedLogMessage> expectedMessages = Lists.newCopyOnWriteArrayList();
private final List<LogEvent> unexpectedMessages = Lists.newCopyOnWriteArrayList();
Trace getCompletedTrace(int timeout, TimeUnit unit) throws InterruptedException {
Stopwatch stopwatch = Stopwatch.createStarted();
while (stopwatch.elapsed(unit) < timeout) {
Trace trace = this.trace;
if (trace != null && !trace.getHeader().getPartial()) {
return trace;
}
Thread.sleep(10);
}
throw new IllegalStateException("No trace was collected");
}
Trace getPartialTrace(int timeout, TimeUnit unit) throws InterruptedException {
Stopwatch stopwatch = Stopwatch.createStarted();
while (stopwatch.elapsed(unit) < timeout) {
Trace trace = this.trace;
if (trace != null) {
if (!trace.getHeader().getPartial()) {
throw new IllegalStateException("Trace was collected but is not partial");
}
return trace;
}
Thread.sleep(10);
}
throw new IllegalStateException("No trace was collected");
}
boolean hasTrace() {
return trace != null;
}
void clearTrace() {
trace = null;
}
void addExpectedLogMessage(String loggerName, String partialMessage) {
expectedMessages.add(ImmutableExpectedLogMessage.of(loggerName, partialMessage));
}
public void checkAndResetLogMessages() throws InterruptedException {
Stopwatch stopwatch = Stopwatch.createStarted();
while (stopwatch.elapsed(SECONDS) < 10 && !expectedMessages.isEmpty()
&& unexpectedMessages.isEmpty()) {
Thread.sleep(10);
}
try {
if (!unexpectedMessages.isEmpty()) {
throw new AssertionError("Unexpected messages were logged:\n\n"
+ Joiner.on("\n").join(unexpectedMessages));
}
if (!expectedMessages.isEmpty()) {
throw new AssertionError("One or more expected messages were not logged");
}
} finally {
expectedMessages.clear();
unexpectedMessages.clear();
}
}
public void collectTrace(Trace trace) {
Trace currTrace = this.trace;
if (currTrace == null
|| currTrace.getHeader().getCaptureTime() <= trace.getHeader().getCaptureTime()) {
this.trace = trace;
}
}
public void log(LogEvent logEvent) {
if (isExpected(logEvent)) {
return;
}
if (logEvent.getLevel().ordinal() >= LogEvent.Level.WARN_VALUE) {
unexpectedMessages.add(logEvent);
}
}
private boolean isExpected(LogEvent logEvent) {
if (expectedMessages.isEmpty()) {
return false;
}
ExpectedLogMessage expectedMessage = expectedMessages.get(0);
if (expectedMessage.loggerName().equals(logEvent.getLoggerName())
&& logEvent.getMessage().contains(expectedMessage.partialMessage())) {
expectedMessages.remove(0);
return true;
}
return false;
}
@Value.Immutable
@Value.Style(allParameters = true)
interface ExpectedLogMessage {
String loggerName();
String partialMessage();
}
}