blob: 5669d1ff6d0e98e7cac8928239c960bf49019ad6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.ignite.testframework;
import java.util.Iterator;
import org.apache.ignite.internal.util.GridConcurrentLinkedHashSet;
/**
* This log listener allows to check the order or presence of messages in log. Messages are matched via regexps.
* Also allows to unify various messages into groups to check messages only within group.
* Groups can be ordered or non-ordered. In non-ordered groups, message order will not be checked, only
* will be checked the presence of given messages.
* <p>
* Message groups can also be unified into higher-level groups, that can also be ordered or non-ordered and in general
* work like message groups.
*/
public class MessageOrderLogListener extends LogListener {
/** */
private final MessageGroup matchesGrp;
/**
* Constructor accepting array of messages.
*
* @param messages array of messages that will be unified into ordered group.
*/
public MessageOrderLogListener(String... messages) {
this.matchesGrp = new MessageGroup(true);
for (String m : messages)
matchesGrp.add(m);
}
/**
* Constructor accepting message group
*
* @param matchesGrp group
*/
public MessageOrderLogListener(MessageGroup matchesGrp) {
this.matchesGrp = matchesGrp;
}
/** {@inheritDoc} */
@Override public boolean check() {
return matchesGrp.check();
}
/** {@inheritDoc} */
@Override public void reset() {
matchesGrp.reset();
}
/** {@inheritDoc} */
@Override public void accept(String s) {
matchesGrp.accept(s);
}
/**
* Allows to unify messages into groups and groups into higher-level groups.
*/
public static class MessageGroup extends LogListener {
/** */
private final boolean ordered;
/** */
private final String containedStr;
/** */
private final GridConcurrentLinkedHashSet<MessageGroup> groups;
/** */
private final GridConcurrentLinkedHashSet<MessageGroup> matched = new GridConcurrentLinkedHashSet<>();
/** */
private volatile boolean checked;
/** */
private volatile String actualStr;
/** */
private volatile int lastAcceptedIdx;
/**
* Default constructor.
*
* @param ordered whether to check order of messages in this group.
*/
public MessageGroup(boolean ordered) {
this(ordered, null);
}
/** */
private MessageGroup(boolean ordered, String s) {
this.ordered = ordered;
containedStr = s;
groups = s == null ? new GridConcurrentLinkedHashSet<>() : null;
}
/**
* Adds a message regexp to group.
*
* @param s message regexp
* @return this for chaining
*/
public MessageGroup add(String s) {
return add(new MessageGroup(false, s));
}
/**
* Adds another message group to this group.
*
* @param grp group
* @return this for chaining
*/
public MessageGroup add(MessageGroup grp) {
groups.add(grp);
return this;
}
/** {@inheritDoc} */
@Override public boolean check() {
if (checked)
return true;
if (groups != null) {
for (MessageGroup group : groups) {
if (!matched.contains(group) || !group.check())
return false;
}
return true;
}
return false;
}
/** {@inheritDoc} */
@Override public void reset() {
checked = false;
actualStr = null;
lastAcceptedIdx = 0;
if (groups != null) {
for (MessageGroup group : groups)
group.reset();
}
for (Iterator<MessageGroup> iter = matched.iterator(); iter.hasNext();) {
iter.next();
iter.remove();
}
}
/** {@inheritDoc} */
@Override public void accept(String s) {
internalAccept(s);
}
/**
* Tries to accept given string. If fails, tries to accept it using internal message groups.
*
* @param s message
* @return whether accepted
*/
private boolean internalAccept(String s) {
if (checked)
return false;
else if (containedStr != null && s.matches(containedStr)) {
checked = true;
actualStr = s;
return true;
}
else {
if (groups != null) {
int i = 0;
for (MessageGroup group : groups) {
if (i < lastAcceptedIdx && ordered) {
i++;
continue;
}
if (group.internalAccept(s)) {
matched.add(group);
lastAcceptedIdx = i;
return true;
}
i++;
}
}
return false;
}
}
/** */
public String getActualStr() {
return actualStr;
}
}
}