Skip to content

Commit

Permalink
Added property to configure purge options (#1496)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexNetcare authored Apr 25, 2024
1 parent ffdb4de commit 95693ec
Show file tree
Hide file tree
Showing 10 changed files with 151 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ There are more properties which can be used to tweak parts of FitNesse:
* '''VersionsController.days''' - number of days to keep old page versions around when using the Zip file based versions controller.
* '''test.history.days''' - The number of days to keep test results around. Cleaned up after a new test run.
* '''test.history.path''' - Location to store the test results. The default location is ''!-FitNesseRoot-!/files/testResults''.
* '''TestHistory.purgeOptions''' - A comma separated list of the age, in number of days, to offer as purge options on the ''Test History'' page.
* Any variable that can be defined on a wiki page.

The Slim test system has a set of [[custom properties][<UserGuide.WritingAcceptanceTests.SliM]] that can either be set on a page or in the configuration file.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Every time you run a test or a suite, the results are recorded in the ''test history database''. You can view the history by clicking on the !style_code(Test History) button. The reports are pretty self-explanatory.

When you click on !style_code(Test History) you will be shown the directory of all tests and suites that are in thie ''test history database''. This directory also shows you the status of the last 20 results from each test or suite. You can click on the name of the test or suite to get a detailed ''page history'', or you can click on any of the individual status elements to see the particular test result.
When you click on !style_code(Test History) you will be shown the directory of all tests and suites that are in the ''test history database''. This directory also shows you the status of the last 20 results from each test or suite. You can click on the name of the test or suite to get a detailed ''page history'', or you can click on any of the individual status elements to see the particular test result.

The detailed ''page history'' shows you a directory of all the test results for that test or suite. The bar chart shows how how the number of tests (for suites) or assertions (for tests) has grown over time, and the pass/fail ratio. Clicking on an entry takes you to that specific test result.

Expand All @@ -12,7 +12,7 @@ The test result files are named using the following scheme !style_code(YYYYMMDDH
The test files contain the XML that describes the test run. The format of this XML is identical to the XML packet returned by the format=xml flag when you run a test. (See <UserGuide.RestfulTests).

!4 Purging
There are buttons at the top of the ''Test History'' page that allow you to purge old history files. You have your choice of ''all'', ''>7 days'', or ''>30 days''. If you want to purge a different number of days, you can use the RESTful URL form. (See [[!-RestfulServices-!][<UserGuide.AdministeringFitNesse.RestfulServices]]).
There are buttons at the top of the ''Test History'' page that allow you to purge old history files. You have your choice of ''all'', ''>7 days'', or ''>30 days''. If you want to purge a different number of days, you can change the ''TestHistory.purgeOptions'' in the [[configuration file][<UserGuide.AdministeringFitNesse.ConfigurationFile]] to allow additional purge options, or you can use the RESTful URL form. (See [[!-RestfulServices-!][<UserGuide.AdministeringFitNesse.RestfulServices]]).

You can also clean up the test history right after a test execution. To do so, configure a property ''test.history.days'' in the [[configuration file][<UserGuide.AdministeringFitNesse.ConfigurationFile]] or as a [[page variable][<UserGuide.FitNesseWiki.MarkupLanguageReference.MarkupVariables]] and assign it the number of days you want to keep history.

Expand Down
7 changes: 7 additions & 0 deletions plugins.properties
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,10 @@ CustomComparators=inverse:fitnesse.slim.test.InverseComparator
##
# Number of days to keep history
test.history.days=1

##
# The given list of numbers represent the options offered for purging test histories.
# Test histories older than the given number of days will be deleted.
# The value 0 represents 'Purge all'.
# Enabling the property without setting any value, removes the offered options completely.
#TestHistory.purgeOptions=0,7,30
3 changes: 2 additions & 1 deletion src/fitnesse/ConfigurationParameter.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ public enum ConfigurationParameter {
CONTEXT_ROOT("ContextRoot"),
LOCALHOST_ONLY("LocalhostOnly"),
MAXIMUM_WORKERS("MaximumWorkers"),
THEME("Theme");
THEME("Theme"),
PURGE_OPTIONS("TestHistory.purgeOptions");

private static final Logger LOG = Logger.getLogger(ConfigurationParameter.class.getName());

Expand Down
31 changes: 31 additions & 0 deletions src/fitnesse/resources/javascript/fitnesse.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,37 @@ $(document)
}
});

