/* * Pentaho Data Integration * * Copyright (C) 2002-2015 by Pentaho : http://www.pentaho.com * * ************************************************************************** * * 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.pentaho.di.core.logging; import org.junit.Assert; import org.junit.Test; import org.pentaho.di.core.Const; import java.util.Iterator; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; public class LoggingBufferTest { @Test public void testRaceCondition() throws Exception { final int eventCount = 100; final LoggingBuffer buf = new LoggingBuffer( 200 ); final AtomicBoolean done = new AtomicBoolean( false ); final KettleLoggingEventListener lsnr = new KettleLoggingEventListener() { @Override public void eventAdded( KettleLoggingEvent event ) { //stub } }; final KettleLoggingEvent event = new KettleLoggingEvent(); final CountDownLatch latch = new CountDownLatch( 1 ); Thread.UncaughtExceptionHandler errorHandler = new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException( Thread t, Throwable e ) { e.printStackTrace(); } }; Thread addListeners = new Thread( new Runnable() { @Override public void run() { try { while ( !done.get() ) { buf.addLoggingEventListener( lsnr ); } } finally { latch.countDown(); } } }, "Add Listeners Thread" ) { }; Thread addEvents = new Thread( new Runnable() { @Override public void run() { try { for ( int i = 0; i < eventCount; i++ ) { buf.addLogggingEvent( event ); } done.set( true ); } finally { latch.countDown(); } } }, "Add Events Thread" ) { }; // add error handlers to pass exceptions outside the thread addListeners.setUncaughtExceptionHandler( errorHandler ); addEvents.setUncaughtExceptionHandler( errorHandler ); // start addListeners.start(); addEvents.start(); // wait both latch.await(); // check Assert.assertEquals( "Failed", true, done.get() ); } @Test public void testBufferSizeRestrictions() { final LoggingBuffer buff = new LoggingBuffer( 10 ); Assert.assertEquals( 10, buff.getMaxNrLines() ); Assert.assertEquals( 0, buff.getLastBufferLineNr() ); Assert.assertEquals( 0, buff.getNrLines() ); // Load 20 records. Only last 10 should be kept for ( int i = 1; i <= 20; i++ ) { buff.addLogggingEvent( new KettleLoggingEvent( "Test #" + i + Const.CR + "Hello World!", Long.valueOf( i ), LogLevel.DETAILED ) ); } Assert.assertEquals( 10, buff.getNrLines() ); // Check remaining records, confirm that they are the proper records int i = 11; Iterator<BufferLine> it = buff.getBufferIterator(); Assert.assertNotNull( it ); while ( it.hasNext() ) { BufferLine bl = it.next(); Assert.assertNotNull( bl.getEvent() ); Assert.assertEquals( "Test #" + i + Const.CR + "Hello World!", bl.getEvent().getMessage() ); Assert.assertEquals( Long.valueOf( i ).longValue(), bl.getEvent().getTimeStamp() ); Assert.assertEquals( LogLevel.DETAILED, bl.getEvent().getLevel() ); i++; } Assert.assertEquals( i, 21 ); // Confirm that only 10 lines were iterated over Assert.assertEquals( 0, buff.getBufferLinesBefore( 10L ).size() ); Assert.assertEquals( 5, buff.getBufferLinesBefore( 16L ).size() ); Assert.assertEquals( 10, buff.getBufferLinesBefore( System.currentTimeMillis() ).size() ); buff.clear(); Assert.assertEquals( 0, buff.getNrLines() ); it = buff.getBufferIterator(); Assert.assertNotNull( it ); while ( it.hasNext() ) { Assert.fail( "This should never be reached, as the LogBuffer is empty" ); } } }