/*
* The MIT License
*
* Copyright 2012 Sony Ericsson Mobile Communications. All rights reserved.
* Copyright 2012 Sony Mobile Communications AB. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.sonyericsson.jenkins.plugins.bfa.model;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.SequenceInputStream;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipInputStream;
import com.sonyericsson.jenkins.plugins.bfa.model.indication.BuildLogIndication;
import com.sonyericsson.jenkins.plugins.bfa.model.indication.FoundIndication;
import com.sonyericsson.jenkins.plugins.bfa.model.indication.Indication;
import com.sonyericsson.jenkins.plugins.bfa.model.indication.MultilineBuildLogIndication;
import hudson.model.Run;
import org.junit.Test;
import org.powermock.api.mockito.PowerMockito;
import static junit.framework.TestCase.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
//CS IGNORE MagicNumber FOR NEXT 300 LINES. REASON: TestData.
/**
* Tests for the FailureReader.
*
* @author Claes Elgemark <claes.egemark@sonymobile.com>
*/
public class FailureReaderTest {
/**
* Simple FailureReader used in the tests.
*/
class TestReader extends FailureReader {
/**
* Standard constructor.
* @param indication the indication for the reader
*/
public TestReader(final Indication indication) {
super(indication);
}
@Override
public FoundIndication scan(Run build) throws IOException {
return null;
}
@Override
public FoundIndication scan(Run build, PrintStream buildLog) {
return null;
}
}
/**
* @param indication indication that we are looking for
* @param reader build reader
* @param currentFile current file name
* @return found indication
* @throws IOException Exception
*/
private FoundIndication scan(BuildLogIndication indication,
BufferedReader reader,
String currentFile) throws IOException {
Run run = PowerMockito.mock(Run.class);
List<FailureCause> causes = new ArrayList<FailureCause>();
FailureCause cause = new FailureCause("test", "description");
cause.addIndication(indication);
causes.add(cause);
List<FoundFailureCause> foundFailureCauses = FailureReader.scanSingleLinePatterns(
causes,
run,
reader,
currentFile);
if (foundFailureCauses.isEmpty()) {
return null;
}
assertEquals(1, foundFailureCauses.size());
assertFalse(foundFailureCauses.get(0).getIndications().isEmpty());
return foundFailureCauses.get(0).getIndications().get(0);
}
/**
* Happy test verifying that a scan doesn't take an exceptional amount of time.
* @throws Exception if so
*/
@Test
public void testScanOneFile() throws Exception {
BufferedReader br = new BufferedReader(new StringReader("scan for me please will you!\nA second line"));
long startTime = System.currentTimeMillis();
FoundIndication indication = scan(new BuildLogIndication(".*scan for me please.*"), br, "test");
long elapsedTime = System.currentTimeMillis() - startTime;
br.close();
assertTrue("Unexpected long time to parse log: " + elapsedTime, elapsedTime <= 1000);
assertNotNull("Expected to find an indication", indication);
}
/**
* Test of timeout on abusive line. Should timeout on two lines
* each timeout between 1 and 2 seconds.
* @throws Exception if so
*/
@Test
public void testScanOneFileWithLineTimeout() throws Exception {
InputStream resStream = this.getClass().getResourceAsStream("FailureReaderTest.zip");
ZipInputStream zipStream = new ZipInputStream(resStream);
zipStream.getNextEntry();
BufferedReader br = new QuadrupleDupleLineReader(new BufferedReader(new InputStreamReader(zipStream)));
long startTime = System.currentTimeMillis();
FoundIndication indication = scan(new BuildLogIndication(".*scan for me please.*"), br, "test");
long elapsedTime = System.currentTimeMillis() - startTime;
br.close();
assertTrue("Unexpected time to parse log: " + elapsedTime, elapsedTime >= 1000 && elapsedTime <= 5000);
assertNotNull("Expected to find an indication", indication);
}
/**
* Test of timeout on abusive file. Should timeout on entire scan.
* @throws Exception if so
*/
@Test
public void testScanOneFileWithFileTimeout() throws Exception {
InputStream inStream = new ByteArrayInputStream(new byte[0]);
for (int i = 0; i < 10; i++) {
InputStream resStream = this.getClass().getResourceAsStream("FailureReaderTest.zip");
ZipInputStream zipStream = new ZipInputStream(resStream);
zipStream.getNextEntry();
inStream = new SequenceInputStream(inStream, zipStream);
}
BufferedReader br = new QuadrupleDupleLineReader(new BufferedReader(new InputStreamReader(inStream)));
long startTime = System.currentTimeMillis();
FoundIndication indication = scan(new BuildLogIndication(".*non existing string"), br, "test");
long elapsedTime = System.currentTimeMillis() - startTime;
br.close();
assertTrue("Unexpected time to parse log: " + elapsedTime, elapsedTime >= 10000 && elapsedTime <= 12000);
assertNull("Did not expect to find an indication", indication);
}
/**
* Happy test verifying that a scan doesn't take an exceptional amount of time.
* @throws Exception if so
*/
@Test
public void testScanMultiLineOneFile() throws Exception {
FailureReader reader = new TestReader(new MultilineBuildLogIndication(".*scan for me please.*"));
BufferedReader br = new BufferedReader(new StringReader("scan for me please will you!\nA second line"));
long startTime = System.currentTimeMillis();
FoundIndication indication = reader.scanMultiLineOneFile(null, br, "test");
long elapsedTime = System.currentTimeMillis() - startTime;
br.close();
assertTrue("Unexpected long time to parse log: " + elapsedTime, elapsedTime <= 1000);
assertNotNull("Expected to find an indication", indication);
}
/**
* Test of timeout on abusive line.
* @throws Exception if so
*/
@Test
public void testScanMultiLineOneFileWithBlockTimeout() throws Exception {
// Evil input + expression. Will timeout every time.
FailureReader reader = new TestReader(new MultilineBuildLogIndication("^(([a-z])+.)+[A-Z]([a-z])+$"));
BufferedReader br = new BufferedReader(new InputStreamReader(
new ByteArrayInputStream("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".getBytes())));
long startTime = System.currentTimeMillis();
FoundIndication indication = reader.scanMultiLineOneFile(null, br, "test");
long elapsedTime = System.currentTimeMillis() - startTime;
br.close();
assertTrue("Unexpected time to parse log: " + elapsedTime, elapsedTime <= 5000);
assertNull("Did not expect to find an indication", indication);
}
/**
* Test of timeout on abusive file. Should timeout on entire scan.
* @throws Exception if so
*/
@Test
public void testScanMultilineOneFileWithFileTimeout() throws Exception {
FailureReader reader = new TestReader(new MultilineBuildLogIndication(".*non existing string"));
InputStream inStream = new ByteArrayInputStream(new byte[0]);
for (int i = 0; i < 10; i++) {
InputStream resStream = this.getClass().getResourceAsStream("FailureReaderTest.zip");
ZipInputStream zipStream = new ZipInputStream(resStream);
zipStream.getNextEntry();
inStream = new SequenceInputStream(inStream, zipStream);
}
BufferedReader br = new QuadrupleDupleLineReader(new BufferedReader(new InputStreamReader(inStream)));
long startTime = System.currentTimeMillis();
FoundIndication indication = reader.scanMultiLineOneFile(null, br, "test");
long elapsedTime = System.currentTimeMillis() - startTime;
br.close();
assertTrue("Unexpected time to parse log: " + elapsedTime, elapsedTime <= 12000);
assertNull("Did not expect to find an indication", indication);
}
/**
* Desperate attempt at making a line longer to scan.
* When the readLine method is called it returns the line from the underlying reader
* and constructs the same line 15 times on top of the original.
* This so that the scanning has more to work on and can timeout
*/
static class QuadrupleDupleLineReader extends BufferedReader {
/**
* Standard constructor
*
* @param in internal reader
* @param sz input buffer size.
*
* @see BufferedReader#BufferedReader(java.io.Reader, int)
*/
public QuadrupleDupleLineReader(BufferedReader in, int sz) {
super(in, sz);
}
/**
* Standard constructor.
*
* @param in internal reader.
*
* @see BufferedReader#BufferedReader(java.io.Reader)
*/
public QuadrupleDupleLineReader(BufferedReader in) {
super(in);
}
@Override
public String readLine() throws IOException {
String line = super.readLine();
if (line == null) {
return null;
}
StringBuilder str = new StringBuilder(line);
str.append(line);
str.append(line);
str.append(line);
str.append(line);
str.append(line);
str.append(line);
str.append(line);
str.append(line);
str.append(line);
str.append(line);
str.append(line);
str.append(line);
str.append(line);
str.append(line);
return str.toString();
}
}
}