// When checking purgeGlobal then change the href elements to send true
$(document)
.on('change', '.testHistory #purgeGlobal', function() {
const purgeGlobal = "&purgeGlobal=true";
const elems = $("a[href^='?responder=purgeHistory']");

if (this.checked) {
elems.each((index, link) => {
// Only adjust the href if it was not already adjusted
if (!link.href.includes(purgeGlobal)) {
link.href = link.href.substring(link.href.indexOf("?")) + purgeGlobal;
}
});
} else {
elems.each((index, link) => {
// Only adjust the href if it was adjusted before
if (link.href.includes(purgeGlobal)) {
link.href = link.href.substring(link.href.indexOf("?"), link.href.length - purgeGlobal.length);
}
});
}
});

// When clicking on a purge link then ask before deletion
function purgeConfirmation(event) {
if (!confirm('Are you sure you want to purge the test histories?')) {
event.preventDefault();
return false;
}
}

/**
* Notify user when changing page while test execution is in progress.
*/
Expand Down
11 changes: 8 additions & 3 deletions src/fitnesse/resources/templates/testHistory.vm
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@
#set($noHistory = true)
<div>
<a class="button" href="?responder=overview">View as Overview</a>
<a class="button" href="?responder=purgeHistory&days=30">Purge &gt; 30 days</a>
<a class="button" href="?responder=purgeHistory&days=7">Purge &gt; 7 days</a>
<a class="button" href="?responder=purgeHistory&days=0">Purge all</a>
<a class="button" href="$viewLocation">Cancel</a>
<label for="hidePassedTests"><input type="checkbox" id="hidePassedTests"/>Hide passed tests</label>
</div>
<div>
#if(!$purgeOptions.isEmpty())
#foreach($purgeOption in $purgeOptions)
<a class="button" href="?responder=purgeHistory&days=$purgeOption" onclick="purgeConfirmation(event)">Purge#if ($purgeOption == 0) all#else &gt; $purgeOption days#end</a>
#end
<label for="purgeGlobal"><input type="checkbox" id="purgeGlobal" />Purge global</label>
#end
</div>

<table>
<tr>
Expand Down
22 changes: 19 additions & 3 deletions src/fitnesse/responders/testHistory/PurgeHistoryResponder.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.io.File;

import org.apache.commons.lang3.StringUtils;

import fitnesse.FitNesseContext;
import fitnesse.authentication.AlwaysSecureOperation;
import fitnesse.authentication.SecureOperation;
Expand All @@ -11,6 +13,7 @@
import fitnesse.http.SimpleResponse;
import fitnesse.reporting.history.HistoryPurger;
import fitnesse.responders.ErrorResponder;
import fitnesse.wiki.WikiPagePath;

