From 0f638d8d0a85f61be2cb44d1bf9f8893b1504121 Mon Sep 17 00:00:00 2001 From: Weiller Carvalho Date: Mon, 17 Nov 2025 16:37:51 -0300 Subject: [PATCH 1/2] RandomDate: include end date and handle single-day ranges --- .../apache/jmeter/functions/RandomDate.java | 11 ++++- .../functions/TestTimeRandomDateFunction.java | 42 +++++++++++++++---- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/functions/src/main/java/org/apache/jmeter/functions/RandomDate.java b/src/functions/src/main/java/org/apache/jmeter/functions/RandomDate.java index fcf90aa9dea..f14e8d277a4 100644 --- a/src/functions/src/main/java/org/apache/jmeter/functions/RandomDate.java +++ b/src/functions/src/main/java/org/apache/jmeter/functions/RandomDate.java @@ -189,7 +189,7 @@ public String execute(SampleResult previousResult, Sampler currentSampler) throw if (localEndDate < localStartDate) { log.error("End Date '{}' must be greater than Start Date '{}'", dateEnd, dateStart); // $NON-NLS-1$ } else { - long randomDay = ThreadLocalRandom.current().nextLong(localStartDate, localEndDate); + long randomDay = pickRandomDay(localStartDate, localEndDate); try { dateString = LocalDate.ofEpochDay(randomDay).format(formatter); } catch (DateTimeParseException | NumberFormatException ex) { @@ -200,6 +200,15 @@ public String execute(SampleResult previousResult, Sampler currentSampler) throw return dateString; } + private static long pickRandomDay(long startInclusive, long endInclusive) { + if (startInclusive == endInclusive) { + return startInclusive; + } + long exclusiveUpperBound = Math.incrementExact(endInclusive); + return ThreadLocalRandom.current() + .nextLong(startInclusive, exclusiveUpperBound); + } + @SuppressWarnings("JavaTimeDefaultTimeZone") private static DateTimeFormatter createFormatter(LocaleFormatObject format) { log.debug("Create a new instance of DateTimeFormatter for format '{}' in the cache", format); diff --git a/src/functions/src/test/java/org/apache/jmeter/functions/TestTimeRandomDateFunction.java b/src/functions/src/test/java/org/apache/jmeter/functions/TestTimeRandomDateFunction.java index 95de9d93847..78206d709ac 100644 --- a/src/functions/src/test/java/org/apache/jmeter/functions/TestTimeRandomDateFunction.java +++ b/src/functions/src/test/java/org/apache/jmeter/functions/TestTimeRandomDateFunction.java @@ -69,7 +69,7 @@ void testDefault() throws Exception { LocalDate result = LocalDate.parse(value, formatter); LocalDate now = LocalDate.now(ZoneId.systemDefault()); LocalDate max = LocalDate.parse(endDate, formatter); - Assertions.assertTrue(now.isBefore(result) && result.isBefore(max)); + Assertions.assertTrue(!result.isBefore(now) && !result.isAfter(max)); } @Test @@ -92,7 +92,7 @@ void testFormatDate() throws Exception { LocalDate result = LocalDate.parse(value, formatter); LocalDate now = LocalDate.now(ZoneId.systemDefault()); LocalDate max = LocalDate.parse(endDate, formatter); - Assertions.assertTrue(now.isBefore(result) && result.isBefore(max)); + Assertions.assertTrue(!result.isBefore(now) && !result.isAfter(max)); } @Test @@ -114,7 +114,7 @@ void testFormatDate3() throws Exception { Collection params = makeParams(formatDate, startDate, endDate, localeAsString, ""); function.setParameters(params); value = function.execute(result, null); - assertEquals("29 Aug 2111", value); + Assertions.assertTrue(startDate.equals(value) || endDate.equals(value)); } @Test @@ -126,7 +126,7 @@ void testFrenchFormatDate() throws Exception { Collection params = makeParams(formatDate, startDate, endDate, localeAsString, ""); function.setParameters(params); value = function.execute(result, null); - assertEquals("29 mars 2111", value); + Assertions.assertTrue(startDate.equals(value) || endDate.equals(value)); } @Test @@ -138,7 +138,33 @@ void testEmptyFormatDate() throws Exception { Collection params = makeParams(formatDate, startDate, endDate, localeAsString, ""); function.setParameters(params); value = function.execute(result, null); - assertEquals("2111-03-29", value); + Assertions.assertTrue(startDate.equals(value) || endDate.equals(value)); + } + + @Test + void testSameStartAndEndDateReturnsSameValue() throws Exception { + String date = "2111-03-29"; + Collection params = makeParams("yyyy-MM-dd", date, date, "", "MY_VAR"); + function.setParameters(params); + value = function.execute(result, null); + assertEquals(date, value); + assertEquals(date, vars.get("MY_VAR")); + } + + @Test + void testEndDateCanBeReturned() throws Exception { + String startDate = "2111-03-29"; + String endDate = "2111-03-30"; + Collection params = makeParams("yyyy-MM-dd", startDate, endDate, "", ""); + function.setParameters(params); + boolean sawEndDate = false; + for (int i = 0; i < 200 && !sawEndDate; i++) { + value = function.execute(result, null); + if (endDate.equals(value)) { + sawEndDate = true; + } + } + Assertions.assertTrue(sawEndDate, "RandomDate never returned the configured end date"); } @Test @@ -162,7 +188,7 @@ void testEndDateBeforeStartDateNullVariable() throws Exception { Collection params = makeParams(formatDate, startDate, endDate, localeAsString, null); function.setParameters(params); value = function.execute(result, null); - assertEquals("2111-03-29", value); + Assertions.assertTrue(startDate.equals(value) || endDate.equals(value)); } @Test @@ -174,8 +200,8 @@ void testEndDateBeforeStartDateWithVariable() throws Exception { Collection params = makeParams(formatDate, startDate, endDate, localeAsString, "MY_VAR"); function.setParameters(params); value = function.execute(result, null); - assertEquals("2111-03-29", value); - assertEquals("2111-03-29", vars.get("MY_VAR")); + Assertions.assertTrue(startDate.equals(value) || endDate.equals(value)); + assertEquals(value, vars.get("MY_VAR")); } @Test From 9175372f066b4c593ba681dd471120d68ca50ebc Mon Sep 17 00:00:00 2001 From: Weiller Carvalho Date: Wed, 19 Nov 2025 11:23:36 -0300 Subject: [PATCH 2/2] RandomDate: align range semantics with __Random --- .../apache/jmeter/functions/RandomDate.java | 7 ++-- .../functions/TestTimeRandomDateFunction.java | 32 +++++-------------- xdocs/changes.xml | 5 +++ xdocs/usermanual/functions.xml | 4 +-- 4 files changed, 18 insertions(+), 30 deletions(-) diff --git a/src/functions/src/main/java/org/apache/jmeter/functions/RandomDate.java b/src/functions/src/main/java/org/apache/jmeter/functions/RandomDate.java index f14e8d277a4..7e5c548df84 100644 --- a/src/functions/src/main/java/org/apache/jmeter/functions/RandomDate.java +++ b/src/functions/src/main/java/org/apache/jmeter/functions/RandomDate.java @@ -200,13 +200,12 @@ public String execute(SampleResult previousResult, Sampler currentSampler) throw return dateString; } - private static long pickRandomDay(long startInclusive, long endInclusive) { - if (startInclusive == endInclusive) { + private static long pickRandomDay(long startInclusive, long endExclusive) { + if (startInclusive == endExclusive) { return startInclusive; } - long exclusiveUpperBound = Math.incrementExact(endInclusive); return ThreadLocalRandom.current() - .nextLong(startInclusive, exclusiveUpperBound); + .nextLong(startInclusive, endExclusive); } @SuppressWarnings("JavaTimeDefaultTimeZone") diff --git a/src/functions/src/test/java/org/apache/jmeter/functions/TestTimeRandomDateFunction.java b/src/functions/src/test/java/org/apache/jmeter/functions/TestTimeRandomDateFunction.java index 78206d709ac..eb951267fcb 100644 --- a/src/functions/src/test/java/org/apache/jmeter/functions/TestTimeRandomDateFunction.java +++ b/src/functions/src/test/java/org/apache/jmeter/functions/TestTimeRandomDateFunction.java @@ -69,7 +69,7 @@ void testDefault() throws Exception { LocalDate result = LocalDate.parse(value, formatter); LocalDate now = LocalDate.now(ZoneId.systemDefault()); LocalDate max = LocalDate.parse(endDate, formatter); - Assertions.assertTrue(!result.isBefore(now) && !result.isAfter(max)); + Assertions.assertTrue(!result.isBefore(now) && result.isBefore(max)); } @Test @@ -92,7 +92,7 @@ void testFormatDate() throws Exception { LocalDate result = LocalDate.parse(value, formatter); LocalDate now = LocalDate.now(ZoneId.systemDefault()); LocalDate max = LocalDate.parse(endDate, formatter); - Assertions.assertTrue(!result.isBefore(now) && !result.isAfter(max)); + Assertions.assertTrue(!result.isBefore(now) && result.isBefore(max)); } @Test @@ -114,7 +114,7 @@ void testFormatDate3() throws Exception { Collection params = makeParams(formatDate, startDate, endDate, localeAsString, ""); function.setParameters(params); value = function.execute(result, null); - Assertions.assertTrue(startDate.equals(value) || endDate.equals(value)); + assertEquals("29 Aug 2111", value); } @Test @@ -126,7 +126,7 @@ void testFrenchFormatDate() throws Exception { Collection params = makeParams(formatDate, startDate, endDate, localeAsString, ""); function.setParameters(params); value = function.execute(result, null); - Assertions.assertTrue(startDate.equals(value) || endDate.equals(value)); + assertEquals("29 mars 2111", value); } @Test @@ -138,7 +138,7 @@ void testEmptyFormatDate() throws Exception { Collection params = makeParams(formatDate, startDate, endDate, localeAsString, ""); function.setParameters(params); value = function.execute(result, null); - Assertions.assertTrue(startDate.equals(value) || endDate.equals(value)); + assertEquals("2111-03-29", value); } @Test @@ -151,22 +151,6 @@ void testSameStartAndEndDateReturnsSameValue() throws Exception { assertEquals(date, vars.get("MY_VAR")); } - @Test - void testEndDateCanBeReturned() throws Exception { - String startDate = "2111-03-29"; - String endDate = "2111-03-30"; - Collection params = makeParams("yyyy-MM-dd", startDate, endDate, "", ""); - function.setParameters(params); - boolean sawEndDate = false; - for (int i = 0; i < 200 && !sawEndDate; i++) { - value = function.execute(result, null); - if (endDate.equals(value)) { - sawEndDate = true; - } - } - Assertions.assertTrue(sawEndDate, "RandomDate never returned the configured end date"); - } - @Test void testEndDateBeforeStartDate() throws Exception { String startDate = "2111-03-29"; @@ -188,7 +172,7 @@ void testEndDateBeforeStartDateNullVariable() throws Exception { Collection params = makeParams(formatDate, startDate, endDate, localeAsString, null); function.setParameters(params); value = function.execute(result, null); - Assertions.assertTrue(startDate.equals(value) || endDate.equals(value)); + assertEquals("2111-03-29", value); } @Test @@ -200,8 +184,8 @@ void testEndDateBeforeStartDateWithVariable() throws Exception { Collection params = makeParams(formatDate, startDate, endDate, localeAsString, "MY_VAR"); function.setParameters(params); value = function.execute(result, null); - Assertions.assertTrue(startDate.equals(value) || endDate.equals(value)); - assertEquals(value, vars.get("MY_VAR")); + assertEquals("2111-03-29", value); + assertEquals("2111-03-29", vars.get("MY_VAR")); } @Test diff --git a/xdocs/changes.xml b/xdocs/changes.xml index 17d8185c337..72d04be1221 100644 --- a/xdocs/changes.xml +++ b/xdocs/changes.xml @@ -76,6 +76,11 @@ Summary
  • 5891Skip Internet Explorer 6-9 conditional comment processing when fetching resource links
  • +

    Functions

    +
      +
    • __RandomDate now handles identical start and end dates without throwing an exception while preserving Java-like semantics (start inclusive, end exclusive).
    • +
    + Thanks diff --git a/xdocs/usermanual/functions.xml b/xdocs/usermanual/functions.xml index 5e4078ea48c..1d89d17db3b 100644 --- a/xdocs/usermanual/functions.xml +++ b/xdocs/usermanual/functions.xml @@ -672,7 +672,7 @@ the comma after 7 is escaped. Format string for DateTimeFormatter (default yyyy-MM-dd) The start date, the default is now - The end date + The end date (exclusive). Add one day if you need the specified date to appear in the output. The string format of a locale. The language code must be lowercase. The country code must be uppercase. The separator must be an underscore, e.g. en_EN. See http://www.oracle.com/technetwork/java/javase/javase7locales-334809.html. @@ -682,7 +682,7 @@ the comma after 7 is escaped.

    Examples: -${__RandomDate(,,2050-07-08,,)} will return a random date between now and 2050-07-08. For example 2039-06-21
    +${__RandomDate(,,2050-07-08,,)} will return a random date between now (inclusive) and 2050-07-08 (exclusive). For example 2039-06-21
    ${__RandomDate(dd MM yyyy,,08 07 2050,,)} will return a random date with a custom format like 04 03 2034