public class PurgeHistoryResponder implements SecureResponder {

Expand All @@ -31,13 +34,26 @@ private SimpleResponse makeValidResponse() {
}

private void purgeHistory(Request request, FitNesseContext context) {
WikiPagePath currentPath = new WikiPagePath(request.getResource().split("\\."));
String purgeGlobalInput = request.getInput("purgeGlobal");

File resultsDirectory = context.getTestHistoryDirectory();
int days = getDaysInput(request);
deleteTestHistoryOlderThanDays(resultsDirectory, days);
// If purgeGlobal is not set then only delete current path
if (StringUtils.isBlank(purgeGlobalInput) || !Boolean.parseBoolean(purgeGlobalInput)) {
deleteTestHistoryOlderThanDays(resultsDirectory, days, currentPath);
} else {
deleteTestHistoryOlderThanDays(resultsDirectory, days, null);
}
}

public void deleteTestHistoryOlderThanDays(File resultsDirectory, int days) {
new HistoryPurger(resultsDirectory, days).deleteTestHistoryOlderThanDays();
public void deleteTestHistoryOlderThanDays(File resultsDirectory, int days, WikiPagePath path) {
HistoryPurger historyPurger = new HistoryPurger(resultsDirectory, days);
if (path != null) {
historyPurger.deleteTestHistoryOlderThanDays(path);
} else {
historyPurger.deleteTestHistoryOlderThanDays();
}
}

private Integer getDaysInput(Request request) {
Expand Down
17 changes: 17 additions & 0 deletions src/fitnesse/responders/testHistory/TestHistoryResponder.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@

import fitnesse.reporting.history.TestHistory;
import fitnesse.wiki.PathParser;

import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.VelocityContext;

import fitnesse.ConfigurationParameter;
import fitnesse.FitNesseContext;
import fitnesse.authentication.SecureOperation;
import fitnesse.authentication.SecureReadOperation;
Expand Down Expand Up @@ -43,12 +46,26 @@ private Response makeTestHistoryResponse(TestHistory testHistory, Request reques
page.setNavTemplate("viewNav");
page.put("viewLocation", request.getResource());
page.put("testHistory", testHistory);
page.put("purgeOptions", getPurgeOptions());
page.setMainTemplate("testHistory");
SimpleResponse response = new SimpleResponse();
response.setContent(page.html(request));
return response;
}

private String[] getPurgeOptions() {
String configuredPurgeOptions = context.getProperties().getProperty(ConfigurationParameter.PURGE_OPTIONS.getKey());
String[] purgeOptionsForPage;
if(configuredPurgeOptions == null) {
purgeOptionsForPage = new String[] { "0", "7", "30" };
} else if (configuredPurgeOptions.isBlank()) {
purgeOptionsForPage = new String[0];
} else {
purgeOptionsForPage = configuredPurgeOptions.split(",");
}
return purgeOptionsForPage;
}

private Response makeTestHistoryXmlResponse(TestHistory history) throws UnsupportedEncodingException {
SimpleResponse response = new SimpleResponse();
VelocityContext velocityContext = new VelocityContext();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
import fitnesse.http.Response;
import fitnesse.http.SimpleResponse;
import fitnesse.testutil.FitNesseUtil;
import fitnesse.wiki.WikiPagePath;

import org.junit.After;
import static org.junit.Assert.*;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import org.junit.Before;
import org.junit.Test;
import util.FileUtil;
Expand Down Expand Up @@ -50,6 +53,7 @@ private void removeResultsDirectory() throws IOException {
public void shouldDeleteHistoryFromRequestAndRedirect() throws Exception {
StubbedPurgeHistoryResponder responder = new StubbedPurgeHistoryResponder();
request.addInput("days", "30");
request.addInput("purgeGlobal", "true");
SimpleResponse response = (SimpleResponse) responder.makeResponse(context, request);
assertEquals(30, responder.daysDeleted);
assertEquals(303, response.getStatus());
Expand All @@ -68,14 +72,35 @@ public void shouldMakeErrorResponseWhenItGetsInvalidTypeForNumberOfDays() throws
request.addInput("days", "bob");
Response response = responder.makeResponse(context, request);
assertEquals(400, response.getStatus());
}

@Test
public void shouldDeleteHistoryFromRequestForWikiPathWhenPurgeGlobalNotSet() throws Exception {
assertThatPurgeGlobalIsNotUsed();
}

@Test
public void shouldDeleteHistoryFromRequestForWikiPathWhenPurgeGlobalFalse() throws Exception {
request.addInput("purgeGlobal", "false");
assertThatPurgeGlobalIsNotUsed();
}

private void assertThatPurgeGlobalIsNotUsed() throws Exception {
request.addInput("days", "0");
StubbedPurgeHistoryResponder responderSpy = spy(new StubbedPurgeHistoryResponder());
WikiPagePath expectedPath = new WikiPagePath(request.getResource().split("\\."));

SimpleResponse response = (SimpleResponse) responderSpy.makeResponse(context, request);
assertEquals(303, response.getStatus());
assertEquals("?testHistory", response.getHeader("Location"));
verify(responderSpy).deleteTestHistoryOlderThanDays(resultsDirectory, 0, expectedPath);
}

private static class StubbedPurgeHistoryResponder extends PurgeHistoryResponder {
public int daysDeleted = -1;

@Override
public void deleteTestHistoryOlderThanDays(File resultsDirectory, int days) {
public void deleteTestHistoryOlderThanDays(File resultsDirectory, int days, WikiPagePath path) {
daysDeleted = days;
}
}
Expand Down
38 changes: 38 additions & 0 deletions test/fitnesse/responders/testHistory/TestHistoryResponderTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package fitnesse.responders.testHistory;

import fitnesse.ConfigurationParameter;
import fitnesse.FitNesseContext;
import fitnesse.http.MockRequest;
import fitnesse.http.SimpleResponse;
Expand Down Expand Up @@ -27,6 +28,8 @@
import static org.junit.Assert.assertTrue;
import static util.RegexTestCase.assertDoesntHaveRegexp;
import static util.RegexTestCase.assertHasRegexp;
import static util.RegexTestCase.assertNotSubString;
import static util.RegexTestCase.assertSubString;

public class TestHistoryResponderTest {
private File resultsDirectory;
Expand Down Expand Up @@ -340,4 +343,39 @@ public void shouldntBeCaseSensitiveForXMLRequest() throws Exception {
response = (SimpleResponse) responder.makeResponse(context, request);
assertHasRegexp("text/xml", response.getContentType());
}

@Test
public void shouldShowDefaultPurgeOptions() throws Exception {
MockRequest request = new MockRequest();
SimpleResponse response = (SimpleResponse) new TestHistoryResponder().makeResponse(context, request);
String html = response.getContent();
assertSubString("<a class=\"button\" href=\"?responder=purgeHistory&days=0\" onclick=\"purgeConfirmation(event)\">Purge all</a>", html);
assertSubString("<a class=\"button\" href=\"?responder=purgeHistory&days=7\" onclick=\"purgeConfirmation(event)\">Purge &gt; 7 days</a>", html);
assertSubString("<a class=\"button\" href=\"?responder=purgeHistory&days=30\" onclick=\"purgeConfirmation(event)\">Purge &gt; 30 days</a>", html);
assertSubString("<label for=\"purgeGlobal\"><input type=\"checkbox\" id=\"purgeGlobal\" />Purge global</label>", html);
}

@Test
public void shouldShowConfiguredPurgeOptions() throws Exception {
MockRequest request = new MockRequest();
context.getProperties().setProperty(ConfigurationParameter.PURGE_OPTIONS.getKey(), "30,60,90");
SimpleResponse response = (SimpleResponse) new TestHistoryResponder().makeResponse(context, request);
String html = response.getContent();
assertNotSubString("<a class=\"button\" href=\"?responder=purgeHistory&days=0\" onclick=\"purgeConfirmation(event)\">Purge all</a>", html);
assertSubString("<a class=\"button\" href=\"?responder=purgeHistory&days=30\" onclick=\"purgeConfirmation(event)\">Purge &gt; 30 days</a>", html);
assertSubString("<a class=\"button\" href=\"?responder=purgeHistory&days=60\" onclick=\"purgeConfirmation(event)\">Purge &gt; 60 days</a>", html);
assertSubString("<a class=\"button\" href=\"?responder=purgeHistory&days=90\" onclick=\"purgeConfirmation(event)\">Purge &gt; 90 days</a>", html);
assertSubString("<label for=\"purgeGlobal\"><input type=\"checkbox\" id=\"purgeGlobal\" />Purge global</label>", html);
}

@Test
public void shouldShowNoPurgeOptions() throws Exception {
MockRequest request = new MockRequest();
context.getProperties().setProperty(ConfigurationParameter.PURGE_OPTIONS.getKey(), "");
SimpleResponse response = (SimpleResponse) new TestHistoryResponder().makeResponse(context, request);
String html = response.getContent();
assertNotSubString("<a class=\"button\" href=\"?responder=purgeHistory&days=0\" onclick=\"purgeConfirmation(event)\">Purge all</a>", html);
assertNotSubString("<a class=\"button\" href=\"?responder=purgeHistory&days=7\" onclick=\"purgeConfirmation(event)\">Purge &gt; 7 days</a>", html);
assertNotSubString("<label for=\"purgeGlobal\"><input type=\"checkbox\" id=\"purgeGlobal\" />Purge global</label>", html);
}
}

0 comments on commit 95693ec

Please sign in to comment.