From ea1e17f5e6a6c6c2b699b4477a15e8bdefe066d2 Mon Sep 17 00:00:00 2001 From: sirivarma Date: Sun, 9 Mar 2025 00:07:42 -0800 Subject: [PATCH 01/30] Add jobs Signed-off-by: sirivarma --- pom.xml | 1 + sdk-jobs/pom.xml | 133 +++++++++ .../jobs/client/CronExpressionBuilder.java | 234 ++++++++++++++++ .../java/io/dapr/jobs/client/CronPeriod.java | 16 ++ .../java/io/dapr/jobs/client/DayOfWeek.java | 22 ++ .../io/dapr/jobs/client/JobsSchedule.java | 73 +++++ .../java/io/dapr/jobs/client/MonthOfYear.java | 27 ++ .../dapr/jobs/CronExpressionBuilderTest.java | 253 ++++++++++++++++++ 8 files changed, 759 insertions(+) create mode 100644 sdk-jobs/pom.xml create mode 100644 sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java create mode 100644 sdk-jobs/src/main/java/io/dapr/jobs/client/CronPeriod.java create mode 100644 sdk-jobs/src/main/java/io/dapr/jobs/client/DayOfWeek.java create mode 100644 sdk-jobs/src/main/java/io/dapr/jobs/client/JobsSchedule.java create mode 100644 sdk-jobs/src/main/java/io/dapr/jobs/client/MonthOfYear.java create mode 100644 sdk-jobs/test/test/io/dapr/jobs/CronExpressionBuilderTest.java diff --git a/pom.xml b/pom.xml index 729eb0a71b..1c1b569ec5 100644 --- a/pom.xml +++ b/pom.xml @@ -507,6 +507,7 @@ spring-boot-examples testcontainers-dapr + sdk-jobs diff --git a/sdk-jobs/pom.xml b/sdk-jobs/pom.xml new file mode 100644 index 0000000000..6f10b61412 --- /dev/null +++ b/sdk-jobs/pom.xml @@ -0,0 +1,133 @@ + + 4.0.0 + + + io.dapr + dapr-sdk-parent + 1.15.0-SNAPSHOT + + + dapr-sdk-jobs + jar + 0.15.0-SNAPSHOT + dapr-sdk-jobs + SDK for Jobs on Dapr + + + false + + + + + io.dapr + dapr-sdk + ${project.parent.version} + + + io.dapr + dapr-sdk-autogen + 1.15.0-SNAPSHOT + + + org.mockito + mockito-core + test + + + org.mockito + mockito-inline + 4.2.0 + test + + + org.junit.jupiter + junit-jupiter + test + + + org.junit.vintage + junit-vintage-engine + 5.7.0 + test + + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.1 + + + attach-sources + + jar-no-fork + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.2.0 + + + attach-javadocs + + jar + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.11 + + + default-prepare-agent + + prepare-agent + + + + report + test + + report + + + target/jacoco-report/ + + + + check + + check + + + + + BUNDLE + + + LINE + COVEREDRATIO + 80% + + + + + + + + + + + + diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java new file mode 100644 index 0000000000..00fd1b24eb --- /dev/null +++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java @@ -0,0 +1,234 @@ +package io.dapr.jobs.client; + +import java.util.ArrayList; +import java.util.List; + +public class CronExpressionBuilder { + + private final List seconds; + private final List minutes; + private final List hours; + private final List dayOfMonth; + private final List dayOfWeek; + private final List monthOfYear; + + public CronExpressionBuilder() { + this.seconds = new ArrayList<>(); + this.minutes = new ArrayList<>(); + this.hours = new ArrayList<>(); + this.dayOfMonth = new ArrayList<>(); + this.dayOfWeek = new ArrayList<>(); + this.monthOfYear = new ArrayList<>(); + } + + /** + * Convert to cron expression depending on period and values. + * + * @param cronPeriod {@link CronPeriod}. + * @param values for the cronPeriod. + * @return this. + */ + public CronExpressionBuilder add(CronPeriod cronPeriod, Integer... values) { + throwIfNull(cronPeriod); + throwIfNull(values); + + StringBuilder builder = new StringBuilder(); + for (Integer value: values) { + throwIfNull(value); + validatePeriod(cronPeriod, value); + builder.append(value).append(","); + } + + addToPeriod(cronPeriod, builder.deleteCharAt(builder.length() - 1).toString()); + + return this; + } + + public CronExpressionBuilder add(MonthOfYear... values) { + throwIfNull(values); + + StringBuilder builder = new StringBuilder(); + for (MonthOfYear value: values) { + throwIfNull(value); + builder.append(value).append(","); + } + + addToPeriod(CronPeriod.MonthOfYear, builder.deleteCharAt(builder.length() - 1).toString()); + + return this; + } + + public CronExpressionBuilder add(DayOfWeek... values) { + throwIfNull(values); + + StringBuilder builder = new StringBuilder(); + for (DayOfWeek value: values) { + throwIfNull(value); + builder.append(value).append(","); + } + + addToPeriod(CronPeriod.DayOfWeek, builder.deleteCharAt(builder.length() - 1).toString()); + + return this; + } + + public CronExpressionBuilder addRange(CronPeriod period, int from, int to) { + throwIfNull(period); + validateRange(from, to); + validatePeriod(period, from); + validatePeriod(period, to); + + addToPeriod(period, from + "-" + to); + + return this; + } + + public CronExpressionBuilder addRange(DayOfWeek from, DayOfWeek to) { + throwIfNull(from); + throwIfNull(to); + validateRange(from.getValue(), to.getValue()); + + addToPeriod(CronPeriod.DayOfWeek, from + "-" + to); + return this; + } + + public CronExpressionBuilder addRange(MonthOfYear from, MonthOfYear to) { + throwIfNull(from); + throwIfNull(to); + + addToPeriod(CronPeriod.MonthOfYear, from + "-" + to); + return this; + } + + public CronExpressionBuilder addStepRange(CronPeriod period, int from, int to, int denominator) { + throwIfNull(period); + validateRange(from, to); + validatePeriod(period, denominator); + + addToPeriod(period, from + "-" + to + "/" + denominator); + return this; + } + + public CronExpressionBuilder addStep(CronPeriod period, int numerator, int denominator) { + throwIfNull(period); + validatePeriod(period, numerator); + validatePeriod(period, denominator); + + addToPeriod(period, numerator + "/" + denominator); + return this; + } + + public CronExpressionBuilder addStep(CronPeriod period, int denominator) { + throwIfNull(period); + validatePeriod(period, denominator); + + addToPeriod(period, "*/" + denominator); + return this; + } + + public String build() { + + if (this.monthOfYear.isEmpty()) { + this.monthOfYear.add("*"); + } + + if (this.dayOfWeek.isEmpty()) { + this.dayOfWeek.add("*"); + } + + if (this.seconds.isEmpty()) { + this.seconds.add("*"); + } + + if (this.minutes.isEmpty()) { + this.minutes.add("*"); + } + + if (this.hours.isEmpty()) { + this.hours.add("*"); + } + + if (this.dayOfMonth.isEmpty()) { + this.dayOfMonth.add("*"); + } + + StringBuilder cronExpression = new StringBuilder(); + cronExpression.append(String.join(",", this.seconds)).append(" "); + cronExpression.append(String.join(",", this.minutes)).append(" "); + cronExpression.append(String.join(",", this.hours)).append(" "); + cronExpression.append(String.join(",", this.dayOfMonth)).append(" "); + cronExpression.append(String.join(",", this.monthOfYear)).append(" "); + cronExpression.append(String.join(",", this.dayOfWeek)); + + return cronExpression.toString(); + } + + private void validatePeriod(CronPeriod cronPeriod, int value) { + switch (cronPeriod) { + case SECONDS: + case MINUTES: + if (value < 0 || value > 59) { + throw new IllegalArgumentException(cronPeriod + " must be between [0, 59] inclusive"); + } + break; + case HOURS: + if (value < 0 || value > 23) { + throw new IllegalArgumentException(cronPeriod + " must be between [0, 23] inclusive"); + } + break; + case DayOfMonth: + if (value < 1 || value > 31) { + throw new IllegalArgumentException(cronPeriod + " must be between [1, 31] inclusive"); + } + break; + case MonthOfYear: + if (value < 1 || value > 12) { + throw new IllegalArgumentException(cronPeriod + " must be between [1, 12] inclusive"); + } + break; + case DayOfWeek: + if (value < 0 || value > 6) { + throw new IllegalArgumentException(cronPeriod + " must be between [0, 6] inclusive"); + } + break; + default: throw new IllegalArgumentException("Invalid CronPeriod: " + cronPeriod); + } + } + + private void validateRange(int from, int to) { + if (from > to || from == to) { + throw new IllegalArgumentException("from must be before to (from < to)"); + } + } + + private void addToPeriod(CronPeriod cronPeriod, String value) { + switch (cronPeriod) { + case SECONDS: + this.seconds.add(value); + break; + case MINUTES: + this.minutes.add(value); + break; + case HOURS: + this.hours.add(value); + break; + case DayOfMonth: + this.dayOfMonth.add(value); + break; + case MonthOfYear: + this.monthOfYear.add(value); + break; + case DayOfWeek: + this.dayOfWeek.add(value); + break; + default: + throw new IllegalArgumentException("Invalid CronPeriod: " + cronPeriod); + } + } + + private void throwIfNull(Object obj) { + if (obj == null) { + throw new IllegalArgumentException("None of the parameters can be null"); + } + } +} \ No newline at end of file diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/CronPeriod.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/CronPeriod.java new file mode 100644 index 0000000000..b58b8a6454 --- /dev/null +++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/CronPeriod.java @@ -0,0 +1,16 @@ +package io.dapr.jobs.client; + +public enum CronPeriod { + + SECONDS, + + MINUTES, + + HOURS, + + DayOfMonth, + + MonthOfYear, + + DayOfWeek, +} diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/DayOfWeek.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/DayOfWeek.java new file mode 100644 index 0000000000..ff3a1d705c --- /dev/null +++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/DayOfWeek.java @@ -0,0 +1,22 @@ +package io.dapr.jobs.client; + +public enum DayOfWeek { + + SUN(0), + MON(1), + TUE(2), + WED(3), + THU(4), + FRI(5), + SAT(6); + + private final int value; + + private DayOfWeek(int value) { + this.value = value; + } + + int getValue() { + return this.value; + } +} \ No newline at end of file diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/JobsSchedule.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/JobsSchedule.java new file mode 100644 index 0000000000..b602b92886 --- /dev/null +++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/JobsSchedule.java @@ -0,0 +1,73 @@ +package io.dapr.jobs.client; + +import java.time.Duration; + +public class JobsSchedule { + + private final String expression; + + private JobsSchedule(String expression) { + this.expression = expression; + } + + public static JobsSchedule fromPeriod(Duration duration) { + if (duration == null) { + throw new IllegalArgumentException("duration cannot be null"); + } + + String formattedDuration = String.format("%dh%dm%ds%dms", + duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart(), duration.toMillisPart()); + return new JobsSchedule("@every " + formattedDuration); + } + + public static JobsSchedule fromString(String cronExpression) { + return new JobsSchedule(cronExpression); + } + + public static JobsSchedule yearly() { + return new JobsSchedule(new CronExpressionBuilder() + .add(CronPeriod.SECONDS, 0) + .add(CronPeriod.MINUTES, 0) + .add(CronPeriod.HOURS, 0) + .add(CronPeriod.DayOfMonth, 1) + .add(CronPeriod.MonthOfYear, 1) + .build()); + } + + public static JobsSchedule monthly() { + return new JobsSchedule(new CronExpressionBuilder() + .add(CronPeriod.SECONDS, 0) + .add(CronPeriod.MINUTES, 0) + .add(CronPeriod.HOURS, 0) + .add(CronPeriod.DayOfMonth, 1) + .build()); + } + + public static JobsSchedule weekly() { + return new JobsSchedule(new CronExpressionBuilder() + .add(CronPeriod.SECONDS, 0) + .add(CronPeriod.MINUTES, 0) + .add(CronPeriod.HOURS, 0) + .add(CronPeriod.DayOfWeek, 0) + .build()); + } + + public static JobsSchedule daily() { + return new JobsSchedule(new CronExpressionBuilder() + .add(CronPeriod.SECONDS, 0) + .add(CronPeriod.MINUTES, 0) + .add(CronPeriod.HOURS, 0) + .build()); + } + + public static JobsSchedule hourly() { + return new JobsSchedule(new CronExpressionBuilder() + .add(CronPeriod.SECONDS, 0) + .add(CronPeriod.MINUTES, 0) + .build()); + } + + public String getExpression() { + return this.expression; + } +} diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/MonthOfYear.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/MonthOfYear.java new file mode 100644 index 0000000000..d9def02d68 --- /dev/null +++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/MonthOfYear.java @@ -0,0 +1,27 @@ +package io.dapr.jobs.client; + +public enum MonthOfYear { + + JAN(1), + FEB(2), + MAR(3), + APR(4), + MAY(5), + JUN(6), + JUL(7), + AUG(8), + SEP(9), + OCT(10), + NOV(11), + DEC(12); + + private final int value; + + MonthOfYear(int value) { + this.value = value; + } + + int getValue() { + return this.value; + } +} \ No newline at end of file diff --git a/sdk-jobs/test/test/io/dapr/jobs/CronExpressionBuilderTest.java b/sdk-jobs/test/test/io/dapr/jobs/CronExpressionBuilderTest.java new file mode 100644 index 0000000000..6a30925355 --- /dev/null +++ b/sdk-jobs/test/test/io/dapr/jobs/CronExpressionBuilderTest.java @@ -0,0 +1,253 @@ +package io.dapr.jobs; + +import io.dapr.jobs.client.CronExpressionBuilder; +import io.dapr.jobs.client.CronPeriod; +import io.dapr.jobs.client.DayOfWeek; +import io.dapr.jobs.client.MonthOfYear; +import org.junit.Assert; +import org.junit.Test; + +public class CronExpressionBuilderTest { + + @Test + public void builderWithoutParametersShouldReturnDefaultValues() { + String cronExpression = new CronExpressionBuilder().build(); + Assert.assertEquals("* * * * * *", cronExpression); + } + + @Test + public void builderWithInvalidSecondsShouldThrowIllegalArgumentException() { + IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .add(CronPeriod.SECONDS, 60).build()); + Assert.assertTrue(exception.getMessage().contains("SECONDS must be between [0, 59]")); + exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .add(CronPeriod.SECONDS, -1).build()); + Assert.assertTrue(exception.getMessage().contains("SECONDS must be between [0, 59]")); + } + + @Test + public void builderWithInvalidMinutesShouldThrowIllegalArgumentException() { + IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .add(CronPeriod.MINUTES, 60).build()); + Assert.assertTrue(exception.getMessage().contains("MINUTES must be between [0, 59]")); + exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .add(CronPeriod.MINUTES, -1).build()); + Assert.assertTrue(exception.getMessage().contains("MINUTES must be between [0, 59]")); + } + + @Test + public void builderWithInvalidHoursShouldThrowIllegalArgumentException() { + IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .add(CronPeriod.HOURS, -1).build()); + Assert.assertTrue(exception.getMessage().contains("HOURS must be between [0, 23]")); + exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .add(CronPeriod.HOURS, 24).build()); + Assert.assertTrue(exception.getMessage().contains("HOURS must be between [0, 23]")); + } + + @Test + public void builderWithInvalidDayOfMonthShouldThrowIllegalArgumentException() { + IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .add(CronPeriod.DayOfMonth, 32).build()); + Assert.assertTrue(exception.getMessage().contains("DayOfMonth must be between [1, 31]")); + exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .add(CronPeriod.DayOfMonth, 0).build()); + Assert.assertTrue(exception.getMessage().contains("DayOfMonth must be between [1, 31]")); + } + + @Test + public void builderWithInvalidMonthOfYearShouldThrowIllegalArgumentException() { + IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .add(CronPeriod.MonthOfYear, 0).build()); + Assert.assertTrue(exception.getMessage().contains("MonthOfYear must be between [1, 12]")); + exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .add(CronPeriod.MonthOfYear, 13).build()); + Assert.assertTrue(exception.getMessage().contains("MonthOfYear must be between [1, 12]")); + } + + @Test + public void builderWithInvalidDayOfWeekShouldThrowIllegalArgumentException() { + IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .add(CronPeriod.DayOfWeek, -1).build()); + Assert.assertTrue(exception.getMessage().contains("DayOfWeek must be between [0, 6]")); + exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .add(CronPeriod.DayOfWeek, 7).build()); + Assert.assertTrue(exception.getMessage().contains("DayOfWeek must be between [0, 6]")); + } + + @Test + public void builderWithSecondsShouldReturnWithOnlySecondsSet() { + String cronExpression = new CronExpressionBuilder() + .add(CronPeriod.SECONDS, 5) + .build(); + Assert.assertEquals("5 * * * * *", cronExpression); + } + + @Test + public void builderWithMultipleCallsToAddSecondsShouldReturnWithMultipleValues() { + String cronExpression = new CronExpressionBuilder() + .add(CronPeriod.SECONDS, 5) + .add(CronPeriod.SECONDS, 10) + .add(CronPeriod.SECONDS, 20) + .build(); + Assert.assertEquals("5,10,20 * * * * *", cronExpression); + } + + @Test + public void builderWithCallToAddRangeForSecondShouldReturnCorrectValues() { + String cronExpression = new CronExpressionBuilder() + .add(CronPeriod.SECONDS, 5) + .add(CronPeriod.SECONDS, 10) + .addRange(CronPeriod.SECONDS, 40, 50) + .build(); + Assert.assertEquals("5,10,40-50 * * * * *", cronExpression); + } + + @Test + public void builderWithCallToAddStepForSecondShouldReturnCorrectValues() { + String cronExpression = new CronExpressionBuilder() + .add(CronPeriod.SECONDS, 5) + .addStep(CronPeriod.SECONDS, 10) + .addRange(CronPeriod.SECONDS, 40, 50) + .build(); + Assert.assertEquals("5,*/10,40-50 * * * * *", cronExpression); + } + + @Test + public void builderWithMinutesShouldReturnWithOnlySecondsSet() { + String cronExpression = new CronExpressionBuilder() + .add(CronPeriod.MINUTES, 5) + .build(); + Assert.assertEquals("* 5 * * * *", cronExpression); + } + + @Test + public void builderWithMultipleCallsToAddMinutesShouldReturnWithMultipleValues() { + String cronExpression = new CronExpressionBuilder() + .add(CronPeriod.MINUTES, 5) + .add(CronPeriod.MINUTES, 10) + .add(CronPeriod.MINUTES, 20) + .build(); + Assert.assertEquals("* 5,10,20 * * * *", cronExpression); + } + + @Test + public void builderWithCallToAddRangeForMinutesShouldReturnCorrectValues() { + String cronExpression = new CronExpressionBuilder() + .add(CronPeriod.MINUTES, 5) + .add(CronPeriod.MINUTES, 10) + .addRange(CronPeriod.MINUTES, 40, 50) + .build(); + Assert.assertEquals("* 5,10,40-50 * * * *", cronExpression); + } + + @Test + public void builderWithCallToAddStepForMinutesShouldReturnCorrectValues() { + String cronExpression = new CronExpressionBuilder() + .add(CronPeriod.MINUTES, 5) + .addStep(CronPeriod.MINUTES, 10) + .addRange(CronPeriod.MINUTES, 40, 50) + .build(); + Assert.assertEquals("* 5,*/10,40-50 * * * *", cronExpression); + } + + @Test + public void builderWithCallToAddForSecondsAndMinutesShouldReturnCorrectValues() { + String cronExpression = new CronExpressionBuilder() + .add(CronPeriod.SECONDS, 2) + .add(CronPeriod.MINUTES, 5) + .addStep(CronPeriod.MINUTES, 10) + .addRange(CronPeriod.MINUTES, 40, 50) + .build(); + Assert.assertEquals("2 5,*/10,40-50 * * * *", cronExpression); + } + + @Test + public void builderWithHoursShouldReturnWithOnlySecondsSet() { + String cronExpression = new CronExpressionBuilder() + .add(CronPeriod.HOURS, 5) + .build(); + Assert.assertEquals("* * 5 * * *", cronExpression); + } + + @Test + public void builderWithMultipleCallsToAddHoursShouldReturnWithMultipleValues() { + String cronExpression = new CronExpressionBuilder() + .add(CronPeriod.HOURS, 5) + .add(CronPeriod.HOURS, 10) + .add(CronPeriod.HOURS, 20) + .build(); + Assert.assertEquals("* * 5,10,20 * * *", cronExpression); + } + + @Test + public void builderWithCallToAddRangeForHoursShouldReturnCorrectValues() { + String cronExpression = new CronExpressionBuilder() + .add(CronPeriod.HOURS, 5) + .add(CronPeriod.HOURS, 10) + .addRange(CronPeriod.HOURS, 11, 12) + .build(); + Assert.assertEquals("* * 5,10,11-12 * * *", cronExpression); + } + + @Test + public void builderWithCallToAddStepForHoursShouldReturnCorrectValues() { + String cronExpression = new CronExpressionBuilder() + .add(CronPeriod.HOURS, 5) + .addStep(CronPeriod.HOURS, 10) + .addRange(CronPeriod.HOURS, 13, 14) + .build(); + Assert.assertEquals("* * 5,*/10,13-14 * * *", cronExpression); + } + + @Test + public void builderWithCallToAddForSecondsMinutesHoursShouldReturnCorrectValues() { + String cronExpression = new CronExpressionBuilder() + .add(CronPeriod.SECONDS, 2) + .add(CronPeriod.MINUTES, 5) + .addStep(CronPeriod.MINUTES, 10) + .addRange(CronPeriod.MINUTES, 40, 50) + .add(CronPeriod.HOURS, 20) + .addRange(CronPeriod.HOURS, 1, 2) + .addStep(CronPeriod.HOURS, 4) + .addStepRange(CronPeriod.HOURS, 5, 6, 3) + .build(); + Assert.assertEquals("2 5,*/10,40-50 20,1-2,*/4,5-6/3 * * *", cronExpression); + } + + @Test + public void builderWithCallToAddForMonthOfDayAndDayOfWeekShouldReturnCorrectValues() { + String cronExpression = new CronExpressionBuilder() + .add(MonthOfYear.JAN, MonthOfYear.FEB) + .add(DayOfWeek.MON, DayOfWeek.THU) + .add(CronPeriod.SECONDS, 1,2,3) + .add(CronPeriod.MINUTES, 20,30) + .build(); + Assert.assertEquals("1,2,3 20,30 * * JAN,FEB MON,THU", cronExpression); + } + + @Test + public void builderWithCallToAddForRangeMonthOfDayAndDayOfWeekShouldReturnCorrectValues() { + String cronExpression = new CronExpressionBuilder() + .add(MonthOfYear.JAN, MonthOfYear.FEB) + .add(DayOfWeek.MON, DayOfWeek.THU) + .add(CronPeriod.SECONDS, 1,2,3) + .add(CronPeriod.MINUTES, 20,30) + .addRange(MonthOfYear.MAR, MonthOfYear.APR) + .addRange(DayOfWeek.SUN, DayOfWeek.MON) + .build(); + Assert.assertEquals("1,2,3 20,30 * * JAN,FEB,MAR-APR MON,THU,SUN-MON", cronExpression); + } +} From 6ff418d4ddc204cb4e734e4a45638d8d670424f6 Mon Sep 17 00:00:00 2001 From: sirivarma Date: Sun, 9 Mar 2025 08:52:36 -0700 Subject: [PATCH 02/30] Add validations Signed-off-by: sirivarma --- .../jobs/client/CronExpressionBuilder.java | 22 ++-- .../dapr/jobs/CronExpressionBuilderTest.java | 114 ++++++++++++++---- .../test/io/dapr/jobs/JobsScheduleTest.java | 68 +++++++++++ 3 files changed, 172 insertions(+), 32 deletions(-) create mode 100644 sdk-jobs/test/test/io/dapr/jobs/JobsScheduleTest.java diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java index 00fd1b24eb..c8a53ee464 100644 --- a/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java +++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java @@ -100,29 +100,29 @@ public CronExpressionBuilder addRange(MonthOfYear from, MonthOfYear to) { return this; } - public CronExpressionBuilder addStepRange(CronPeriod period, int from, int to, int denominator) { + public CronExpressionBuilder addStepRange(CronPeriod period, int from, int to, int interval) { throwIfNull(period); validateRange(from, to); - validatePeriod(period, denominator); + validatePeriod(period, interval); - addToPeriod(period, from + "-" + to + "/" + denominator); + addToPeriod(period, from + "-" + to + "/" + interval); return this; } - public CronExpressionBuilder addStep(CronPeriod period, int numerator, int denominator) { + public CronExpressionBuilder addStep(CronPeriod period, int numerator, int interval) { throwIfNull(period); validatePeriod(period, numerator); - validatePeriod(period, denominator); + validatePeriod(period, interval); - addToPeriod(period, numerator + "/" + denominator); + addToPeriod(period, numerator + "/" + interval); return this; } - public CronExpressionBuilder addStep(CronPeriod period, int denominator) { + public CronExpressionBuilder addStep(CronPeriod period, int interval) { throwIfNull(period); - validatePeriod(period, denominator); + validatePeriod(period, interval); - addToPeriod(period, "*/" + denominator); + addToPeriod(period, "*/" + interval); return this; } @@ -197,7 +197,7 @@ private void validatePeriod(CronPeriod cronPeriod, int value) { private void validateRange(int from, int to) { if (from > to || from == to) { - throw new IllegalArgumentException("from must be before to (from < to)"); + throw new IllegalArgumentException("from must be less than to (from < to)"); } } @@ -228,7 +228,7 @@ private void addToPeriod(CronPeriod cronPeriod, String value) { private void throwIfNull(Object obj) { if (obj == null) { - throw new IllegalArgumentException("None of the parameters can be null"); + throw new IllegalArgumentException("None of the input parameters can be null"); } } } \ No newline at end of file diff --git a/sdk-jobs/test/test/io/dapr/jobs/CronExpressionBuilderTest.java b/sdk-jobs/test/test/io/dapr/jobs/CronExpressionBuilderTest.java index 6a30925355..3ee235d9c0 100644 --- a/sdk-jobs/test/test/io/dapr/jobs/CronExpressionBuilderTest.java +++ b/sdk-jobs/test/test/io/dapr/jobs/CronExpressionBuilderTest.java @@ -6,13 +6,17 @@ import io.dapr.jobs.client.MonthOfYear; import org.junit.Assert; import org.junit.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.junit.Assert.assertEquals; public class CronExpressionBuilderTest { @Test public void builderWithoutParametersShouldReturnDefaultValues() { String cronExpression = new CronExpressionBuilder().build(); - Assert.assertEquals("* * * * * *", cronExpression); + assertEquals("* * * * * *", cronExpression); } @Test @@ -52,14 +56,18 @@ public void builderWithInvalidHoursShouldThrowIllegalArgumentException() { } @Test - public void builderWithInvalidDayOfMonthShouldThrowIllegalArgumentException() { + public void builderWithInvalidDayOfMonthShouldThrowIllegalArgumentException1() { IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, () -> new CronExpressionBuilder() - .add(CronPeriod.DayOfMonth, 32).build()); + .add(CronPeriod.DayOfMonth, 0).build()); Assert.assertTrue(exception.getMessage().contains("DayOfMonth must be between [1, 31]")); - exception = Assert.assertThrows(IllegalArgumentException.class, + } + + @Test + public void builderWithInvalidDayOfMonthShouldThrowIllegalArgumentException() { + IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, () -> new CronExpressionBuilder() - .add(CronPeriod.DayOfMonth, 0).build()); + .add(CronPeriod.DayOfMonth, 32).build()); Assert.assertTrue(exception.getMessage().contains("DayOfMonth must be between [1, 31]")); } @@ -87,12 +95,66 @@ public void builderWithInvalidDayOfWeekShouldThrowIllegalArgumentException() { Assert.assertTrue(exception.getMessage().contains("DayOfWeek must be between [0, 6]")); } + @Test + public void builderWithInvalidRangeShouldThrowIllegalArgumentException() { + IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .addRange(CronPeriod.HOURS, 20, 19).build()); + Assert.assertTrue(exception.getMessage().contains("from must be less than to")); + } + + @Test + public void builderWithInvalidMinuteRangeSpecifiedShouldThrowIllegalArgumentException() { + IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .addRange(CronPeriod.MINUTES, 1, 1).build()); + Assert.assertTrue(exception.getMessage().contains("from must be less than to (from < to)")); + } + + @Test + public void builderWithInvalidParametersShouldThrowIllegalArgumentException() { + IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .addRange(null, 1, 2).build()); + Assert.assertTrue(exception.getMessage().contains("None of the input parameters can be null")); + } + + @ParameterizedTest + @CsvSource({ + "SECONDS, 0, '0 * * * * *'", + "MINUTES, 30, '* 30 * * * *'", + "HOURS, 12, '* * 12 * * *'", + "DayOfMonth, 15, '* * * 15 * *'", + "MonthOfYear, 6, '* * * * 6 *'", + "DayOfWeek, 3, '* * * * * 3'" + }) + void testAddSingleValue(CronPeriod period, int value, String expected) { + CronExpressionBuilder builder = new CronExpressionBuilder().add(period, value); + assertEquals(expected, builder.build()); + } + + @Test + public void builderWithInvalidParameterInValuesShouldThrowIllegalArgumentException() { + IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .add(null, MonthOfYear.JAN, null, MonthOfYear.FEB).build()); + Assert.assertTrue(exception.getMessage().contains("None of the input parameters can be null")); + } + + @Test + public void builderWithInvalidParameterInDayOfWeekValuesShouldThrowIllegalArgumentException() { + IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .add(null, DayOfWeek.MON, null, DayOfWeek.THU).build()); + Assert.assertTrue(exception.getMessage().contains("None of the input parameters can be null")); + } + @Test public void builderWithSecondsShouldReturnWithOnlySecondsSet() { String cronExpression = new CronExpressionBuilder() .add(CronPeriod.SECONDS, 5) .build(); - Assert.assertEquals("5 * * * * *", cronExpression); + assertEquals("5 * * * * *", cronExpression); } @Test @@ -102,7 +164,7 @@ public void builderWithMultipleCallsToAddSecondsShouldReturnWithMultipleValues() .add(CronPeriod.SECONDS, 10) .add(CronPeriod.SECONDS, 20) .build(); - Assert.assertEquals("5,10,20 * * * * *", cronExpression); + assertEquals("5,10,20 * * * * *", cronExpression); } @Test @@ -112,7 +174,7 @@ public void builderWithCallToAddRangeForSecondShouldReturnCorrectValues() { .add(CronPeriod.SECONDS, 10) .addRange(CronPeriod.SECONDS, 40, 50) .build(); - Assert.assertEquals("5,10,40-50 * * * * *", cronExpression); + assertEquals("5,10,40-50 * * * * *", cronExpression); } @Test @@ -122,7 +184,7 @@ public void builderWithCallToAddStepForSecondShouldReturnCorrectValues() { .addStep(CronPeriod.SECONDS, 10) .addRange(CronPeriod.SECONDS, 40, 50) .build(); - Assert.assertEquals("5,*/10,40-50 * * * * *", cronExpression); + assertEquals("5,*/10,40-50 * * * * *", cronExpression); } @Test @@ -130,7 +192,7 @@ public void builderWithMinutesShouldReturnWithOnlySecondsSet() { String cronExpression = new CronExpressionBuilder() .add(CronPeriod.MINUTES, 5) .build(); - Assert.assertEquals("* 5 * * * *", cronExpression); + assertEquals("* 5 * * * *", cronExpression); } @Test @@ -140,7 +202,7 @@ public void builderWithMultipleCallsToAddMinutesShouldReturnWithMultipleValues() .add(CronPeriod.MINUTES, 10) .add(CronPeriod.MINUTES, 20) .build(); - Assert.assertEquals("* 5,10,20 * * * *", cronExpression); + assertEquals("* 5,10,20 * * * *", cronExpression); } @Test @@ -150,7 +212,7 @@ public void builderWithCallToAddRangeForMinutesShouldReturnCorrectValues() { .add(CronPeriod.MINUTES, 10) .addRange(CronPeriod.MINUTES, 40, 50) .build(); - Assert.assertEquals("* 5,10,40-50 * * * *", cronExpression); + assertEquals("* 5,10,40-50 * * * *", cronExpression); } @Test @@ -160,7 +222,7 @@ public void builderWithCallToAddStepForMinutesShouldReturnCorrectValues() { .addStep(CronPeriod.MINUTES, 10) .addRange(CronPeriod.MINUTES, 40, 50) .build(); - Assert.assertEquals("* 5,*/10,40-50 * * * *", cronExpression); + assertEquals("* 5,*/10,40-50 * * * *", cronExpression); } @Test @@ -171,7 +233,7 @@ public void builderWithCallToAddForSecondsAndMinutesShouldReturnCorrectValues() .addStep(CronPeriod.MINUTES, 10) .addRange(CronPeriod.MINUTES, 40, 50) .build(); - Assert.assertEquals("2 5,*/10,40-50 * * * *", cronExpression); + assertEquals("2 5,*/10,40-50 * * * *", cronExpression); } @Test @@ -179,7 +241,7 @@ public void builderWithHoursShouldReturnWithOnlySecondsSet() { String cronExpression = new CronExpressionBuilder() .add(CronPeriod.HOURS, 5) .build(); - Assert.assertEquals("* * 5 * * *", cronExpression); + assertEquals("* * 5 * * *", cronExpression); } @Test @@ -189,7 +251,7 @@ public void builderWithMultipleCallsToAddHoursShouldReturnWithMultipleValues() { .add(CronPeriod.HOURS, 10) .add(CronPeriod.HOURS, 20) .build(); - Assert.assertEquals("* * 5,10,20 * * *", cronExpression); + assertEquals("* * 5,10,20 * * *", cronExpression); } @Test @@ -199,7 +261,7 @@ public void builderWithCallToAddRangeForHoursShouldReturnCorrectValues() { .add(CronPeriod.HOURS, 10) .addRange(CronPeriod.HOURS, 11, 12) .build(); - Assert.assertEquals("* * 5,10,11-12 * * *", cronExpression); + assertEquals("* * 5,10,11-12 * * *", cronExpression); } @Test @@ -209,7 +271,7 @@ public void builderWithCallToAddStepForHoursShouldReturnCorrectValues() { .addStep(CronPeriod.HOURS, 10) .addRange(CronPeriod.HOURS, 13, 14) .build(); - Assert.assertEquals("* * 5,*/10,13-14 * * *", cronExpression); + assertEquals("* * 5,*/10,13-14 * * *", cronExpression); } @Test @@ -224,7 +286,7 @@ public void builderWithCallToAddForSecondsMinutesHoursShouldReturnCorrectValues( .addStep(CronPeriod.HOURS, 4) .addStepRange(CronPeriod.HOURS, 5, 6, 3) .build(); - Assert.assertEquals("2 5,*/10,40-50 20,1-2,*/4,5-6/3 * * *", cronExpression); + assertEquals("2 5,*/10,40-50 20,1-2,*/4,5-6/3 * * *", cronExpression); } @Test @@ -235,7 +297,7 @@ public void builderWithCallToAddForMonthOfDayAndDayOfWeekShouldReturnCorrectValu .add(CronPeriod.SECONDS, 1,2,3) .add(CronPeriod.MINUTES, 20,30) .build(); - Assert.assertEquals("1,2,3 20,30 * * JAN,FEB MON,THU", cronExpression); + assertEquals("1,2,3 20,30 * * JAN,FEB MON,THU", cronExpression); } @Test @@ -248,6 +310,16 @@ public void builderWithCallToAddForRangeMonthOfDayAndDayOfWeekShouldReturnCorrec .addRange(MonthOfYear.MAR, MonthOfYear.APR) .addRange(DayOfWeek.SUN, DayOfWeek.MON) .build(); - Assert.assertEquals("1,2,3 20,30 * * JAN,FEB,MAR-APR MON,THU,SUN-MON", cronExpression); + assertEquals("1,2,3 20,30 * * JAN,FEB,MAR-APR MON,THU,SUN-MON", cronExpression); + } + + @Test + public void builderWithCallToAddForStepShouldReturnCorrectValues() { + String cronExpression = new CronExpressionBuilder() + .add(MonthOfYear.JAN, MonthOfYear.FEB) + .add(DayOfWeek.MON, DayOfWeek.THU) + .addStep(CronPeriod.HOURS, 20, 2) + .build(); + assertEquals("* * 20/2 * JAN,FEB MON,THU", cronExpression); } } diff --git a/sdk-jobs/test/test/io/dapr/jobs/JobsScheduleTest.java b/sdk-jobs/test/test/io/dapr/jobs/JobsScheduleTest.java new file mode 100644 index 0000000000..b37b372cb2 --- /dev/null +++ b/sdk-jobs/test/test/io/dapr/jobs/JobsScheduleTest.java @@ -0,0 +1,68 @@ +package io.dapr.jobs.client; + +import org.junit.jupiter.api.Test; + +import java.time.Duration; + +import static org.junit.jupiter.api.Assertions.*; + +class JobsScheduleTest { + + @Test + void testFromPeriodValidDuration() { + Duration duration = Duration.ofHours(1).plusMinutes(30) + .plusSeconds(15).plusMillis(500); + JobsSchedule schedule = JobsSchedule.fromPeriod(duration); + assertEquals("@every 1h30m15s500ms", schedule.getExpression()); + } + + @Test + void testFromPeriodValidDurationWithoutSecondsAndMillSeconds() { + Duration duration = Duration.ofHours(1).plusMinutes(30); + JobsSchedule schedule = JobsSchedule.fromPeriod(duration); + assertEquals("@every 1h30m0s0ms", schedule.getExpression()); + } + + @Test + void testFromPeriodNullDuration() { + Exception exception = assertThrows(IllegalArgumentException.class, () -> JobsSchedule.fromPeriod(null)); + assertEquals("duration cannot be null", exception.getMessage()); + } + + @Test + void testFromString() { + String cronExpression = "0 0 * * *"; + JobsSchedule schedule = JobsSchedule.fromString(cronExpression); + assertEquals(cronExpression, schedule.getExpression()); + } + + @Test + void testYearly() { + JobsSchedule schedule = JobsSchedule.yearly(); + assertEquals("0 0 0 1 1 *", schedule.getExpression()); + } + + @Test + void testMonthly() { + JobsSchedule schedule = JobsSchedule.monthly(); + assertEquals("0 0 0 1 * *", schedule.getExpression()); + } + + @Test + void testWeekly() { + JobsSchedule schedule = JobsSchedule.weekly(); + assertEquals("0 0 0 * * 0", schedule.getExpression()); + } + + @Test + void testDaily() { + JobsSchedule schedule = JobsSchedule.daily(); + assertEquals("0 0 0 * * *", schedule.getExpression()); + } + + @Test + void testHourly() { + JobsSchedule schedule = JobsSchedule.hourly(); + assertEquals("0 0 * * * *", schedule.getExpression()); + } +} From 540607fd508ce6ce15ff15fcf15e0760e1398d45 Mon Sep 17 00:00:00 2001 From: sirivarma Date: Sun, 9 Mar 2025 13:08:26 -0700 Subject: [PATCH 03/30] Add things Signed-off-by: sirivarma --- .../jobs/client/CronExpressionBuilder.java | 295 +++++++++++++----- .../java/io/dapr/jobs/client/CronPeriod.java | 32 +- .../java/io/dapr/jobs/client/DayOfWeek.java | 27 +- .../io/dapr/jobs/client/JobsSchedule.java | 69 ++++ .../java/io/dapr/jobs/client/MonthOfYear.java | 17 +- .../java/io/dapr/jobs/client/OrdinalEnum.java | 11 + .../dapr/jobs/CronExpressionBuilderTest.java | 23 ++ 7 files changed, 385 insertions(+), 89 deletions(-) create mode 100644 sdk-jobs/src/main/java/io/dapr/jobs/client/OrdinalEnum.java diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java index c8a53ee464..d8c633186a 100644 --- a/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java +++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java @@ -1,8 +1,24 @@ package io.dapr.jobs.client; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +/** + * A builder class for constructing cron expressions. This class provides an easy way to construct cron expressions + * by adding individual values or ranges for each of the cron fields: seconds, minutes, hours, day of month, + * day of week, and month of year. It supports adding steps and ranges for fields where appropriate. + *

+ * Example usage: + *

+ * CronExpressionBuilder builder = new CronExpressionBuilder();
+ * builder.add(CronPeriod.MINUTES, 0, 15, 30); // Every 15 minutes starting at 0
+ * builder.add(CronPeriod.HOURS, 12); // At noon
+ * builder.addRange(CronPeriod.DAYOFMONTH, 1, 31); // On the 1st through the 31st day of the month
+ * builder.addStep(CronPeriod.MINUTES, 5); // Every 5 minutes
+ * System.out.println(builder.build()); // Outputs the cron expression
+ * 
+ */ public class CronExpressionBuilder { private final List seconds; @@ -12,6 +28,9 @@ public class CronExpressionBuilder { private final List dayOfWeek; private final List monthOfYear; + /** + * Constructs a new {@link CronExpressionBuilder} instance with empty cron fields. + */ public CronExpressionBuilder() { this.seconds = new ArrayList<>(); this.minutes = new ArrayList<>(); @@ -22,110 +41,121 @@ public CronExpressionBuilder() { } /** - * Convert to cron expression depending on period and values. + * Adds values to the specified cron period (e.g., minutes, hours, etc.). + * example: + * builder.add(CronPeriod.MINUTES, 0, 15, 30); // Adds 0, 15, and 30 minutes to the cron expression + * + * @param cronPeriod The cron period to modify (e.g., {CronPeriod.MINUTES}). + * @param values The values to be added to the cron period. + * @return The {@link CronExpressionBuilder} instance for method chaining. + * @throws IllegalArgumentException if values are invalid or empty. * - * @param cronPeriod {@link CronPeriod}. - * @param values for the cronPeriod. - * @return this. */ - public CronExpressionBuilder add(CronPeriod cronPeriod, Integer... values) { - throwIfNull(cronPeriod); - throwIfNull(values); - - StringBuilder builder = new StringBuilder(); - for (Integer value: values) { - throwIfNull(value); - validatePeriod(cronPeriod, value); - builder.append(value).append(","); - } - - addToPeriod(cronPeriod, builder.deleteCharAt(builder.length() - 1).toString()); - - return this; + public CronExpressionBuilder add(CronPeriod cronPeriod, int... values) { + return addInternal(cronPeriod, Arrays.stream(values).boxed().toArray()); } + /** + * Adds values for the {@link MonthOfYear} cron period. + * + * @param values The {@link MonthOfYear} values to be added. + * @return The {@link CronExpressionBuilder} instance for method chaining. + */ public CronExpressionBuilder add(MonthOfYear... values) { - throwIfNull(values); - - StringBuilder builder = new StringBuilder(); - for (MonthOfYear value: values) { - throwIfNull(value); - builder.append(value).append(","); - } - - addToPeriod(CronPeriod.MonthOfYear, builder.deleteCharAt(builder.length() - 1).toString()); - - return this; + return addInternal(CronPeriod.MonthOfYear, values); } + /** + * Adds values for the {@link DayOfWeek} cron period. + * + * @param values The {@link DayOfWeek} values to be added. + * @return The {@link CronExpressionBuilder} instance for method chaining. + */ public CronExpressionBuilder add(DayOfWeek... values) { - throwIfNull(values); - - StringBuilder builder = new StringBuilder(); - for (DayOfWeek value: values) { - throwIfNull(value); - builder.append(value).append(","); - } - - addToPeriod(CronPeriod.DayOfWeek, builder.deleteCharAt(builder.length() - 1).toString()); - - return this; + return addInternal(CronPeriod.DayOfWeek, values); } - - public CronExpressionBuilder addRange(CronPeriod period, int from, int to) { - throwIfNull(period); - validateRange(from, to); - validatePeriod(period, from); - validatePeriod(period, to); - - addToPeriod(period, from + "-" + to); - return this; + /** + * Adds a range of values to a cron period. + * + * @param period The cron period to modify (e.g., {CronPeriod.MONTHOFYEAR}). + * @param from The starting value of the range (inclusive). + * @param to The ending value of the range (inclusive). + * @return The {@link CronExpressionBuilder} instance for method chaining. + * @throws IllegalArgumentException if the range is invalid. + */ + public CronExpressionBuilder addRange(CronPeriod period, int from, int to) { + return addRangeInternal(period, from, to); } + /** + * Adds a range of {@link DayOfWeek} values to the cron expression. + * + * @param from The starting {@link DayOfWeek} value. + * @param to The ending {@link DayOfWeek} value. + * @return The {@link CronExpressionBuilder} instance for method chaining. + */ public CronExpressionBuilder addRange(DayOfWeek from, DayOfWeek to) { - throwIfNull(from); - throwIfNull(to); - validateRange(from.getValue(), to.getValue()); - - addToPeriod(CronPeriod.DayOfWeek, from + "-" + to); - return this; + return addRangeInternal(CronPeriod.DayOfWeek, from, to); } + /** + * Adds a range of {@link MonthOfYear} values to the cron expression. + * + * @param from The starting {@link MonthOfYear} value. + * @param to The ending {@link MonthOfYear} value. + * @return The {@link CronExpressionBuilder} instance for method chaining. + */ public CronExpressionBuilder addRange(MonthOfYear from, MonthOfYear to) { - throwIfNull(from); - throwIfNull(to); - - addToPeriod(CronPeriod.MonthOfYear, from + "-" + to); - return this; + return addRangeInternal(CronPeriod.MonthOfYear, from, to); } + /** + * Adds a step range for a cron period. + * + * @param period The cron period to modify. + * @param from The starting value for the step range (inclusive). + * @param to The ending value for the step range (inclusive). + * @param interval The interval for the step range. + * @return The {@link CronExpressionBuilder} instance for method chaining. + */ public CronExpressionBuilder addStepRange(CronPeriod period, int from, int to, int interval) { - throwIfNull(period); - validateRange(from, to); - validatePeriod(period, interval); - - addToPeriod(period, from + "-" + to + "/" + interval); - return this; + return addStepInternal(period, from, to, interval); } - public CronExpressionBuilder addStep(CronPeriod period, int numerator, int interval) { - throwIfNull(period); - validatePeriod(period, numerator); - validatePeriod(period, interval); - - addToPeriod(period, numerator + "/" + interval); - return this; + /** + * Adds a step for a cron period. + * + * @param period The cron period to modify. + * @param interval The interval for the step. + * @return The {@link CronExpressionBuilder} instance for method chaining. + */ + public CronExpressionBuilder addStep(CronPeriod period, int interval) { + return addStepInternal(period, null, null, interval); } - public CronExpressionBuilder addStep(CronPeriod period, int interval) { + /** + * Adds a specific value with a step interval for the cron period. + * + * @param period The cron period to modify. + * @param value The starting value for the step. + * @param interval The interval for the step. + * @return The {@link CronExpressionBuilder} instance for method chaining. + */ + public CronExpressionBuilder addStep(CronPeriod period, int value, int interval) { throwIfNull(period); + validatePeriod(period, value); validatePeriod(period, interval); - addToPeriod(period, "*/" + interval); + addToPeriod(period, value + "/" + interval); return this; } + /** + * Builds the cron expression by combining all the specified cron periods and their values. + * + * @return A string representation of the cron expression. + */ public String build() { if (this.monthOfYear.isEmpty()) { @@ -152,17 +182,110 @@ public String build() { this.dayOfMonth.add("*"); } - StringBuilder cronExpression = new StringBuilder(); - cronExpression.append(String.join(",", this.seconds)).append(" "); - cronExpression.append(String.join(",", this.minutes)).append(" "); - cronExpression.append(String.join(",", this.hours)).append(" "); - cronExpression.append(String.join(",", this.dayOfMonth)).append(" "); - cronExpression.append(String.join(",", this.monthOfYear)).append(" "); - cronExpression.append(String.join(",", this.dayOfWeek)); + return String.join(",", this.seconds) + " " + + String.join(",", this.minutes) + " " + + String.join(",", this.hours) + " " + + String.join(",", this.dayOfMonth) + " " + + String.join(",", this.monthOfYear) + " " + + String.join(",", this.dayOfWeek); + } + + /** + * Internal method to add values to a cron period. + * + * @param period The cron period to modify. + * @param values The values to add. + * @return The {@link CronExpressionBuilder} instance for method chaining. + */ + private CronExpressionBuilder addInternal(CronPeriod period, T[] values) { + throwIfNull(period); + throwIfNull(values); + + if (values.length == 0) { + throw new IllegalArgumentException(period + " values cannot be empty"); + } + + List valueStrings = new ArrayList<>(values.length); + for (T value : values) { + throwIfNull(value); + if (value instanceof OrdinalEnum) { + validatePeriod(period, ((OrdinalEnum) value).getRank()); + valueStrings.add(value.toString()); + } else { + validatePeriod(period, (int)value); + valueStrings.add(String.valueOf(value)); + } + } + + addToPeriod(period, String.join(",", valueStrings)); + + return this; + } + + /** + * Internal method to add a range of values to a cron period. + * + * @param period The cron period to modify. + * @param from The starting value for the range (inclusive). + * @param to The ending value for the range (inclusive). + * @return The {@link CronExpressionBuilder} instance for method chaining. + */ + private CronExpressionBuilder addRangeInternal(CronPeriod period, T from, T to) { + throwIfNull(period); + throwIfNull(from); + throwIfNull(to); + + if (from instanceof OrdinalEnum && to instanceof OrdinalEnum) { + int fromInterval = ((OrdinalEnum) from).getRank(); + int toInterval = ((OrdinalEnum) to).getRank(); + validateRange(fromInterval, toInterval); + validatePeriod(period, fromInterval); + validatePeriod(period, toInterval); + } else { + validateRange((int)from, (int)to); + validatePeriod(period, (int)from); + validatePeriod(period, (int)to); + } + + addToPeriod(period, from + "-" + to); + return this; + } + + /** + * Internal method to add a step range to a cron period. + * + * @param period The cron period to modify. + * @param from The starting value for the step range (inclusive). + * @param to The ending value for the step range (inclusive). + * @param interval The interval for the step. + * @return The {@link CronExpressionBuilder} instance for method chaining. + */ + private CronExpressionBuilder addStepInternal(CronPeriod period, Integer from, Integer to, Integer interval) { + throwIfNull(period); + throwIfNull(interval); - return cronExpression.toString(); + if (from != null || to != null) { + throwIfNull(from); + throwIfNull(to); + validatePeriod(period, from); + validatePeriod(period, to); + validateRange(from, to); + + addToPeriod(period, from + "-" + to + "/" + interval); + return this; + } + + addToPeriod(period, "*/" + interval); + return this; } + /** + * Validates the value for a specific cron period. + * + * @param cronPeriod The cron period to validate (e.g., {@link CronPeriod.HOURS}). + * @param value The value to validate. + * @throws IllegalArgumentException if the value is invalid for the cron period. + */ private void validatePeriod(CronPeriod cronPeriod, int value) { switch (cronPeriod) { case SECONDS: @@ -201,6 +324,12 @@ private void validateRange(int from, int to) { } } + /** + * Helper method to add values to the period. + * + * @param period The cron period to modify. + * @param value The value to add to the period. + */ private void addToPeriod(CronPeriod cronPeriod, String value) { switch (cronPeriod) { case SECONDS: diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/CronPeriod.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/CronPeriod.java index b58b8a6454..04449f5ac8 100644 --- a/sdk-jobs/src/main/java/io/dapr/jobs/client/CronPeriod.java +++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/CronPeriod.java @@ -1,16 +1,46 @@ package io.dapr.jobs.client; +/** + * Represents the different fields of a cron expression that can be modified + * using the {@link CronExpressionBuilder}. + *

+ * Each enum value corresponds to a specific component of a cron schedule. + *

+ * Example usage: + *

+ * CronPeriod period = CronPeriod.MINUTES;
+ * System.out.println(period); // Outputs: MINUTES
+ * 
+ */ public enum CronPeriod { + /** + * Represents the seconds field in a cron expression (0-59). + */ SECONDS, + /** + * Represents the minutes field in a cron expression (0-59). + */ MINUTES, + /** + * Represents the hours field in a cron expression (0-23). + */ HOURS, + /** + * Represents the day of the month field in a cron expression (1-31). + */ DayOfMonth, + /** + * Represents the month of the year field in a cron expression (1-12). + */ MonthOfYear, + /** + * Represents the day of the week field in a cron expression (0-6, where 0 is Sunday). + */ DayOfWeek, -} +} \ No newline at end of file diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/DayOfWeek.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/DayOfWeek.java index ff3a1d705c..7a5c5999f0 100644 --- a/sdk-jobs/src/main/java/io/dapr/jobs/client/DayOfWeek.java +++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/DayOfWeek.java @@ -1,6 +1,21 @@ package io.dapr.jobs.client; -public enum DayOfWeek { +/** + * Represents the days of the week in a cron expression. + *

+ * This enum maps each day of the week to its corresponding integer value + * as used in cron expressions (0 for Sunday through 6 for Saturday). + *

+ * Implements {@link OrdinalEnum} to provide an ordinal ranking for each day. + *

+ * Example usage: + *

+ * DayOfWeek day = DayOfWeek.MON;
+ * System.out.println(day.getRank()); // Outputs: 1
+ * 
+ */ +public enum DayOfWeek implements OrdinalEnum { + SUN(0), MON(1), @@ -12,11 +27,17 @@ public enum DayOfWeek { private final int value; - private DayOfWeek(int value) { + /** + * Constructs a {@code DayOfWeek} enum with the given value. + * + * @param value the integer representation of the day (0-6). + */ + DayOfWeek(int value) { this.value = value; } - int getValue() { + @Override + public int getRank() { return this.value; } } \ No newline at end of file diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/JobsSchedule.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/JobsSchedule.java index b602b92886..da4f069c8c 100644 --- a/sdk-jobs/src/main/java/io/dapr/jobs/client/JobsSchedule.java +++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/JobsSchedule.java @@ -2,14 +2,47 @@ import java.time.Duration; +/** + * Represents a job schedule using cron expressions or fixed intervals. + *

+ * This class provides various static methods to create schedules based on predefined periods + * (e.g., daily, weekly, monthly) or using custom cron expressions. + *

+ * Example usage: + *

+ * JobsSchedule schedule = JobsSchedule.daily();
+ * System.out.println(schedule.getExpression()); // Outputs: "0 0 0 * * *"
+ * 
+ */ public class JobsSchedule { private final String expression; + /** + * Private constructor to create a job schedule from a cron expression. + * + * @param expression the cron expression defining the schedule. + */ private JobsSchedule(String expression) { this.expression = expression; } + /** + * Creates a job schedule from a fixed period using a {@link Duration}. + *

+ * The resulting expression follows the format: "@every XhYmZsWms" + * where X, Y, Z, and W represent hours, minutes, seconds, and milliseconds respectively. + *

+ * Example: + *

+   * JobsSchedule schedule = JobsSchedule.fromPeriod(Duration.ofMinutes(30));
+   * System.out.println(schedule.getExpression()); // Outputs: "@every 0h30m0s0ms"
+   * 
+ * + * @param duration the duration of the period. + * @return a {@code JobsSchedule} with the corresponding interval. + * @throws IllegalArgumentException if the duration is null. + */ public static JobsSchedule fromPeriod(Duration duration) { if (duration == null) { throw new IllegalArgumentException("duration cannot be null"); @@ -20,10 +53,21 @@ public static JobsSchedule fromPeriod(Duration duration) { return new JobsSchedule("@every " + formattedDuration); } + /** + * Creates a job schedule from a custom cron expression. + * + * @param cronExpression the cron expression. + * @return a {@code JobsSchedule} representing the given cron expression. + */ public static JobsSchedule fromString(String cronExpression) { return new JobsSchedule(cronExpression); } + /** + * Creates a yearly job schedule, running at midnight on January 1st. + * + * @return a {@code JobsSchedule} for yearly execution. + */ public static JobsSchedule yearly() { return new JobsSchedule(new CronExpressionBuilder() .add(CronPeriod.SECONDS, 0) @@ -34,6 +78,11 @@ public static JobsSchedule yearly() { .build()); } + /** + * Creates a monthly job schedule, running at midnight on the first day of each month. + * + * @return a {@code JobsSchedule} for monthly execution. + */ public static JobsSchedule monthly() { return new JobsSchedule(new CronExpressionBuilder() .add(CronPeriod.SECONDS, 0) @@ -43,6 +92,11 @@ public static JobsSchedule monthly() { .build()); } + /** + * Creates a weekly job schedule, running at midnight on Sunday. + * + * @return a {@code JobsSchedule} for weekly execution. + */ public static JobsSchedule weekly() { return new JobsSchedule(new CronExpressionBuilder() .add(CronPeriod.SECONDS, 0) @@ -52,6 +106,11 @@ public static JobsSchedule weekly() { .build()); } + /** + * Creates a daily job schedule, running at midnight every day. + * + * @return a {@code JobsSchedule} for daily execution. + */ public static JobsSchedule daily() { return new JobsSchedule(new CronExpressionBuilder() .add(CronPeriod.SECONDS, 0) @@ -60,6 +119,11 @@ public static JobsSchedule daily() { .build()); } + /** + * Creates an hourly job schedule, running at the start of every hour. + * + * @return a {@code JobsSchedule} for hourly execution. + */ public static JobsSchedule hourly() { return new JobsSchedule(new CronExpressionBuilder() .add(CronPeriod.SECONDS, 0) @@ -67,6 +131,11 @@ public static JobsSchedule hourly() { .build()); } + /** + * Gets the cron expression representing this job schedule. + * + * @return the cron expression as a string. + */ public String getExpression() { return this.expression; } diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/MonthOfYear.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/MonthOfYear.java index d9def02d68..2c47d7915e 100644 --- a/sdk-jobs/src/main/java/io/dapr/jobs/client/MonthOfYear.java +++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/MonthOfYear.java @@ -1,6 +1,18 @@ package io.dapr.jobs.client; -public enum MonthOfYear { +/** + * Represents the months of the year, each associated with its ordinal position (1-12). + *

+ * This enum implements {@link OrdinalEnum}, allowing retrieval of the numerical rank of each month. + *

+ * Example usage: + *

+ * MonthOfYear month = MonthOfYear.JAN;
+ * int rank = month.getRank(); // Returns 1
+ * 
+ */ + +public enum MonthOfYear implements OrdinalEnum { JAN(1), FEB(2), @@ -21,7 +33,8 @@ public enum MonthOfYear { this.value = value; } - int getValue() { + @Override + public int getRank() { return this.value; } } \ No newline at end of file diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/OrdinalEnum.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/OrdinalEnum.java new file mode 100644 index 0000000000..8ee171a2c9 --- /dev/null +++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/OrdinalEnum.java @@ -0,0 +1,11 @@ +package io.dapr.jobs.client; + +public interface OrdinalEnum { + + /** + * Returns the ordinal rank of the implementing enum. + * + * @return the rank as an integer. + */ + public int getRank(); +} diff --git a/sdk-jobs/test/test/io/dapr/jobs/CronExpressionBuilderTest.java b/sdk-jobs/test/test/io/dapr/jobs/CronExpressionBuilderTest.java index 3ee235d9c0..5bfcd65334 100644 --- a/sdk-jobs/test/test/io/dapr/jobs/CronExpressionBuilderTest.java +++ b/sdk-jobs/test/test/io/dapr/jobs/CronExpressionBuilderTest.java @@ -4,6 +4,7 @@ import io.dapr.jobs.client.CronPeriod; import io.dapr.jobs.client.DayOfWeek; import io.dapr.jobs.client.MonthOfYear; +import org.checkerframework.checker.units.qual.C; import org.junit.Assert; import org.junit.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -43,6 +44,14 @@ public void builderWithInvalidMinutesShouldThrowIllegalArgumentException() { Assert.assertTrue(exception.getMessage().contains("MINUTES must be between [0, 59]")); } + @Test + public void builderWithEmptyParametersShouldThrowIllegalArgumentException() { + IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, + () -> new CronExpressionBuilder() + .add(CronPeriod.MINUTES).build()); + Assert.assertTrue(exception.getMessage().contains("MINUTES values cannot be empty")); + } + @Test public void builderWithInvalidHoursShouldThrowIllegalArgumentException() { IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, @@ -322,4 +331,18 @@ public void builderWithCallToAddForStepShouldReturnCorrectValues() { .build(); assertEquals("* * 20/2 * JAN,FEB MON,THU", cronExpression); } + + @Test + public void builderWithCallToAddAllFieldsShouldReturnCorrectValues() { + String cronExpression = new CronExpressionBuilder() + .add(MonthOfYear.JAN, MonthOfYear.FEB) + .add(DayOfWeek.MON, DayOfWeek.THU) + .addStep(CronPeriod.HOURS, 20, 2) + .add(CronPeriod.SECONDS, 1) + .add(CronPeriod.MINUTES, 1) + .add(CronPeriod.HOURS, 1) + .add(CronPeriod.DayOfMonth, 1) + .build(); + assertEquals("1 1 20/2,1 1 JAN,FEB MON,THU", cronExpression); + } } From 50ee84d16e9e7d5da94a51e2aad425ce94253a53 Mon Sep 17 00:00:00 2001 From: sirivarma Date: Sun, 9 Mar 2025 13:17:02 -0700 Subject: [PATCH 04/30] Add things Signed-off-by: sirivarma --- pom.xml | 2 +- sdk-jobs/pom.xml | 29 +- .../jobs/client/CronExpressionBuilder.java | 13 +- .../java/io/dapr/jobs/client/CronPeriod.java | 2 - .../io/dapr/jobs/client/DaprJobsClient.java | 254 ++++++++++++++ .../java/io/dapr/jobs/client/DayOfWeek.java | 4 - .../io/dapr/jobs/client/DeleteJobRequest.java | 56 ++++ .../io/dapr/jobs/client/GetJobRequest.java | 56 ++++ .../io/dapr/jobs/client/GetJobResponse.java | 178 ++++++++++ .../{JobsSchedule.java => JobSchedule.java} | 40 +-- .../java/io/dapr/jobs/client/MonthOfYear.java | 2 - .../java/io/dapr/jobs/client/OrdinalEnum.java | 7 +- .../dapr/jobs/client/ScheduleJobRequest.java | 178 ++++++++++ .../client}/CronExpressionBuilderTest.java | 7 +- .../dapr/jobs/client/DaprJobsClientTest.java | 313 ++++++++++++++++++ .../dapr/jobs/client}/JobsScheduleTest.java | 24 +- sdk-tests/pom.xml | 6 + .../io/dapr/it/testcontainers/DaprJobsIT.java | 139 ++++++++ .../TestDaprJobsConfiguration.java | 38 +++ .../testcontainers/TestJobsApplication.java | 26 ++ .../io/dapr/testcontainers/DaprContainer.java | 31 +- .../DaprSchedulerContainer.java | 82 +++++ 22 files changed, 1428 insertions(+), 59 deletions(-) create mode 100644 sdk-jobs/src/main/java/io/dapr/jobs/client/DaprJobsClient.java create mode 100644 sdk-jobs/src/main/java/io/dapr/jobs/client/DeleteJobRequest.java create mode 100644 sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobRequest.java create mode 100644 sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobResponse.java rename sdk-jobs/src/main/java/io/dapr/jobs/client/{JobsSchedule.java => JobSchedule.java} (79%) create mode 100644 sdk-jobs/src/main/java/io/dapr/jobs/client/ScheduleJobRequest.java rename sdk-jobs/test/test/{io/dapr/jobs => java/io/dapr/jobs/client}/CronExpressionBuilderTest.java (98%) create mode 100644 sdk-jobs/test/test/java/io/dapr/jobs/client/DaprJobsClientTest.java rename sdk-jobs/test/test/{io/dapr/jobs => java/io/dapr/jobs/client}/JobsScheduleTest.java (65%) create mode 100644 sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java create mode 100644 sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprJobsConfiguration.java create mode 100644 sdk-tests/src/test/java/io/dapr/it/testcontainers/TestJobsApplication.java create mode 100644 testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprSchedulerContainer.java diff --git a/pom.xml b/pom.xml index 1c1b569ec5..ad8726f0c8 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ 1.69.0 3.25.5 protoc - https://raw.githubusercontent.com/dapr/dapr/v1.14.4/dapr/proto + https://raw.githubusercontent.com/dapr/dapr/v1.15.2/dapr/proto 1.15.0-SNAPSHOT 0.15.0-SNAPSHOT 1.7.1 diff --git a/sdk-jobs/pom.xml b/sdk-jobs/pom.xml index 6f10b61412..406060a947 100644 --- a/sdk-jobs/pom.xml +++ b/sdk-jobs/pom.xml @@ -12,7 +12,7 @@ dapr-sdk-jobs jar - 0.15.0-SNAPSHOT + 1.15.0-SNAPSHOT dapr-sdk-jobs SDK for Jobs on Dapr @@ -24,12 +24,12 @@ io.dapr dapr-sdk - ${project.parent.version} + ${project.version} io.dapr dapr-sdk-autogen - 1.15.0-SNAPSHOT + ${project.version} org.mockito @@ -50,13 +50,34 @@ org.junit.vintage junit-vintage-engine - 5.7.0 + 5.7.2 test + + org.testng + testng + RELEASE + compile + + + org.junit.platform + junit-platform-console-standalone + 1.11.4 + compile + + + org.mockito + mockito-core + compile + + + org.sonatype.plugins + nexus-staging-maven-plugin + org.apache.maven.plugins maven-source-plugin diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java index d8c633186a..f2111bb400 100644 --- a/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java +++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java @@ -8,7 +8,6 @@ * A builder class for constructing cron expressions. This class provides an easy way to construct cron expressions * by adding individual values or ranges for each of the cron fields: seconds, minutes, hours, day of month, * day of week, and month of year. It supports adding steps and ranges for fields where appropriate. - *

* Example usage: *

  * CronExpressionBuilder builder = new CronExpressionBuilder();
@@ -182,12 +181,12 @@ public String build() {
       this.dayOfMonth.add("*");
     }
 
-    return String.join(",", this.seconds) + " " +
-        String.join(",", this.minutes) + " " +
-        String.join(",", this.hours) + " " +
-        String.join(",", this.dayOfMonth) + " " +
-        String.join(",", this.monthOfYear) + " " +
-        String.join(",", this.dayOfWeek);
+    return String.join(",", this.seconds) + " "
+        + String.join(",", this.minutes) + " "
+        + String.join(",", this.hours) + " "
+        + String.join(",", this.dayOfMonth) + " "
+        + String.join(",", this.monthOfYear) + " "
+        + String.join(",", this.dayOfWeek);
   }
 
   /**
diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/CronPeriod.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/CronPeriod.java
index 04449f5ac8..f8172d105f 100644
--- a/sdk-jobs/src/main/java/io/dapr/jobs/client/CronPeriod.java
+++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/CronPeriod.java
@@ -3,9 +3,7 @@
 /**
  * Represents the different fields of a cron expression that can be modified
  * using the {@link CronExpressionBuilder}.
- * 

* Each enum value corresponds to a specific component of a cron schedule. - *

* Example usage: *

  * CronPeriod period = CronPeriod.MINUTES;
diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/DaprJobsClient.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/DaprJobsClient.java
new file mode 100644
index 0000000000..db219d9591
--- /dev/null
+++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/DaprJobsClient.java
@@ -0,0 +1,254 @@
+package io.dapr.jobs.client;
+
+import com.google.protobuf.Any;
+import com.google.protobuf.ByteString;
+import io.dapr.client.resiliency.ResiliencyOptions;
+import io.dapr.config.Properties;
+import io.dapr.exceptions.DaprException;
+import io.dapr.internal.exceptions.DaprHttpException;
+import io.dapr.internal.grpc.interceptors.DaprTimeoutInterceptor;
+import io.dapr.internal.grpc.interceptors.DaprTracingInterceptor;
+import io.dapr.internal.resiliency.RetryPolicy;
+import io.dapr.internal.resiliency.TimeoutPolicy;
+import io.dapr.utils.NetworkUtils;
+import io.dapr.v1.DaprGrpc;
+import io.dapr.v1.DaprProtos;
+import io.grpc.ManagedChannel;
+import io.grpc.stub.StreamObserver;
+import reactor.core.publisher.Mono;
+import reactor.core.publisher.MonoSink;
+import reactor.util.context.ContextView;
+
+import java.time.OffsetDateTime;
+import java.util.function.Consumer;
+
+public class DaprJobsClient implements AutoCloseable {
+
+  /**
+   * Stub that has the method to call the conversation apis.
+   */
+  private final DaprGrpc.DaprStub asyncStub;
+
+  /**
+   * The retry policy.
+   */
+  private final RetryPolicy retryPolicy;
+
+  /**
+   * The timeout policy.
+   */
+  private final TimeoutPolicy timeoutPolicy;
+
+  /**
+   * Constructor to create conversation client.
+   */
+  public DaprJobsClient() {
+    this(DaprGrpc.newStub(NetworkUtils.buildGrpcManagedChannel(new Properties())), null);
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param properties with client configuration options.
+   * @param resiliencyOptions retry options.
+   */
+  public DaprJobsClient(
+      Properties properties,
+      ResiliencyOptions resiliencyOptions) {
+    this(DaprGrpc.newStub(NetworkUtils.buildGrpcManagedChannel(properties)), resiliencyOptions);
+  }
+
+  /**
+   * ConversationClient constructor.
+   *
+   * @param resiliencyOptions timeout and retry policies.
+   */
+  protected DaprJobsClient(
+      DaprGrpc.DaprStub asyncStub,
+      ResiliencyOptions resiliencyOptions) {
+    this.asyncStub = asyncStub;
+    this.retryPolicy = new RetryPolicy(resiliencyOptions == null ? null : resiliencyOptions.getMaxRetries());
+    this.timeoutPolicy = new TimeoutPolicy(resiliencyOptions == null ? null : resiliencyOptions.getTimeout());
+  }
+
+  /**
+   * Schedules a job using the provided job request details.
+   *
+   * @param createJobRequest The request containing the details of the job to schedule.
+   *                         Must include a name and optional schedule, data, and other related properties.
+   * @return A {@link Mono} that completes when the job scheduling operation is successful or raises an error.
+   * @throws IllegalArgumentException If the request or its required fields like name are null or empty.
+   */
+  public Mono scheduleJob(ScheduleJobRequest createJobRequest) {
+    try {
+      if (createJobRequest == null) {
+        throw new IllegalArgumentException("scheduleJobRequest cannot be null");
+      }
+
+      if (createJobRequest.getName() == null || createJobRequest.getName().isEmpty()) {
+        throw new IllegalArgumentException("Name in the request cannot be null or empty");
+      }
+
+      if (createJobRequest.getSchedule() == null && createJobRequest.getDueTime() == null) {
+        throw new IllegalArgumentException("At least one of schedule or dueTime must be provided");
+      }
+
+      DaprProtos.Job.Builder scheduleJobRequestBuilder = DaprProtos.Job.newBuilder();
+      scheduleJobRequestBuilder.setName(createJobRequest.getName());
+
+      if (createJobRequest.getData() != null) {
+        scheduleJobRequestBuilder.setData(Any.newBuilder()
+                .setValue(ByteString.copyFrom(createJobRequest.getData())).build());
+      }
+
+      if (createJobRequest.getSchedule() != null) {
+        scheduleJobRequestBuilder.setSchedule(createJobRequest.getSchedule().getExpression());
+      }
+
+      if (createJobRequest.getTtl() != null) {
+        scheduleJobRequestBuilder.setTtl(createJobRequest.getTtl().toString());
+      }
+
+      if (createJobRequest.getRepeats() != null) {
+        scheduleJobRequestBuilder.setRepeats(createJobRequest.getRepeats());
+      }
+
+      if (createJobRequest.getDueTime() != null) {
+        scheduleJobRequestBuilder.setDueTime(createJobRequest.getDueTime().toString());
+      }
+
+      DaprProtos.ScheduleJobRequest scheduleJobRequest = DaprProtos.ScheduleJobRequest.newBuilder()
+              .setJob(scheduleJobRequestBuilder.build()).build();
+
+      Mono scheduleJobResponseMono =
+              Mono.deferContextual(context -> this.createMono(
+                              it -> intercept(context, asyncStub)
+                                      .scheduleJobAlpha1(scheduleJobRequest, it)
+                      )
+              );
+
+      return scheduleJobResponseMono.then();
+    } catch (Exception ex) {
+      return DaprException.wrapMono(ex);
+    }
+  }
+
+  /**
+   * Retrieves details of a specific job.
+   *
+   * @param getJobRequest The request containing the job name for which the details are to be fetched.
+   *      The name property is mandatory.
+   * @return A {@link Mono} that emits the {@link GetJobResponse} containing job details or raises an
+   *      error if the job is not found.
+   * @throws IllegalArgumentException If the request or its required fields like name are null or empty.
+   */
+
+  public Mono getJob(GetJobRequest getJobRequest) {
+    try {
+      if (getJobRequest == null) {
+        throw new IllegalArgumentException("getJobRequest cannot be null");
+      }
+
+      if (getJobRequest.getName() == null || getJobRequest.getName().isEmpty()) {
+        throw new IllegalArgumentException("Name in the request cannot be null or empty");
+      }
+
+      Mono getJobResponseMono =
+          Mono.deferContextual(context -> this.createMono(
+                  it -> intercept(context, asyncStub)
+                      .getJobAlpha1(DaprProtos.GetJobRequest.newBuilder()
+                          .setName(getJobRequest.getName()).build(), it)
+              )
+          );
+
+      return getJobResponseMono.map(getJobResponse -> {
+        DaprProtos.Job job = getJobResponse.getJob();
+        return GetJobResponse.builder()
+                .setName(job.getName())
+                .setTtl(job.hasTtl() ? OffsetDateTime.parse(job.getTtl()) : null)
+                .setData(job.hasData() ? job.getData().getValue().toByteArray() : null)
+                .setRepeat(job.hasRepeats() ? job.getRepeats() : null)
+                .setSchedule(job.hasSchedule() ? JobSchedule.fromString(job.getSchedule()) : null)
+                .setDueTime(job.hasDueTime() ? OffsetDateTime.parse(job.getDueTime()) : null)
+                .build();
+      });
+    } catch (Exception ex) {
+      return DaprException.wrapMono(ex);
+    }
+  }
+
+  /**
+   * Deletes a job based on the given request.
+   *
+   * @param deleteJobRequest The request containing the job name to be deleted.
+   *                        The name property is mandatory.
+   * @return A {@link Mono} that completes when the job is successfully deleted or raises an error.
+   * @throws IllegalArgumentException If the request or its required fields like name are null or empty.
+   */
+  public Mono deleteJob(DeleteJobRequest deleteJobRequest) {
+    try {
+      if (deleteJobRequest == null) {
+        throw new IllegalArgumentException("deleteJobRequest cannot be null");
+      }
+
+      if (deleteJobRequest.getName() == null || deleteJobRequest.getName().isEmpty()) {
+        throw new IllegalArgumentException("Name in the request cannot be null or empty");
+      }
+
+      Mono deleteJobResponseMono =
+              Mono.deferContextual(context -> this.createMono(
+                              it -> intercept(context, asyncStub)
+                                      .deleteJobAlpha1(DaprProtos.DeleteJobRequest.newBuilder()
+                                              .setName(deleteJobRequest.getName()).build(), it)
+                      )
+              );
+
+      return deleteJobResponseMono.then();
+    } catch (Exception ex) {
+      return DaprException.wrapMono(ex);
+    }
+  }
+
+  @Override
+  public void close() throws Exception {
+    ManagedChannel channel = (ManagedChannel) this.asyncStub.getChannel();
+
+    DaprException.wrap(() -> {
+      if (channel != null && !channel.isShutdown()) {
+        channel.shutdown();
+      }
+
+      return true;
+    }).call();
+  }
+
+  private DaprGrpc.DaprStub intercept(
+      ContextView context, DaprGrpc.DaprStub client) {
+    return client.withInterceptors(new DaprTimeoutInterceptor(this.timeoutPolicy), new DaprTracingInterceptor(context));
+  }
+
+  private  Mono createMono(Consumer> consumer) {
+    return retryPolicy.apply(
+        Mono.create(sink -> DaprException.wrap(() -> consumer.accept(
+            createStreamObserver(sink))).run()));
+  }
+
+  private  StreamObserver createStreamObserver(MonoSink sink) {
+    return new StreamObserver() {
+      @Override
+      public void onNext(T value) {
+        sink.success(value);
+      }
+
+      @Override
+      public void onError(Throwable t) {
+        sink.error(DaprException.propagate(DaprHttpException.fromGrpcExecutionException(null, t)));
+      }
+
+      @Override
+      public void onCompleted() {
+        sink.success();
+      }
+    };
+  }
+}
diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/DayOfWeek.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/DayOfWeek.java
index 7a5c5999f0..4221ccfb57 100644
--- a/sdk-jobs/src/main/java/io/dapr/jobs/client/DayOfWeek.java
+++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/DayOfWeek.java
@@ -2,12 +2,9 @@
 
 /**
  * Represents the days of the week in a cron expression.
- * 

* This enum maps each day of the week to its corresponding integer value * as used in cron expressions (0 for Sunday through 6 for Saturday). - *

* Implements {@link OrdinalEnum} to provide an ordinal ranking for each day. - *

* Example usage: *

  * DayOfWeek day = DayOfWeek.MON;
@@ -16,7 +13,6 @@
  */
 public enum DayOfWeek implements OrdinalEnum {
 
-
   SUN(0),
   MON(1),
   TUE(2),
diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/DeleteJobRequest.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/DeleteJobRequest.java
new file mode 100644
index 0000000000..358ba386ed
--- /dev/null
+++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/DeleteJobRequest.java
@@ -0,0 +1,56 @@
+package io.dapr.jobs.client;
+
+/**
+ * Represents a request to schedule a job in Dapr.
+ */
+public class DeleteJobRequest {
+  private final String name;
+
+  private DeleteJobRequest(Builder builder) {
+    this.name = builder.name;
+  }
+
+  /**
+   * Creates a new builder instance for {@link DeleteJobRequest}.
+   *
+   * @return A new {@link Builder} instance.
+   */
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  public static class Builder {
+    private String name;
+
+    /**
+     * Sets the name of the job.
+     *
+     * @param name The job name.
+     * @return This builder instance.
+     */
+    public Builder setName(String name) {
+      this.name = name;
+      return this;
+    }
+
+    /**
+     * Builds a {@link DeleteJobRequest} instance.
+     *
+     * @return A new {@link DeleteJobRequest} instance.
+     */
+    public DeleteJobRequest build() {
+      return new DeleteJobRequest(this);
+    }
+  }
+
+  // Getters
+
+  /**
+   * Gets the name of the job.
+   *
+   * @return The job name.
+   */
+  public String getName() {
+    return name;
+  }
+}
diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobRequest.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobRequest.java
new file mode 100644
index 0000000000..3c8a428b84
--- /dev/null
+++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobRequest.java
@@ -0,0 +1,56 @@
+package io.dapr.jobs.client;
+
+/**
+ * Represents a request to schedule a job in Dapr.
+ */
+public class GetJobRequest {
+  private final String name;
+
+  private GetJobRequest(Builder builder) {
+    this.name = builder.name;
+  }
+
+  /**
+   * Creates a new builder instance for {@link GetJobRequest}.
+   *
+   * @return A new {@link Builder} instance.
+   */
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  public static class Builder {
+    private String name;
+
+    /**
+     * Sets the name of the job.
+     *
+     * @param name The job name.
+     * @return This builder instance.
+     */
+    public Builder setName(String name) {
+      this.name = name;
+      return this;
+    }
+
+    /**
+     * Builds a {@link GetJobRequest} instance.
+     *
+     * @return A new {@link GetJobRequest} instance.
+     */
+    public GetJobRequest build() {
+      return new GetJobRequest(this);
+    }
+  }
+
+  // Getters
+
+  /**
+   * Gets the name of the job.
+   *
+   * @return The job name.
+   */
+  public String getName() {
+    return name;
+  }
+}
diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobResponse.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobResponse.java
new file mode 100644
index 0000000000..62c6e8b5e6
--- /dev/null
+++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobResponse.java
@@ -0,0 +1,178 @@
+package io.dapr.jobs.client;
+
+import java.time.OffsetDateTime;
+
+/**
+ * Represents a request to schedule a job in Dapr.
+ */
+public class GetJobResponse {
+  private final String name;
+  private final byte[] data;
+  private final JobSchedule schedule;
+  private final OffsetDateTime dueTime;
+  private final Integer repeat;
+  private final OffsetDateTime ttl;
+
+  private GetJobResponse(Builder builder) {
+    this.name = builder.name;
+    this.data = builder.data;
+    this.schedule = builder.schedule;
+    this.dueTime = builder.dueTime;
+    this.repeat = builder.repeat;
+    this.ttl = builder.ttl;
+  }
+
+  /**
+   * Creates a new builder instance for {@link GetJobResponse}.
+   *
+   * @return A new {@link Builder} instance.
+   */
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  public static class Builder {
+    private String name;
+    private byte[] data;
+    private JobSchedule schedule;
+    private OffsetDateTime dueTime;
+    private Integer repeat;
+    private OffsetDateTime ttl;
+
+    /**
+     * Sets the name of the job.
+     *
+     * @param name The job name.
+     * @return This builder instance.
+     */
+    public Builder setName(String name) {
+      this.name = name;
+      return this;
+    }
+
+    /**
+     * Sets the data payload for the job.
+     * This should be a JSON serialized value or object.
+     *
+     * @param data The job data in byte array format.
+     * @return This builder instance.
+     */
+    public Builder setData(byte[] data) {
+      this.data = data;
+      return this;
+    }
+
+    /**
+     * Sets the schedule for the job.
+     * The format should follow cron expressions or other supported scheduling formats.
+     *
+     * @param schedule The job schedule.
+     * @return This builder instance.
+     */
+    public Builder setSchedule(JobSchedule schedule) {
+      this.schedule = schedule;
+      return this;
+    }
+
+    /**
+     * Sets the due time when the job should become active or execute once.
+     * This can be in RFC3339, Go duration string, or non-repeating ISO8601 format.
+     *
+     * @param dueTime The due time of the job.
+     * @return This builder instance.
+     */
+    public Builder setDueTime(OffsetDateTime dueTime) {
+      this.dueTime = dueTime;
+      return this;
+    }
+
+    /**
+     * Sets the number of times the job should be triggered.
+     * If not set, the job runs indefinitely or until expiration.
+     *
+     * @param repeat The number of times the job should repeat.
+     * @return This builder instance.
+     */
+    public Builder setRepeat(Integer repeat) {
+      this.repeat = repeat;
+      return this;
+    }
+
+    /**
+     * Sets the time-to-live (TTL) or expiration for the job.
+     * This can be in RFC3339, Go duration string, or non-repeating ISO8601 format.
+     *
+     * @param ttl The time-to-live for the job.
+     * @return This builder instance.
+     */
+    public Builder setTtl(OffsetDateTime ttl) {
+      this.ttl = ttl;
+      return this;
+    }
+
+    /**
+     * Builds a {@link GetJobResponse} instance.
+     *
+     * @return A new {@link GetJobResponse} instance.
+     */
+    public GetJobResponse build() {
+      return new GetJobResponse(this);
+    }
+  }
+
+  // Getters
+
+  /**
+   * Gets the name of the job.
+   *
+   * @return The job name.
+   */
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * Gets the data payload of the job.
+   *
+   * @return The job data as a byte array.
+   */
+  public byte[] getData() {
+    return data;
+  }
+
+  /**
+   * Gets the schedule of the job.
+   *
+   * @return The job schedule.
+   */
+  public JobSchedule getSchedule() {
+    return schedule;
+  }
+
+  /**
+   * Gets the due time of the job.
+   *
+   * @return The due time.
+   */
+  public OffsetDateTime getDueTime() {
+    return dueTime;
+  }
+
+  /**
+   * Gets the number of times the job should repeat.
+   *
+   * @return The repeat count, or null if not set.
+   */
+  public Integer getRepeat() {
+    return repeat;
+  }
+
+  /**
+   * Gets the time-to-live (TTL) or expiration of the job.
+   *
+   * @return The TTL value.
+   */
+  public OffsetDateTime getTtl() {
+    return ttl;
+  }
+}
diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/JobsSchedule.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/JobSchedule.java
similarity index 79%
rename from sdk-jobs/src/main/java/io/dapr/jobs/client/JobsSchedule.java
rename to sdk-jobs/src/main/java/io/dapr/jobs/client/JobSchedule.java
index da4f069c8c..87f2a83ced 100644
--- a/sdk-jobs/src/main/java/io/dapr/jobs/client/JobsSchedule.java
+++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/JobSchedule.java
@@ -4,17 +4,15 @@
 
 /**
  * Represents a job schedule using cron expressions or fixed intervals.
- * 

* This class provides various static methods to create schedules based on predefined periods * (e.g., daily, weekly, monthly) or using custom cron expressions. - *

* Example usage: *

  * JobsSchedule schedule = JobsSchedule.daily();
  * System.out.println(schedule.getExpression()); // Outputs: "0 0 0 * * *"
  * 
*/ -public class JobsSchedule { +public class JobSchedule { private final String expression; @@ -23,16 +21,14 @@ public class JobsSchedule { * * @param expression the cron expression defining the schedule. */ - private JobsSchedule(String expression) { + private JobSchedule(String expression) { this.expression = expression; } /** * Creates a job schedule from a fixed period using a {@link Duration}. - *

* The resulting expression follows the format: "@every XhYmZsWms" * where X, Y, Z, and W represent hours, minutes, seconds, and milliseconds respectively. - *

* Example: *

    * JobsSchedule schedule = JobsSchedule.fromPeriod(Duration.ofMinutes(30));
@@ -43,14 +39,14 @@ private JobsSchedule(String expression) {
    * @return a {@code JobsSchedule} with the corresponding interval.
    * @throws IllegalArgumentException if the duration is null.
    */
-  public static JobsSchedule fromPeriod(Duration duration) {
+  public static JobSchedule fromPeriod(Duration duration) {
     if (duration == null) {
       throw new IllegalArgumentException("duration cannot be null");
     }
 
     String formattedDuration = String.format("%dh%dm%ds%dms",
         duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart(), duration.toMillisPart());
-    return new JobsSchedule("@every " + formattedDuration);
+    return new JobSchedule("@every " + formattedDuration);
   }
 
   /**
@@ -59,8 +55,12 @@ public static JobsSchedule fromPeriod(Duration duration) {
    * @param cronExpression the cron expression.
    * @return a {@code JobsSchedule} representing the given cron expression.
    */
-  public static JobsSchedule fromString(String cronExpression) {
-    return new JobsSchedule(cronExpression);
+  public static JobSchedule fromString(String cronExpression) {
+    if (cronExpression == null) {
+      throw new IllegalArgumentException("cronExpression cannot be null");
+    }
+
+    return new JobSchedule(cronExpression);
   }
 
   /**
@@ -68,8 +68,8 @@ public static JobsSchedule fromString(String cronExpression) {
    *
    * @return a {@code JobsSchedule} for yearly execution.
    */
-  public static JobsSchedule yearly() {
-    return new JobsSchedule(new CronExpressionBuilder()
+  public static JobSchedule yearly() {
+    return new JobSchedule(new CronExpressionBuilder()
         .add(CronPeriod.SECONDS, 0)
         .add(CronPeriod.MINUTES, 0)
         .add(CronPeriod.HOURS, 0)
@@ -83,8 +83,8 @@ public static JobsSchedule yearly() {
    *
    * @return a {@code JobsSchedule} for monthly execution.
    */
-  public static JobsSchedule monthly() {
-    return new JobsSchedule(new CronExpressionBuilder()
+  public static JobSchedule monthly() {
+    return new JobSchedule(new CronExpressionBuilder()
         .add(CronPeriod.SECONDS, 0)
         .add(CronPeriod.MINUTES, 0)
         .add(CronPeriod.HOURS, 0)
@@ -97,8 +97,8 @@ public static JobsSchedule monthly() {
    *
    * @return a {@code JobsSchedule} for weekly execution.
    */
-  public static JobsSchedule weekly() {
-    return new JobsSchedule(new CronExpressionBuilder()
+  public static JobSchedule weekly() {
+    return new JobSchedule(new CronExpressionBuilder()
         .add(CronPeriod.SECONDS, 0)
         .add(CronPeriod.MINUTES, 0)
         .add(CronPeriod.HOURS, 0)
@@ -111,8 +111,8 @@ public static JobsSchedule weekly() {
    *
    * @return a {@code JobsSchedule} for daily execution.
    */
-  public static JobsSchedule daily() {
-    return new JobsSchedule(new CronExpressionBuilder()
+  public static JobSchedule daily() {
+    return new JobSchedule(new CronExpressionBuilder()
         .add(CronPeriod.SECONDS, 0)
         .add(CronPeriod.MINUTES, 0)
         .add(CronPeriod.HOURS, 0)
@@ -124,8 +124,8 @@ public static JobsSchedule daily() {
    *
    * @return a {@code JobsSchedule} for hourly execution.
    */
-  public static JobsSchedule hourly() {
-    return new JobsSchedule(new CronExpressionBuilder()
+  public static JobSchedule hourly() {
+    return new JobSchedule(new CronExpressionBuilder()
         .add(CronPeriod.SECONDS, 0)
         .add(CronPeriod.MINUTES, 0)
         .build());
diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/MonthOfYear.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/MonthOfYear.java
index 2c47d7915e..57fc4ed36c 100644
--- a/sdk-jobs/src/main/java/io/dapr/jobs/client/MonthOfYear.java
+++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/MonthOfYear.java
@@ -2,9 +2,7 @@
 
 /**
  * Represents the months of the year, each associated with its ordinal position (1-12).
- * 

* This enum implements {@link OrdinalEnum}, allowing retrieval of the numerical rank of each month. - *

* Example usage: *

  * MonthOfYear month = MonthOfYear.JAN;
diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/OrdinalEnum.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/OrdinalEnum.java
index 8ee171a2c9..d86ed7545f 100644
--- a/sdk-jobs/src/main/java/io/dapr/jobs/client/OrdinalEnum.java
+++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/OrdinalEnum.java
@@ -1,5 +1,10 @@
 package io.dapr.jobs.client;
 
+/**
+ * Represents an enumeration that has an associated ordinal rank.
+ * This interface is intended to be implemented by enums that need to provide
+ * a numerical representation for their values, such as days of the week or months of the year.
+ */
 public interface OrdinalEnum {
 
   /**
@@ -7,5 +12,5 @@ public interface OrdinalEnum {
    *
    * @return the rank as an integer.
    */
-  public int getRank();
+  int getRank();
 }
diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/ScheduleJobRequest.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/ScheduleJobRequest.java
new file mode 100644
index 0000000000..783fb3a32e
--- /dev/null
+++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/ScheduleJobRequest.java
@@ -0,0 +1,178 @@
+package io.dapr.jobs.client;
+
+import java.time.OffsetDateTime;
+
+/**
+ * Represents a request to schedule a job in Dapr.
+ */
+public class ScheduleJobRequest {
+  private final String name;
+  private final byte[] data;
+  private final JobSchedule schedule;
+  private final OffsetDateTime dueTime;
+  private final Integer repeats;
+  private final OffsetDateTime ttl;
+
+  private ScheduleJobRequest(Builder builder) {
+    this.name = builder.name;
+    this.data = builder.data;
+    this.schedule = builder.schedule;
+    this.dueTime = builder.dueTime;
+    this.repeats = builder.repeat;
+    this.ttl = builder.ttl;
+  }
+
+  /**
+   * Creates a new builder instance for {@link ScheduleJobRequest}.
+   *
+   * @return A new {@link Builder} instance.
+   */
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  public static class Builder {
+    private String name;
+    private byte[] data;
+    private JobSchedule schedule;
+    private OffsetDateTime dueTime;
+    private Integer repeat;
+    private OffsetDateTime ttl;
+
+    /**
+     * Sets the name of the job.
+     *
+     * @param name The job name.
+     * @return This builder instance.
+     */
+    public Builder setName(String name) {
+      this.name = name;
+      return this;
+    }
+
+    /**
+     * Sets the data payload for the job.
+     * This should be a JSON serialized value or object.
+     *
+     * @param data The job data in byte array format.
+     * @return This builder instance.
+     */
+    public Builder setData(byte[] data) {
+      this.data = data;
+      return this;
+    }
+
+    /**
+     * Sets the schedule for the job.
+     * The format should follow cron expressions or other supported scheduling formats.
+     *
+     * @param schedule The job schedule.
+     * @return This builder instance.
+     */
+    public Builder setSchedule(JobSchedule schedule) {
+      this.schedule = schedule;
+      return this;
+    }
+
+    /**
+     * Sets the due time when the job should become active or execute once.
+     * This can be in RFC3339, Go duration string, or non-repeating ISO8601 format.
+     *
+     * @param dueTime The due time of the job.
+     * @return This builder instance.
+     */
+    public Builder setDueTime(OffsetDateTime dueTime) {
+      this.dueTime = dueTime;
+      return this;
+    }
+
+    /**
+     * Sets the number of times the job should be triggered.
+     * If not set, the job runs indefinitely or until expiration.
+     *
+     * @param repeat The number of times the job should repeat.
+     * @return This builder instance.
+     */
+    public Builder setRepeat(Integer repeat) {
+      this.repeat = repeat;
+      return this;
+    }
+
+    /**
+     * Sets the time-to-live (TTL) or expiration for the job.
+     * This can be in RFC3339, Go duration string, or non-repeating ISO8601 format.
+     *
+     * @param ttl The time-to-live for the job.
+     * @return This builder instance.
+     */
+    public Builder setTtl(OffsetDateTime ttl) {
+      this.ttl = ttl;
+      return this;
+    }
+
+    /**
+     * Builds a {@link ScheduleJobRequest} instance.
+     *
+     * @return A new {@link ScheduleJobRequest} instance.
+     */
+    public ScheduleJobRequest build() {
+      return new ScheduleJobRequest(this);
+    }
+  }
+
+  // Getters
+
+  /**
+   * Gets the name of the job.
+   *
+   * @return The job name.
+   */
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * Gets the data payload of the job.
+   *
+   * @return The job data as a byte array.
+   */
+  public byte[] getData() {
+    return data;
+  }
+
+  /**
+   * Gets the schedule of the job.
+   *
+   * @return The job schedule.
+   */
+  public JobSchedule getSchedule() {
+    return schedule;
+  }
+
+  /**
+   * Gets the due time of the job.
+   *
+   * @return The due time.
+   */
+  public OffsetDateTime getDueTime() {
+    return dueTime;
+  }
+
+  /**
+   * Gets the number of times the job should repeat.
+   *
+   * @return The repeat count, or null if not set.
+   */
+  public Integer getRepeats() {
+    return repeats;
+  }
+
+  /**
+   * Gets the time-to-live (TTL) or expiration of the job.
+   *
+   * @return The TTL value.
+   */
+  public OffsetDateTime getTtl() {
+    return ttl;
+  }
+}
diff --git a/sdk-jobs/test/test/io/dapr/jobs/CronExpressionBuilderTest.java b/sdk-jobs/test/test/java/io/dapr/jobs/client/CronExpressionBuilderTest.java
similarity index 98%
rename from sdk-jobs/test/test/io/dapr/jobs/CronExpressionBuilderTest.java
rename to sdk-jobs/test/test/java/io/dapr/jobs/client/CronExpressionBuilderTest.java
index 5bfcd65334..342284e5af 100644
--- a/sdk-jobs/test/test/io/dapr/jobs/CronExpressionBuilderTest.java
+++ b/sdk-jobs/test/test/java/io/dapr/jobs/client/CronExpressionBuilderTest.java
@@ -1,10 +1,5 @@
-package io.dapr.jobs;
+package io.dapr.jobs.client;
 
-import io.dapr.jobs.client.CronExpressionBuilder;
-import io.dapr.jobs.client.CronPeriod;
-import io.dapr.jobs.client.DayOfWeek;
-import io.dapr.jobs.client.MonthOfYear;
-import org.checkerframework.checker.units.qual.C;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.jupiter.params.ParameterizedTest;
diff --git a/sdk-jobs/test/test/java/io/dapr/jobs/client/DaprJobsClientTest.java b/sdk-jobs/test/test/java/io/dapr/jobs/client/DaprJobsClientTest.java
new file mode 100644
index 0000000000..da48f4212d
--- /dev/null
+++ b/sdk-jobs/test/test/java/io/dapr/jobs/client/DaprJobsClientTest.java
@@ -0,0 +1,313 @@
+package io.dapr.jobs.client;
+
+import com.google.protobuf.Any;
+import com.google.protobuf.ByteString;
+import io.dapr.client.resiliency.ResiliencyOptions;
+import io.dapr.v1.DaprGrpc;
+import io.dapr.v1.DaprProtos;
+import io.grpc.ManagedChannel;
+import io.grpc.stub.StreamObserver;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import reactor.core.publisher.Mono;
+
+import java.nio.charset.StandardCharsets;
+import java.time.OffsetDateTime;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+class DaprJobsClientTest {
+
+  private DaprGrpc.DaprStub daprStub;
+
+  private DaprJobsClient daprJobsClient;
+
+  @BeforeEach
+  void setup() {
+    ManagedChannel channel = mock(ManagedChannel.class);
+    daprStub = mock(DaprGrpc.DaprStub.class);
+    when(daprStub.getChannel()).thenReturn(channel);
+    when(daprStub.withInterceptors(Mockito.any(), Mockito.any())).thenReturn(daprStub);
+
+    ResiliencyOptions resiliencyOptions = new ResiliencyOptions(); // Default resiliency options
+    daprJobsClient = new DaprJobsClient(daprStub, resiliencyOptions);
+  }
+
+  @Test
+  void scheduleJobShouldSucceedWhenAllFieldsArePresentInRequest() {
+    ScheduleJobRequest expectedScheduleJobRequest = ScheduleJobRequest.builder()
+            .setName("testJob")
+            .setData("testData".getBytes())
+            .setSchedule(JobSchedule.fromString("*/5 * * * *"))
+            .setTtl(OffsetDateTime.now().plusDays(1))
+            .setRepeat(5)
+            .setDueTime(OffsetDateTime.now().plusMinutes(10))
+            .build();
+
+    doAnswer(invocation -> {
+      StreamObserver observer = invocation.getArgument(1);
+      observer.onCompleted(); // Simulate successful response
+      return null;
+    }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any());
+
+    assertDoesNotThrow(() -> new DaprJobsClient(daprStub, null).scheduleJob(expectedScheduleJobRequest).block());
+
+    ArgumentCaptor captor =
+            ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class);
+
+    verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any());
+    DaprProtos.ScheduleJobRequest actualScheduleJobReq = captor.getValue();
+
+    assertEquals("testJob", actualScheduleJobReq.getJob().getName());
+    assertEquals("testData",
+            new String(actualScheduleJobReq.getJob().getData().getValue().toByteArray(), StandardCharsets.UTF_8));
+    assertEquals("*/5 * * * *", actualScheduleJobReq.getJob().getSchedule());
+    assertEquals(expectedScheduleJobRequest.getTtl().toString(), actualScheduleJobReq.getJob().getTtl());
+    assertEquals(expectedScheduleJobRequest.getRepeats(), actualScheduleJobReq.getJob().getRepeats());
+    assertEquals(expectedScheduleJobRequest.getDueTime().toString(), actualScheduleJobReq.getJob().getDueTime());
+  }
+
+  @Test
+  void scheduleJobShouldSucceedWhenRequiredFieldsNameAndDueTimeArePresentInRequest() {
+
+    doAnswer(invocation -> {
+      StreamObserver observer = invocation.getArgument(1);
+      observer.onCompleted(); // Simulate successful response
+      return null;
+    }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any());
+
+    ScheduleJobRequest expectedScheduleJobRequest = ScheduleJobRequest.builder()
+        .setName("testJob")
+        .setDueTime(OffsetDateTime.now().plusMinutes(10))
+        .build();
+    assertDoesNotThrow(() -> daprJobsClient.scheduleJob(expectedScheduleJobRequest).block());
+
+    ArgumentCaptor captor =
+            ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class);
+
+    verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any());
+    DaprProtos.ScheduleJobRequest actualScheduleJobRequest = captor.getValue();
+    DaprProtos.Job job = actualScheduleJobRequest.getJob();
+    assertEquals("testJob", job.getName());
+    assertFalse(job.hasData());
+    assertFalse(job.hasSchedule());
+    assertEquals(0, job.getRepeats());
+    assertFalse(job.hasTtl());
+    assertEquals(job.getDueTime(), actualScheduleJobRequest.getJob().getDueTime());
+  }
+
+  @Test
+  void scheduleJobShouldSucceedWhenRequiredFieldsNameAndScheduleArePresentInRequest() {
+
+    doAnswer(invocation -> {
+      StreamObserver observer = invocation.getArgument(1);
+      observer.onCompleted(); // Simulate successful response
+      return null;
+    }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any());
+
+    ScheduleJobRequest expectedScheduleJobRequest = ScheduleJobRequest.builder()
+        .setName("testJob")
+        .setSchedule(JobSchedule.fromString("* * * * * *"))
+        .build();
+    assertDoesNotThrow(() -> daprJobsClient.scheduleJob(expectedScheduleJobRequest).block());
+
+    ArgumentCaptor captor =
+        ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class);
+
+    verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any());
+    DaprProtos.ScheduleJobRequest actualScheduleJobRequest = captor.getValue();
+    DaprProtos.Job job = actualScheduleJobRequest.getJob();
+    assertEquals("testJob", job.getName());
+    assertFalse(job.hasData());
+    assertEquals( "* * * * * *", job.getSchedule());
+    assertEquals(0, job.getRepeats());
+    assertFalse(job.hasTtl());
+    assertEquals(job.getDueTime(), actualScheduleJobRequest.getJob().getDueTime());
+  }
+
+  @Test
+  void scheduleJobShouldThrowIllegalArgumentWhenBothScheduleAndDueTimeAreNotPresent() {
+    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
+      daprJobsClient.scheduleJob(ScheduleJobRequest.builder().setName("abcd").build()).block();
+    });
+    assertEquals("At least one of schedule or dueTime must be provided", exception.getMessage());
+  }
+
+  @Test
+  void scheduleJobShouldThrowWhenRequestIsNull() {
+    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
+      daprJobsClient.scheduleJob(null).block();
+    });
+    assertEquals("scheduleJobRequest cannot be null", exception.getMessage());
+  }
+
+  @Test
+  void scheduleJobShouldThrowWhenInvalidRequest() {
+    ScheduleJobRequest scheduleJobRequest = ScheduleJobRequest.builder()
+            .setData("testData".getBytes())
+            .build();
+
+    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
+      daprJobsClient.scheduleJob(scheduleJobRequest).block();
+    });
+    assertEquals("Name in the request cannot be null or empty", exception.getMessage());
+  }
+
+  @Test
+  void scheduleJobShouldThrowWhenNameInRequestIsEmpty() {
+    ScheduleJobRequest scheduleJobRequest = ScheduleJobRequest.builder().setName("").build();
+
+    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
+      daprJobsClient.scheduleJob(scheduleJobRequest).block();
+    });
+    assertEquals("Name in the request cannot be null or empty", exception.getMessage());
+  }
+
+  @Test
+  void getJobShouldReturnResponseWhenAllFieldsArePresentInRequest() {
+    GetJobRequest getJobRequest = GetJobRequest.builder().setName("testJob").build();
+
+    DaprProtos.Job job = DaprProtos.Job.newBuilder()
+            .setName("testJob")
+            .setTtl(OffsetDateTime.now().toString())
+            .setData(Any.newBuilder().setValue(ByteString.copyFrom("testData".getBytes())).build())
+            .setSchedule("*/5 * * * *")
+            .setRepeats(5)
+            .setDueTime(OffsetDateTime.now().plusMinutes(10).toString())
+            .build();
+
+    doAnswer(invocation -> {
+      StreamObserver observer = invocation.getArgument(1);
+      observer.onNext(DaprProtos.GetJobResponse.newBuilder()
+              .setJob(job)
+              .build());
+      observer.onCompleted();
+      return null;
+    }).when(daprStub).getJobAlpha1(any(DaprProtos.GetJobRequest.class), any());
+
+    Mono resultMono = daprJobsClient.getJob(getJobRequest);
+
+    GetJobResponse response = resultMono.block();
+    assertNotNull(response);
+    assertEquals("testJob", response.getName());
+    assertEquals("testData", new String(response.getData(), StandardCharsets.UTF_8));
+    assertEquals("*/5 * * * *", response.getSchedule().getExpression());
+    assertEquals(5, response.getRepeat());
+    assertEquals(job.getTtl(), response.getTtl().toString());
+    assertEquals(job.getDueTime(), response.getDueTime().toString());
+  }
+
+  @Test
+  void getJobShouldReturnResponseWhenRequiredFieldsArePresentInRequest() {
+    GetJobRequest getJobRequest = GetJobRequest.builder().setName("testJob").build();
+
+    DaprProtos.Job job = DaprProtos.Job.newBuilder()
+            .setName("testJob")
+            .build();
+
+    doAnswer(invocation -> {
+      StreamObserver observer = invocation.getArgument(1);
+      observer.onNext(DaprProtos.GetJobResponse.newBuilder()
+              .setJob(job)
+              .build());
+      observer.onCompleted();
+      return null;
+    }).when(daprStub).getJobAlpha1(any(DaprProtos.GetJobRequest.class), any());
+
+    Mono resultMono = daprJobsClient.getJob(getJobRequest);
+
+    GetJobResponse response = resultMono.block();
+    assertNotNull(response);
+    assertEquals("testJob", response.getName());
+    assertNull(response.getData());
+    assertNull(response.getSchedule());
+    assertNull(response.getRepeat());
+    assertNull(response.getTtl());
+    assertNull(response.getDueTime());
+  }
+
+  @Test
+  void getJobShouldThrowWhenRequestIsNull() {
+    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
+      daprJobsClient.getJob(null).block();
+    });
+    assertEquals("getJobRequest cannot be null", exception.getMessage());
+  }
+
+  @Test
+  void getJobShouldThrowWhenNameIsNullRequest() {
+    GetJobRequest getJobRequest = GetJobRequest.builder().build();
+
+    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
+      daprJobsClient.getJob(getJobRequest).block();
+    });
+    assertEquals("Name in the request cannot be null or empty", exception.getMessage());
+  }
+
+  @Test
+  void getJobShouldThrowWhenNameIsEmptyRequest() {
+    GetJobRequest getJobRequest = GetJobRequest.builder().setName("").build();
+
+    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
+      daprJobsClient.getJob(getJobRequest).block();
+    });
+    assertEquals("Name in the request cannot be null or empty", exception.getMessage());
+  }
+
+  @Test
+  void deleteJobShouldSucceedWhenValidRequest() {
+    DeleteJobRequest deleteJobRequest = DeleteJobRequest.builder().setName("testJob").build();
+
+    doAnswer(invocation -> {
+      StreamObserver observer = invocation.getArgument(1);
+      observer.onCompleted(); // Simulate successful response
+      return null;
+    }).when(daprStub).deleteJobAlpha1(any(DaprProtos.DeleteJobRequest.class), any());
+
+    Mono resultMono = daprJobsClient.deleteJob(deleteJobRequest);
+
+    assertDoesNotThrow(() -> resultMono.block());
+  }
+
+  @Test
+  void deleteJobShouldThrowRequestIsNull() {
+    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
+      daprJobsClient.deleteJob(null).block();
+    });
+    assertEquals("deleteJobRequest cannot be null", exception.getMessage());
+  }
+
+  @Test
+  void deleteJobShouldThrowWhenNameIsNullRequest() {
+    DeleteJobRequest deleteJobRequest = DeleteJobRequest.builder().build();
+    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
+      daprJobsClient.deleteJob(deleteJobRequest).block();
+    });
+    assertEquals("Name in the request cannot be null or empty", exception.getMessage());
+  }
+
+  @Test
+  void deleteJobShouldThrowWhenNameIsEmptyRequest() {
+    DeleteJobRequest deleteJobRequest = DeleteJobRequest.builder().setName("").build();
+    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
+      daprJobsClient.deleteJob(deleteJobRequest).block();
+    });
+    assertEquals("Name in the request cannot be null or empty", exception.getMessage());
+  }
+
+  @Test
+  void closeShouldCloseChannel() throws Exception {
+    ManagedChannel mockChannel = mock(ManagedChannel.class);
+    when(daprStub.getChannel()).thenReturn(mockChannel);
+
+    when(mockChannel.isShutdown()).thenReturn(Boolean.valueOf(false));
+
+    daprJobsClient.close();
+
+    verify(mockChannel, times(1)).shutdown();
+  }
+}
\ No newline at end of file
diff --git a/sdk-jobs/test/test/io/dapr/jobs/JobsScheduleTest.java b/sdk-jobs/test/test/java/io/dapr/jobs/client/JobsScheduleTest.java
similarity index 65%
rename from sdk-jobs/test/test/io/dapr/jobs/JobsScheduleTest.java
rename to sdk-jobs/test/test/java/io/dapr/jobs/client/JobsScheduleTest.java
index b37b372cb2..0a70c45414 100644
--- a/sdk-jobs/test/test/io/dapr/jobs/JobsScheduleTest.java
+++ b/sdk-jobs/test/test/java/io/dapr/jobs/client/JobsScheduleTest.java
@@ -12,57 +12,63 @@ class JobsScheduleTest {
   void testFromPeriodValidDuration() {
     Duration duration = Duration.ofHours(1).plusMinutes(30)
         .plusSeconds(15).plusMillis(500);
-    JobsSchedule schedule = JobsSchedule.fromPeriod(duration);
+    JobSchedule schedule = JobSchedule.fromPeriod(duration);
     assertEquals("@every 1h30m15s500ms", schedule.getExpression());
   }
 
   @Test
   void testFromPeriodValidDurationWithoutSecondsAndMillSeconds() {
     Duration duration = Duration.ofHours(1).plusMinutes(30);
-    JobsSchedule schedule = JobsSchedule.fromPeriod(duration);
+    JobSchedule schedule = JobSchedule.fromPeriod(duration);
     assertEquals("@every 1h30m0s0ms", schedule.getExpression());
   }
 
   @Test
   void testFromPeriodNullDuration() {
-    Exception exception = assertThrows(IllegalArgumentException.class, () -> JobsSchedule.fromPeriod(null));
+    Exception exception = assertThrows(IllegalArgumentException.class, () -> JobSchedule.fromPeriod(null));
     assertEquals("duration cannot be null", exception.getMessage());
   }
 
+  @Test
+  void testFromStringThrowsIllegalArgumentWhenExpressionIsNull() {
+    Exception exception = assertThrows(IllegalArgumentException.class, () -> JobSchedule.fromString(null));
+    assertEquals("cronExpression cannot be null", exception.getMessage());
+  }
+
   @Test
   void testFromString() {
     String cronExpression = "0 0 * * *";
-    JobsSchedule schedule = JobsSchedule.fromString(cronExpression);
+    JobSchedule schedule = JobSchedule.fromString(cronExpression);
     assertEquals(cronExpression, schedule.getExpression());
   }
 
   @Test
   void testYearly() {
-    JobsSchedule schedule = JobsSchedule.yearly();
+    JobSchedule schedule = JobSchedule.yearly();
     assertEquals("0 0 0 1 1 *", schedule.getExpression());
   }
 
   @Test
   void testMonthly() {
-    JobsSchedule schedule = JobsSchedule.monthly();
+    JobSchedule schedule = JobSchedule.monthly();
     assertEquals("0 0 0 1 * *", schedule.getExpression());
   }
 
   @Test
   void testWeekly() {
-    JobsSchedule schedule = JobsSchedule.weekly();
+    JobSchedule schedule = JobSchedule.weekly();
     assertEquals("0 0 0 * * 0", schedule.getExpression());
   }
 
   @Test
   void testDaily() {
-    JobsSchedule schedule = JobsSchedule.daily();
+    JobSchedule schedule = JobSchedule.daily();
     assertEquals("0 0 0 * * *", schedule.getExpression());
   }
 
   @Test
   void testHourly() {
-    JobsSchedule schedule = JobsSchedule.hourly();
+    JobSchedule schedule = JobSchedule.hourly();
     assertEquals("0 0 * * * *", schedule.getExpression());
   }
 }
diff --git a/sdk-tests/pom.xml b/sdk-tests/pom.xml
index 850dd0e6d8..a2267e250f 100644
--- a/sdk-tests/pom.xml
+++ b/sdk-tests/pom.xml
@@ -151,6 +151,12 @@
       ${dapr.sdk.version}
       test
     
+    
+      io.dapr
+      dapr-sdk-jobs
+      ${dapr.sdk.version}
+      test
+    
     
       io.dapr
       dapr-sdk-actors
diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java
new file mode 100644
index 0000000000..5754d53b4f
--- /dev/null
+++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java
@@ -0,0 +1,139 @@
+package io.dapr.it.testcontainers;
+
+import io.dapr.jobs.client.*;
+import io.dapr.testcontainers.DaprContainer;
+import io.dapr.testcontainers.DaprLogLevel;
+import org.junit.Assert;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+import org.testcontainers.containers.Network;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+import java.time.OffsetDateTime;
+import java.util.Random;
+
+@SpringBootTest(
+    webEnvironment = WebEnvironment.RANDOM_PORT,
+    classes = {
+        TestDaprJobsConfiguration.class,
+        TestJobsApplication.class
+    }
+)
+@Testcontainers
+@Tag("testcontainers")
+public class DaprJobsIT {
+
+  private static final Network DAPR_NETWORK = Network.newNetwork();
+  private static final Random RANDOM = new Random();
+  private static final int PORT = RANDOM.nextInt(1000) + 8000;
+
+  @Container
+  private static final DaprContainer DAPR_CONTAINER = new DaprContainer("daprio/daprd:1.15.2")
+      .withAppName("jobs-dapr-app")
+      .withNetwork(DAPR_NETWORK)
+      .withDaprLogLevel(DaprLogLevel.DEBUG)
+      .withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
+      .withAppChannelAddress("host.testcontainers.internal")
+      .withAppPort(PORT);
+
+  /**
+   * Expose the Dapr ports to the host.
+   *
+   * @param registry the dynamic property registry
+   */
+  @DynamicPropertySource
+  static void daprProperties(DynamicPropertyRegistry registry) {
+    registry.add("dapr.http.endpoint", DAPR_CONTAINER::getHttpEndpoint);
+    registry.add("dapr.grpc.endpoint", DAPR_CONTAINER::getGrpcEndpoint);
+    registry.add("server.port", () -> PORT);
+  }
+
+  @Autowired
+  private DaprJobsClient daprJobsClient;
+
+  @BeforeEach
+  public void setUp(){
+    org.testcontainers.Testcontainers.exposeHostPorts(PORT);
+    // Ensure the subscriptions are registered
+  }
+
+  @Test
+  public void testJobScheduleCreationWithDueTime() {
+    OffsetDateTime currentTime = OffsetDateTime.now();
+    daprJobsClient.scheduleJob(ScheduleJobRequest.builder().setName("Job").setDueTime(currentTime).build()).block();
+
+    GetJobResponse getJobResponse =
+        daprJobsClient.getJob(GetJobRequest.builder().setName("Job").build()).block();
+    Assert.assertEquals(currentTime.toString(), getJobResponse.getDueTime().toString());
+    Assert.assertEquals("Job", getJobResponse.getName());
+  }
+
+  @Test
+  public void testJobScheduleCreationWithSchedule() {
+    OffsetDateTime currentTime = OffsetDateTime.now();
+    daprJobsClient.scheduleJob(ScheduleJobRequest.builder().setName("Job")
+        .setSchedule(JobSchedule.hourly())
+        .setDueTime(currentTime).build()).block();
+
+    GetJobResponse getJobResponse =
+        daprJobsClient.getJob(GetJobRequest.builder().setName("Job").build()).block();
+    Assert.assertEquals(currentTime.toString(), getJobResponse.getDueTime().toString());
+    Assert.assertEquals(JobSchedule.hourly().getExpression(), getJobResponse.getSchedule().getExpression());
+    Assert.assertEquals("Job", getJobResponse.getName());
+  }
+
+  @Test
+  public void testJobScheduleCreationWithAllParameters() {
+    OffsetDateTime currentTime = OffsetDateTime.now();
+
+    String cronExpression = new CronExpressionBuilder()
+        .add(CronPeriod.SECONDS, 2)
+        .add(CronPeriod.HOURS, 3)
+        .add(DayOfWeek.FRI)
+        .build();
+
+    daprJobsClient.scheduleJob(ScheduleJobRequest.builder().setName("Job")
+        .setTtl(currentTime.plusHours(2))
+        .setData("Job data".getBytes())
+        .setRepeat(3)
+        .setSchedule(JobSchedule.fromString(cronExpression))
+        .setDueTime(currentTime).build()).block();
+
+    GetJobResponse getJobResponse =
+        daprJobsClient.getJob(GetJobRequest.builder().setName("Job").build()).block();
+    Assertions.assertEquals(currentTime.toString(), getJobResponse.getDueTime().toString());
+    Assertions.assertEquals("2 * 3 * * FRI", getJobResponse.getSchedule().getExpression());
+    Assertions.assertEquals("Job", getJobResponse.getName());
+    Assertions.assertEquals(3, getJobResponse.getRepeat());
+    Assertions.assertEquals("Job data", new String(getJobResponse.getData()));
+    Assertions.assertEquals(currentTime.plusHours(2), getJobResponse.getTtl());
+  }
+
+  @Test
+  public void testDeleteJobRequest() {
+    OffsetDateTime currentTime = OffsetDateTime.now();
+
+    String cronExpression = new CronExpressionBuilder()
+        .add(CronPeriod.SECONDS, 2)
+        .add(CronPeriod.HOURS, 3)
+        .add(DayOfWeek.FRI)
+        .build();
+
+    daprJobsClient.scheduleJob(ScheduleJobRequest.builder().setName("Job")
+        .setTtl(currentTime.plusHours(2))
+        .setData("Job data".getBytes())
+        .setRepeat(3)
+        .setSchedule(JobSchedule.fromString(cronExpression))
+        .setDueTime(currentTime).build()).block();
+
+    daprJobsClient.deleteJob(DeleteJobRequest.builder().setName("Job").build()).block();
+  }
+}
diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprJobsConfiguration.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprJobsConfiguration.java
new file mode 100644
index 0000000000..e565b18017
--- /dev/null
+++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprJobsConfiguration.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2025 The Dapr Authors
+ * 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 io.dapr.it.testcontainers;
+
+import io.dapr.config.Properties;
+import io.dapr.jobs.client.DaprJobsClient;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Map;
+
+@Configuration
+public class TestDaprJobsConfiguration {
+  @Bean
+  public DaprJobsClient daprJobsClient(
+      @Value("${dapr.http.endpoint}") String daprHttpEndpoint,
+      @Value("${dapr.grpc.endpoint}") String daprGrpcEndpoint
+  ){
+    Map overrides = Map.of(
+        "dapr.http.endpoint", daprHttpEndpoint,
+        "dapr.grpc.endpoint", daprGrpcEndpoint
+    );
+
+    return new DaprJobsClient(new Properties(overrides), null);
+  }
+}
diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestJobsApplication.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestJobsApplication.java
new file mode 100644
index 0000000000..61ddaea792
--- /dev/null
+++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestJobsApplication.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2024 The Dapr Authors
+ * 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 io.dapr.it.testcontainers;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class TestJobsApplication {
+
+  public static void main(String[] args) {
+    SpringApplication.run(TestJobsApplication.class, args);
+  }
+
+}
diff --git a/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java
index 145f61deaa..c3fb7a2ac9 100644
--- a/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java
+++ b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java
@@ -27,6 +27,7 @@
 import org.testcontainers.containers.wait.strategy.WaitStrategy;
 import org.testcontainers.images.builder.Transferable;
 import org.testcontainers.utility.DockerImageName;
+import org.testcontainers.utility.MountableFile;
 import org.yaml.snakeyaml.Yaml;
 
 import java.io.IOException;
@@ -62,14 +63,18 @@ public class DaprContainer extends GenericContainer {
   private DaprLogLevel daprLogLevel = DaprLogLevel.INFO;
   private String appChannelAddress = "localhost";
   private String placementService = "placement";
+  private String schedulerService = "scheduler";
   private String placementDockerImageName = "daprio/placement";
+  private String schedulerDockerImageName = "daprio/scheduler";
 
   private Configuration configuration;
   private DaprPlacementContainer placementContainer;
+  private DaprSchedulerContainer schedulerContainer;
   private String appName;
   private Integer appPort;
   private String appHealthCheckPath;
   private boolean shouldReusePlacement;
+  private boolean shouldReuseScheduler;
 
   /**
    * Creates a new Dapr container.
@@ -157,8 +162,13 @@ public DaprContainer withPlacementImage(String placementDockerImageName) {
     return this;
   }
 
-  public DaprContainer withReusablePlacement(boolean reuse) {
-    this.shouldReusePlacement = reuse;
+  public DaprContainer withReusablePlacement(boolean shouldReusePlacement) {
+    this.shouldReusePlacement = shouldReusePlacement;
+    return this;
+  }
+
+  public DaprContainer withResueScheduler(boolean shouldReuseScheduler) {
+    this.shouldReuseScheduler = shouldReuseScheduler;
     return this;
   }
 
@@ -167,6 +177,11 @@ public DaprContainer withPlacementContainer(DaprPlacementContainer placementCont
     return this;
   }
 
+  public DaprContainer withSchedulerContainer(DaprSchedulerContainer schedulerContainer) {
+    this.schedulerContainer = schedulerContainer;
+    return this;
+  }
+
   public DaprContainer withComponent(Component component) {
     components.add(component);
     return this;
@@ -237,6 +252,14 @@ protected void configure() {
       this.placementContainer.start();
     }
 
+    if (this.schedulerContainer == null) {
+      this.schedulerContainer = new DaprSchedulerContainer(this.schedulerDockerImageName)
+          .withNetwork(getNetwork())
+          .withNetworkAliases(schedulerService)
+          .withReuse(this.shouldReuseScheduler);
+      this.schedulerContainer.start();
+    }
+
     List cmds = new ArrayList<>();
     cmds.add("./daprd");
     cmds.add("--app-id");
@@ -246,6 +269,8 @@ protected void configure() {
     cmds.add(DAPR_PROTOCOL.getName());
     cmds.add("--placement-host-address");
     cmds.add(placementService + ":50005");
+    cmds.add("--scheduler-host-address");
+    cmds.add(schedulerService + ":51005");
 
     if (appChannelAddress != null && !appChannelAddress.isEmpty()) {
       cmds.add("--app-channel-address");
@@ -324,7 +349,7 @@ protected void configure() {
       withCopyToContainer(Transferable.of(endpointYaml), "/dapr-resources/" + endpoint.getName() + ".yaml");
     }
 
-    dependsOn(placementContainer);
+    dependsOn(placementContainer, schedulerContainer);
   }
 
   public String getAppName() {
diff --git a/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprSchedulerContainer.java b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprSchedulerContainer.java
new file mode 100644
index 0000000000..bcac6a426e
--- /dev/null
+++ b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprSchedulerContainer.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2024 The Dapr Authors
+ * 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 io.dapr.testcontainers;
+
+import org.testcontainers.containers.BindMode;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.images.builder.Transferable;
+import org.testcontainers.utility.DockerImageName;
+import org.testcontainers.utility.MountableFile;
+
+import java.io.IOException;
+
+/**
+ * Test container for Dapr scheduler service.
+ */
+public class DaprSchedulerContainer extends GenericContainer {
+
+  private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("daprio/scheduler");
+  private int schedulerPort = 51005;
+
+  /**
+   * Creates a new Dapr scheduler container.
+   * @param dockerImageName Docker image name.
+   */
+  public DaprSchedulerContainer(DockerImageName dockerImageName) {
+    super(dockerImageName);
+    dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME);
+    withExposedPorts(schedulerPort);
+  }
+
+  /**
+   * Creates a new Dapr scheduler container.
+   * @param image Docker image name.
+   */
+  public DaprSchedulerContainer(String image) {
+    this(DockerImageName.parse(image));
+  }
+
+  @Override
+  protected void configure() {
+    super.configure();
+
+    withCopyToContainer(Transferable.of("", 0777), "./default-dapr-scheduler-server-0/dapr-0.1/");
+    withCopyToContainer(Transferable.of("", 0777), "./dapr-scheduler-existing-cluster/");
+    withCommand("./scheduler", "--port", Integer.toString(schedulerPort), "--etcd-data-dir", ".");
+  }
+
+  public static DockerImageName getDefaultImageName() {
+    return DEFAULT_IMAGE_NAME;
+  }
+
+  public DaprSchedulerContainer withPort(Integer port) {
+    this.schedulerPort = port;
+    return this;
+  }
+
+  public int getPort() {
+    return schedulerPort;
+  }
+
+  // Required by spotbugs plugin
+  @Override
+  public boolean equals(Object o) {
+    return super.equals(o);
+  }
+
+  @Override
+  public int hashCode() {
+    return super.hashCode();
+  }
+}

From a8a340fa1ad389119b56cc8f075d671bed5d568e Mon Sep 17 00:00:00 2001
From: sirivarma 
Date: Thu, 13 Mar 2025 22:28:23 -0700
Subject: [PATCH 05/30] Remove builder and change to setter

Signed-off-by: sirivarma 
---
 .../io/dapr/jobs/client/DaprJobsClient.java   |  23 ++-
 .../io/dapr/jobs/client/DeleteJobRequest.java |  38 +---
 .../io/dapr/jobs/client/GetJobRequest.java    |  38 +---
 .../io/dapr/jobs/client/GetJobResponse.java   | 189 ++++++++----------
 .../dapr/jobs/client/ScheduleJobRequest.java  | 185 ++++++++---------
 .../dapr/jobs/client/DaprJobsClientTest.java  |  53 ++---
 6 files changed, 203 insertions(+), 323 deletions(-)

diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/DaprJobsClient.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/DaprJobsClient.java
index db219d9591..7aa704da1c 100644
--- a/sdk-jobs/src/main/java/io/dapr/jobs/client/DaprJobsClient.java
+++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/DaprJobsClient.java
@@ -161,16 +161,19 @@ public Mono getJob(GetJobRequest getJobRequest) {
               )
           );
 
-      return getJobResponseMono.map(getJobResponse -> {
-        DaprProtos.Job job = getJobResponse.getJob();
-        return GetJobResponse.builder()
-                .setName(job.getName())
-                .setTtl(job.hasTtl() ? OffsetDateTime.parse(job.getTtl()) : null)
-                .setData(job.hasData() ? job.getData().getValue().toByteArray() : null)
-                .setRepeat(job.hasRepeats() ? job.getRepeats() : null)
-                .setSchedule(job.hasSchedule() ? JobSchedule.fromString(job.getSchedule()) : null)
-                .setDueTime(job.hasDueTime() ? OffsetDateTime.parse(job.getDueTime()) : null)
-                .build();
+      return getJobResponseMono.map(response -> {
+        DaprProtos.Job job = response.getJob();
+        GetJobResponse getJobResponse = null;
+        if (job.hasSchedule()) {
+          getJobResponse = new GetJobResponse(job.getName(), JobSchedule.fromString(job.getSchedule()));
+        } else {
+          getJobResponse = new GetJobResponse(job.getName(), OffsetDateTime.parse(job.getDueTime()));
+        }
+
+        return getJobResponse
+            .setTtl(job.hasTtl() ? OffsetDateTime.parse(job.getTtl()) : null)
+            .setData(job.hasData() ? job.getData().getValue().toByteArray() : null)
+            .setRepeat(job.hasRepeats() ? job.getRepeats() : null);
       });
     } catch (Exception ex) {
       return DaprException.wrapMono(ex);
diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/DeleteJobRequest.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/DeleteJobRequest.java
index 358ba386ed..abdf4c18c4 100644
--- a/sdk-jobs/src/main/java/io/dapr/jobs/client/DeleteJobRequest.java
+++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/DeleteJobRequest.java
@@ -6,45 +6,15 @@
 public class DeleteJobRequest {
   private final String name;
 
-  private DeleteJobRequest(Builder builder) {
-    this.name = builder.name;
-  }
-
   /**
-   * Creates a new builder instance for {@link DeleteJobRequest}.
+   * Constructor to create Delete Job Request.
    *
-   * @return A new {@link Builder} instance.
+   * @param name of the job to delete.
    */
-  public static Builder builder() {
-    return new Builder();
+  public DeleteJobRequest(String name) {
+    this.name = name;
   }
 
-  public static class Builder {
-    private String name;
-
-    /**
-     * Sets the name of the job.
-     *
-     * @param name The job name.
-     * @return This builder instance.
-     */
-    public Builder setName(String name) {
-      this.name = name;
-      return this;
-    }
-
-    /**
-     * Builds a {@link DeleteJobRequest} instance.
-     *
-     * @return A new {@link DeleteJobRequest} instance.
-     */
-    public DeleteJobRequest build() {
-      return new DeleteJobRequest(this);
-    }
-  }
-
-  // Getters
-
   /**
    * Gets the name of the job.
    *
diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobRequest.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobRequest.java
index 3c8a428b84..7c32509aca 100644
--- a/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobRequest.java
+++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobRequest.java
@@ -6,45 +6,15 @@
 public class GetJobRequest {
   private final String name;
 
-  private GetJobRequest(Builder builder) {
-    this.name = builder.name;
-  }
-
   /**
-   * Creates a new builder instance for {@link GetJobRequest}.
+   * Constructor to create Get Job Request.
    *
-   * @return A new {@link Builder} instance.
+   * @param name of the job to fetch..
    */
-  public static Builder builder() {
-    return new Builder();
+  public GetJobRequest(String name) {
+    this.name = name;
   }
 
-  public static class Builder {
-    private String name;
-
-    /**
-     * Sets the name of the job.
-     *
-     * @param name The job name.
-     * @return This builder instance.
-     */
-    public Builder setName(String name) {
-      this.name = name;
-      return this;
-    }
-
-    /**
-     * Builds a {@link GetJobRequest} instance.
-     *
-     * @return A new {@link GetJobRequest} instance.
-     */
-    public GetJobRequest build() {
-      return new GetJobRequest(this);
-    }
-  }
-
-  // Getters
-
   /**
    * Gets the name of the job.
    *
diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobResponse.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobResponse.java
index 62c6e8b5e6..6759802186 100644
--- a/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobResponse.java
+++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobResponse.java
@@ -7,117 +7,94 @@
  */
 public class GetJobResponse {
   private final String name;
-  private final byte[] data;
-  private final JobSchedule schedule;
-  private final OffsetDateTime dueTime;
-  private final Integer repeat;
-  private final OffsetDateTime ttl;
-
-  private GetJobResponse(Builder builder) {
-    this.name = builder.name;
-    this.data = builder.data;
-    this.schedule = builder.schedule;
-    this.dueTime = builder.dueTime;
-    this.repeat = builder.repeat;
-    this.ttl = builder.ttl;
+  private byte[] data;
+  private JobSchedule schedule;
+  private OffsetDateTime dueTime;
+  private Integer repeats;
+  private OffsetDateTime ttl;
+
+  /**
+   * Constructor to create GetJobResponse.
+   *
+   * @param name of the job.
+   * @param schedule job has to run.
+   */
+  public GetJobResponse(String name, JobSchedule schedule) {
+    this.name = name;
+    this.schedule = schedule;
+  }
+
+  /**
+   * Constructor to create GetJobResponse.
+   *
+   * @param name of the job.
+   * @param dueTime An optional time at which the job should be active, or the “one shot” time, if other scheduling
+   *                type fields are not provided. Accepts a “point in time” string in the format of RFC3339,
+   *                Go duration string (calculated from creation time), or non-repeating ISO8601
+   */
+  public GetJobResponse(String name, OffsetDateTime dueTime) {
+    this.name = name;
+    this.dueTime = dueTime;
+  }
+
+  /**
+   * Sets the data payload for the job.
+   * This should be a JSON serialized value or object.
+   *
+   * @param data The job data in byte array format.
+   * @return This builder instance.
+   */
+  public GetJobResponse setData(byte[] data) {
+    this.data = data;
+    return this;
   }
 
   /**
-   * Creates a new builder instance for {@link GetJobResponse}.
+   * Sets the schedule for the job.
+   * The format should follow cron expressions or other supported scheduling formats.
    *
-   * @return A new {@link Builder} instance.
+   * @param schedule The job schedule.
+   * @return This builder instance.
    */
-  public static Builder builder() {
-    return new Builder();
+  public GetJobResponse setSchedule(JobSchedule schedule) {
+    this.schedule = schedule;
+    return this;
   }
 
-  public static class Builder {
-    private String name;
-    private byte[] data;
-    private JobSchedule schedule;
-    private OffsetDateTime dueTime;
-    private Integer repeat;
-    private OffsetDateTime ttl;
-
-    /**
-     * Sets the name of the job.
-     *
-     * @param name The job name.
-     * @return This builder instance.
-     */
-    public Builder setName(String name) {
-      this.name = name;
-      return this;
-    }
-
-    /**
-     * Sets the data payload for the job.
-     * This should be a JSON serialized value or object.
-     *
-     * @param data The job data in byte array format.
-     * @return This builder instance.
-     */
-    public Builder setData(byte[] data) {
-      this.data = data;
-      return this;
-    }
-
-    /**
-     * Sets the schedule for the job.
-     * The format should follow cron expressions or other supported scheduling formats.
-     *
-     * @param schedule The job schedule.
-     * @return This builder instance.
-     */
-    public Builder setSchedule(JobSchedule schedule) {
-      this.schedule = schedule;
-      return this;
-    }
-
-    /**
-     * Sets the due time when the job should become active or execute once.
-     * This can be in RFC3339, Go duration string, or non-repeating ISO8601 format.
-     *
-     * @param dueTime The due time of the job.
-     * @return This builder instance.
-     */
-    public Builder setDueTime(OffsetDateTime dueTime) {
-      this.dueTime = dueTime;
-      return this;
-    }
-
-    /**
-     * Sets the number of times the job should be triggered.
-     * If not set, the job runs indefinitely or until expiration.
-     *
-     * @param repeat The number of times the job should repeat.
-     * @return This builder instance.
-     */
-    public Builder setRepeat(Integer repeat) {
-      this.repeat = repeat;
-      return this;
-    }
-
-    /**
-     * Sets the time-to-live (TTL) or expiration for the job.
-     * This can be in RFC3339, Go duration string, or non-repeating ISO8601 format.
-     *
-     * @param ttl The time-to-live for the job.
-     * @return This builder instance.
-     */
-    public Builder setTtl(OffsetDateTime ttl) {
-      this.ttl = ttl;
-      return this;
-    }
-
-    /**
-     * Builds a {@link GetJobResponse} instance.
-     *
-     * @return A new {@link GetJobResponse} instance.
-     */
-    public GetJobResponse build() {
-      return new GetJobResponse(this);
-    }
+  /**
+   * Sets the due time when the job should become active or execute once.
+   * This can be in RFC3339, Go duration string, or non-repeating ISO8601 format.
+   *
+   * @param dueTime The due time of the job.
+   * @return This builder instance.
+   */
+  public GetJobResponse setDueTime(OffsetDateTime dueTime) {
+    this.dueTime = dueTime;
+    return this;
+  }
+
+  /**
+   * Sets the number of times the job should be triggered.
+   * If not set, the job runs indefinitely or until expiration.
+   *
+   * @param repeats The number of times the job should repeat.
+   * @return This builder instance.
+   */
+  public GetJobResponse setRepeat(Integer repeats) {
+    this.repeats = repeats;
+    return this;
+  }
+
+  /**
+   * Sets the time-to-live (TTL) or expiration for the job.
+   * This can be in RFC3339, Go duration string, or non-repeating ISO8601 format.
+   *
+   * @param ttl The time-to-live for the job.
+   * @return This builder instance.
+   */
+  public GetJobResponse setTtl(OffsetDateTime ttl) {
+    this.ttl = ttl;
+    return this;
   }
 
   // Getters
@@ -163,8 +140,8 @@ public OffsetDateTime getDueTime() {
    *
    * @return The repeat count, or null if not set.
    */
-  public Integer getRepeat() {
-    return repeat;
+  public Integer getRepeats() {
+    return repeats;
   }
 
   /**
diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/ScheduleJobRequest.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/ScheduleJobRequest.java
index 783fb3a32e..5477d8c8de 100644
--- a/sdk-jobs/src/main/java/io/dapr/jobs/client/ScheduleJobRequest.java
+++ b/sdk-jobs/src/main/java/io/dapr/jobs/client/ScheduleJobRequest.java
@@ -7,117 +7,94 @@
  */
 public class ScheduleJobRequest {
   private final String name;
-  private final byte[] data;
-  private final JobSchedule schedule;
-  private final OffsetDateTime dueTime;
-  private final Integer repeats;
-  private final OffsetDateTime ttl;
-
-  private ScheduleJobRequest(Builder builder) {
-    this.name = builder.name;
-    this.data = builder.data;
-    this.schedule = builder.schedule;
-    this.dueTime = builder.dueTime;
-    this.repeats = builder.repeat;
-    this.ttl = builder.ttl;
+  private byte[] data;
+  private JobSchedule schedule;
+  private OffsetDateTime dueTime;
+  private Integer repeats;
+  private OffsetDateTime ttl;
+
+  /**
+   * Constructor to create ScheduleJobRequest.
+   *
+   * @param name of the job.
+   * @param schedule job has to run.
+   */
+  public ScheduleJobRequest(String name, JobSchedule schedule) {
+    this.name = name;
+    this.schedule = schedule;
+  }
+
+  /**
+   * Constructor to create ScheduleJobRequest.
+   *
+   * @param name of the job.
+   * @param dueTime An optional time at which the job should be active, or the “one shot” time, if other scheduling
+   *                type fields are not provided. Accepts a “point in time” string in the format of RFC3339,
+   *                Go duration string (calculated from creation time), or non-repeating ISO8601
+   */
+  public ScheduleJobRequest(String name, OffsetDateTime dueTime) {
+    this.name = name;
+    this.dueTime = dueTime;
+  }
+
+  /**
+   * Sets the data payload for the job.
+   * This should be a JSON serialized value or object.
+   *
+   * @param data The job data in byte array format.
+   * @return This builder instance.
+   */
+  public ScheduleJobRequest setData(byte[] data) {
+    this.data = data;
+    return this;
   }
 
   /**
-   * Creates a new builder instance for {@link ScheduleJobRequest}.
+   * Sets the schedule for the job.
+   * The format should follow cron expressions or other supported scheduling formats.
    *
-   * @return A new {@link Builder} instance.
+   * @param schedule The job schedule.
+   * @return This builder instance.
    */
-  public static Builder builder() {
-    return new Builder();
+  public ScheduleJobRequest setSchedule(JobSchedule schedule) {
+    this.schedule = schedule;
+    return this;
   }
 
-  public static class Builder {
-    private String name;
-    private byte[] data;
-    private JobSchedule schedule;
-    private OffsetDateTime dueTime;
-    private Integer repeat;
-    private OffsetDateTime ttl;
-
-    /**
-     * Sets the name of the job.
-     *
-     * @param name The job name.
-     * @return This builder instance.
-     */
-    public Builder setName(String name) {
-      this.name = name;
-      return this;
-    }
-
-    /**
-     * Sets the data payload for the job.
-     * This should be a JSON serialized value or object.
-     *
-     * @param data The job data in byte array format.
-     * @return This builder instance.
-     */
-    public Builder setData(byte[] data) {
-      this.data = data;
-      return this;
-    }
-
-    /**
-     * Sets the schedule for the job.
-     * The format should follow cron expressions or other supported scheduling formats.
-     *
-     * @param schedule The job schedule.
-     * @return This builder instance.
-     */
-    public Builder setSchedule(JobSchedule schedule) {
-      this.schedule = schedule;
-      return this;
-    }
-
-    /**
-     * Sets the due time when the job should become active or execute once.
-     * This can be in RFC3339, Go duration string, or non-repeating ISO8601 format.
-     *
-     * @param dueTime The due time of the job.
-     * @return This builder instance.
-     */
-    public Builder setDueTime(OffsetDateTime dueTime) {
-      this.dueTime = dueTime;
-      return this;
-    }
-
-    /**
-     * Sets the number of times the job should be triggered.
-     * If not set, the job runs indefinitely or until expiration.
-     *
-     * @param repeat The number of times the job should repeat.
-     * @return This builder instance.
-     */
-    public Builder setRepeat(Integer repeat) {
-      this.repeat = repeat;
-      return this;
-    }
-
-    /**
-     * Sets the time-to-live (TTL) or expiration for the job.
-     * This can be in RFC3339, Go duration string, or non-repeating ISO8601 format.
-     *
-     * @param ttl The time-to-live for the job.
-     * @return This builder instance.
-     */
-    public Builder setTtl(OffsetDateTime ttl) {
-      this.ttl = ttl;
-      return this;
-    }
-
-    /**
-     * Builds a {@link ScheduleJobRequest} instance.
-     *
-     * @return A new {@link ScheduleJobRequest} instance.
-     */
-    public ScheduleJobRequest build() {
-      return new ScheduleJobRequest(this);
-    }
+  /**
+   * Sets the due time when the job should become active or execute once.
+   * This can be in RFC3339, Go duration string, or non-repeating ISO8601 format.
+   *
+   * @param dueTime The due time of the job.
+   * @return This builder instance.
+   */
+  public ScheduleJobRequest setDueTime(OffsetDateTime dueTime) {
+    this.dueTime = dueTime;
+    return this;
+  }
+
+  /**
+   * Sets the number of times the job should be triggered.
+   * If not set, the job runs indefinitely or until expiration.
+   *
+   * @param repeats The number of times the job should repeat.
+   * @return This builder instance.
+   */
+  public ScheduleJobRequest setRepeat(Integer repeats) {
+    this.repeats = repeats;
+    return this;
+  }
+
+  /**
+   * Sets the time-to-live (TTL) or expiration for the job.
+   * This can be in RFC3339, Go duration string, or non-repeating ISO8601 format.
+   *
+   * @param ttl The time-to-live for the job.
+   * @return This builder instance.
+   */
+  public ScheduleJobRequest setTtl(OffsetDateTime ttl) {
+    this.ttl = ttl;
+    return this;
   }
 
   // Getters
diff --git a/sdk-jobs/test/test/java/io/dapr/jobs/client/DaprJobsClientTest.java b/sdk-jobs/test/test/java/io/dapr/jobs/client/DaprJobsClientTest.java
index da48f4212d..1b2e13afb2 100644
--- a/sdk-jobs/test/test/java/io/dapr/jobs/client/DaprJobsClientTest.java
+++ b/sdk-jobs/test/test/java/io/dapr/jobs/client/DaprJobsClientTest.java
@@ -39,14 +39,12 @@ void setup() {
 
   @Test
   void scheduleJobShouldSucceedWhenAllFieldsArePresentInRequest() {
-    ScheduleJobRequest expectedScheduleJobRequest = ScheduleJobRequest.builder()
-            .setName("testJob")
+    ScheduleJobRequest expectedScheduleJobRequest = new ScheduleJobRequest("testJob",
+        JobSchedule.fromString("*/5 * * * *"))
             .setData("testData".getBytes())
-            .setSchedule(JobSchedule.fromString("*/5 * * * *"))
             .setTtl(OffsetDateTime.now().plusDays(1))
             .setRepeat(5)
-            .setDueTime(OffsetDateTime.now().plusMinutes(10))
-            .build();
+            .setDueTime(OffsetDateTime.now().plusMinutes(10));
 
     doAnswer(invocation -> {
       StreamObserver observer = invocation.getArgument(1);
@@ -80,10 +78,8 @@ void scheduleJobShouldSucceedWhenRequiredFieldsNameAndDueTimeArePresentInRequest
       return null;
     }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any());
 
-    ScheduleJobRequest expectedScheduleJobRequest = ScheduleJobRequest.builder()
-        .setName("testJob")
-        .setDueTime(OffsetDateTime.now().plusMinutes(10))
-        .build();
+    ScheduleJobRequest expectedScheduleJobRequest =
+        new ScheduleJobRequest("testJob", OffsetDateTime.now().plusMinutes(10));
     assertDoesNotThrow(() -> daprJobsClient.scheduleJob(expectedScheduleJobRequest).block());
 
     ArgumentCaptor captor =
@@ -109,10 +105,8 @@ void scheduleJobShouldSucceedWhenRequiredFieldsNameAndScheduleArePresentInReques
       return null;
     }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any());
 
-    ScheduleJobRequest expectedScheduleJobRequest = ScheduleJobRequest.builder()
-        .setName("testJob")
-        .setSchedule(JobSchedule.fromString("* * * * * *"))
-        .build();
+    ScheduleJobRequest expectedScheduleJobRequest = new ScheduleJobRequest("testJob",
+        JobSchedule.fromString("* * * * * *"));
     assertDoesNotThrow(() -> daprJobsClient.scheduleJob(expectedScheduleJobRequest).block());
 
     ArgumentCaptor captor =
@@ -129,14 +123,6 @@ void scheduleJobShouldSucceedWhenRequiredFieldsNameAndScheduleArePresentInReques
     assertEquals(job.getDueTime(), actualScheduleJobRequest.getJob().getDueTime());
   }
 
-  @Test
-  void scheduleJobShouldThrowIllegalArgumentWhenBothScheduleAndDueTimeAreNotPresent() {
-    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
-      daprJobsClient.scheduleJob(ScheduleJobRequest.builder().setName("abcd").build()).block();
-    });
-    assertEquals("At least one of schedule or dueTime must be provided", exception.getMessage());
-  }
-
   @Test
   void scheduleJobShouldThrowWhenRequestIsNull() {
     IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
@@ -147,10 +133,7 @@ void scheduleJobShouldThrowWhenRequestIsNull() {
 
   @Test
   void scheduleJobShouldThrowWhenInvalidRequest() {
-    ScheduleJobRequest scheduleJobRequest = ScheduleJobRequest.builder()
-            .setData("testData".getBytes())
-            .build();
-
+    ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest(null, OffsetDateTime.now());
     IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
       daprJobsClient.scheduleJob(scheduleJobRequest).block();
     });
@@ -159,7 +142,7 @@ void scheduleJobShouldThrowWhenInvalidRequest() {
 
   @Test
   void scheduleJobShouldThrowWhenNameInRequestIsEmpty() {
-    ScheduleJobRequest scheduleJobRequest = ScheduleJobRequest.builder().setName("").build();
+    ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest("", OffsetDateTime.now());
 
     IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
       daprJobsClient.scheduleJob(scheduleJobRequest).block();
@@ -169,7 +152,7 @@ void scheduleJobShouldThrowWhenNameInRequestIsEmpty() {
 
   @Test
   void getJobShouldReturnResponseWhenAllFieldsArePresentInRequest() {
-    GetJobRequest getJobRequest = GetJobRequest.builder().setName("testJob").build();
+    GetJobRequest getJobRequest = new GetJobRequest("testJob");
 
     DaprProtos.Job job = DaprProtos.Job.newBuilder()
             .setName("testJob")
@@ -196,14 +179,14 @@ void getJobShouldReturnResponseWhenAllFieldsArePresentInRequest() {
     assertEquals("testJob", response.getName());
     assertEquals("testData", new String(response.getData(), StandardCharsets.UTF_8));
     assertEquals("*/5 * * * *", response.getSchedule().getExpression());
-    assertEquals(5, response.getRepeat());
+    assertEquals(5, response.getRepeats());
     assertEquals(job.getTtl(), response.getTtl().toString());
     assertEquals(job.getDueTime(), response.getDueTime().toString());
   }
 
   @Test
   void getJobShouldReturnResponseWhenRequiredFieldsArePresentInRequest() {
-    GetJobRequest getJobRequest = GetJobRequest.builder().setName("testJob").build();
+    GetJobRequest getJobRequest = new GetJobRequest("testJob");
 
     DaprProtos.Job job = DaprProtos.Job.newBuilder()
             .setName("testJob")
@@ -225,7 +208,7 @@ void getJobShouldReturnResponseWhenRequiredFieldsArePresentInRequest() {
     assertEquals("testJob", response.getName());
     assertNull(response.getData());
     assertNull(response.getSchedule());
-    assertNull(response.getRepeat());
+    assertNull(response.getRepeats());
     assertNull(response.getTtl());
     assertNull(response.getDueTime());
   }
@@ -240,7 +223,7 @@ void getJobShouldThrowWhenRequestIsNull() {
 
   @Test
   void getJobShouldThrowWhenNameIsNullRequest() {
-    GetJobRequest getJobRequest = GetJobRequest.builder().build();
+    GetJobRequest getJobRequest = new GetJobRequest(null);
 
     IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
       daprJobsClient.getJob(getJobRequest).block();
@@ -250,7 +233,7 @@ void getJobShouldThrowWhenNameIsNullRequest() {
 
   @Test
   void getJobShouldThrowWhenNameIsEmptyRequest() {
-    GetJobRequest getJobRequest = GetJobRequest.builder().setName("").build();
+    GetJobRequest getJobRequest =new GetJobRequest("");;
 
     IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
       daprJobsClient.getJob(getJobRequest).block();
@@ -260,7 +243,7 @@ void getJobShouldThrowWhenNameIsEmptyRequest() {
 
   @Test
   void deleteJobShouldSucceedWhenValidRequest() {
-    DeleteJobRequest deleteJobRequest = DeleteJobRequest.builder().setName("testJob").build();
+    DeleteJobRequest deleteJobRequest = new DeleteJobRequest("testJob");
 
     doAnswer(invocation -> {
       StreamObserver observer = invocation.getArgument(1);
@@ -283,7 +266,7 @@ void deleteJobShouldThrowRequestIsNull() {
 
   @Test
   void deleteJobShouldThrowWhenNameIsNullRequest() {
-    DeleteJobRequest deleteJobRequest = DeleteJobRequest.builder().build();
+    DeleteJobRequest deleteJobRequest = new DeleteJobRequest(null);
     IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
       daprJobsClient.deleteJob(deleteJobRequest).block();
     });
@@ -292,7 +275,7 @@ void deleteJobShouldThrowWhenNameIsNullRequest() {
 
   @Test
   void deleteJobShouldThrowWhenNameIsEmptyRequest() {
-    DeleteJobRequest deleteJobRequest = DeleteJobRequest.builder().setName("").build();
+    DeleteJobRequest deleteJobRequest = new DeleteJobRequest("");
     IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
       daprJobsClient.deleteJob(deleteJobRequest).block();
     });

From 066a0c37cc82c3227de6cd354bb99f9826b085fe Mon Sep 17 00:00:00 2001
From: sirivarma 
Date: Mon, 17 Mar 2025 22:54:55 -0700
Subject: [PATCH 06/30] Remove module

Signed-off-by: sirivarma 
---
 pom.xml                                       |   1 -
 sdk-jobs/pom.xml                              | 154 --------
 .../jobs/client/CronExpressionBuilder.java    | 362 ------------------
 .../java/io/dapr/jobs/client/CronPeriod.java  |  44 ---
 .../io/dapr/jobs/client/DaprJobsClient.java   | 257 -------------
 .../java/io/dapr/jobs/client/DayOfWeek.java   |  39 --
 .../java/io/dapr/jobs/client/MonthOfYear.java |  38 --
 .../java/io/dapr/jobs/client/OrdinalEnum.java |  16 -
 .../client/CronExpressionBuilderTest.java     | 343 -----------------
 .../dapr/jobs/client/DaprJobsClientTest.java  | 296 --------------
 .../io/dapr/it/testcontainers/DaprJobsIT.java |  59 ++-
 .../TestDaprJobsConfiguration.java            |  10 +-
 .../java/io/dapr/client/DaprClientImpl.java   | 146 ++++++-
 .../io/dapr/client/DaprPreviewClient.java     |  36 ++
 .../dapr/client/domain}/DeleteJobRequest.java |   2 +-
 .../io/dapr/client/domain}/GetJobRequest.java |   2 +-
 .../dapr/client/domain}/GetJobResponse.java   |   2 +-
 .../io/dapr/client/domain}/JobSchedule.java   |  35 +-
 .../client/domain}/ScheduleJobRequest.java    |   2 +-
 .../io/dapr/client/DaprClientHttpTest.java    |  13 +-
 .../client/DaprPreviewClientGrpcTest.java     | 306 ++++++++++++++-
 .../dapr/client/domain}/JobsScheduleTest.java |   2 +-
 22 files changed, 516 insertions(+), 1649 deletions(-)
 delete mode 100644 sdk-jobs/pom.xml
 delete mode 100644 sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java
 delete mode 100644 sdk-jobs/src/main/java/io/dapr/jobs/client/CronPeriod.java
 delete mode 100644 sdk-jobs/src/main/java/io/dapr/jobs/client/DaprJobsClient.java
 delete mode 100644 sdk-jobs/src/main/java/io/dapr/jobs/client/DayOfWeek.java
 delete mode 100644 sdk-jobs/src/main/java/io/dapr/jobs/client/MonthOfYear.java
 delete mode 100644 sdk-jobs/src/main/java/io/dapr/jobs/client/OrdinalEnum.java
 delete mode 100644 sdk-jobs/test/test/java/io/dapr/jobs/client/CronExpressionBuilderTest.java
 delete mode 100644 sdk-jobs/test/test/java/io/dapr/jobs/client/DaprJobsClientTest.java
 rename {sdk-jobs/src/main/java/io/dapr/jobs/client => sdk/src/main/java/io/dapr/client/domain}/DeleteJobRequest.java (93%)
 rename {sdk-jobs/src/main/java/io/dapr/jobs/client => sdk/src/main/java/io/dapr/client/domain}/GetJobRequest.java (92%)
 rename {sdk-jobs/src/main/java/io/dapr/jobs/client => sdk/src/main/java/io/dapr/client/domain}/GetJobResponse.java (99%)
 rename {sdk-jobs/src/main/java/io/dapr/jobs/client => sdk/src/main/java/io/dapr/client/domain}/JobSchedule.java (76%)
 rename {sdk-jobs/src/main/java/io/dapr/jobs/client => sdk/src/main/java/io/dapr/client/domain}/ScheduleJobRequest.java (99%)
 rename {sdk-jobs/test/test/java/io/dapr/jobs/client => sdk/src/test/java/io/dapr/client/domain}/JobsScheduleTest.java (98%)

diff --git a/pom.xml b/pom.xml
index ad8726f0c8..e14bf980cb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -507,7 +507,6 @@
     spring-boot-examples
     
     testcontainers-dapr
-    sdk-jobs
   
 
   
diff --git a/sdk-jobs/pom.xml b/sdk-jobs/pom.xml
deleted file mode 100644
index 406060a947..0000000000
--- a/sdk-jobs/pom.xml
+++ /dev/null
@@ -1,154 +0,0 @@
-
-    4.0.0
-
-    
-        io.dapr
-        dapr-sdk-parent
-        1.15.0-SNAPSHOT
-    
-
-    dapr-sdk-jobs
-    jar
-    1.15.0-SNAPSHOT
-    dapr-sdk-jobs
-    SDK for Jobs on Dapr
-
-    
-        false
-    
-
-    
-        
-            io.dapr
-            dapr-sdk
-            ${project.version}
-        
-        
-            io.dapr
-            dapr-sdk-autogen
-            ${project.version}
-        
-        
-            org.mockito
-            mockito-core
-            test
-        
-        
-            org.mockito
-            mockito-inline
-            4.2.0
-            test
-        
-        
-            org.junit.jupiter
-            junit-jupiter
-            test
-        
-        
-            org.junit.vintage
-            junit-vintage-engine
-            5.7.2
-            test
-        
-        
-            org.testng
-            testng
-            RELEASE
-            compile
-        
-        
-            org.junit.platform
-            junit-platform-console-standalone
-            1.11.4
-            compile
-        
-        
-            org.mockito
-            mockito-core
-            compile
-        
-    
-
-    
-        
-            
-                org.sonatype.plugins
-                nexus-staging-maven-plugin
-            
-            
-                org.apache.maven.plugins
-                maven-source-plugin
-                3.2.1
-                
-                    
-                        attach-sources
-                        
-                            jar-no-fork
-                        
-                    
-                
-            
-
-            
-                org.apache.maven.plugins
-                maven-javadoc-plugin
-                3.2.0
-                
-                    
-                        attach-javadocs
-                        
-                            jar
-                        
-                    
-                
-            
-            
-                org.jacoco
-                jacoco-maven-plugin
-                0.8.11
-                
-                    
-                        default-prepare-agent
-                        
-                            prepare-agent
-                        
-                    
-                    
-                        report
-                        test
-                        
-                            report
-                        
-                        
-                            target/jacoco-report/
-                        
-                    
-                    
-                        check
-                        
-                            check
-                        
-                        
-                            
-                                
-                                    BUNDLE
-                                    
-                                        
-                                            LINE
-                                            COVEREDRATIO
-                                            80%
-                                        
-                                    
-                                
-                            
-                        
-                    
-
-                
-            
-        
-    
-
diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java
deleted file mode 100644
index f2111bb400..0000000000
--- a/sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java
+++ /dev/null
@@ -1,362 +0,0 @@
-package io.dapr.jobs.client;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * A builder class for constructing cron expressions. This class provides an easy way to construct cron expressions
- * by adding individual values or ranges for each of the cron fields: seconds, minutes, hours, day of month,
- * day of week, and month of year. It supports adding steps and ranges for fields where appropriate.
- * Example usage:
- * 
- * CronExpressionBuilder builder = new CronExpressionBuilder();
- * builder.add(CronPeriod.MINUTES, 0, 15, 30); // Every 15 minutes starting at 0
- * builder.add(CronPeriod.HOURS, 12); // At noon
- * builder.addRange(CronPeriod.DAYOFMONTH, 1, 31); // On the 1st through the 31st day of the month
- * builder.addStep(CronPeriod.MINUTES, 5); // Every 5 minutes
- * System.out.println(builder.build()); // Outputs the cron expression
- * 
- */ -public class CronExpressionBuilder { - - private final List seconds; - private final List minutes; - private final List hours; - private final List dayOfMonth; - private final List dayOfWeek; - private final List monthOfYear; - - /** - * Constructs a new {@link CronExpressionBuilder} instance with empty cron fields. - */ - public CronExpressionBuilder() { - this.seconds = new ArrayList<>(); - this.minutes = new ArrayList<>(); - this.hours = new ArrayList<>(); - this.dayOfMonth = new ArrayList<>(); - this.dayOfWeek = new ArrayList<>(); - this.monthOfYear = new ArrayList<>(); - } - - /** - * Adds values to the specified cron period (e.g., minutes, hours, etc.). - * example: - * builder.add(CronPeriod.MINUTES, 0, 15, 30); // Adds 0, 15, and 30 minutes to the cron expression - * - * @param cronPeriod The cron period to modify (e.g., {CronPeriod.MINUTES}). - * @param values The values to be added to the cron period. - * @return The {@link CronExpressionBuilder} instance for method chaining. - * @throws IllegalArgumentException if values are invalid or empty. - * - */ - public CronExpressionBuilder add(CronPeriod cronPeriod, int... values) { - return addInternal(cronPeriod, Arrays.stream(values).boxed().toArray()); - } - - /** - * Adds values for the {@link MonthOfYear} cron period. - * - * @param values The {@link MonthOfYear} values to be added. - * @return The {@link CronExpressionBuilder} instance for method chaining. - */ - public CronExpressionBuilder add(MonthOfYear... values) { - return addInternal(CronPeriod.MonthOfYear, values); - } - - /** - * Adds values for the {@link DayOfWeek} cron period. - * - * @param values The {@link DayOfWeek} values to be added. - * @return The {@link CronExpressionBuilder} instance for method chaining. - */ - public CronExpressionBuilder add(DayOfWeek... values) { - return addInternal(CronPeriod.DayOfWeek, values); - } - - /** - * Adds a range of values to a cron period. - * - * @param period The cron period to modify (e.g., {CronPeriod.MONTHOFYEAR}). - * @param from The starting value of the range (inclusive). - * @param to The ending value of the range (inclusive). - * @return The {@link CronExpressionBuilder} instance for method chaining. - * @throws IllegalArgumentException if the range is invalid. - */ - public CronExpressionBuilder addRange(CronPeriod period, int from, int to) { - return addRangeInternal(period, from, to); - } - - /** - * Adds a range of {@link DayOfWeek} values to the cron expression. - * - * @param from The starting {@link DayOfWeek} value. - * @param to The ending {@link DayOfWeek} value. - * @return The {@link CronExpressionBuilder} instance for method chaining. - */ - public CronExpressionBuilder addRange(DayOfWeek from, DayOfWeek to) { - return addRangeInternal(CronPeriod.DayOfWeek, from, to); - } - - /** - * Adds a range of {@link MonthOfYear} values to the cron expression. - * - * @param from The starting {@link MonthOfYear} value. - * @param to The ending {@link MonthOfYear} value. - * @return The {@link CronExpressionBuilder} instance for method chaining. - */ - public CronExpressionBuilder addRange(MonthOfYear from, MonthOfYear to) { - return addRangeInternal(CronPeriod.MonthOfYear, from, to); - } - - /** - * Adds a step range for a cron period. - * - * @param period The cron period to modify. - * @param from The starting value for the step range (inclusive). - * @param to The ending value for the step range (inclusive). - * @param interval The interval for the step range. - * @return The {@link CronExpressionBuilder} instance for method chaining. - */ - public CronExpressionBuilder addStepRange(CronPeriod period, int from, int to, int interval) { - return addStepInternal(period, from, to, interval); - } - - /** - * Adds a step for a cron period. - * - * @param period The cron period to modify. - * @param interval The interval for the step. - * @return The {@link CronExpressionBuilder} instance for method chaining. - */ - public CronExpressionBuilder addStep(CronPeriod period, int interval) { - return addStepInternal(period, null, null, interval); - } - - /** - * Adds a specific value with a step interval for the cron period. - * - * @param period The cron period to modify. - * @param value The starting value for the step. - * @param interval The interval for the step. - * @return The {@link CronExpressionBuilder} instance for method chaining. - */ - public CronExpressionBuilder addStep(CronPeriod period, int value, int interval) { - throwIfNull(period); - validatePeriod(period, value); - validatePeriod(period, interval); - - addToPeriod(period, value + "/" + interval); - return this; - } - - /** - * Builds the cron expression by combining all the specified cron periods and their values. - * - * @return A string representation of the cron expression. - */ - public String build() { - - if (this.monthOfYear.isEmpty()) { - this.monthOfYear.add("*"); - } - - if (this.dayOfWeek.isEmpty()) { - this.dayOfWeek.add("*"); - } - - if (this.seconds.isEmpty()) { - this.seconds.add("*"); - } - - if (this.minutes.isEmpty()) { - this.minutes.add("*"); - } - - if (this.hours.isEmpty()) { - this.hours.add("*"); - } - - if (this.dayOfMonth.isEmpty()) { - this.dayOfMonth.add("*"); - } - - return String.join(",", this.seconds) + " " - + String.join(",", this.minutes) + " " - + String.join(",", this.hours) + " " - + String.join(",", this.dayOfMonth) + " " - + String.join(",", this.monthOfYear) + " " - + String.join(",", this.dayOfWeek); - } - - /** - * Internal method to add values to a cron period. - * - * @param period The cron period to modify. - * @param values The values to add. - * @return The {@link CronExpressionBuilder} instance for method chaining. - */ - private CronExpressionBuilder addInternal(CronPeriod period, T[] values) { - throwIfNull(period); - throwIfNull(values); - - if (values.length == 0) { - throw new IllegalArgumentException(period + " values cannot be empty"); - } - - List valueStrings = new ArrayList<>(values.length); - for (T value : values) { - throwIfNull(value); - if (value instanceof OrdinalEnum) { - validatePeriod(period, ((OrdinalEnum) value).getRank()); - valueStrings.add(value.toString()); - } else { - validatePeriod(period, (int)value); - valueStrings.add(String.valueOf(value)); - } - } - - addToPeriod(period, String.join(",", valueStrings)); - - return this; - } - - /** - * Internal method to add a range of values to a cron period. - * - * @param period The cron period to modify. - * @param from The starting value for the range (inclusive). - * @param to The ending value for the range (inclusive). - * @return The {@link CronExpressionBuilder} instance for method chaining. - */ - private CronExpressionBuilder addRangeInternal(CronPeriod period, T from, T to) { - throwIfNull(period); - throwIfNull(from); - throwIfNull(to); - - if (from instanceof OrdinalEnum && to instanceof OrdinalEnum) { - int fromInterval = ((OrdinalEnum) from).getRank(); - int toInterval = ((OrdinalEnum) to).getRank(); - validateRange(fromInterval, toInterval); - validatePeriod(period, fromInterval); - validatePeriod(period, toInterval); - } else { - validateRange((int)from, (int)to); - validatePeriod(period, (int)from); - validatePeriod(period, (int)to); - } - - addToPeriod(period, from + "-" + to); - return this; - } - - /** - * Internal method to add a step range to a cron period. - * - * @param period The cron period to modify. - * @param from The starting value for the step range (inclusive). - * @param to The ending value for the step range (inclusive). - * @param interval The interval for the step. - * @return The {@link CronExpressionBuilder} instance for method chaining. - */ - private CronExpressionBuilder addStepInternal(CronPeriod period, Integer from, Integer to, Integer interval) { - throwIfNull(period); - throwIfNull(interval); - - if (from != null || to != null) { - throwIfNull(from); - throwIfNull(to); - validatePeriod(period, from); - validatePeriod(period, to); - validateRange(from, to); - - addToPeriod(period, from + "-" + to + "/" + interval); - return this; - } - - addToPeriod(period, "*/" + interval); - return this; - } - - /** - * Validates the value for a specific cron period. - * - * @param cronPeriod The cron period to validate (e.g., {@link CronPeriod.HOURS}). - * @param value The value to validate. - * @throws IllegalArgumentException if the value is invalid for the cron period. - */ - private void validatePeriod(CronPeriod cronPeriod, int value) { - switch (cronPeriod) { - case SECONDS: - case MINUTES: - if (value < 0 || value > 59) { - throw new IllegalArgumentException(cronPeriod + " must be between [0, 59] inclusive"); - } - break; - case HOURS: - if (value < 0 || value > 23) { - throw new IllegalArgumentException(cronPeriod + " must be between [0, 23] inclusive"); - } - break; - case DayOfMonth: - if (value < 1 || value > 31) { - throw new IllegalArgumentException(cronPeriod + " must be between [1, 31] inclusive"); - } - break; - case MonthOfYear: - if (value < 1 || value > 12) { - throw new IllegalArgumentException(cronPeriod + " must be between [1, 12] inclusive"); - } - break; - case DayOfWeek: - if (value < 0 || value > 6) { - throw new IllegalArgumentException(cronPeriod + " must be between [0, 6] inclusive"); - } - break; - default: throw new IllegalArgumentException("Invalid CronPeriod: " + cronPeriod); - } - } - - private void validateRange(int from, int to) { - if (from > to || from == to) { - throw new IllegalArgumentException("from must be less than to (from < to)"); - } - } - - /** - * Helper method to add values to the period. - * - * @param period The cron period to modify. - * @param value The value to add to the period. - */ - private void addToPeriod(CronPeriod cronPeriod, String value) { - switch (cronPeriod) { - case SECONDS: - this.seconds.add(value); - break; - case MINUTES: - this.minutes.add(value); - break; - case HOURS: - this.hours.add(value); - break; - case DayOfMonth: - this.dayOfMonth.add(value); - break; - case MonthOfYear: - this.monthOfYear.add(value); - break; - case DayOfWeek: - this.dayOfWeek.add(value); - break; - default: - throw new IllegalArgumentException("Invalid CronPeriod: " + cronPeriod); - } - } - - private void throwIfNull(Object obj) { - if (obj == null) { - throw new IllegalArgumentException("None of the input parameters can be null"); - } - } -} \ No newline at end of file diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/CronPeriod.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/CronPeriod.java deleted file mode 100644 index f8172d105f..0000000000 --- a/sdk-jobs/src/main/java/io/dapr/jobs/client/CronPeriod.java +++ /dev/null @@ -1,44 +0,0 @@ -package io.dapr.jobs.client; - -/** - * Represents the different fields of a cron expression that can be modified - * using the {@link CronExpressionBuilder}. - * Each enum value corresponds to a specific component of a cron schedule. - * Example usage: - *
- * CronPeriod period = CronPeriod.MINUTES;
- * System.out.println(period); // Outputs: MINUTES
- * 
- */ -public enum CronPeriod { - - /** - * Represents the seconds field in a cron expression (0-59). - */ - SECONDS, - - /** - * Represents the minutes field in a cron expression (0-59). - */ - MINUTES, - - /** - * Represents the hours field in a cron expression (0-23). - */ - HOURS, - - /** - * Represents the day of the month field in a cron expression (1-31). - */ - DayOfMonth, - - /** - * Represents the month of the year field in a cron expression (1-12). - */ - MonthOfYear, - - /** - * Represents the day of the week field in a cron expression (0-6, where 0 is Sunday). - */ - DayOfWeek, -} \ No newline at end of file diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/DaprJobsClient.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/DaprJobsClient.java deleted file mode 100644 index 7aa704da1c..0000000000 --- a/sdk-jobs/src/main/java/io/dapr/jobs/client/DaprJobsClient.java +++ /dev/null @@ -1,257 +0,0 @@ -package io.dapr.jobs.client; - -import com.google.protobuf.Any; -import com.google.protobuf.ByteString; -import io.dapr.client.resiliency.ResiliencyOptions; -import io.dapr.config.Properties; -import io.dapr.exceptions.DaprException; -import io.dapr.internal.exceptions.DaprHttpException; -import io.dapr.internal.grpc.interceptors.DaprTimeoutInterceptor; -import io.dapr.internal.grpc.interceptors.DaprTracingInterceptor; -import io.dapr.internal.resiliency.RetryPolicy; -import io.dapr.internal.resiliency.TimeoutPolicy; -import io.dapr.utils.NetworkUtils; -import io.dapr.v1.DaprGrpc; -import io.dapr.v1.DaprProtos; -import io.grpc.ManagedChannel; -import io.grpc.stub.StreamObserver; -import reactor.core.publisher.Mono; -import reactor.core.publisher.MonoSink; -import reactor.util.context.ContextView; - -import java.time.OffsetDateTime; -import java.util.function.Consumer; - -public class DaprJobsClient implements AutoCloseable { - - /** - * Stub that has the method to call the conversation apis. - */ - private final DaprGrpc.DaprStub asyncStub; - - /** - * The retry policy. - */ - private final RetryPolicy retryPolicy; - - /** - * The timeout policy. - */ - private final TimeoutPolicy timeoutPolicy; - - /** - * Constructor to create conversation client. - */ - public DaprJobsClient() { - this(DaprGrpc.newStub(NetworkUtils.buildGrpcManagedChannel(new Properties())), null); - } - - /** - * Constructor. - * - * @param properties with client configuration options. - * @param resiliencyOptions retry options. - */ - public DaprJobsClient( - Properties properties, - ResiliencyOptions resiliencyOptions) { - this(DaprGrpc.newStub(NetworkUtils.buildGrpcManagedChannel(properties)), resiliencyOptions); - } - - /** - * ConversationClient constructor. - * - * @param resiliencyOptions timeout and retry policies. - */ - protected DaprJobsClient( - DaprGrpc.DaprStub asyncStub, - ResiliencyOptions resiliencyOptions) { - this.asyncStub = asyncStub; - this.retryPolicy = new RetryPolicy(resiliencyOptions == null ? null : resiliencyOptions.getMaxRetries()); - this.timeoutPolicy = new TimeoutPolicy(resiliencyOptions == null ? null : resiliencyOptions.getTimeout()); - } - - /** - * Schedules a job using the provided job request details. - * - * @param createJobRequest The request containing the details of the job to schedule. - * Must include a name and optional schedule, data, and other related properties. - * @return A {@link Mono} that completes when the job scheduling operation is successful or raises an error. - * @throws IllegalArgumentException If the request or its required fields like name are null or empty. - */ - public Mono scheduleJob(ScheduleJobRequest createJobRequest) { - try { - if (createJobRequest == null) { - throw new IllegalArgumentException("scheduleJobRequest cannot be null"); - } - - if (createJobRequest.getName() == null || createJobRequest.getName().isEmpty()) { - throw new IllegalArgumentException("Name in the request cannot be null or empty"); - } - - if (createJobRequest.getSchedule() == null && createJobRequest.getDueTime() == null) { - throw new IllegalArgumentException("At least one of schedule or dueTime must be provided"); - } - - DaprProtos.Job.Builder scheduleJobRequestBuilder = DaprProtos.Job.newBuilder(); - scheduleJobRequestBuilder.setName(createJobRequest.getName()); - - if (createJobRequest.getData() != null) { - scheduleJobRequestBuilder.setData(Any.newBuilder() - .setValue(ByteString.copyFrom(createJobRequest.getData())).build()); - } - - if (createJobRequest.getSchedule() != null) { - scheduleJobRequestBuilder.setSchedule(createJobRequest.getSchedule().getExpression()); - } - - if (createJobRequest.getTtl() != null) { - scheduleJobRequestBuilder.setTtl(createJobRequest.getTtl().toString()); - } - - if (createJobRequest.getRepeats() != null) { - scheduleJobRequestBuilder.setRepeats(createJobRequest.getRepeats()); - } - - if (createJobRequest.getDueTime() != null) { - scheduleJobRequestBuilder.setDueTime(createJobRequest.getDueTime().toString()); - } - - DaprProtos.ScheduleJobRequest scheduleJobRequest = DaprProtos.ScheduleJobRequest.newBuilder() - .setJob(scheduleJobRequestBuilder.build()).build(); - - Mono scheduleJobResponseMono = - Mono.deferContextual(context -> this.createMono( - it -> intercept(context, asyncStub) - .scheduleJobAlpha1(scheduleJobRequest, it) - ) - ); - - return scheduleJobResponseMono.then(); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - } - - /** - * Retrieves details of a specific job. - * - * @param getJobRequest The request containing the job name for which the details are to be fetched. - * The name property is mandatory. - * @return A {@link Mono} that emits the {@link GetJobResponse} containing job details or raises an - * error if the job is not found. - * @throws IllegalArgumentException If the request or its required fields like name are null or empty. - */ - - public Mono getJob(GetJobRequest getJobRequest) { - try { - if (getJobRequest == null) { - throw new IllegalArgumentException("getJobRequest cannot be null"); - } - - if (getJobRequest.getName() == null || getJobRequest.getName().isEmpty()) { - throw new IllegalArgumentException("Name in the request cannot be null or empty"); - } - - Mono getJobResponseMono = - Mono.deferContextual(context -> this.createMono( - it -> intercept(context, asyncStub) - .getJobAlpha1(DaprProtos.GetJobRequest.newBuilder() - .setName(getJobRequest.getName()).build(), it) - ) - ); - - return getJobResponseMono.map(response -> { - DaprProtos.Job job = response.getJob(); - GetJobResponse getJobResponse = null; - if (job.hasSchedule()) { - getJobResponse = new GetJobResponse(job.getName(), JobSchedule.fromString(job.getSchedule())); - } else { - getJobResponse = new GetJobResponse(job.getName(), OffsetDateTime.parse(job.getDueTime())); - } - - return getJobResponse - .setTtl(job.hasTtl() ? OffsetDateTime.parse(job.getTtl()) : null) - .setData(job.hasData() ? job.getData().getValue().toByteArray() : null) - .setRepeat(job.hasRepeats() ? job.getRepeats() : null); - }); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - } - - /** - * Deletes a job based on the given request. - * - * @param deleteJobRequest The request containing the job name to be deleted. - * The name property is mandatory. - * @return A {@link Mono} that completes when the job is successfully deleted or raises an error. - * @throws IllegalArgumentException If the request or its required fields like name are null or empty. - */ - public Mono deleteJob(DeleteJobRequest deleteJobRequest) { - try { - if (deleteJobRequest == null) { - throw new IllegalArgumentException("deleteJobRequest cannot be null"); - } - - if (deleteJobRequest.getName() == null || deleteJobRequest.getName().isEmpty()) { - throw new IllegalArgumentException("Name in the request cannot be null or empty"); - } - - Mono deleteJobResponseMono = - Mono.deferContextual(context -> this.createMono( - it -> intercept(context, asyncStub) - .deleteJobAlpha1(DaprProtos.DeleteJobRequest.newBuilder() - .setName(deleteJobRequest.getName()).build(), it) - ) - ); - - return deleteJobResponseMono.then(); - } catch (Exception ex) { - return DaprException.wrapMono(ex); - } - } - - @Override - public void close() throws Exception { - ManagedChannel channel = (ManagedChannel) this.asyncStub.getChannel(); - - DaprException.wrap(() -> { - if (channel != null && !channel.isShutdown()) { - channel.shutdown(); - } - - return true; - }).call(); - } - - private DaprGrpc.DaprStub intercept( - ContextView context, DaprGrpc.DaprStub client) { - return client.withInterceptors(new DaprTimeoutInterceptor(this.timeoutPolicy), new DaprTracingInterceptor(context)); - } - - private Mono createMono(Consumer> consumer) { - return retryPolicy.apply( - Mono.create(sink -> DaprException.wrap(() -> consumer.accept( - createStreamObserver(sink))).run())); - } - - private StreamObserver createStreamObserver(MonoSink sink) { - return new StreamObserver() { - @Override - public void onNext(T value) { - sink.success(value); - } - - @Override - public void onError(Throwable t) { - sink.error(DaprException.propagate(DaprHttpException.fromGrpcExecutionException(null, t))); - } - - @Override - public void onCompleted() { - sink.success(); - } - }; - } -} diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/DayOfWeek.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/DayOfWeek.java deleted file mode 100644 index 4221ccfb57..0000000000 --- a/sdk-jobs/src/main/java/io/dapr/jobs/client/DayOfWeek.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.dapr.jobs.client; - -/** - * Represents the days of the week in a cron expression. - * This enum maps each day of the week to its corresponding integer value - * as used in cron expressions (0 for Sunday through 6 for Saturday). - * Implements {@link OrdinalEnum} to provide an ordinal ranking for each day. - * Example usage: - *
- * DayOfWeek day = DayOfWeek.MON;
- * System.out.println(day.getRank()); // Outputs: 1
- * 
- */ -public enum DayOfWeek implements OrdinalEnum { - - SUN(0), - MON(1), - TUE(2), - WED(3), - THU(4), - FRI(5), - SAT(6); - - private final int value; - - /** - * Constructs a {@code DayOfWeek} enum with the given value. - * - * @param value the integer representation of the day (0-6). - */ - DayOfWeek(int value) { - this.value = value; - } - - @Override - public int getRank() { - return this.value; - } -} \ No newline at end of file diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/MonthOfYear.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/MonthOfYear.java deleted file mode 100644 index 57fc4ed36c..0000000000 --- a/sdk-jobs/src/main/java/io/dapr/jobs/client/MonthOfYear.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.dapr.jobs.client; - -/** - * Represents the months of the year, each associated with its ordinal position (1-12). - * This enum implements {@link OrdinalEnum}, allowing retrieval of the numerical rank of each month. - * Example usage: - *
- * MonthOfYear month = MonthOfYear.JAN;
- * int rank = month.getRank(); // Returns 1
- * 
- */ - -public enum MonthOfYear implements OrdinalEnum { - - JAN(1), - FEB(2), - MAR(3), - APR(4), - MAY(5), - JUN(6), - JUL(7), - AUG(8), - SEP(9), - OCT(10), - NOV(11), - DEC(12); - - private final int value; - - MonthOfYear(int value) { - this.value = value; - } - - @Override - public int getRank() { - return this.value; - } -} \ No newline at end of file diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/OrdinalEnum.java b/sdk-jobs/src/main/java/io/dapr/jobs/client/OrdinalEnum.java deleted file mode 100644 index d86ed7545f..0000000000 --- a/sdk-jobs/src/main/java/io/dapr/jobs/client/OrdinalEnum.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.dapr.jobs.client; - -/** - * Represents an enumeration that has an associated ordinal rank. - * This interface is intended to be implemented by enums that need to provide - * a numerical representation for their values, such as days of the week or months of the year. - */ -public interface OrdinalEnum { - - /** - * Returns the ordinal rank of the implementing enum. - * - * @return the rank as an integer. - */ - int getRank(); -} diff --git a/sdk-jobs/test/test/java/io/dapr/jobs/client/CronExpressionBuilderTest.java b/sdk-jobs/test/test/java/io/dapr/jobs/client/CronExpressionBuilderTest.java deleted file mode 100644 index 342284e5af..0000000000 --- a/sdk-jobs/test/test/java/io/dapr/jobs/client/CronExpressionBuilderTest.java +++ /dev/null @@ -1,343 +0,0 @@ -package io.dapr.jobs.client; - -import org.junit.Assert; -import org.junit.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -import static org.junit.Assert.assertEquals; - -public class CronExpressionBuilderTest { - - @Test - public void builderWithoutParametersShouldReturnDefaultValues() { - String cronExpression = new CronExpressionBuilder().build(); - assertEquals("* * * * * *", cronExpression); - } - - @Test - public void builderWithInvalidSecondsShouldThrowIllegalArgumentException() { - IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .add(CronPeriod.SECONDS, 60).build()); - Assert.assertTrue(exception.getMessage().contains("SECONDS must be between [0, 59]")); - exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .add(CronPeriod.SECONDS, -1).build()); - Assert.assertTrue(exception.getMessage().contains("SECONDS must be between [0, 59]")); - } - - @Test - public void builderWithInvalidMinutesShouldThrowIllegalArgumentException() { - IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .add(CronPeriod.MINUTES, 60).build()); - Assert.assertTrue(exception.getMessage().contains("MINUTES must be between [0, 59]")); - exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .add(CronPeriod.MINUTES, -1).build()); - Assert.assertTrue(exception.getMessage().contains("MINUTES must be between [0, 59]")); - } - - @Test - public void builderWithEmptyParametersShouldThrowIllegalArgumentException() { - IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .add(CronPeriod.MINUTES).build()); - Assert.assertTrue(exception.getMessage().contains("MINUTES values cannot be empty")); - } - - @Test - public void builderWithInvalidHoursShouldThrowIllegalArgumentException() { - IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .add(CronPeriod.HOURS, -1).build()); - Assert.assertTrue(exception.getMessage().contains("HOURS must be between [0, 23]")); - exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .add(CronPeriod.HOURS, 24).build()); - Assert.assertTrue(exception.getMessage().contains("HOURS must be between [0, 23]")); - } - - @Test - public void builderWithInvalidDayOfMonthShouldThrowIllegalArgumentException1() { - IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .add(CronPeriod.DayOfMonth, 0).build()); - Assert.assertTrue(exception.getMessage().contains("DayOfMonth must be between [1, 31]")); - } - - @Test - public void builderWithInvalidDayOfMonthShouldThrowIllegalArgumentException() { - IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .add(CronPeriod.DayOfMonth, 32).build()); - Assert.assertTrue(exception.getMessage().contains("DayOfMonth must be between [1, 31]")); - } - - @Test - public void builderWithInvalidMonthOfYearShouldThrowIllegalArgumentException() { - IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .add(CronPeriod.MonthOfYear, 0).build()); - Assert.assertTrue(exception.getMessage().contains("MonthOfYear must be between [1, 12]")); - exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .add(CronPeriod.MonthOfYear, 13).build()); - Assert.assertTrue(exception.getMessage().contains("MonthOfYear must be between [1, 12]")); - } - - @Test - public void builderWithInvalidDayOfWeekShouldThrowIllegalArgumentException() { - IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .add(CronPeriod.DayOfWeek, -1).build()); - Assert.assertTrue(exception.getMessage().contains("DayOfWeek must be between [0, 6]")); - exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .add(CronPeriod.DayOfWeek, 7).build()); - Assert.assertTrue(exception.getMessage().contains("DayOfWeek must be between [0, 6]")); - } - - @Test - public void builderWithInvalidRangeShouldThrowIllegalArgumentException() { - IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .addRange(CronPeriod.HOURS, 20, 19).build()); - Assert.assertTrue(exception.getMessage().contains("from must be less than to")); - } - - @Test - public void builderWithInvalidMinuteRangeSpecifiedShouldThrowIllegalArgumentException() { - IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .addRange(CronPeriod.MINUTES, 1, 1).build()); - Assert.assertTrue(exception.getMessage().contains("from must be less than to (from < to)")); - } - - @Test - public void builderWithInvalidParametersShouldThrowIllegalArgumentException() { - IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .addRange(null, 1, 2).build()); - Assert.assertTrue(exception.getMessage().contains("None of the input parameters can be null")); - } - - @ParameterizedTest - @CsvSource({ - "SECONDS, 0, '0 * * * * *'", - "MINUTES, 30, '* 30 * * * *'", - "HOURS, 12, '* * 12 * * *'", - "DayOfMonth, 15, '* * * 15 * *'", - "MonthOfYear, 6, '* * * * 6 *'", - "DayOfWeek, 3, '* * * * * 3'" - }) - void testAddSingleValue(CronPeriod period, int value, String expected) { - CronExpressionBuilder builder = new CronExpressionBuilder().add(period, value); - assertEquals(expected, builder.build()); - } - - @Test - public void builderWithInvalidParameterInValuesShouldThrowIllegalArgumentException() { - IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .add(null, MonthOfYear.JAN, null, MonthOfYear.FEB).build()); - Assert.assertTrue(exception.getMessage().contains("None of the input parameters can be null")); - } - - @Test - public void builderWithInvalidParameterInDayOfWeekValuesShouldThrowIllegalArgumentException() { - IllegalArgumentException exception = Assert.assertThrows(IllegalArgumentException.class, - () -> new CronExpressionBuilder() - .add(null, DayOfWeek.MON, null, DayOfWeek.THU).build()); - Assert.assertTrue(exception.getMessage().contains("None of the input parameters can be null")); - } - - @Test - public void builderWithSecondsShouldReturnWithOnlySecondsSet() { - String cronExpression = new CronExpressionBuilder() - .add(CronPeriod.SECONDS, 5) - .build(); - assertEquals("5 * * * * *", cronExpression); - } - - @Test - public void builderWithMultipleCallsToAddSecondsShouldReturnWithMultipleValues() { - String cronExpression = new CronExpressionBuilder() - .add(CronPeriod.SECONDS, 5) - .add(CronPeriod.SECONDS, 10) - .add(CronPeriod.SECONDS, 20) - .build(); - assertEquals("5,10,20 * * * * *", cronExpression); - } - - @Test - public void builderWithCallToAddRangeForSecondShouldReturnCorrectValues() { - String cronExpression = new CronExpressionBuilder() - .add(CronPeriod.SECONDS, 5) - .add(CronPeriod.SECONDS, 10) - .addRange(CronPeriod.SECONDS, 40, 50) - .build(); - assertEquals("5,10,40-50 * * * * *", cronExpression); - } - - @Test - public void builderWithCallToAddStepForSecondShouldReturnCorrectValues() { - String cronExpression = new CronExpressionBuilder() - .add(CronPeriod.SECONDS, 5) - .addStep(CronPeriod.SECONDS, 10) - .addRange(CronPeriod.SECONDS, 40, 50) - .build(); - assertEquals("5,*/10,40-50 * * * * *", cronExpression); - } - - @Test - public void builderWithMinutesShouldReturnWithOnlySecondsSet() { - String cronExpression = new CronExpressionBuilder() - .add(CronPeriod.MINUTES, 5) - .build(); - assertEquals("* 5 * * * *", cronExpression); - } - - @Test - public void builderWithMultipleCallsToAddMinutesShouldReturnWithMultipleValues() { - String cronExpression = new CronExpressionBuilder() - .add(CronPeriod.MINUTES, 5) - .add(CronPeriod.MINUTES, 10) - .add(CronPeriod.MINUTES, 20) - .build(); - assertEquals("* 5,10,20 * * * *", cronExpression); - } - - @Test - public void builderWithCallToAddRangeForMinutesShouldReturnCorrectValues() { - String cronExpression = new CronExpressionBuilder() - .add(CronPeriod.MINUTES, 5) - .add(CronPeriod.MINUTES, 10) - .addRange(CronPeriod.MINUTES, 40, 50) - .build(); - assertEquals("* 5,10,40-50 * * * *", cronExpression); - } - - @Test - public void builderWithCallToAddStepForMinutesShouldReturnCorrectValues() { - String cronExpression = new CronExpressionBuilder() - .add(CronPeriod.MINUTES, 5) - .addStep(CronPeriod.MINUTES, 10) - .addRange(CronPeriod.MINUTES, 40, 50) - .build(); - assertEquals("* 5,*/10,40-50 * * * *", cronExpression); - } - - @Test - public void builderWithCallToAddForSecondsAndMinutesShouldReturnCorrectValues() { - String cronExpression = new CronExpressionBuilder() - .add(CronPeriod.SECONDS, 2) - .add(CronPeriod.MINUTES, 5) - .addStep(CronPeriod.MINUTES, 10) - .addRange(CronPeriod.MINUTES, 40, 50) - .build(); - assertEquals("2 5,*/10,40-50 * * * *", cronExpression); - } - - @Test - public void builderWithHoursShouldReturnWithOnlySecondsSet() { - String cronExpression = new CronExpressionBuilder() - .add(CronPeriod.HOURS, 5) - .build(); - assertEquals("* * 5 * * *", cronExpression); - } - - @Test - public void builderWithMultipleCallsToAddHoursShouldReturnWithMultipleValues() { - String cronExpression = new CronExpressionBuilder() - .add(CronPeriod.HOURS, 5) - .add(CronPeriod.HOURS, 10) - .add(CronPeriod.HOURS, 20) - .build(); - assertEquals("* * 5,10,20 * * *", cronExpression); - } - - @Test - public void builderWithCallToAddRangeForHoursShouldReturnCorrectValues() { - String cronExpression = new CronExpressionBuilder() - .add(CronPeriod.HOURS, 5) - .add(CronPeriod.HOURS, 10) - .addRange(CronPeriod.HOURS, 11, 12) - .build(); - assertEquals("* * 5,10,11-12 * * *", cronExpression); - } - - @Test - public void builderWithCallToAddStepForHoursShouldReturnCorrectValues() { - String cronExpression = new CronExpressionBuilder() - .add(CronPeriod.HOURS, 5) - .addStep(CronPeriod.HOURS, 10) - .addRange(CronPeriod.HOURS, 13, 14) - .build(); - assertEquals("* * 5,*/10,13-14 * * *", cronExpression); - } - - @Test - public void builderWithCallToAddForSecondsMinutesHoursShouldReturnCorrectValues() { - String cronExpression = new CronExpressionBuilder() - .add(CronPeriod.SECONDS, 2) - .add(CronPeriod.MINUTES, 5) - .addStep(CronPeriod.MINUTES, 10) - .addRange(CronPeriod.MINUTES, 40, 50) - .add(CronPeriod.HOURS, 20) - .addRange(CronPeriod.HOURS, 1, 2) - .addStep(CronPeriod.HOURS, 4) - .addStepRange(CronPeriod.HOURS, 5, 6, 3) - .build(); - assertEquals("2 5,*/10,40-50 20,1-2,*/4,5-6/3 * * *", cronExpression); - } - - @Test - public void builderWithCallToAddForMonthOfDayAndDayOfWeekShouldReturnCorrectValues() { - String cronExpression = new CronExpressionBuilder() - .add(MonthOfYear.JAN, MonthOfYear.FEB) - .add(DayOfWeek.MON, DayOfWeek.THU) - .add(CronPeriod.SECONDS, 1,2,3) - .add(CronPeriod.MINUTES, 20,30) - .build(); - assertEquals("1,2,3 20,30 * * JAN,FEB MON,THU", cronExpression); - } - - @Test - public void builderWithCallToAddForRangeMonthOfDayAndDayOfWeekShouldReturnCorrectValues() { - String cronExpression = new CronExpressionBuilder() - .add(MonthOfYear.JAN, MonthOfYear.FEB) - .add(DayOfWeek.MON, DayOfWeek.THU) - .add(CronPeriod.SECONDS, 1,2,3) - .add(CronPeriod.MINUTES, 20,30) - .addRange(MonthOfYear.MAR, MonthOfYear.APR) - .addRange(DayOfWeek.SUN, DayOfWeek.MON) - .build(); - assertEquals("1,2,3 20,30 * * JAN,FEB,MAR-APR MON,THU,SUN-MON", cronExpression); - } - - @Test - public void builderWithCallToAddForStepShouldReturnCorrectValues() { - String cronExpression = new CronExpressionBuilder() - .add(MonthOfYear.JAN, MonthOfYear.FEB) - .add(DayOfWeek.MON, DayOfWeek.THU) - .addStep(CronPeriod.HOURS, 20, 2) - .build(); - assertEquals("* * 20/2 * JAN,FEB MON,THU", cronExpression); - } - - @Test - public void builderWithCallToAddAllFieldsShouldReturnCorrectValues() { - String cronExpression = new CronExpressionBuilder() - .add(MonthOfYear.JAN, MonthOfYear.FEB) - .add(DayOfWeek.MON, DayOfWeek.THU) - .addStep(CronPeriod.HOURS, 20, 2) - .add(CronPeriod.SECONDS, 1) - .add(CronPeriod.MINUTES, 1) - .add(CronPeriod.HOURS, 1) - .add(CronPeriod.DayOfMonth, 1) - .build(); - assertEquals("1 1 20/2,1 1 JAN,FEB MON,THU", cronExpression); - } -} diff --git a/sdk-jobs/test/test/java/io/dapr/jobs/client/DaprJobsClientTest.java b/sdk-jobs/test/test/java/io/dapr/jobs/client/DaprJobsClientTest.java deleted file mode 100644 index 1b2e13afb2..0000000000 --- a/sdk-jobs/test/test/java/io/dapr/jobs/client/DaprJobsClientTest.java +++ /dev/null @@ -1,296 +0,0 @@ -package io.dapr.jobs.client; - -import com.google.protobuf.Any; -import com.google.protobuf.ByteString; -import io.dapr.client.resiliency.ResiliencyOptions; -import io.dapr.v1.DaprGrpc; -import io.dapr.v1.DaprProtos; -import io.grpc.ManagedChannel; -import io.grpc.stub.StreamObserver; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; -import reactor.core.publisher.Mono; - -import java.nio.charset.StandardCharsets; -import java.time.OffsetDateTime; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - -class DaprJobsClientTest { - - private DaprGrpc.DaprStub daprStub; - - private DaprJobsClient daprJobsClient; - - @BeforeEach - void setup() { - ManagedChannel channel = mock(ManagedChannel.class); - daprStub = mock(DaprGrpc.DaprStub.class); - when(daprStub.getChannel()).thenReturn(channel); - when(daprStub.withInterceptors(Mockito.any(), Mockito.any())).thenReturn(daprStub); - - ResiliencyOptions resiliencyOptions = new ResiliencyOptions(); // Default resiliency options - daprJobsClient = new DaprJobsClient(daprStub, resiliencyOptions); - } - - @Test - void scheduleJobShouldSucceedWhenAllFieldsArePresentInRequest() { - ScheduleJobRequest expectedScheduleJobRequest = new ScheduleJobRequest("testJob", - JobSchedule.fromString("*/5 * * * *")) - .setData("testData".getBytes()) - .setTtl(OffsetDateTime.now().plusDays(1)) - .setRepeat(5) - .setDueTime(OffsetDateTime.now().plusMinutes(10)); - - doAnswer(invocation -> { - StreamObserver observer = invocation.getArgument(1); - observer.onCompleted(); // Simulate successful response - return null; - }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any()); - - assertDoesNotThrow(() -> new DaprJobsClient(daprStub, null).scheduleJob(expectedScheduleJobRequest).block()); - - ArgumentCaptor captor = - ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); - - verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any()); - DaprProtos.ScheduleJobRequest actualScheduleJobReq = captor.getValue(); - - assertEquals("testJob", actualScheduleJobReq.getJob().getName()); - assertEquals("testData", - new String(actualScheduleJobReq.getJob().getData().getValue().toByteArray(), StandardCharsets.UTF_8)); - assertEquals("*/5 * * * *", actualScheduleJobReq.getJob().getSchedule()); - assertEquals(expectedScheduleJobRequest.getTtl().toString(), actualScheduleJobReq.getJob().getTtl()); - assertEquals(expectedScheduleJobRequest.getRepeats(), actualScheduleJobReq.getJob().getRepeats()); - assertEquals(expectedScheduleJobRequest.getDueTime().toString(), actualScheduleJobReq.getJob().getDueTime()); - } - - @Test - void scheduleJobShouldSucceedWhenRequiredFieldsNameAndDueTimeArePresentInRequest() { - - doAnswer(invocation -> { - StreamObserver observer = invocation.getArgument(1); - observer.onCompleted(); // Simulate successful response - return null; - }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any()); - - ScheduleJobRequest expectedScheduleJobRequest = - new ScheduleJobRequest("testJob", OffsetDateTime.now().plusMinutes(10)); - assertDoesNotThrow(() -> daprJobsClient.scheduleJob(expectedScheduleJobRequest).block()); - - ArgumentCaptor captor = - ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); - - verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any()); - DaprProtos.ScheduleJobRequest actualScheduleJobRequest = captor.getValue(); - DaprProtos.Job job = actualScheduleJobRequest.getJob(); - assertEquals("testJob", job.getName()); - assertFalse(job.hasData()); - assertFalse(job.hasSchedule()); - assertEquals(0, job.getRepeats()); - assertFalse(job.hasTtl()); - assertEquals(job.getDueTime(), actualScheduleJobRequest.getJob().getDueTime()); - } - - @Test - void scheduleJobShouldSucceedWhenRequiredFieldsNameAndScheduleArePresentInRequest() { - - doAnswer(invocation -> { - StreamObserver observer = invocation.getArgument(1); - observer.onCompleted(); // Simulate successful response - return null; - }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any()); - - ScheduleJobRequest expectedScheduleJobRequest = new ScheduleJobRequest("testJob", - JobSchedule.fromString("* * * * * *")); - assertDoesNotThrow(() -> daprJobsClient.scheduleJob(expectedScheduleJobRequest).block()); - - ArgumentCaptor captor = - ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); - - verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any()); - DaprProtos.ScheduleJobRequest actualScheduleJobRequest = captor.getValue(); - DaprProtos.Job job = actualScheduleJobRequest.getJob(); - assertEquals("testJob", job.getName()); - assertFalse(job.hasData()); - assertEquals( "* * * * * *", job.getSchedule()); - assertEquals(0, job.getRepeats()); - assertFalse(job.hasTtl()); - assertEquals(job.getDueTime(), actualScheduleJobRequest.getJob().getDueTime()); - } - - @Test - void scheduleJobShouldThrowWhenRequestIsNull() { - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - daprJobsClient.scheduleJob(null).block(); - }); - assertEquals("scheduleJobRequest cannot be null", exception.getMessage()); - } - - @Test - void scheduleJobShouldThrowWhenInvalidRequest() { - ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest(null, OffsetDateTime.now()); - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - daprJobsClient.scheduleJob(scheduleJobRequest).block(); - }); - assertEquals("Name in the request cannot be null or empty", exception.getMessage()); - } - - @Test - void scheduleJobShouldThrowWhenNameInRequestIsEmpty() { - ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest("", OffsetDateTime.now()); - - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - daprJobsClient.scheduleJob(scheduleJobRequest).block(); - }); - assertEquals("Name in the request cannot be null or empty", exception.getMessage()); - } - - @Test - void getJobShouldReturnResponseWhenAllFieldsArePresentInRequest() { - GetJobRequest getJobRequest = new GetJobRequest("testJob"); - - DaprProtos.Job job = DaprProtos.Job.newBuilder() - .setName("testJob") - .setTtl(OffsetDateTime.now().toString()) - .setData(Any.newBuilder().setValue(ByteString.copyFrom("testData".getBytes())).build()) - .setSchedule("*/5 * * * *") - .setRepeats(5) - .setDueTime(OffsetDateTime.now().plusMinutes(10).toString()) - .build(); - - doAnswer(invocation -> { - StreamObserver observer = invocation.getArgument(1); - observer.onNext(DaprProtos.GetJobResponse.newBuilder() - .setJob(job) - .build()); - observer.onCompleted(); - return null; - }).when(daprStub).getJobAlpha1(any(DaprProtos.GetJobRequest.class), any()); - - Mono resultMono = daprJobsClient.getJob(getJobRequest); - - GetJobResponse response = resultMono.block(); - assertNotNull(response); - assertEquals("testJob", response.getName()); - assertEquals("testData", new String(response.getData(), StandardCharsets.UTF_8)); - assertEquals("*/5 * * * *", response.getSchedule().getExpression()); - assertEquals(5, response.getRepeats()); - assertEquals(job.getTtl(), response.getTtl().toString()); - assertEquals(job.getDueTime(), response.getDueTime().toString()); - } - - @Test - void getJobShouldReturnResponseWhenRequiredFieldsArePresentInRequest() { - GetJobRequest getJobRequest = new GetJobRequest("testJob"); - - DaprProtos.Job job = DaprProtos.Job.newBuilder() - .setName("testJob") - .build(); - - doAnswer(invocation -> { - StreamObserver observer = invocation.getArgument(1); - observer.onNext(DaprProtos.GetJobResponse.newBuilder() - .setJob(job) - .build()); - observer.onCompleted(); - return null; - }).when(daprStub).getJobAlpha1(any(DaprProtos.GetJobRequest.class), any()); - - Mono resultMono = daprJobsClient.getJob(getJobRequest); - - GetJobResponse response = resultMono.block(); - assertNotNull(response); - assertEquals("testJob", response.getName()); - assertNull(response.getData()); - assertNull(response.getSchedule()); - assertNull(response.getRepeats()); - assertNull(response.getTtl()); - assertNull(response.getDueTime()); - } - - @Test - void getJobShouldThrowWhenRequestIsNull() { - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - daprJobsClient.getJob(null).block(); - }); - assertEquals("getJobRequest cannot be null", exception.getMessage()); - } - - @Test - void getJobShouldThrowWhenNameIsNullRequest() { - GetJobRequest getJobRequest = new GetJobRequest(null); - - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - daprJobsClient.getJob(getJobRequest).block(); - }); - assertEquals("Name in the request cannot be null or empty", exception.getMessage()); - } - - @Test - void getJobShouldThrowWhenNameIsEmptyRequest() { - GetJobRequest getJobRequest =new GetJobRequest("");; - - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - daprJobsClient.getJob(getJobRequest).block(); - }); - assertEquals("Name in the request cannot be null or empty", exception.getMessage()); - } - - @Test - void deleteJobShouldSucceedWhenValidRequest() { - DeleteJobRequest deleteJobRequest = new DeleteJobRequest("testJob"); - - doAnswer(invocation -> { - StreamObserver observer = invocation.getArgument(1); - observer.onCompleted(); // Simulate successful response - return null; - }).when(daprStub).deleteJobAlpha1(any(DaprProtos.DeleteJobRequest.class), any()); - - Mono resultMono = daprJobsClient.deleteJob(deleteJobRequest); - - assertDoesNotThrow(() -> resultMono.block()); - } - - @Test - void deleteJobShouldThrowRequestIsNull() { - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - daprJobsClient.deleteJob(null).block(); - }); - assertEquals("deleteJobRequest cannot be null", exception.getMessage()); - } - - @Test - void deleteJobShouldThrowWhenNameIsNullRequest() { - DeleteJobRequest deleteJobRequest = new DeleteJobRequest(null); - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - daprJobsClient.deleteJob(deleteJobRequest).block(); - }); - assertEquals("Name in the request cannot be null or empty", exception.getMessage()); - } - - @Test - void deleteJobShouldThrowWhenNameIsEmptyRequest() { - DeleteJobRequest deleteJobRequest = new DeleteJobRequest(""); - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - daprJobsClient.deleteJob(deleteJobRequest).block(); - }); - assertEquals("Name in the request cannot be null or empty", exception.getMessage()); - } - - @Test - void closeShouldCloseChannel() throws Exception { - ManagedChannel mockChannel = mock(ManagedChannel.class); - when(daprStub.getChannel()).thenReturn(mockChannel); - - when(mockChannel.isShutdown()).thenReturn(Boolean.valueOf(false)); - - daprJobsClient.close(); - - verify(mockChannel, times(1)).shutdown(); - } -} \ No newline at end of file diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java index 5754d53b4f..170e7e969a 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java @@ -1,9 +1,13 @@ package io.dapr.it.testcontainers; -import io.dapr.jobs.client.*; +import io.dapr.client.DaprPreviewClient; +import io.dapr.client.domain.DeleteJobRequest; +import io.dapr.client.domain.GetJobRequest; +import io.dapr.client.domain.GetJobResponse; +import io.dapr.client.domain.JobSchedule; +import io.dapr.client.domain.ScheduleJobRequest; import io.dapr.testcontainers.DaprContainer; import io.dapr.testcontainers.DaprLogLevel; -import org.junit.Assert; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; @@ -57,7 +61,7 @@ static void daprProperties(DynamicPropertyRegistry registry) { } @Autowired - private DaprJobsClient daprJobsClient; + private DaprPreviewClient daprPreviewClient; @BeforeEach public void setUp(){ @@ -68,51 +72,45 @@ public void setUp(){ @Test public void testJobScheduleCreationWithDueTime() { OffsetDateTime currentTime = OffsetDateTime.now(); - daprJobsClient.scheduleJob(ScheduleJobRequest.builder().setName("Job").setDueTime(currentTime).build()).block(); + daprPreviewClient.scheduleJob(new ScheduleJobRequest("Job", currentTime)).block(); GetJobResponse getJobResponse = - daprJobsClient.getJob(GetJobRequest.builder().setName("Job").build()).block(); - Assert.assertEquals(currentTime.toString(), getJobResponse.getDueTime().toString()); - Assert.assertEquals("Job", getJobResponse.getName()); + daprPreviewClient.getJob(new GetJobRequest("Job")).block(); + Assertions.assertEquals(currentTime.toString(), getJobResponse.getDueTime().toString()); + Assertions.assertEquals("Job", getJobResponse.getName()); } @Test public void testJobScheduleCreationWithSchedule() { OffsetDateTime currentTime = OffsetDateTime.now(); - daprJobsClient.scheduleJob(ScheduleJobRequest.builder().setName("Job") - .setSchedule(JobSchedule.hourly()) - .setDueTime(currentTime).build()).block(); + daprPreviewClient.scheduleJob(new ScheduleJobRequest("Job", JobSchedule.hourly()) + .setDueTime(currentTime)).block(); GetJobResponse getJobResponse = - daprJobsClient.getJob(GetJobRequest.builder().setName("Job").build()).block(); - Assert.assertEquals(currentTime.toString(), getJobResponse.getDueTime().toString()); - Assert.assertEquals(JobSchedule.hourly().getExpression(), getJobResponse.getSchedule().getExpression()); - Assert.assertEquals("Job", getJobResponse.getName()); + daprPreviewClient.getJob(new GetJobRequest("Job")).block(); + Assertions.assertEquals(currentTime.toString(), getJobResponse.getDueTime().toString()); + Assertions.assertEquals(JobSchedule.hourly().getExpression(), getJobResponse.getSchedule().getExpression()); + Assertions.assertEquals("Job", getJobResponse.getName()); } @Test public void testJobScheduleCreationWithAllParameters() { OffsetDateTime currentTime = OffsetDateTime.now(); - String cronExpression = new CronExpressionBuilder() - .add(CronPeriod.SECONDS, 2) - .add(CronPeriod.HOURS, 3) - .add(DayOfWeek.FRI) - .build(); + String cronExpression = "2 * 3 * * FRI"; - daprJobsClient.scheduleJob(ScheduleJobRequest.builder().setName("Job") + daprPreviewClient.scheduleJob(new ScheduleJobRequest("Job", currentTime) .setTtl(currentTime.plusHours(2)) .setData("Job data".getBytes()) .setRepeat(3) - .setSchedule(JobSchedule.fromString(cronExpression)) - .setDueTime(currentTime).build()).block(); + .setSchedule(JobSchedule.fromString(cronExpression))).block(); GetJobResponse getJobResponse = - daprJobsClient.getJob(GetJobRequest.builder().setName("Job").build()).block(); + daprPreviewClient.getJob(new GetJobRequest("Job")).block(); Assertions.assertEquals(currentTime.toString(), getJobResponse.getDueTime().toString()); Assertions.assertEquals("2 * 3 * * FRI", getJobResponse.getSchedule().getExpression()); Assertions.assertEquals("Job", getJobResponse.getName()); - Assertions.assertEquals(3, getJobResponse.getRepeat()); + Assertions.assertEquals(3, getJobResponse.getRepeats()); Assertions.assertEquals("Job data", new String(getJobResponse.getData())); Assertions.assertEquals(currentTime.plusHours(2), getJobResponse.getTtl()); } @@ -121,19 +119,14 @@ public void testJobScheduleCreationWithAllParameters() { public void testDeleteJobRequest() { OffsetDateTime currentTime = OffsetDateTime.now(); - String cronExpression = new CronExpressionBuilder() - .add(CronPeriod.SECONDS, 2) - .add(CronPeriod.HOURS, 3) - .add(DayOfWeek.FRI) - .build(); + String cronExpression = "2 * 3 * * FRI"; - daprJobsClient.scheduleJob(ScheduleJobRequest.builder().setName("Job") + daprPreviewClient.scheduleJob(new ScheduleJobRequest("Job", currentTime) .setTtl(currentTime.plusHours(2)) .setData("Job data".getBytes()) .setRepeat(3) - .setSchedule(JobSchedule.fromString(cronExpression)) - .setDueTime(currentTime).build()).block(); + .setSchedule(JobSchedule.fromString(cronExpression))).block(); - daprJobsClient.deleteJob(DeleteJobRequest.builder().setName("Job").build()).block(); + daprPreviewClient.deleteJob(new DeleteJobRequest("Job")).block(); } } diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprJobsConfiguration.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprJobsConfiguration.java index e565b18017..b5ca40088e 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprJobsConfiguration.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprJobsConfiguration.java @@ -13,8 +13,10 @@ package io.dapr.it.testcontainers; -import io.dapr.config.Properties; -import io.dapr.jobs.client.DaprJobsClient; +import io.dapr.client.DaprClientBuilder; +import io.dapr.client.DaprClientImpl; +import io.dapr.client.DaprPreviewClient; +import io.dapr.serializer.DefaultObjectSerializer; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -24,7 +26,7 @@ @Configuration public class TestDaprJobsConfiguration { @Bean - public DaprJobsClient daprJobsClient( + public DaprPreviewClient daprJobsClient( @Value("${dapr.http.endpoint}") String daprHttpEndpoint, @Value("${dapr.grpc.endpoint}") String daprGrpcEndpoint ){ @@ -33,6 +35,6 @@ public DaprJobsClient daprJobsClient( "dapr.grpc.endpoint", daprGrpcEndpoint ); - return new DaprJobsClient(new Properties(overrides), null); + return new DaprClientBuilder().buildPreviewClient(); } } diff --git a/sdk/src/main/java/io/dapr/client/DaprClientImpl.java b/sdk/src/main/java/io/dapr/client/DaprClientImpl.java index 0c1264eb19..9f5ed481fb 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientImpl.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientImpl.java @@ -14,6 +14,7 @@ package io.dapr.client; import com.google.common.base.Strings; +import com.google.protobuf.Any; import com.google.protobuf.ByteString; import com.google.protobuf.Empty; import io.dapr.client.domain.ActorMetadata; @@ -27,17 +28,21 @@ import io.dapr.client.domain.ComponentMetadata; import io.dapr.client.domain.ConfigurationItem; import io.dapr.client.domain.DaprMetadata; +import io.dapr.client.domain.DeleteJobRequest; import io.dapr.client.domain.DeleteStateRequest; import io.dapr.client.domain.ExecuteStateTransactionRequest; import io.dapr.client.domain.GetBulkSecretRequest; import io.dapr.client.domain.GetBulkStateRequest; import io.dapr.client.domain.GetConfigurationRequest; +import io.dapr.client.domain.GetJobRequest; +import io.dapr.client.domain.GetJobResponse; import io.dapr.client.domain.GetSecretRequest; import io.dapr.client.domain.GetStateRequest; import io.dapr.client.domain.HttpEndpointMetadata; import io.dapr.client.domain.HttpExtension; import io.dapr.client.domain.InvokeBindingRequest; import io.dapr.client.domain.InvokeMethodRequest; +import io.dapr.client.domain.JobSchedule; import io.dapr.client.domain.LockRequest; import io.dapr.client.domain.PublishEventRequest; import io.dapr.client.domain.QueryStateItem; @@ -45,6 +50,7 @@ import io.dapr.client.domain.QueryStateResponse; import io.dapr.client.domain.RuleMetadata; import io.dapr.client.domain.SaveStateRequest; +import io.dapr.client.domain.ScheduleJobRequest; import io.dapr.client.domain.State; import io.dapr.client.domain.StateOptions; import io.dapr.client.domain.SubscribeConfigurationRequest; @@ -90,9 +96,9 @@ import reactor.util.retry.Retry; import javax.annotation.Nonnull; - import java.io.IOException; import java.time.Duration; +import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -1290,6 +1296,144 @@ public Mono unsubscribeConfiguration(Unsubscri } } + /** + * {@inheritDoc} + */ + public Mono scheduleJob(ScheduleJobRequest scheduleJobRequest) { + try { + validateScheduleJobRequest(scheduleJobRequest); + + DaprProtos.Job.Builder scheduleJobRequestBuilder = DaprProtos.Job.newBuilder(); + scheduleJobRequestBuilder.setName(scheduleJobRequest.getName()); + + if (scheduleJobRequest.getData() != null) { + scheduleJobRequestBuilder.setData(Any.newBuilder() + .setValue(ByteString.copyFrom(scheduleJobRequest.getData())).build()); + } + + if (scheduleJobRequest.getSchedule() != null) { + scheduleJobRequestBuilder.setSchedule(scheduleJobRequest.getSchedule().getExpression()); + } + + if (scheduleJobRequest.getTtl() != null) { + scheduleJobRequestBuilder.setTtl(scheduleJobRequest.getTtl().toString()); + } + + if (scheduleJobRequest.getRepeats() != null) { + scheduleJobRequestBuilder.setRepeats(scheduleJobRequest.getRepeats()); + } + + if (scheduleJobRequest.getDueTime() != null) { + scheduleJobRequestBuilder.setDueTime(scheduleJobRequest.getDueTime().toString()); + } + + Mono scheduleJobResponseMono = + Mono.deferContextual(context -> this.createMono( + it -> intercept(context, asyncStub) + .scheduleJobAlpha1(DaprProtos.ScheduleJobRequest.newBuilder() + .setJob(scheduleJobRequestBuilder.build()).build(), it) + ) + ); + + return scheduleJobResponseMono.then(); + } catch (Exception ex) { + return DaprException.wrapMono(ex); + } + } + + /** + * {@inheritDoc} + */ + public Mono getJob(GetJobRequest getJobRequest) { + try { + validateGetJobRequest(getJobRequest); + + Mono getJobResponseMono = + Mono.deferContextual(context -> this.createMono( + it -> intercept(context, asyncStub) + .getJobAlpha1(DaprProtos.GetJobRequest.newBuilder() + .setName(getJobRequest.getName()).build(), it) + ) + ); + + return getJobResponseMono.map(response -> { + DaprProtos.Job job = response.getJob(); + GetJobResponse getJobResponse = null; + + if (job.hasSchedule() && job.hasDueTime()) { + getJobResponse = new GetJobResponse(job.getName(), JobSchedule.fromString(job.getSchedule())); + getJobResponse.setDueTime(OffsetDateTime.parse(job.getDueTime())); + } else if (job.hasSchedule()) { + getJobResponse = new GetJobResponse(job.getName(), JobSchedule.fromString(job.getSchedule())); + } else { + getJobResponse = new GetJobResponse(job.getName(), OffsetDateTime.parse(job.getDueTime())); + } + + return getJobResponse + .setTtl(job.hasTtl() ? OffsetDateTime.parse(job.getTtl()) : null) + .setData(job.hasData() ? job.getData().getValue().toByteArray() : null) + .setRepeat(job.hasRepeats() ? job.getRepeats() : null); + }); + } catch (Exception ex) { + return DaprException.wrapMono(ex); + } + } + + /** + * {@inheritDoc} + */ + public Mono deleteJob(DeleteJobRequest deleteJobRequest) { + try { + validateDeleteJobRequest(deleteJobRequest); + + Mono deleteJobResponseMono = + Mono.deferContextual(context -> this.createMono( + it -> intercept(context, asyncStub) + .deleteJobAlpha1(DaprProtos.DeleteJobRequest.newBuilder() + .setName(deleteJobRequest.getName()).build(), it) + ) + ); + + return deleteJobResponseMono.then(); + } catch (Exception ex) { + return DaprException.wrapMono(ex); + } + } + + private void validateScheduleJobRequest(ScheduleJobRequest scheduleJobRequest) { + if (scheduleJobRequest == null) { + throw new IllegalArgumentException("scheduleJobRequest cannot be null"); + } + + if (scheduleJobRequest.getName() == null || scheduleJobRequest.getName().isEmpty()) { + throw new IllegalArgumentException("Name in the request cannot be null or empty"); + } + + if (scheduleJobRequest.getSchedule() == null && scheduleJobRequest.getDueTime() == null) { + throw new IllegalArgumentException("At least one of schedule or dueTime must be provided"); + } + } + + private void validateGetJobRequest(GetJobRequest getJobRequest) { + if (getJobRequest == null) { + throw new IllegalArgumentException("getJobRequest cannot be null"); + } + + if (getJobRequest.getName() == null || getJobRequest.getName().isEmpty()) { + throw new IllegalArgumentException("Name in the request cannot be null or empty"); + } + } + + private void validateDeleteJobRequest(DeleteJobRequest deleteJobRequest) { + if (deleteJobRequest == null) { + throw new IllegalArgumentException("deleteJobRequest cannot be null"); + } + + if (deleteJobRequest.getName() == null || deleteJobRequest.getName().isEmpty()) { + throw new IllegalArgumentException("Name in the request cannot be null or empty"); + } + } + /** * Build a new Configuration Item from provided parameter. * diff --git a/sdk/src/main/java/io/dapr/client/DaprPreviewClient.java b/sdk/src/main/java/io/dapr/client/DaprPreviewClient.java index 95911efc23..b4fba8ef38 100644 --- a/sdk/src/main/java/io/dapr/client/DaprPreviewClient.java +++ b/sdk/src/main/java/io/dapr/client/DaprPreviewClient.java @@ -17,9 +17,13 @@ import io.dapr.client.domain.BulkPublishRequest; import io.dapr.client.domain.BulkPublishResponse; import io.dapr.client.domain.BulkPublishResponseFailedEntry; +import io.dapr.client.domain.DeleteJobRequest; +import io.dapr.client.domain.GetJobRequest; +import io.dapr.client.domain.GetJobResponse; import io.dapr.client.domain.LockRequest; import io.dapr.client.domain.QueryStateRequest; import io.dapr.client.domain.QueryStateResponse; +import io.dapr.client.domain.ScheduleJobRequest; import io.dapr.client.domain.UnlockRequest; import io.dapr.client.domain.UnlockResponseStatus; import io.dapr.client.domain.query.Query; @@ -268,4 +272,36 @@ Mono> publishEvents(String pubsubName, String topicNa */ Subscription subscribeToEvents( String pubsubName, String topic, SubscriptionListener listener, TypeRef type); + + /** + * Schedules a job using the provided job request details. + * + * @param scheduleJobRequest The request containing the details of the job to schedule. + * Must include a name and optional schedule, data, and other related properties. + * @return A {@link Mono} that completes when the job scheduling operation is successful or raises an error. + * @throws IllegalArgumentException If the request or its required fields like name are null or empty. + */ + public Mono scheduleJob(ScheduleJobRequest scheduleJobRequest); + + /** + * Retrieves details of a specific job. + * + * @param getJobRequest The request containing the job name for which the details are to be fetched. + * The name property is mandatory. + * @return A {@link Mono} that emits the {@link GetJobResponse} containing job details or raises an + * error if the job is not found. + * @throws IllegalArgumentException If the request or its required fields like name are null or empty. + */ + + public Mono getJob(GetJobRequest getJobRequest); + + /** + * Deletes a job based on the given request. + * + * @param deleteJobRequest The request containing the job name to be deleted. + * The name property is mandatory. + * @return A {@link Mono} that completes when the job is successfully deleted or raises an error. + * @throws IllegalArgumentException If the request or its required fields like name are null or empty. + */ + public Mono deleteJob(DeleteJobRequest deleteJobRequest); } diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/DeleteJobRequest.java b/sdk/src/main/java/io/dapr/client/domain/DeleteJobRequest.java similarity index 93% rename from sdk-jobs/src/main/java/io/dapr/jobs/client/DeleteJobRequest.java rename to sdk/src/main/java/io/dapr/client/domain/DeleteJobRequest.java index abdf4c18c4..8d47487139 100644 --- a/sdk-jobs/src/main/java/io/dapr/jobs/client/DeleteJobRequest.java +++ b/sdk/src/main/java/io/dapr/client/domain/DeleteJobRequest.java @@ -1,4 +1,4 @@ -package io.dapr.jobs.client; +package io.dapr.client.domain; /** * Represents a request to schedule a job in Dapr. diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobRequest.java b/sdk/src/main/java/io/dapr/client/domain/GetJobRequest.java similarity index 92% rename from sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobRequest.java rename to sdk/src/main/java/io/dapr/client/domain/GetJobRequest.java index 7c32509aca..5332e137e5 100644 --- a/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobRequest.java +++ b/sdk/src/main/java/io/dapr/client/domain/GetJobRequest.java @@ -1,4 +1,4 @@ -package io.dapr.jobs.client; +package io.dapr.client.domain; /** * Represents a request to schedule a job in Dapr. diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobResponse.java b/sdk/src/main/java/io/dapr/client/domain/GetJobResponse.java similarity index 99% rename from sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobResponse.java rename to sdk/src/main/java/io/dapr/client/domain/GetJobResponse.java index 6759802186..1e7002a34b 100644 --- a/sdk-jobs/src/main/java/io/dapr/jobs/client/GetJobResponse.java +++ b/sdk/src/main/java/io/dapr/client/domain/GetJobResponse.java @@ -1,4 +1,4 @@ -package io.dapr.jobs.client; +package io.dapr.client.domain; import java.time.OffsetDateTime; diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/JobSchedule.java b/sdk/src/main/java/io/dapr/client/domain/JobSchedule.java similarity index 76% rename from sdk-jobs/src/main/java/io/dapr/jobs/client/JobSchedule.java rename to sdk/src/main/java/io/dapr/client/domain/JobSchedule.java index 87f2a83ced..4cc2c85b01 100644 --- a/sdk-jobs/src/main/java/io/dapr/jobs/client/JobSchedule.java +++ b/sdk/src/main/java/io/dapr/client/domain/JobSchedule.java @@ -1,4 +1,4 @@ -package io.dapr.jobs.client; +package io.dapr.client.domain; import java.time.Duration; @@ -69,13 +69,7 @@ public static JobSchedule fromString(String cronExpression) { * @return a {@code JobsSchedule} for yearly execution. */ public static JobSchedule yearly() { - return new JobSchedule(new CronExpressionBuilder() - .add(CronPeriod.SECONDS, 0) - .add(CronPeriod.MINUTES, 0) - .add(CronPeriod.HOURS, 0) - .add(CronPeriod.DayOfMonth, 1) - .add(CronPeriod.MonthOfYear, 1) - .build()); + return new JobSchedule("0 0 0 1 1 *"); } /** @@ -84,12 +78,7 @@ public static JobSchedule yearly() { * @return a {@code JobsSchedule} for monthly execution. */ public static JobSchedule monthly() { - return new JobSchedule(new CronExpressionBuilder() - .add(CronPeriod.SECONDS, 0) - .add(CronPeriod.MINUTES, 0) - .add(CronPeriod.HOURS, 0) - .add(CronPeriod.DayOfMonth, 1) - .build()); + return new JobSchedule("0 0 0 1 * *"); } /** @@ -98,12 +87,7 @@ public static JobSchedule monthly() { * @return a {@code JobsSchedule} for weekly execution. */ public static JobSchedule weekly() { - return new JobSchedule(new CronExpressionBuilder() - .add(CronPeriod.SECONDS, 0) - .add(CronPeriod.MINUTES, 0) - .add(CronPeriod.HOURS, 0) - .add(CronPeriod.DayOfWeek, 0) - .build()); + return new JobSchedule("0 0 0 * * 0"); } /** @@ -112,11 +96,7 @@ public static JobSchedule weekly() { * @return a {@code JobsSchedule} for daily execution. */ public static JobSchedule daily() { - return new JobSchedule(new CronExpressionBuilder() - .add(CronPeriod.SECONDS, 0) - .add(CronPeriod.MINUTES, 0) - .add(CronPeriod.HOURS, 0) - .build()); + return new JobSchedule("0 0 0 * * *"); } /** @@ -125,10 +105,7 @@ public static JobSchedule daily() { * @return a {@code JobsSchedule} for hourly execution. */ public static JobSchedule hourly() { - return new JobSchedule(new CronExpressionBuilder() - .add(CronPeriod.SECONDS, 0) - .add(CronPeriod.MINUTES, 0) - .build()); + return new JobSchedule("0 0 * * * *"); } /** diff --git a/sdk-jobs/src/main/java/io/dapr/jobs/client/ScheduleJobRequest.java b/sdk/src/main/java/io/dapr/client/domain/ScheduleJobRequest.java similarity index 99% rename from sdk-jobs/src/main/java/io/dapr/jobs/client/ScheduleJobRequest.java rename to sdk/src/main/java/io/dapr/client/domain/ScheduleJobRequest.java index 5477d8c8de..b76a077f6b 100644 --- a/sdk-jobs/src/main/java/io/dapr/jobs/client/ScheduleJobRequest.java +++ b/sdk/src/main/java/io/dapr/client/domain/ScheduleJobRequest.java @@ -1,4 +1,4 @@ -package io.dapr.jobs.client; +package io.dapr.client.domain; import java.time.OffsetDateTime; diff --git a/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java index 6864a1ee07..276a700e38 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java @@ -13,8 +13,7 @@ package io.dapr.client; import com.fasterxml.jackson.core.JsonParseException; -import io.dapr.client.domain.HttpExtension; -import io.dapr.client.domain.InvokeMethodRequest; +import io.dapr.client.domain.*; import io.dapr.config.Properties; import io.dapr.exceptions.DaprException; import io.dapr.serializer.DefaultObjectSerializer; @@ -45,14 +44,9 @@ import static io.dapr.utils.TestUtils.assertThrowsDaprException; import static io.dapr.utils.TestUtils.findFreePort; import static io.dapr.utils.TestUtils.formatIpAddress; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; public class DaprClientHttpTest { @@ -632,5 +626,4 @@ public void close() throws Exception { daprClientHttp = buildDaprClient(daprHttp); daprClientHttp.close(); } - } diff --git a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java index a28dad0f42..10cfa921b6 100644 --- a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java @@ -16,15 +16,9 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.protobuf.Any; import com.google.protobuf.ByteString; -import io.dapr.client.domain.BulkPublishEntry; -import io.dapr.client.domain.BulkPublishRequest; -import io.dapr.client.domain.BulkPublishResponse; -import io.dapr.client.domain.CloudEvent; -import io.dapr.client.domain.QueryStateItem; -import io.dapr.client.domain.QueryStateRequest; -import io.dapr.client.domain.QueryStateResponse; -import io.dapr.client.domain.UnlockResponseStatus; +import io.dapr.client.domain.*; import io.dapr.client.domain.query.Query; import io.dapr.serializer.DaprObjectSerializer; import io.dapr.serializer.DefaultObjectSerializer; @@ -32,6 +26,7 @@ import io.dapr.v1.DaprAppCallbackProtos; import io.dapr.v1.DaprGrpc; import io.dapr.v1.DaprProtos; +import io.grpc.ManagedChannel; import io.grpc.Status; import io.grpc.StatusRuntimeException; import io.grpc.stub.StreamObserver; @@ -39,11 +34,15 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; import org.mockito.stubbing.Answer; import reactor.core.publisher.Mono; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -57,16 +56,10 @@ import java.util.concurrent.atomic.AtomicInteger; import static io.dapr.utils.TestUtils.assertThrowsDaprException; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.times; public class DaprPreviewClientGrpcTest { @@ -539,6 +532,285 @@ public void onError(RuntimeException exception) { assertEquals(numDrops, dropCounter.get()); assertEquals(numErrors, errors.size()); } + + + @Test + void scheduleJobShouldSucceedWhenAllFieldsArePresentInRequest() { + ScheduleJobRequest expectedScheduleJobRequest = new ScheduleJobRequest("testJob", + JobSchedule.fromString("*/5 * * * *")) + .setData("testData".getBytes()) + .setTtl(OffsetDateTime.now().plusDays(1)) + .setRepeat(5) + .setDueTime(OffsetDateTime.now().plusMinutes(10)); + + doAnswer(invocation -> { + StreamObserver observer = invocation.getArgument(1); + observer.onCompleted(); // Simulate successful response + return null; + }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any()); + + assertDoesNotThrow(() -> previewClient.scheduleJob(expectedScheduleJobRequest).block()); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); + + verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any()); + DaprProtos.ScheduleJobRequest actualScheduleJobReq = captor.getValue(); + + assertEquals("testJob", actualScheduleJobReq.getJob().getName()); + assertEquals("testData", + new String(actualScheduleJobReq.getJob().getData().getValue().toByteArray(), StandardCharsets.UTF_8)); + assertEquals("*/5 * * * *", actualScheduleJobReq.getJob().getSchedule()); + assertEquals(expectedScheduleJobRequest.getTtl().toString(), actualScheduleJobReq.getJob().getTtl()); + assertEquals(expectedScheduleJobRequest.getRepeats(), actualScheduleJobReq.getJob().getRepeats()); + assertEquals(expectedScheduleJobRequest.getDueTime().toString(), actualScheduleJobReq.getJob().getDueTime()); + } + + @Test + void scheduleJobShouldSucceedWhenRequiredFieldsNameAndDueTimeArePresentInRequest() { + + doAnswer(invocation -> { + StreamObserver observer = invocation.getArgument(1); + observer.onCompleted(); // Simulate successful response + return null; + }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any()); + + ScheduleJobRequest expectedScheduleJobRequest = + new ScheduleJobRequest("testJob", OffsetDateTime.now().plusMinutes(10)); + assertDoesNotThrow(() -> previewClient.scheduleJob(expectedScheduleJobRequest).block()); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); + + verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any()); + DaprProtos.ScheduleJobRequest actualScheduleJobRequest = captor.getValue(); + DaprProtos.Job job = actualScheduleJobRequest.getJob(); + assertEquals("testJob", job.getName()); + assertFalse(job.hasData()); + assertFalse(job.hasSchedule()); + assertEquals(0, job.getRepeats()); + assertFalse(job.hasTtl()); + assertEquals(job.getDueTime(), actualScheduleJobRequest.getJob().getDueTime()); + } + + @Test + void scheduleJobShouldSucceedWhenRequiredFieldsNameAndScheduleArePresentInRequest() { + + doAnswer(invocation -> { + StreamObserver observer = invocation.getArgument(1); + observer.onCompleted(); // Simulate successful response + return null; + }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any()); + + ScheduleJobRequest expectedScheduleJobRequest = new ScheduleJobRequest("testJob", + JobSchedule.fromString("* * * * * *")); + assertDoesNotThrow(() -> previewClient.scheduleJob(expectedScheduleJobRequest).block()); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); + + verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any()); + DaprProtos.ScheduleJobRequest actualScheduleJobRequest = captor.getValue(); + DaprProtos.Job job = actualScheduleJobRequest.getJob(); + assertEquals("testJob", job.getName()); + assertFalse(job.hasData()); + assertEquals( "* * * * * *", job.getSchedule()); + assertEquals(0, job.getRepeats()); + assertFalse(job.hasTtl()); + assertEquals(job.getDueTime(), actualScheduleJobRequest.getJob().getDueTime()); + } + + @Test + void scheduleJobShouldThrowWhenRequestIsNull() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.scheduleJob(null).block(); + }); + assertEquals("scheduleJobRequest cannot be null", exception.getMessage()); + } + + @Test + void scheduleJobShouldThrowWhenInvalidRequest() { + ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest(null, OffsetDateTime.now()); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.scheduleJob(scheduleJobRequest).block(); + }); + assertEquals("Name in the request cannot be null or empty", exception.getMessage()); + } + + @Test + void scheduleJobShouldThrowWhenNameInRequestIsEmpty() { + ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest("", OffsetDateTime.now()); + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.scheduleJob(scheduleJobRequest).block(); + }); + assertEquals("Name in the request cannot be null or empty", exception.getMessage()); + } + + @Test + void getJobShouldReturnResponseWhenAllFieldsArePresentInRequest() { + GetJobRequest getJobRequest = new GetJobRequest("testJob"); + + DaprProtos.Job job = DaprProtos.Job.newBuilder() + .setName("testJob") + .setTtl(OffsetDateTime.now().toString()) + .setData(Any.newBuilder().setValue(ByteString.copyFrom("testData".getBytes())).build()) + .setSchedule("*/5 * * * *") + .setRepeats(5) + .setDueTime(OffsetDateTime.now().plusMinutes(10).toString()) + .build(); + + doAnswer(invocation -> { + StreamObserver observer = invocation.getArgument(1); + observer.onNext(DaprProtos.GetJobResponse.newBuilder() + .setJob(job) + .build()); + observer.onCompleted(); + return null; + }).when(daprStub).getJobAlpha1(any(DaprProtos.GetJobRequest.class), any()); + + Mono resultMono = previewClient.getJob(getJobRequest); + + GetJobResponse response = resultMono.block(); + assertNotNull(response); + assertEquals("testJob", response.getName()); + assertEquals("testData", new String(response.getData(), StandardCharsets.UTF_8)); + assertEquals("*/5 * * * *", response.getSchedule().getExpression()); + assertEquals(5, response.getRepeats()); + assertEquals(job.getTtl(), response.getTtl().toString()); + assertEquals(job.getDueTime(), response.getDueTime().toString()); + } + + @Test + void getJobShouldReturnResponseWithScheduleSetWhenResponseHasSchedule() { + GetJobRequest getJobRequest = new GetJobRequest("testJob"); + + DaprProtos.Job job = DaprProtos.Job.newBuilder() + .setName("testJob") + .setSchedule("0 0 0 1 1 *") + .build(); + + doAnswer(invocation -> { + StreamObserver observer = invocation.getArgument(1); + observer.onNext(DaprProtos.GetJobResponse.newBuilder() + .setJob(job) + .build()); + observer.onCompleted(); + return null; + }).when(daprStub).getJobAlpha1(any(DaprProtos.GetJobRequest.class), any()); + + Mono resultMono = previewClient.getJob(getJobRequest); + + GetJobResponse response = resultMono.block(); + assertNotNull(response); + assertEquals("testJob", response.getName()); + assertNull(response.getData()); + assertEquals("0 0 0 1 1 *", response.getSchedule().getExpression()); + assertNull(response.getRepeats()); + assertNull(response.getTtl()); + assertNull(response.getDueTime()); + } + + @Test + void getJobShouldReturnResponseWithDueTimeSetWhenResponseHasDueTime() { + GetJobRequest getJobRequest = new GetJobRequest("testJob"); + + String datetime = OffsetDateTime.now().toString(); + DaprProtos.Job job = DaprProtos.Job.newBuilder() + .setName("testJob") + .setDueTime(datetime) + .build(); + + doAnswer(invocation -> { + StreamObserver observer = invocation.getArgument(1); + observer.onNext(DaprProtos.GetJobResponse.newBuilder() + .setJob(job) + .build()); + observer.onCompleted(); + return null; + }).when(daprStub).getJobAlpha1(any(DaprProtos.GetJobRequest.class), any()); + + Mono resultMono = previewClient.getJob(getJobRequest); + + GetJobResponse response = resultMono.block(); + assertNotNull(response); + assertEquals("testJob", response.getName()); + assertNull(response.getData()); + assertNull(response.getSchedule()); + assertNull(response.getRepeats()); + assertNull(response.getTtl()); + assertEquals(job.getDueTime(), datetime); + } + + @Test + void getJobShouldThrowWhenRequestIsNull() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.getJob(null).block(); + }); + assertEquals("getJobRequest cannot be null", exception.getMessage()); + } + + @Test + void getJobShouldThrowWhenNameIsNullRequest() { + GetJobRequest getJobRequest = new GetJobRequest(null); + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.getJob(getJobRequest).block(); + }); + assertEquals("Name in the request cannot be null or empty", exception.getMessage()); + } + + @Test + void getJobShouldThrowWhenNameIsEmptyRequest() { + GetJobRequest getJobRequest =new GetJobRequest("");; + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.getJob(getJobRequest).block(); + }); + assertEquals("Name in the request cannot be null or empty", exception.getMessage()); + } + + @Test + void deleteJobShouldSucceedWhenValidRequest() { + DeleteJobRequest deleteJobRequest = new DeleteJobRequest("testJob"); + + doAnswer(invocation -> { + StreamObserver observer = invocation.getArgument(1); + observer.onCompleted(); // Simulate successful response + return null; + }).when(daprStub).deleteJobAlpha1(any(DaprProtos.DeleteJobRequest.class), any()); + + Mono resultMono = previewClient.deleteJob(deleteJobRequest); + + assertDoesNotThrow(() -> resultMono.block()); + } + + @Test + void deleteJobShouldThrowRequestIsNull() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.deleteJob(null).block(); + }); + assertEquals("deleteJobRequest cannot be null", exception.getMessage()); + } + + @Test + void deleteJobShouldThrowWhenNameIsNullRequest() { + DeleteJobRequest deleteJobRequest = new DeleteJobRequest(null); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.deleteJob(deleteJobRequest).block(); + }); + assertEquals("Name in the request cannot be null or empty", exception.getMessage()); + } + + @Test + void deleteJobShouldThrowWhenNameIsEmptyRequest() { + DeleteJobRequest deleteJobRequest = new DeleteJobRequest(""); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.deleteJob(deleteJobRequest).block(); + }); + assertEquals("Name in the request cannot be null or empty", exception.getMessage()); + } + private DaprProtos.QueryStateResponse buildQueryStateResponse(List> resp,String token) throws JsonProcessingException { List items = new ArrayList<>(); diff --git a/sdk-jobs/test/test/java/io/dapr/jobs/client/JobsScheduleTest.java b/sdk/src/test/java/io/dapr/client/domain/JobsScheduleTest.java similarity index 98% rename from sdk-jobs/test/test/java/io/dapr/jobs/client/JobsScheduleTest.java rename to sdk/src/test/java/io/dapr/client/domain/JobsScheduleTest.java index 0a70c45414..e0e16f49d4 100644 --- a/sdk-jobs/test/test/java/io/dapr/jobs/client/JobsScheduleTest.java +++ b/sdk/src/test/java/io/dapr/client/domain/JobsScheduleTest.java @@ -1,4 +1,4 @@ -package io.dapr.jobs.client; +package io.dapr.client.domain; import org.junit.jupiter.api.Test; From de1db0a706f265f31e53d2443dd96ada9ef49f29 Mon Sep 17 00:00:00 2001 From: sirivarma Date: Mon, 24 Mar 2025 10:41:02 -0700 Subject: [PATCH 07/30] remove jobs Signed-off-by: sirivarma --- sdk-tests/pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sdk-tests/pom.xml b/sdk-tests/pom.xml index a2267e250f..850dd0e6d8 100644 --- a/sdk-tests/pom.xml +++ b/sdk-tests/pom.xml @@ -151,12 +151,6 @@ ${dapr.sdk.version} test
- - io.dapr - dapr-sdk-jobs - ${dapr.sdk.version} - test - io.dapr dapr-sdk-actors From ebea4c7f2df4f1bdbae917995c9f4daa0ff7afa7 Mon Sep 17 00:00:00 2001 From: sirivarma Date: Wed, 26 Mar 2025 06:41:48 -0700 Subject: [PATCH 08/30] change bean name Signed-off-by: sirivarma --- .../io/dapr/it/testcontainers/TestDaprJobsConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprJobsConfiguration.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprJobsConfiguration.java index b5ca40088e..679007ec02 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprJobsConfiguration.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprJobsConfiguration.java @@ -26,7 +26,7 @@ @Configuration public class TestDaprJobsConfiguration { @Bean - public DaprPreviewClient daprJobsClient( + public DaprPreviewClient daprPreviewClient( @Value("${dapr.http.endpoint}") String daprHttpEndpoint, @Value("${dapr.grpc.endpoint}") String daprGrpcEndpoint ){ From 87c07ca90382361ff51ad85e2c7b23512cd0e663 Mon Sep 17 00:00:00 2001 From: artur-ciocanu Date: Fri, 28 Mar 2025 17:48:52 +0200 Subject: [PATCH 09/30] Use latest Dapr release Signed-off-by: artur-ciocanu --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e14bf980cb..45344dac67 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ 1.69.0 3.25.5 protoc - https://raw.githubusercontent.com/dapr/dapr/v1.15.2/dapr/proto + https://raw.githubusercontent.com/dapr/dapr/v1.15.3/dapr/proto 1.15.0-SNAPSHOT 0.15.0-SNAPSHOT 1.7.1 From ab3a75da37afdbbca8e8dfc25e396c5f6b997e8d Mon Sep 17 00:00:00 2001 From: siri-varma Date: Sun, 6 Apr 2025 14:58:46 +0530 Subject: [PATCH 10/30] fix things Signed-off-by: siri-varma --- .../io/dapr/it/testcontainers/DaprJobsIT.java | 27 ++++++++++--------- .../TestDaprJobsConfiguration.java | 10 ++++--- .../java/io/dapr/client/DaprClientImpl.java | 17 +++++++++--- .../client/DaprPreviewClientGrpcTest.java | 16 ++++++++--- 4 files changed, 46 insertions(+), 24 deletions(-) diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java index 170e7e969a..dde8df7bdb 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java @@ -20,10 +20,13 @@ import org.testcontainers.containers.Network; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.shaded.org.yaml.snakeyaml.scanner.Constant; import java.time.OffsetDateTime; import java.util.Random; +import static org.junit.Assert.assertEquals; + @SpringBootTest( webEnvironment = WebEnvironment.RANDOM_PORT, classes = { @@ -40,7 +43,7 @@ public class DaprJobsIT { private static final int PORT = RANDOM.nextInt(1000) + 8000; @Container - private static final DaprContainer DAPR_CONTAINER = new DaprContainer("daprio/daprd:1.15.2") + private static final DaprContainer DAPR_CONTAINER = new DaprContainer(DaprContainerConstants.IMAGE_TAG) .withAppName("jobs-dapr-app") .withNetwork(DAPR_NETWORK) .withDaprLogLevel(DaprLogLevel.DEBUG) @@ -76,8 +79,8 @@ public void testJobScheduleCreationWithDueTime() { GetJobResponse getJobResponse = daprPreviewClient.getJob(new GetJobRequest("Job")).block(); - Assertions.assertEquals(currentTime.toString(), getJobResponse.getDueTime().toString()); - Assertions.assertEquals("Job", getJobResponse.getName()); + assertEquals(currentTime.toString(), getJobResponse.getDueTime().toString()); + assertEquals("Job", getJobResponse.getName()); } @Test @@ -88,9 +91,9 @@ public void testJobScheduleCreationWithSchedule() { GetJobResponse getJobResponse = daprPreviewClient.getJob(new GetJobRequest("Job")).block(); - Assertions.assertEquals(currentTime.toString(), getJobResponse.getDueTime().toString()); - Assertions.assertEquals(JobSchedule.hourly().getExpression(), getJobResponse.getSchedule().getExpression()); - Assertions.assertEquals("Job", getJobResponse.getName()); + assertEquals(currentTime.toString(), getJobResponse.getDueTime().toString()); + assertEquals(JobSchedule.hourly().getExpression(), getJobResponse.getSchedule().getExpression()); + assertEquals("Job", getJobResponse.getName()); } @Test @@ -107,12 +110,12 @@ public void testJobScheduleCreationWithAllParameters() { GetJobResponse getJobResponse = daprPreviewClient.getJob(new GetJobRequest("Job")).block(); - Assertions.assertEquals(currentTime.toString(), getJobResponse.getDueTime().toString()); - Assertions.assertEquals("2 * 3 * * FRI", getJobResponse.getSchedule().getExpression()); - Assertions.assertEquals("Job", getJobResponse.getName()); - Assertions.assertEquals(3, getJobResponse.getRepeats()); - Assertions.assertEquals("Job data", new String(getJobResponse.getData())); - Assertions.assertEquals(currentTime.plusHours(2), getJobResponse.getTtl()); + assertEquals(currentTime.toString(), getJobResponse.getDueTime().toString()); + assertEquals("2 * 3 * * FRI", getJobResponse.getSchedule().getExpression()); + assertEquals("Job", getJobResponse.getName()); + assertEquals(Integer.valueOf(3), getJobResponse.getRepeats()); + assertEquals("Job data", new String(getJobResponse.getData())); + assertEquals(currentTime.plusHours(2), getJobResponse.getTtl()); } @Test diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprJobsConfiguration.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprJobsConfiguration.java index 679007ec02..5e0e2e8c89 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprJobsConfiguration.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/TestDaprJobsConfiguration.java @@ -16,6 +16,8 @@ import io.dapr.client.DaprClientBuilder; import io.dapr.client.DaprClientImpl; import io.dapr.client.DaprPreviewClient; +import io.dapr.config.Properties; +import io.dapr.config.Property; import io.dapr.serializer.DefaultObjectSerializer; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; @@ -30,11 +32,11 @@ public DaprPreviewClient daprPreviewClient( @Value("${dapr.http.endpoint}") String daprHttpEndpoint, @Value("${dapr.grpc.endpoint}") String daprGrpcEndpoint ){ - Map overrides = Map.of( - "dapr.http.endpoint", daprHttpEndpoint, - "dapr.grpc.endpoint", daprGrpcEndpoint + Map, String> overrides = Map.of( + Properties.HTTP_ENDPOINT, daprHttpEndpoint, + Properties.GRPC_ENDPOINT, daprGrpcEndpoint ); - return new DaprClientBuilder().buildPreviewClient(); + return new DaprClientBuilder().withPropertyOverrides(overrides).buildPreviewClient(); } } diff --git a/sdk/src/main/java/io/dapr/client/DaprClientImpl.java b/sdk/src/main/java/io/dapr/client/DaprClientImpl.java index 9f5ed481fb..89ec0e98f7 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientImpl.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientImpl.java @@ -99,6 +99,8 @@ import java.io.IOException; import java.time.Duration; import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -1303,6 +1305,9 @@ public Mono scheduleJob(ScheduleJobRequest scheduleJobRequest) { try { validateScheduleJobRequest(scheduleJobRequest); + DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + .withZone(ZoneOffset.UTC); + DaprProtos.Job.Builder scheduleJobRequestBuilder = DaprProtos.Job.newBuilder(); scheduleJobRequestBuilder.setName(scheduleJobRequest.getName()); @@ -1316,7 +1321,7 @@ public Mono scheduleJob(ScheduleJobRequest scheduleJobRequest) { } if (scheduleJobRequest.getTtl() != null) { - scheduleJobRequestBuilder.setTtl(scheduleJobRequest.getTtl().toString()); + scheduleJobRequestBuilder.setTtl(scheduleJobRequest.getTtl().format(iso8601Formatter)); } if (scheduleJobRequest.getRepeats() != null) { @@ -1324,7 +1329,8 @@ public Mono scheduleJob(ScheduleJobRequest scheduleJobRequest) { } if (scheduleJobRequest.getDueTime() != null) { - scheduleJobRequestBuilder.setDueTime(scheduleJobRequest.getDueTime().toString()); + scheduleJobRequestBuilder.setDueTime(scheduleJobRequest.getDueTime() + .format(iso8601Formatter)); } Mono scheduleJobResponseMono = @@ -1348,6 +1354,9 @@ public Mono getJob(GetJobRequest getJobRequest) { try { validateGetJobRequest(getJobRequest); + DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + .withZone(ZoneOffset.UTC); + Mono getJobResponseMono = Mono.deferContextual(context -> this.createMono( it -> intercept(context, asyncStub) @@ -1362,7 +1371,7 @@ public Mono getJob(GetJobRequest getJobRequest) { if (job.hasSchedule() && job.hasDueTime()) { getJobResponse = new GetJobResponse(job.getName(), JobSchedule.fromString(job.getSchedule())); - getJobResponse.setDueTime(OffsetDateTime.parse(job.getDueTime())); + getJobResponse.setDueTime(OffsetDateTime.parse(job.getDueTime(), iso8601Formatter)); } else if (job.hasSchedule()) { getJobResponse = new GetJobResponse(job.getName(), JobSchedule.fromString(job.getSchedule())); } else { @@ -1370,7 +1379,7 @@ public Mono getJob(GetJobRequest getJobRequest) { } return getJobResponse - .setTtl(job.hasTtl() ? OffsetDateTime.parse(job.getTtl()) : null) + .setTtl(job.hasTtl() ? OffsetDateTime.parse(job.getTtl(), iso8601Formatter) : null) .setData(job.hasData() ? job.getData().getValue().toByteArray() : null) .setRepeat(job.hasRepeats() ? job.getRepeats() : null); }); diff --git a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java index 10cfa921b6..e39e5b3ade 100644 --- a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java @@ -43,6 +43,8 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -536,6 +538,9 @@ public void onError(RuntimeException exception) { @Test void scheduleJobShouldSucceedWhenAllFieldsArePresentInRequest() { + DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + .withZone(ZoneOffset.UTC); + ScheduleJobRequest expectedScheduleJobRequest = new ScheduleJobRequest("testJob", JobSchedule.fromString("*/5 * * * *")) .setData("testData".getBytes()) @@ -561,9 +566,9 @@ void scheduleJobShouldSucceedWhenAllFieldsArePresentInRequest() { assertEquals("testData", new String(actualScheduleJobReq.getJob().getData().getValue().toByteArray(), StandardCharsets.UTF_8)); assertEquals("*/5 * * * *", actualScheduleJobReq.getJob().getSchedule()); - assertEquals(expectedScheduleJobRequest.getTtl().toString(), actualScheduleJobReq.getJob().getTtl()); + assertEquals(expectedScheduleJobRequest.getTtl().format(iso8601Formatter), actualScheduleJobReq.getJob().getTtl()); assertEquals(expectedScheduleJobRequest.getRepeats(), actualScheduleJobReq.getJob().getRepeats()); - assertEquals(expectedScheduleJobRequest.getDueTime().toString(), actualScheduleJobReq.getJob().getDueTime()); + assertEquals(expectedScheduleJobRequest.getDueTime().format(iso8601Formatter), actualScheduleJobReq.getJob().getDueTime()); } @Test @@ -649,15 +654,18 @@ void scheduleJobShouldThrowWhenNameInRequestIsEmpty() { @Test void getJobShouldReturnResponseWhenAllFieldsArePresentInRequest() { + DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + .withZone(ZoneOffset.UTC); + GetJobRequest getJobRequest = new GetJobRequest("testJob"); DaprProtos.Job job = DaprProtos.Job.newBuilder() .setName("testJob") - .setTtl(OffsetDateTime.now().toString()) + .setTtl(OffsetDateTime.now().format(iso8601Formatter)) .setData(Any.newBuilder().setValue(ByteString.copyFrom("testData".getBytes())).build()) .setSchedule("*/5 * * * *") .setRepeats(5) - .setDueTime(OffsetDateTime.now().plusMinutes(10).toString()) + .setDueTime(OffsetDateTime.now().plusMinutes(10).format(iso8601Formatter)) .build(); doAnswer(invocation -> { From 1f767ef0bc9d978b6476124609ec6afb5eda2577 Mon Sep 17 00:00:00 2001 From: siri-varma Date: Sun, 6 Apr 2025 21:32:50 +0530 Subject: [PATCH 11/30] Fix comments and fix tests Signed-off-by: siri-varma --- .../DaprContainerConstants.java | 8 +++++ .../io/dapr/it/testcontainers/DaprJobsIT.java | 35 ++++++++++++------- .../DaprPlacementContainerIT.java | 3 +- .../java/io/dapr/client/DaprClientImpl.java | 21 +++++------ .../io/dapr/client/domain/GetJobResponse.java | 16 ++++----- .../client/domain/ScheduleJobRequest.java | 16 ++++----- .../client/DaprPreviewClientGrpcTest.java | 30 +++++++++------- 7 files changed, 76 insertions(+), 53 deletions(-) create mode 100644 sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerConstants.java diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerConstants.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerConstants.java new file mode 100644 index 0000000000..8123937713 --- /dev/null +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerConstants.java @@ -0,0 +1,8 @@ +package io.dapr.it.testcontainers; + +public interface DaprContainerConstants { + String DAPR_RUNTIME_VERSION = "1.15.3"; + String IMAGE_TAG = "daprio/daprd:" + DAPR_RUNTIME_VERSION; + String DAPR_PLACEMENT_IMAGE_TAG = "daprio/placement:" + DAPR_RUNTIME_VERSION; + String DAPR_SCHEDULER_IMAGE_TAG = "daprio/scheduler:" + DAPR_RUNTIME_VERSION; +} diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java index dde8df7bdb..1024916c32 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java @@ -8,7 +8,6 @@ import io.dapr.client.domain.ScheduleJobRequest; import io.dapr.testcontainers.DaprContainer; import io.dapr.testcontainers.DaprLogLevel; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; @@ -20,9 +19,12 @@ import org.testcontainers.containers.Network; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.shaded.org.yaml.snakeyaml.scanner.Constant; +import java.time.Instant; import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; import java.util.Random; import static org.junit.Assert.assertEquals; @@ -74,58 +76,67 @@ public void setUp(){ @Test public void testJobScheduleCreationWithDueTime() { - OffsetDateTime currentTime = OffsetDateTime.now(); + DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + .withZone(ZoneOffset.UTC); + + Instant currentTime = Instant.now(); daprPreviewClient.scheduleJob(new ScheduleJobRequest("Job", currentTime)).block(); GetJobResponse getJobResponse = daprPreviewClient.getJob(new GetJobRequest("Job")).block(); - assertEquals(currentTime.toString(), getJobResponse.getDueTime().toString()); + assertEquals(iso8601Formatter.format(currentTime), getJobResponse.getDueTime().toString()); assertEquals("Job", getJobResponse.getName()); } @Test public void testJobScheduleCreationWithSchedule() { - OffsetDateTime currentTime = OffsetDateTime.now(); + DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + .withZone(ZoneOffset.UTC); + + Instant currentTime = Instant.now(); daprPreviewClient.scheduleJob(new ScheduleJobRequest("Job", JobSchedule.hourly()) .setDueTime(currentTime)).block(); GetJobResponse getJobResponse = daprPreviewClient.getJob(new GetJobRequest("Job")).block(); - assertEquals(currentTime.toString(), getJobResponse.getDueTime().toString()); + assertEquals(iso8601Formatter.format(currentTime), getJobResponse.getDueTime().toString()); assertEquals(JobSchedule.hourly().getExpression(), getJobResponse.getSchedule().getExpression()); assertEquals("Job", getJobResponse.getName()); } @Test public void testJobScheduleCreationWithAllParameters() { - OffsetDateTime currentTime = OffsetDateTime.now(); + Instant currentTime = Instant.now(); + DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + .withZone(ZoneOffset.UTC); String cronExpression = "2 * 3 * * FRI"; daprPreviewClient.scheduleJob(new ScheduleJobRequest("Job", currentTime) - .setTtl(currentTime.plusHours(2)) + .setTtl(currentTime.plus(2, ChronoUnit.HOURS)) .setData("Job data".getBytes()) .setRepeat(3) .setSchedule(JobSchedule.fromString(cronExpression))).block(); GetJobResponse getJobResponse = daprPreviewClient.getJob(new GetJobRequest("Job")).block(); - assertEquals(currentTime.toString(), getJobResponse.getDueTime().toString()); + assertEquals(iso8601Formatter.format(currentTime), getJobResponse.getDueTime().toString()); assertEquals("2 * 3 * * FRI", getJobResponse.getSchedule().getExpression()); assertEquals("Job", getJobResponse.getName()); assertEquals(Integer.valueOf(3), getJobResponse.getRepeats()); assertEquals("Job data", new String(getJobResponse.getData())); - assertEquals(currentTime.plusHours(2), getJobResponse.getTtl()); + assertEquals(iso8601Formatter.format(currentTime.plus(2, ChronoUnit.HOURS)), + getJobResponse.getTtl().toString()); } @Test public void testDeleteJobRequest() { - OffsetDateTime currentTime = OffsetDateTime.now(); + Instant currentTime = Instant.now(); String cronExpression = "2 * 3 * * FRI"; daprPreviewClient.scheduleJob(new ScheduleJobRequest("Job", currentTime) - .setTtl(currentTime.plusHours(2)) + .setTtl(currentTime.plus(2, ChronoUnit.HOURS)) .setData("Job data".getBytes()) .setRepeat(3) .setSchedule(JobSchedule.fromString(cronExpression))).block(); diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprPlacementContainerIT.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprPlacementContainerIT.java index 41f537eb0b..592a7afb0f 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprPlacementContainerIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprPlacementContainerIT.java @@ -26,7 +26,8 @@ public class DaprPlacementContainerIT { @Container - private static final DaprPlacementContainer PLACEMENT_CONTAINER = new DaprPlacementContainer("daprio/placement"); + private static final DaprPlacementContainer PLACEMENT_CONTAINER = + new DaprPlacementContainer(DaprContainerConstants.DAPR_PLACEMENT_IMAGE_TAG); @Test public void testDaprPlacementContainerDefaults() { diff --git a/sdk/src/main/java/io/dapr/client/DaprClientImpl.java b/sdk/src/main/java/io/dapr/client/DaprClientImpl.java index 89ec0e98f7..a21e2c3786 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientImpl.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientImpl.java @@ -98,6 +98,7 @@ import javax.annotation.Nonnull; import java.io.IOException; import java.time.Duration; +import java.time.Instant; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; @@ -1305,12 +1306,12 @@ public Mono scheduleJob(ScheduleJobRequest scheduleJobRequest) { try { validateScheduleJobRequest(scheduleJobRequest); - DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") - .withZone(ZoneOffset.UTC); - DaprProtos.Job.Builder scheduleJobRequestBuilder = DaprProtos.Job.newBuilder(); scheduleJobRequestBuilder.setName(scheduleJobRequest.getName()); + DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + .withZone(ZoneOffset.UTC); + if (scheduleJobRequest.getData() != null) { scheduleJobRequestBuilder.setData(Any.newBuilder() .setValue(ByteString.copyFrom(scheduleJobRequest.getData())).build()); @@ -1321,7 +1322,7 @@ public Mono scheduleJob(ScheduleJobRequest scheduleJobRequest) { } if (scheduleJobRequest.getTtl() != null) { - scheduleJobRequestBuilder.setTtl(scheduleJobRequest.getTtl().format(iso8601Formatter)); + scheduleJobRequestBuilder.setTtl(iso8601Formatter.format(scheduleJobRequest.getTtl())); } if (scheduleJobRequest.getRepeats() != null) { @@ -1329,8 +1330,7 @@ public Mono scheduleJob(ScheduleJobRequest scheduleJobRequest) { } if (scheduleJobRequest.getDueTime() != null) { - scheduleJobRequestBuilder.setDueTime(scheduleJobRequest.getDueTime() - .format(iso8601Formatter)); + scheduleJobRequestBuilder.setDueTime(iso8601Formatter.format(scheduleJobRequest.getDueTime())); } Mono scheduleJobResponseMono = @@ -1354,9 +1354,6 @@ public Mono getJob(GetJobRequest getJobRequest) { try { validateGetJobRequest(getJobRequest); - DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") - .withZone(ZoneOffset.UTC); - Mono getJobResponseMono = Mono.deferContextual(context -> this.createMono( it -> intercept(context, asyncStub) @@ -1371,15 +1368,15 @@ public Mono getJob(GetJobRequest getJobRequest) { if (job.hasSchedule() && job.hasDueTime()) { getJobResponse = new GetJobResponse(job.getName(), JobSchedule.fromString(job.getSchedule())); - getJobResponse.setDueTime(OffsetDateTime.parse(job.getDueTime(), iso8601Formatter)); + getJobResponse.setDueTime(Instant.parse(job.getDueTime())); } else if (job.hasSchedule()) { getJobResponse = new GetJobResponse(job.getName(), JobSchedule.fromString(job.getSchedule())); } else { - getJobResponse = new GetJobResponse(job.getName(), OffsetDateTime.parse(job.getDueTime())); + getJobResponse = new GetJobResponse(job.getName(), Instant.parse(job.getDueTime())); } return getJobResponse - .setTtl(job.hasTtl() ? OffsetDateTime.parse(job.getTtl(), iso8601Formatter) : null) + .setTtl(job.hasTtl() ? Instant.parse(job.getTtl()) : null) .setData(job.hasData() ? job.getData().getValue().toByteArray() : null) .setRepeat(job.hasRepeats() ? job.getRepeats() : null); }); diff --git a/sdk/src/main/java/io/dapr/client/domain/GetJobResponse.java b/sdk/src/main/java/io/dapr/client/domain/GetJobResponse.java index 1e7002a34b..91d5008a64 100644 --- a/sdk/src/main/java/io/dapr/client/domain/GetJobResponse.java +++ b/sdk/src/main/java/io/dapr/client/domain/GetJobResponse.java @@ -1,6 +1,6 @@ package io.dapr.client.domain; -import java.time.OffsetDateTime; +import java.time.Instant; /** * Represents a request to schedule a job in Dapr. @@ -9,9 +9,9 @@ public class GetJobResponse { private final String name; private byte[] data; private JobSchedule schedule; - private OffsetDateTime dueTime; + private Instant dueTime; private Integer repeats; - private OffsetDateTime ttl; + private Instant ttl; /** * Constructor to create GetJobResponse. @@ -32,7 +32,7 @@ public GetJobResponse(String name, JobSchedule schedule) { * type fields are not provided. Accepts a “point in time” string in the format of RFC3339, * Go duration string (calculated from creation time), or non-repeating ISO8601 */ - public GetJobResponse(String name, OffsetDateTime dueTime) { + public GetJobResponse(String name, Instant dueTime) { this.name = name; this.dueTime = dueTime; } @@ -68,7 +68,7 @@ public GetJobResponse setSchedule(JobSchedule schedule) { * @param dueTime The due time of the job. * @return This builder instance. */ - public GetJobResponse setDueTime(OffsetDateTime dueTime) { + public GetJobResponse setDueTime(Instant dueTime) { this.dueTime = dueTime; return this; } @@ -92,7 +92,7 @@ public GetJobResponse setRepeat(Integer repeats) { * @param ttl The time-to-live for the job. * @return This builder instance. */ - public GetJobResponse setTtl(OffsetDateTime ttl) { + public GetJobResponse setTtl(Instant ttl) { this.ttl = ttl; return this; } @@ -131,7 +131,7 @@ public JobSchedule getSchedule() { * * @return The due time. */ - public OffsetDateTime getDueTime() { + public Instant getDueTime() { return dueTime; } @@ -149,7 +149,7 @@ public Integer getRepeats() { * * @return The TTL value. */ - public OffsetDateTime getTtl() { + public Instant getTtl() { return ttl; } } diff --git a/sdk/src/main/java/io/dapr/client/domain/ScheduleJobRequest.java b/sdk/src/main/java/io/dapr/client/domain/ScheduleJobRequest.java index b76a077f6b..89c477d9ee 100644 --- a/sdk/src/main/java/io/dapr/client/domain/ScheduleJobRequest.java +++ b/sdk/src/main/java/io/dapr/client/domain/ScheduleJobRequest.java @@ -1,6 +1,6 @@ package io.dapr.client.domain; -import java.time.OffsetDateTime; +import java.time.Instant; /** * Represents a request to schedule a job in Dapr. @@ -9,9 +9,9 @@ public class ScheduleJobRequest { private final String name; private byte[] data; private JobSchedule schedule; - private OffsetDateTime dueTime; + private Instant dueTime; private Integer repeats; - private OffsetDateTime ttl; + private Instant ttl; /** * Constructor to create ScheduleJobRequest. @@ -32,7 +32,7 @@ public ScheduleJobRequest(String name, JobSchedule schedule) { * type fields are not provided. Accepts a “point in time” string in the format of RFC3339, * Go duration string (calculated from creation time), or non-repeating ISO8601 */ - public ScheduleJobRequest(String name, OffsetDateTime dueTime) { + public ScheduleJobRequest(String name, Instant dueTime) { this.name = name; this.dueTime = dueTime; } @@ -68,7 +68,7 @@ public ScheduleJobRequest setSchedule(JobSchedule schedule) { * @param dueTime The due time of the job. * @return This builder instance. */ - public ScheduleJobRequest setDueTime(OffsetDateTime dueTime) { + public ScheduleJobRequest setDueTime(Instant dueTime) { this.dueTime = dueTime; return this; } @@ -92,7 +92,7 @@ public ScheduleJobRequest setRepeat(Integer repeats) { * @param ttl The time-to-live for the job. * @return This builder instance. */ - public ScheduleJobRequest setTtl(OffsetDateTime ttl) { + public ScheduleJobRequest setTtl(Instant ttl) { this.ttl = ttl; return this; } @@ -131,7 +131,7 @@ public JobSchedule getSchedule() { * * @return The due time. */ - public OffsetDateTime getDueTime() { + public Instant getDueTime() { return dueTime; } @@ -149,7 +149,7 @@ public Integer getRepeats() { * * @return The TTL value. */ - public OffsetDateTime getTtl() { + public Instant getTtl() { return ttl; } } diff --git a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java index e39e5b3ade..7303dde581 100644 --- a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java @@ -42,9 +42,11 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.time.Instant; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -544,9 +546,9 @@ void scheduleJobShouldSucceedWhenAllFieldsArePresentInRequest() { ScheduleJobRequest expectedScheduleJobRequest = new ScheduleJobRequest("testJob", JobSchedule.fromString("*/5 * * * *")) .setData("testData".getBytes()) - .setTtl(OffsetDateTime.now().plusDays(1)) + .setTtl(Instant.now().plus(1, ChronoUnit.DAYS)) .setRepeat(5) - .setDueTime(OffsetDateTime.now().plusMinutes(10)); + .setDueTime(Instant.now().plus(10, ChronoUnit.MINUTES)); doAnswer(invocation -> { StreamObserver observer = invocation.getArgument(1); @@ -566,13 +568,15 @@ void scheduleJobShouldSucceedWhenAllFieldsArePresentInRequest() { assertEquals("testData", new String(actualScheduleJobReq.getJob().getData().getValue().toByteArray(), StandardCharsets.UTF_8)); assertEquals("*/5 * * * *", actualScheduleJobReq.getJob().getSchedule()); - assertEquals(expectedScheduleJobRequest.getTtl().format(iso8601Formatter), actualScheduleJobReq.getJob().getTtl()); + assertEquals(iso8601Formatter.format(expectedScheduleJobRequest.getTtl()), actualScheduleJobReq.getJob().getTtl()); assertEquals(expectedScheduleJobRequest.getRepeats(), actualScheduleJobReq.getJob().getRepeats()); - assertEquals(expectedScheduleJobRequest.getDueTime().format(iso8601Formatter), actualScheduleJobReq.getJob().getDueTime()); + assertEquals(iso8601Formatter.format(expectedScheduleJobRequest.getDueTime()), actualScheduleJobReq.getJob().getDueTime()); } @Test void scheduleJobShouldSucceedWhenRequiredFieldsNameAndDueTimeArePresentInRequest() { + DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + .withZone(ZoneOffset.UTC); doAnswer(invocation -> { StreamObserver observer = invocation.getArgument(1); @@ -581,7 +585,7 @@ void scheduleJobShouldSucceedWhenRequiredFieldsNameAndDueTimeArePresentInRequest }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any()); ScheduleJobRequest expectedScheduleJobRequest = - new ScheduleJobRequest("testJob", OffsetDateTime.now().plusMinutes(10)); + new ScheduleJobRequest("testJob", Instant.now().plus(10, ChronoUnit.MINUTES)); assertDoesNotThrow(() -> previewClient.scheduleJob(expectedScheduleJobRequest).block()); ArgumentCaptor captor = @@ -595,11 +599,14 @@ void scheduleJobShouldSucceedWhenRequiredFieldsNameAndDueTimeArePresentInRequest assertFalse(job.hasSchedule()); assertEquals(0, job.getRepeats()); assertFalse(job.hasTtl()); - assertEquals(job.getDueTime(), actualScheduleJobRequest.getJob().getDueTime()); + assertEquals(iso8601Formatter.format(expectedScheduleJobRequest.getDueTime()), + actualScheduleJobRequest.getJob().getDueTime()); } @Test void scheduleJobShouldSucceedWhenRequiredFieldsNameAndScheduleArePresentInRequest() { + DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + .withZone(ZoneOffset.UTC); doAnswer(invocation -> { StreamObserver observer = invocation.getArgument(1); @@ -622,7 +629,6 @@ void scheduleJobShouldSucceedWhenRequiredFieldsNameAndScheduleArePresentInReques assertEquals( "* * * * * *", job.getSchedule()); assertEquals(0, job.getRepeats()); assertFalse(job.hasTtl()); - assertEquals(job.getDueTime(), actualScheduleJobRequest.getJob().getDueTime()); } @Test @@ -635,7 +641,7 @@ void scheduleJobShouldThrowWhenRequestIsNull() { @Test void scheduleJobShouldThrowWhenInvalidRequest() { - ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest(null, OffsetDateTime.now()); + ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest(null, Instant.now()); IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { previewClient.scheduleJob(scheduleJobRequest).block(); }); @@ -644,7 +650,7 @@ void scheduleJobShouldThrowWhenInvalidRequest() { @Test void scheduleJobShouldThrowWhenNameInRequestIsEmpty() { - ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest("", OffsetDateTime.now()); + ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest("", Instant.now()); IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { previewClient.scheduleJob(scheduleJobRequest).block(); @@ -665,7 +671,7 @@ void getJobShouldReturnResponseWhenAllFieldsArePresentInRequest() { .setData(Any.newBuilder().setValue(ByteString.copyFrom("testData".getBytes())).build()) .setSchedule("*/5 * * * *") .setRepeats(5) - .setDueTime(OffsetDateTime.now().plusMinutes(10).format(iso8601Formatter)) + .setDueTime(iso8601Formatter.format(Instant.now().plus(10, ChronoUnit.MINUTES))) .build(); doAnswer(invocation -> { @@ -685,8 +691,8 @@ void getJobShouldReturnResponseWhenAllFieldsArePresentInRequest() { assertEquals("testData", new String(response.getData(), StandardCharsets.UTF_8)); assertEquals("*/5 * * * *", response.getSchedule().getExpression()); assertEquals(5, response.getRepeats()); - assertEquals(job.getTtl(), response.getTtl().toString()); - assertEquals(job.getDueTime(), response.getDueTime().toString()); + assertEquals(job.getTtl(), iso8601Formatter.format(response.getTtl())); + assertEquals(job.getDueTime(), iso8601Formatter.format(response.getDueTime())); } @Test From 186ed35088fa0a2904abc2852025226aeec75e32 Mon Sep 17 00:00:00 2001 From: siri-varma Date: Tue, 8 Apr 2025 22:56:27 +0530 Subject: [PATCH 12/30] remove * Signed-off-by: siri-varma --- .../io/dapr/client/DaprClientHttpTest.java | 12 ++++++-- .../client/DaprPreviewClientGrpcTest.java | 29 ++++++++++++++++--- .../dapr/client/domain/JobsScheduleTest.java | 3 +- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java index 276a700e38..ca3c1c5341 100644 --- a/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprClientHttpTest.java @@ -13,7 +13,8 @@ package io.dapr.client; import com.fasterxml.jackson.core.JsonParseException; -import io.dapr.client.domain.*; +import io.dapr.client.domain.HttpExtension; +import io.dapr.client.domain.InvokeMethodRequest; import io.dapr.config.Properties; import io.dapr.exceptions.DaprException; import io.dapr.serializer.DefaultObjectSerializer; @@ -44,9 +45,14 @@ import static io.dapr.utils.TestUtils.assertThrowsDaprException; import static io.dapr.utils.TestUtils.findFreePort; import static io.dapr.utils.TestUtils.formatIpAddress; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; public class DaprClientHttpTest { diff --git a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java index 7303dde581..f8767f5111 100644 --- a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java @@ -18,7 +18,19 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.protobuf.Any; import com.google.protobuf.ByteString; -import io.dapr.client.domain.*; +import io.dapr.client.domain.BulkPublishEntry; +import io.dapr.client.domain.BulkPublishRequest; +import io.dapr.client.domain.BulkPublishResponse; +import io.dapr.client.domain.CloudEvent; +import io.dapr.client.domain.DeleteJobRequest; +import io.dapr.client.domain.GetJobRequest; +import io.dapr.client.domain.GetJobResponse; +import io.dapr.client.domain.JobSchedule; +import io.dapr.client.domain.QueryStateItem; +import io.dapr.client.domain.QueryStateRequest; +import io.dapr.client.domain.QueryStateResponse; +import io.dapr.client.domain.ScheduleJobRequest; +import io.dapr.client.domain.UnlockResponseStatus; import io.dapr.client.domain.query.Query; import io.dapr.serializer.DaprObjectSerializer; import io.dapr.serializer.DefaultObjectSerializer; @@ -26,7 +38,6 @@ import io.dapr.v1.DaprAppCallbackProtos; import io.dapr.v1.DaprGrpc; import io.dapr.v1.DaprProtos; -import io.grpc.ManagedChannel; import io.grpc.Status; import io.grpc.StatusRuntimeException; import io.grpc.stub.StreamObserver; @@ -60,10 +71,20 @@ import java.util.concurrent.atomic.AtomicInteger; import static io.dapr.utils.TestUtils.assertThrowsDaprException; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; public class DaprPreviewClientGrpcTest { diff --git a/sdk/src/test/java/io/dapr/client/domain/JobsScheduleTest.java b/sdk/src/test/java/io/dapr/client/domain/JobsScheduleTest.java index e0e16f49d4..d07b26d442 100644 --- a/sdk/src/test/java/io/dapr/client/domain/JobsScheduleTest.java +++ b/sdk/src/test/java/io/dapr/client/domain/JobsScheduleTest.java @@ -4,7 +4,8 @@ import java.time.Duration; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; class JobsScheduleTest { From 519177025938abc62db546fa7b1ce8e38923c5e7 Mon Sep 17 00:00:00 2001 From: siri-varma Date: Tue, 8 Apr 2025 23:13:05 +0530 Subject: [PATCH 13/30] fix conflicts Signed-off-by: siri-varma --- .../io/dapr/it/testcontainers/ContainerConstants.java | 5 ++++- .../io/dapr/it/testcontainers/DaprContainerConstants.java | 8 -------- .../test/java/io/dapr/it/testcontainers/DaprJobsIT.java | 2 +- .../dapr/it/testcontainers/DaprPlacementContainerIT.java | 2 +- 4 files changed, 6 insertions(+), 11 deletions(-) delete mode 100644 sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerConstants.java diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/ContainerConstants.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/ContainerConstants.java index 3c2c42e9a1..76cadb815d 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/ContainerConstants.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/ContainerConstants.java @@ -1,6 +1,9 @@ package io.dapr.it.testcontainers; public interface ContainerConstants { - String DAPR_IMAGE_TAG = "daprio/daprd:1.14.1"; String TOXIPROXY_IMAGE_TAG = "ghcr.io/shopify/toxiproxy:2.5.0"; + String DAPR_RUNTIME_VERSION = "1.15.3"; + String DAPR_IMAGE_TAG = "daprio/daprd:" + DAPR_RUNTIME_VERSION; + String DAPR_PLACEMENT_IMAGE_TAG = "daprio/placement:" + DAPR_RUNTIME_VERSION; + String DAPR_SCHEDULER_IMAGE_TAG = "daprio/scheduler:" + DAPR_RUNTIME_VERSION; } diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerConstants.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerConstants.java deleted file mode 100644 index 8123937713..0000000000 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprContainerConstants.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.dapr.it.testcontainers; - -public interface DaprContainerConstants { - String DAPR_RUNTIME_VERSION = "1.15.3"; - String IMAGE_TAG = "daprio/daprd:" + DAPR_RUNTIME_VERSION; - String DAPR_PLACEMENT_IMAGE_TAG = "daprio/placement:" + DAPR_RUNTIME_VERSION; - String DAPR_SCHEDULER_IMAGE_TAG = "daprio/scheduler:" + DAPR_RUNTIME_VERSION; -} diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java index 1024916c32..602b26f101 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java @@ -45,7 +45,7 @@ public class DaprJobsIT { private static final int PORT = RANDOM.nextInt(1000) + 8000; @Container - private static final DaprContainer DAPR_CONTAINER = new DaprContainer(DaprContainerConstants.IMAGE_TAG) + private static final DaprContainer DAPR_CONTAINER = new DaprContainer(ContainerConstants.DAPR_IMAGE_TAG) .withAppName("jobs-dapr-app") .withNetwork(DAPR_NETWORK) .withDaprLogLevel(DaprLogLevel.DEBUG) diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprPlacementContainerIT.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprPlacementContainerIT.java index 592a7afb0f..d7069a3f14 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprPlacementContainerIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprPlacementContainerIT.java @@ -27,7 +27,7 @@ public class DaprPlacementContainerIT { @Container private static final DaprPlacementContainer PLACEMENT_CONTAINER = - new DaprPlacementContainer(DaprContainerConstants.DAPR_PLACEMENT_IMAGE_TAG); + new DaprPlacementContainer(ContainerConstants.DAPR_PLACEMENT_IMAGE_TAG); @Test public void testDaprPlacementContainerDefaults() { From d193586e2e07e03d8e872a99a435c686890d46df Mon Sep 17 00:00:00 2001 From: siri-varma Date: Wed, 9 Apr 2025 11:24:12 +0530 Subject: [PATCH 14/30] remove space Signed-off-by: siri-varma --- sdk/src/main/java/io/dapr/client/DaprClientImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/src/main/java/io/dapr/client/DaprClientImpl.java b/sdk/src/main/java/io/dapr/client/DaprClientImpl.java index a21e2c3786..aad67bc23d 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientImpl.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientImpl.java @@ -1644,5 +1644,4 @@ private AppConnectionPropertiesHealthMetadata getAppConnectionPropertiesHealth( return new AppConnectionPropertiesHealthMetadata(healthCheckPath, healthProbeInterval, healthProbeTimeout, healthThreshold); } - } From ac19747883eba57bd559db32a3e7fc0466d2305c Mon Sep 17 00:00:00 2001 From: Siri Varma Vegiraju Date: Thu, 10 Apr 2025 04:05:57 -0700 Subject: [PATCH 15/30] Update sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java Co-authored-by: Cassie Coyle Signed-off-by: Siri Varma Vegiraju --- .../src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java index 602b26f101..f75d50d0be 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java @@ -71,7 +71,6 @@ static void daprProperties(DynamicPropertyRegistry registry) { @BeforeEach public void setUp(){ org.testcontainers.Testcontainers.exposeHostPorts(PORT); - // Ensure the subscriptions are registered } @Test From 9e022c57cb903391044e925cc1f7b7338b585b14 Mon Sep 17 00:00:00 2001 From: Siri Varma Vegiraju Date: Thu, 10 Apr 2025 04:06:31 -0700 Subject: [PATCH 16/30] Update testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java Co-authored-by: Cassie Coyle Signed-off-by: Siri Varma Vegiraju --- .../src/main/java/io/dapr/testcontainers/DaprContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java index c3fb7a2ac9..8959d91439 100644 --- a/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java +++ b/testcontainers-dapr/src/main/java/io/dapr/testcontainers/DaprContainer.java @@ -167,7 +167,7 @@ public DaprContainer withReusablePlacement(boolean shouldReusePlacement) { return this; } - public DaprContainer withResueScheduler(boolean shouldReuseScheduler) { + public DaprContainer withReuseScheduler(boolean shouldReuseScheduler) { this.shouldReuseScheduler = shouldReuseScheduler; return this; } From 4678e827fd38b5e88f0c0034751f394fb878b9ed Mon Sep 17 00:00:00 2001 From: siri-varma Date: Thu, 10 Apr 2025 17:53:01 +0530 Subject: [PATCH 17/30] Add comment Signed-off-by: siri-varma --- .../io/dapr/it/testcontainers/DaprJobsIT.java | 13 ++++++++ .../dapr/client/domain/DeleteJobRequest.java | 13 ++++++++ .../io/dapr/client/domain/GetJobRequest.java | 13 ++++++++ .../io/dapr/client/domain/GetJobResponse.java | 13 ++++++++ .../io/dapr/client/domain/JobSchedule.java | 13 ++++++++ .../client/domain/ScheduleJobRequest.java | 13 ++++++++ .../client/DaprPreviewClientGrpcTest.java | 33 +++++++++---------- .../dapr/client/domain/JobsScheduleTest.java | 13 ++++++++ 8 files changed, 107 insertions(+), 17 deletions(-) diff --git a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java index 602b26f101..af012dcaee 100644 --- a/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/testcontainers/DaprJobsIT.java @@ -1,3 +1,16 @@ +/* + * Copyright 2025 The Dapr Authors + * 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 io.dapr.it.testcontainers; import io.dapr.client.DaprPreviewClient; diff --git a/sdk/src/main/java/io/dapr/client/domain/DeleteJobRequest.java b/sdk/src/main/java/io/dapr/client/domain/DeleteJobRequest.java index 8d47487139..31f60a1197 100644 --- a/sdk/src/main/java/io/dapr/client/domain/DeleteJobRequest.java +++ b/sdk/src/main/java/io/dapr/client/domain/DeleteJobRequest.java @@ -1,3 +1,16 @@ +/* + * Copyright 2025 The Dapr Authors + * 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 io.dapr.client.domain; /** diff --git a/sdk/src/main/java/io/dapr/client/domain/GetJobRequest.java b/sdk/src/main/java/io/dapr/client/domain/GetJobRequest.java index 5332e137e5..cbfe6eed6f 100644 --- a/sdk/src/main/java/io/dapr/client/domain/GetJobRequest.java +++ b/sdk/src/main/java/io/dapr/client/domain/GetJobRequest.java @@ -1,3 +1,16 @@ +/* + * Copyright 2025 The Dapr Authors + * 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 io.dapr.client.domain; /** diff --git a/sdk/src/main/java/io/dapr/client/domain/GetJobResponse.java b/sdk/src/main/java/io/dapr/client/domain/GetJobResponse.java index 91d5008a64..f79c0409ab 100644 --- a/sdk/src/main/java/io/dapr/client/domain/GetJobResponse.java +++ b/sdk/src/main/java/io/dapr/client/domain/GetJobResponse.java @@ -1,3 +1,16 @@ +/* + * Copyright 2025 The Dapr Authors + * 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 io.dapr.client.domain; import java.time.Instant; diff --git a/sdk/src/main/java/io/dapr/client/domain/JobSchedule.java b/sdk/src/main/java/io/dapr/client/domain/JobSchedule.java index 4cc2c85b01..5c79d241d8 100644 --- a/sdk/src/main/java/io/dapr/client/domain/JobSchedule.java +++ b/sdk/src/main/java/io/dapr/client/domain/JobSchedule.java @@ -1,3 +1,16 @@ +/* + * Copyright 2025 The Dapr Authors + * 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 io.dapr.client.domain; import java.time.Duration; diff --git a/sdk/src/main/java/io/dapr/client/domain/ScheduleJobRequest.java b/sdk/src/main/java/io/dapr/client/domain/ScheduleJobRequest.java index 89c477d9ee..9f91e6142f 100644 --- a/sdk/src/main/java/io/dapr/client/domain/ScheduleJobRequest.java +++ b/sdk/src/main/java/io/dapr/client/domain/ScheduleJobRequest.java @@ -1,3 +1,16 @@ +/* + * Copyright 2025 The Dapr Authors + * 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 io.dapr.client.domain; import java.time.Instant; diff --git a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java index f8767f5111..b782c6706f 100644 --- a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java @@ -558,9 +558,8 @@ public void onError(RuntimeException exception) { assertEquals(numErrors, errors.size()); } - @Test - void scheduleJobShouldSucceedWhenAllFieldsArePresentInRequest() { + public void scheduleJobShouldSucceedWhenAllFieldsArePresentInRequest() { DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") .withZone(ZoneOffset.UTC); @@ -595,7 +594,7 @@ void scheduleJobShouldSucceedWhenAllFieldsArePresentInRequest() { } @Test - void scheduleJobShouldSucceedWhenRequiredFieldsNameAndDueTimeArePresentInRequest() { + public void scheduleJobShouldSucceedWhenRequiredFieldsNameAndDueTimeArePresentInRequest() { DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") .withZone(ZoneOffset.UTC); @@ -625,7 +624,7 @@ void scheduleJobShouldSucceedWhenRequiredFieldsNameAndDueTimeArePresentInRequest } @Test - void scheduleJobShouldSucceedWhenRequiredFieldsNameAndScheduleArePresentInRequest() { + public void scheduleJobShouldSucceedWhenRequiredFieldsNameAndScheduleArePresentInRequest() { DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") .withZone(ZoneOffset.UTC); @@ -653,7 +652,7 @@ void scheduleJobShouldSucceedWhenRequiredFieldsNameAndScheduleArePresentInReques } @Test - void scheduleJobShouldThrowWhenRequestIsNull() { + public void scheduleJobShouldThrowWhenRequestIsNull() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { previewClient.scheduleJob(null).block(); }); @@ -661,7 +660,7 @@ void scheduleJobShouldThrowWhenRequestIsNull() { } @Test - void scheduleJobShouldThrowWhenInvalidRequest() { + public void scheduleJobShouldThrowWhenInvalidRequest() { ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest(null, Instant.now()); IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { previewClient.scheduleJob(scheduleJobRequest).block(); @@ -670,7 +669,7 @@ void scheduleJobShouldThrowWhenInvalidRequest() { } @Test - void scheduleJobShouldThrowWhenNameInRequestIsEmpty() { + public void scheduleJobShouldThrowWhenNameInRequestIsEmpty() { ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest("", Instant.now()); IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { @@ -680,7 +679,7 @@ void scheduleJobShouldThrowWhenNameInRequestIsEmpty() { } @Test - void getJobShouldReturnResponseWhenAllFieldsArePresentInRequest() { + public void getJobShouldReturnResponseWhenAllFieldsArePresentInRequest() { DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") .withZone(ZoneOffset.UTC); @@ -717,7 +716,7 @@ void getJobShouldReturnResponseWhenAllFieldsArePresentInRequest() { } @Test - void getJobShouldReturnResponseWithScheduleSetWhenResponseHasSchedule() { + public void getJobShouldReturnResponseWithScheduleSetWhenResponseHasSchedule() { GetJobRequest getJobRequest = new GetJobRequest("testJob"); DaprProtos.Job job = DaprProtos.Job.newBuilder() @@ -747,7 +746,7 @@ void getJobShouldReturnResponseWithScheduleSetWhenResponseHasSchedule() { } @Test - void getJobShouldReturnResponseWithDueTimeSetWhenResponseHasDueTime() { + public void getJobShouldReturnResponseWithDueTimeSetWhenResponseHasDueTime() { GetJobRequest getJobRequest = new GetJobRequest("testJob"); String datetime = OffsetDateTime.now().toString(); @@ -778,7 +777,7 @@ void getJobShouldReturnResponseWithDueTimeSetWhenResponseHasDueTime() { } @Test - void getJobShouldThrowWhenRequestIsNull() { + public void getJobShouldThrowWhenRequestIsNull() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { previewClient.getJob(null).block(); }); @@ -786,7 +785,7 @@ void getJobShouldThrowWhenRequestIsNull() { } @Test - void getJobShouldThrowWhenNameIsNullRequest() { + public void getJobShouldThrowWhenNameIsNullRequest() { GetJobRequest getJobRequest = new GetJobRequest(null); IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { @@ -796,7 +795,7 @@ void getJobShouldThrowWhenNameIsNullRequest() { } @Test - void getJobShouldThrowWhenNameIsEmptyRequest() { + public void getJobShouldThrowWhenNameIsEmptyRequest() { GetJobRequest getJobRequest =new GetJobRequest("");; IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { @@ -806,7 +805,7 @@ void getJobShouldThrowWhenNameIsEmptyRequest() { } @Test - void deleteJobShouldSucceedWhenValidRequest() { + public void deleteJobShouldSucceedWhenValidRequest() { DeleteJobRequest deleteJobRequest = new DeleteJobRequest("testJob"); doAnswer(invocation -> { @@ -821,7 +820,7 @@ void deleteJobShouldSucceedWhenValidRequest() { } @Test - void deleteJobShouldThrowRequestIsNull() { + public void deleteJobShouldThrowRequestIsNull() { IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { previewClient.deleteJob(null).block(); }); @@ -829,7 +828,7 @@ void deleteJobShouldThrowRequestIsNull() { } @Test - void deleteJobShouldThrowWhenNameIsNullRequest() { + public void deleteJobShouldThrowWhenNameIsNullRequest() { DeleteJobRequest deleteJobRequest = new DeleteJobRequest(null); IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { previewClient.deleteJob(deleteJobRequest).block(); @@ -838,7 +837,7 @@ void deleteJobShouldThrowWhenNameIsNullRequest() { } @Test - void deleteJobShouldThrowWhenNameIsEmptyRequest() { + public void deleteJobShouldThrowWhenNameIsEmptyRequest() { DeleteJobRequest deleteJobRequest = new DeleteJobRequest(""); IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { previewClient.deleteJob(deleteJobRequest).block(); diff --git a/sdk/src/test/java/io/dapr/client/domain/JobsScheduleTest.java b/sdk/src/test/java/io/dapr/client/domain/JobsScheduleTest.java index d07b26d442..8b71f28d51 100644 --- a/sdk/src/test/java/io/dapr/client/domain/JobsScheduleTest.java +++ b/sdk/src/test/java/io/dapr/client/domain/JobsScheduleTest.java @@ -1,3 +1,16 @@ +/* + * Copyright 2025 The Dapr Authors + * 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 io.dapr.client.domain; import org.junit.jupiter.api.Test; From 9d2daa1a78060b133d56a6e6ffcef7951d23c8a4 Mon Sep 17 00:00:00 2001 From: Siri Varma Vegiraju Date: Thu, 10 Apr 2025 08:21:31 -0700 Subject: [PATCH 18/30] Update DaprPreviewClientGrpcTest.java Signed-off-by: Siri Varma Vegiraju From afeb8c1bfa6f87280f8ffde0a8aa0fc46c6ffe11 Mon Sep 17 00:00:00 2001 From: Siri Varma Vegiraju Date: Thu, 10 Apr 2025 08:39:55 -0700 Subject: [PATCH 19/30] Update DaprPreviewClientGrpcTest.java Signed-off-by: Siri Varma Vegiraju From 4c52d12ff5112ba1feda6f43115af7ebdd688dcc Mon Sep 17 00:00:00 2001 From: siri-varma Date: Thu, 10 Apr 2025 21:12:44 +0530 Subject: [PATCH 20/30] Fix spaces Signed-off-by: siri-varma --- .../client/DaprPreviewClientGrpcTest.java | 194 +++++++++--------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java index b782c6706f..afd4321a63 100644 --- a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java @@ -1,92 +1,92 @@ -/* - * Copyright 2021 The Dapr Authors - * 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 io.dapr.client; - - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.protobuf.Any; -import com.google.protobuf.ByteString; -import io.dapr.client.domain.BulkPublishEntry; -import io.dapr.client.domain.BulkPublishRequest; -import io.dapr.client.domain.BulkPublishResponse; -import io.dapr.client.domain.CloudEvent; -import io.dapr.client.domain.DeleteJobRequest; -import io.dapr.client.domain.GetJobRequest; -import io.dapr.client.domain.GetJobResponse; -import io.dapr.client.domain.JobSchedule; -import io.dapr.client.domain.QueryStateItem; -import io.dapr.client.domain.QueryStateRequest; -import io.dapr.client.domain.QueryStateResponse; -import io.dapr.client.domain.ScheduleJobRequest; -import io.dapr.client.domain.UnlockResponseStatus; -import io.dapr.client.domain.query.Query; -import io.dapr.serializer.DaprObjectSerializer; -import io.dapr.serializer.DefaultObjectSerializer; -import io.dapr.utils.TypeRef; -import io.dapr.v1.DaprAppCallbackProtos; -import io.dapr.v1.DaprGrpc; -import io.dapr.v1.DaprProtos; -import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import io.grpc.stub.StreamObserver; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatchers; -import org.mockito.Mockito; -import org.mockito.stubbing.Answer; -import reactor.core.publisher.Mono; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.time.Instant; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; -import java.time.temporal.ChronoUnit; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Semaphore; -import java.util.concurrent.atomic.AtomicInteger; - -import static io.dapr.utils.TestUtils.assertThrowsDaprException; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -public class DaprPreviewClientGrpcTest { + /* + * Copyright 2021 The Dapr Authors + * 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 io.dapr.client; + + + import com.fasterxml.jackson.core.JsonProcessingException; + import com.fasterxml.jackson.databind.ObjectMapper; + import com.google.protobuf.Any; + import com.google.protobuf.ByteString; + import io.dapr.client.domain.BulkPublishEntry; + import io.dapr.client.domain.BulkPublishRequest; + import io.dapr.client.domain.BulkPublishResponse; + import io.dapr.client.domain.CloudEvent; + import io.dapr.client.domain.DeleteJobRequest; + import io.dapr.client.domain.GetJobRequest; + import io.dapr.client.domain.GetJobResponse; + import io.dapr.client.domain.JobSchedule; + import io.dapr.client.domain.QueryStateItem; + import io.dapr.client.domain.QueryStateRequest; + import io.dapr.client.domain.QueryStateResponse; + import io.dapr.client.domain.ScheduleJobRequest; + import io.dapr.client.domain.UnlockResponseStatus; + import io.dapr.client.domain.query.Query; + import io.dapr.serializer.DaprObjectSerializer; + import io.dapr.serializer.DefaultObjectSerializer; + import io.dapr.utils.TypeRef; + import io.dapr.v1.DaprAppCallbackProtos; + import io.dapr.v1.DaprGrpc; + import io.dapr.v1.DaprProtos; + import io.grpc.Status; + import io.grpc.StatusRuntimeException; + import io.grpc.stub.StreamObserver; + import org.junit.jupiter.api.AfterEach; + import org.junit.jupiter.api.Assertions; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; + import org.mockito.ArgumentCaptor; + import org.mockito.ArgumentMatchers; + import org.mockito.Mockito; + import org.mockito.stubbing.Answer; + import reactor.core.publisher.Mono; + + import java.io.IOException; + import java.nio.charset.StandardCharsets; + import java.time.Instant; + import java.time.OffsetDateTime; + import java.time.ZoneOffset; + import java.time.format.DateTimeFormatter; + import java.time.temporal.ChronoUnit; + import java.util.ArrayList; + import java.util.Collections; + import java.util.HashMap; + import java.util.HashSet; + import java.util.List; + import java.util.Map; + import java.util.Set; + import java.util.UUID; + import java.util.concurrent.ExecutionException; + import java.util.concurrent.Semaphore; + import java.util.concurrent.atomic.AtomicInteger; + + import static io.dapr.utils.TestUtils.assertThrowsDaprException; + import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + import static org.junit.jupiter.api.Assertions.assertEquals; + import static org.junit.jupiter.api.Assertions.assertFalse; + import static org.junit.jupiter.api.Assertions.assertNotNull; + import static org.junit.jupiter.api.Assertions.assertNull; + import static org.junit.jupiter.api.Assertions.assertThrows; + import static org.mockito.ArgumentMatchers.any; + import static org.mockito.Mockito.doAnswer; + import static org.mockito.Mockito.doNothing; + import static org.mockito.Mockito.mock; + import static org.mockito.Mockito.times; + import static org.mockito.Mockito.verify; + import static org.mockito.Mockito.verifyNoMoreInteractions; + import static org.mockito.Mockito.when; + + public class DaprPreviewClientGrpcTest { private static final ObjectMapper MAPPER = new ObjectMapper(); @@ -169,7 +169,7 @@ public void publishEventsContentTypeMismatchException() throws IOException { BulkPublishRequest wrongReq = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, Collections.singletonList(entry)); - assertThrows(IllegalArgumentException.class, () -> previewClient.publishEvents(wrongReq).block()); + assertThrows(IllegalArgumentException.class, () -> previewClient.publishEvents(wrongReq).block()); } @Test @@ -459,12 +459,12 @@ public void subscribeEventTest() throws Exception { StreamObserver observer = (StreamObserver) invocation.getArguments()[0]; var emitterThread = new Thread(() -> { - try { - started.acquire(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.getDefaultInstance()); + try { + started.acquire(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.getDefaultInstance()); for (int i = 0; i < numEvents; i++) { observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.newBuilder() .setEventMessage(DaprAppCallbackProtos.TopicEventRequest.newBuilder() @@ -874,4 +874,4 @@ private DaprProtos.QueryStateItem buildQueryStateItem(QueryStateItem item) th private static StatusRuntimeException newStatusRuntimeException(String status, String message) { return new StatusRuntimeException(Status.fromCode(Status.Code.valueOf(status)).withDescription(message)); } -} + } From 6c833bc0c6b56b32b634c451f036d505cb83d97d Mon Sep 17 00:00:00 2001 From: siri-varma Date: Thu, 10 Apr 2025 21:14:48 +0530 Subject: [PATCH 21/30] Fix spaces Signed-off-by: siri-varma --- .../client/DaprPreviewClientGrpcTest.java | 194 +++++++++--------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java index afd4321a63..b782c6706f 100644 --- a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java @@ -1,92 +1,92 @@ - /* - * Copyright 2021 The Dapr Authors - * 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 io.dapr.client; - - - import com.fasterxml.jackson.core.JsonProcessingException; - import com.fasterxml.jackson.databind.ObjectMapper; - import com.google.protobuf.Any; - import com.google.protobuf.ByteString; - import io.dapr.client.domain.BulkPublishEntry; - import io.dapr.client.domain.BulkPublishRequest; - import io.dapr.client.domain.BulkPublishResponse; - import io.dapr.client.domain.CloudEvent; - import io.dapr.client.domain.DeleteJobRequest; - import io.dapr.client.domain.GetJobRequest; - import io.dapr.client.domain.GetJobResponse; - import io.dapr.client.domain.JobSchedule; - import io.dapr.client.domain.QueryStateItem; - import io.dapr.client.domain.QueryStateRequest; - import io.dapr.client.domain.QueryStateResponse; - import io.dapr.client.domain.ScheduleJobRequest; - import io.dapr.client.domain.UnlockResponseStatus; - import io.dapr.client.domain.query.Query; - import io.dapr.serializer.DaprObjectSerializer; - import io.dapr.serializer.DefaultObjectSerializer; - import io.dapr.utils.TypeRef; - import io.dapr.v1.DaprAppCallbackProtos; - import io.dapr.v1.DaprGrpc; - import io.dapr.v1.DaprProtos; - import io.grpc.Status; - import io.grpc.StatusRuntimeException; - import io.grpc.stub.StreamObserver; - import org.junit.jupiter.api.AfterEach; - import org.junit.jupiter.api.Assertions; - import org.junit.jupiter.api.BeforeEach; - import org.junit.jupiter.api.Test; - import org.mockito.ArgumentCaptor; - import org.mockito.ArgumentMatchers; - import org.mockito.Mockito; - import org.mockito.stubbing.Answer; - import reactor.core.publisher.Mono; - - import java.io.IOException; - import java.nio.charset.StandardCharsets; - import java.time.Instant; - import java.time.OffsetDateTime; - import java.time.ZoneOffset; - import java.time.format.DateTimeFormatter; - import java.time.temporal.ChronoUnit; - import java.util.ArrayList; - import java.util.Collections; - import java.util.HashMap; - import java.util.HashSet; - import java.util.List; - import java.util.Map; - import java.util.Set; - import java.util.UUID; - import java.util.concurrent.ExecutionException; - import java.util.concurrent.Semaphore; - import java.util.concurrent.atomic.AtomicInteger; - - import static io.dapr.utils.TestUtils.assertThrowsDaprException; - import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; - import static org.junit.jupiter.api.Assertions.assertEquals; - import static org.junit.jupiter.api.Assertions.assertFalse; - import static org.junit.jupiter.api.Assertions.assertNotNull; - import static org.junit.jupiter.api.Assertions.assertNull; - import static org.junit.jupiter.api.Assertions.assertThrows; - import static org.mockito.ArgumentMatchers.any; - import static org.mockito.Mockito.doAnswer; - import static org.mockito.Mockito.doNothing; - import static org.mockito.Mockito.mock; - import static org.mockito.Mockito.times; - import static org.mockito.Mockito.verify; - import static org.mockito.Mockito.verifyNoMoreInteractions; - import static org.mockito.Mockito.when; - - public class DaprPreviewClientGrpcTest { +/* + * Copyright 2021 The Dapr Authors + * 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 io.dapr.client; + + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.protobuf.Any; +import com.google.protobuf.ByteString; +import io.dapr.client.domain.BulkPublishEntry; +import io.dapr.client.domain.BulkPublishRequest; +import io.dapr.client.domain.BulkPublishResponse; +import io.dapr.client.domain.CloudEvent; +import io.dapr.client.domain.DeleteJobRequest; +import io.dapr.client.domain.GetJobRequest; +import io.dapr.client.domain.GetJobResponse; +import io.dapr.client.domain.JobSchedule; +import io.dapr.client.domain.QueryStateItem; +import io.dapr.client.domain.QueryStateRequest; +import io.dapr.client.domain.QueryStateResponse; +import io.dapr.client.domain.ScheduleJobRequest; +import io.dapr.client.domain.UnlockResponseStatus; +import io.dapr.client.domain.query.Query; +import io.dapr.serializer.DaprObjectSerializer; +import io.dapr.serializer.DefaultObjectSerializer; +import io.dapr.utils.TypeRef; +import io.dapr.v1.DaprAppCallbackProtos; +import io.dapr.v1.DaprGrpc; +import io.dapr.v1.DaprProtos; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; +import io.grpc.stub.StreamObserver; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; +import org.mockito.stubbing.Answer; +import reactor.core.publisher.Mono; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicInteger; + +import static io.dapr.utils.TestUtils.assertThrowsDaprException; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +public class DaprPreviewClientGrpcTest { private static final ObjectMapper MAPPER = new ObjectMapper(); @@ -169,7 +169,7 @@ public void publishEventsContentTypeMismatchException() throws IOException { BulkPublishRequest wrongReq = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, Collections.singletonList(entry)); - assertThrows(IllegalArgumentException.class, () -> previewClient.publishEvents(wrongReq).block()); + assertThrows(IllegalArgumentException.class, () -> previewClient.publishEvents(wrongReq).block()); } @Test @@ -459,12 +459,12 @@ public void subscribeEventTest() throws Exception { StreamObserver observer = (StreamObserver) invocation.getArguments()[0]; var emitterThread = new Thread(() -> { - try { - started.acquire(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.getDefaultInstance()); + try { + started.acquire(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.getDefaultInstance()); for (int i = 0; i < numEvents; i++) { observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.newBuilder() .setEventMessage(DaprAppCallbackProtos.TopicEventRequest.newBuilder() @@ -874,4 +874,4 @@ private DaprProtos.QueryStateItem buildQueryStateItem(QueryStateItem item) th private static StatusRuntimeException newStatusRuntimeException(String status, String message) { return new StatusRuntimeException(Status.fromCode(Status.Code.valueOf(status)).withDescription(message)); } - } +} From ba1052529bc369bffefb99c8a22430f7bd78b0bb Mon Sep 17 00:00:00 2001 From: siri-varma Date: Thu, 10 Apr 2025 21:26:11 +0530 Subject: [PATCH 22/30] fixt hings Signed-off-by: siri-varma --- .../client/DaprPreviewClientGrpcTest.java | 266 +++++++++--------- 1 file changed, 133 insertions(+), 133 deletions(-) diff --git a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java index b782c6706f..1959a1b266 100644 --- a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java @@ -3,7 +3,7 @@ * 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 + * 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. @@ -110,7 +110,7 @@ public void setup() throws IOException { daprHttp = mock(DaprHttp.class); when(daprStub.withInterceptors(any())).thenReturn(daprStub); previewClient = new DaprClientImpl( - channel, daprStub, daprHttp, new DefaultObjectSerializer(), new DefaultObjectSerializer()); + channel, daprStub, daprHttp, new DefaultObjectSerializer(), new DefaultObjectSerializer()); doNothing().when(channel).close(); } @@ -128,28 +128,28 @@ public void publishEventsExceptionThrownTest() { }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); assertThrowsDaprException( - StatusRuntimeException.class, - "INVALID_ARGUMENT", - "INVALID_ARGUMENT: bad bad argument", - () -> previewClient.publishEvents(new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.EMPTY_LIST)).block()); + StatusRuntimeException.class, + "INVALID_ARGUMENT", + "INVALID_ARGUMENT: bad bad argument", + () -> previewClient.publishEvents(new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, + Collections.EMPTY_LIST)).block()); } @Test public void publishEventsCallbackExceptionThrownTest() { doAnswer((Answer) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; observer.onError(newStatusRuntimeException("INVALID_ARGUMENT", "bad bad argument")); return null; }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); assertThrowsDaprException( - ExecutionException.class, - "INVALID_ARGUMENT", - "INVALID_ARGUMENT: bad bad argument", - () -> previewClient.publishEvents(new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.EMPTY_LIST)).block()); + ExecutionException.class, + "INVALID_ARGUMENT", + "INVALID_ARGUMENT: bad bad argument", + () -> previewClient.publishEvents(new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, + Collections.EMPTY_LIST)).block()); } @Test @@ -157,7 +157,7 @@ public void publishEventsContentTypeMismatchException() throws IOException { DaprObjectSerializer mockSerializer = mock(DaprObjectSerializer.class); doAnswer((Answer) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; observer.onNext(DaprProtos.BulkPublishResponse.getDefaultInstance()); observer.onCompleted(); return null; @@ -165,11 +165,11 @@ public void publishEventsContentTypeMismatchException() throws IOException { BulkPublishEntry entry = new BulkPublishEntry<>("1", "testEntry" - , "application/octet-stream", null); + , "application/octet-stream", null); BulkPublishRequest wrongReq = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.singletonList(entry)); + Collections.singletonList(entry)); - assertThrows(IllegalArgumentException.class, () -> previewClient.publishEvents(wrongReq).block()); + assertThrows(IllegalArgumentException.class, () -> previewClient.publishEvents(wrongReq).block()); } @Test @@ -178,30 +178,30 @@ public void publishEventsSerializeException() throws IOException { previewClient = new DaprClientImpl(channel, daprStub, daprHttp, mockSerializer, new DefaultObjectSerializer()); doAnswer((Answer) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; observer.onNext(DaprProtos.BulkPublishResponse.getDefaultInstance()); observer.onCompleted(); return null; }).when(daprStub).publishEvent(any(DaprProtos.PublishEventRequest.class), any()); BulkPublishEntry> entry = new BulkPublishEntry<>("1", new HashMap<>(), - "application/json", null); + "application/json", null); BulkPublishRequest> req = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.singletonList(entry)); + Collections.singletonList(entry)); when(mockSerializer.serialize(any())).thenThrow(IOException.class); Mono>> result = previewClient.publishEvents(req); assertThrowsDaprException( - IOException.class, - "UNKNOWN", - "UNKNOWN: ", - () -> result.block()); + IOException.class, + "UNKNOWN", + "UNKNOWN: ", + () -> result.block()); } @Test public void publishEventsTest() { doAnswer((Answer) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; DaprProtos.BulkPublishResponse.Builder builder = DaprProtos.BulkPublishResponse.newBuilder(); observer.onNext(builder.build()); observer.onCompleted(); @@ -209,9 +209,9 @@ public void publishEventsTest() { }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); BulkPublishEntry entry = new BulkPublishEntry<>("1", "test", - "text/plain", null); + "text/plain", null); BulkPublishRequest req = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.singletonList(entry)); + Collections.singletonList(entry)); Mono> result = previewClient.publishEvents(req); BulkPublishResponse res = result.block(); Assertions.assertNotNull(res); @@ -222,7 +222,7 @@ public void publishEventsTest() { public void publishEventsWithoutMetaTest() { doAnswer((Answer) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; DaprProtos.BulkPublishResponse.Builder builder = DaprProtos.BulkPublishResponse.newBuilder(); observer.onNext(builder.build()); observer.onCompleted(); @@ -230,7 +230,7 @@ public void publishEventsWithoutMetaTest() { }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); Mono> result = previewClient.publishEvents(PUBSUB_NAME, TOPIC_NAME, - "text/plain", Collections.singletonList("test")); + "text/plain", Collections.singletonList("test")); BulkPublishResponse res = result.block(); Assertions.assertNotNull(res); assertEquals( 0, res.getFailedEntries().size(), "expected no entries in failed entries list"); @@ -240,7 +240,7 @@ public void publishEventsWithoutMetaTest() { public void publishEventsWithRequestMetaTest() { doAnswer((Answer) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; DaprProtos.BulkPublishResponse.Builder builder = DaprProtos.BulkPublishResponse.newBuilder(); observer.onNext(builder.build()); observer.onCompleted(); @@ -248,9 +248,9 @@ public void publishEventsWithRequestMetaTest() { }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); Mono> result = previewClient.publishEvents(PUBSUB_NAME, TOPIC_NAME, - "text/plain", new HashMap(){{ - put("ttlInSeconds", "123"); - }}, Collections.singletonList("test")); + "text/plain", new HashMap(){{ + put("ttlInSeconds", "123"); + }}, Collections.singletonList("test")); BulkPublishResponse res = result.block(); Assertions.assertNotNull(res); assertEquals( 0, res.getFailedEntries().size(), "expected no entry in failed entries list"); @@ -260,7 +260,7 @@ public void publishEventsWithRequestMetaTest() { public void publishEventsObjectTest() { doAnswer((Answer) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; observer.onNext(DaprProtos.BulkPublishResponse.getDefaultInstance()); observer.onCompleted(); return null; @@ -271,7 +271,7 @@ public void publishEventsObjectTest() { } if (!"{\"id\":1,\"value\":\"Event\"}".equals(new String(entry.getEvent().toByteArray())) && - !"{\"value\":\"Event\",\"id\":1}".equals(new String(entry.getEvent().toByteArray()))) { + !"{\"value\":\"Event\",\"id\":1}".equals(new String(entry.getEvent().toByteArray()))) { return false; } return true; @@ -280,9 +280,9 @@ public void publishEventsObjectTest() { DaprClientGrpcTest.MyObject event = new DaprClientGrpcTest.MyObject(1, "Event"); BulkPublishEntry entry = new BulkPublishEntry<>("1", event, - "application/json", null); + "application/json", null); BulkPublishRequest req = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.singletonList(entry)); + Collections.singletonList(entry)); BulkPublishResponse result = previewClient.publishEvents(req).block(); Assertions.assertNotNull(result); Assertions.assertEquals(0, result.getFailedEntries().size(), "expected no entries to be failed"); @@ -292,7 +292,7 @@ public void publishEventsObjectTest() { public void publishEventsContentTypeOverrideTest() { doAnswer((Answer) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; observer.onNext(DaprProtos.BulkPublishResponse.getDefaultInstance()); observer.onCompleted(); return null; @@ -309,9 +309,9 @@ public void publishEventsContentTypeOverrideTest() { }), any()); BulkPublishEntry entry = new BulkPublishEntry<>("1", "hello", - "", null); + "", null); BulkPublishRequest req = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.singletonList(entry)); + Collections.singletonList(entry)); BulkPublishResponse result = previewClient.publishEvents(req).block(); Assertions.assertNotNull(result); Assertions.assertEquals( 0, result.getFailedEntries().size(), "expected no entries to be failed"); @@ -351,7 +351,7 @@ public void queryState() throws JsonProcessingException { assertEquals(0, req.getMetadataCount()); StreamObserver observer = (StreamObserver) - invocation.getArguments()[1]; + invocation.getArguments()[1]; observer.onNext(responseEnvelope); observer.onCompleted(); return null; @@ -378,14 +378,14 @@ public void queryStateMetadataError() throws JsonProcessingException { assertEquals(1, req.getMetadataCount()); StreamObserver observer = (StreamObserver) - invocation.getArguments()[1]; + invocation.getArguments()[1]; observer.onNext(responseEnvelope); observer.onCompleted(); return null; }).when(daprStub).queryStateAlpha1(any(DaprProtos.QueryStateRequest.class), any()); QueryStateResponse response = previewClient.queryState(QUERY_STORE_NAME, "query", - new HashMap(){{ put("key", "error"); }}, String.class).block(); + new HashMap(){{ put("key", "error"); }}, String.class).block(); assertNotNull(response); assertEquals(1, response.getResults().size(), "result size must be 1"); assertEquals( "1", response.getResults().get(0).getKey(), "result must be same"); @@ -396,7 +396,7 @@ public void queryStateMetadataError() throws JsonProcessingException { public void tryLock() { DaprProtos.TryLockResponse.Builder builder = DaprProtos.TryLockResponse.newBuilder() - .setSuccess(true); + .setSuccess(true); DaprProtos.TryLockResponse response = builder.build(); @@ -408,7 +408,7 @@ public void tryLock() { assertEquals(10, req.getExpiryInSeconds()); StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; observer.onNext(response); observer.onCompleted(); return null; @@ -422,7 +422,7 @@ public void tryLock() { public void unLock() { DaprProtos.UnlockResponse.Builder builder = DaprProtos.UnlockResponse.newBuilder() - .setStatus(DaprProtos.UnlockResponse.Status.SUCCESS); + .setStatus(DaprProtos.UnlockResponse.Status.SUCCESS); DaprProtos.UnlockResponse response = builder.build(); @@ -433,7 +433,7 @@ public void unLock() { assertEquals("owner", req.getLockOwner()); StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; observer.onNext(response); observer.onCompleted(); return null; @@ -457,37 +457,37 @@ public void subscribeEventTest() throws Exception { doAnswer((Answer>) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[0]; + (StreamObserver) invocation.getArguments()[0]; var emitterThread = new Thread(() -> { - try { - started.acquire(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.getDefaultInstance()); + try { + started.acquire(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.getDefaultInstance()); for (int i = 0; i < numEvents; i++) { observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.newBuilder() - .setEventMessage(DaprAppCallbackProtos.TopicEventRequest.newBuilder() - .setId(Integer.toString(i)) - .setPubsubName(pubsubName) - .setTopic(topicName) - .setData(ByteString.copyFromUtf8("\"" + data + "\"")) - .setDataContentType("application/json") - .build()) - .build()); + .setEventMessage(DaprAppCallbackProtos.TopicEventRequest.newBuilder() + .setId(Integer.toString(i)) + .setPubsubName(pubsubName) + .setTopic(topicName) + .setData(ByteString.copyFromUtf8("\"" + data + "\"")) + .setDataContentType("application/json") + .build()) + .build()); } for (int i = 0; i < numDrops; i++) { // Bad messages observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.newBuilder() - .setEventMessage(DaprAppCallbackProtos.TopicEventRequest.newBuilder() - .setId(UUID.randomUUID().toString()) - .setPubsubName("bad pubsub") - .setTopic("bad topic") - .setData(ByteString.copyFromUtf8("\"\"")) - .setDataContentType("application/json") - .build()) - .build()); + .setEventMessage(DaprAppCallbackProtos.TopicEventRequest.newBuilder() + .setId(UUID.randomUUID().toString()) + .setPubsubName("bad pubsub") + .setTopic("bad topic") + .setData(ByteString.copyFromUtf8("\"\"")) + .setDataContentType("application/json") + .build()) + .build()); } observer.onCompleted(); }); @@ -517,38 +517,38 @@ public void onCompleted() { final AtomicInteger errorsToBeEmitted = new AtomicInteger(numErrors); var subscription = previewClient.subscribeToEvents( - "pubsubname", - "topic", - new SubscriptionListener<>() { - @Override - public Mono onEvent(CloudEvent event) { - if (event.getPubsubName().equals(pubsubName) && + "pubsubname", + "topic", + new SubscriptionListener<>() { + @Override + public Mono onEvent(CloudEvent event) { + if (event.getPubsubName().equals(pubsubName) && event.getTopic().equals(topicName) && event.getData().equals(data)) { - // Simulate an error - if ((success.size() == 4 /* some random entry */) && errorsToBeEmitted.decrementAndGet() >= 0) { - throw new RuntimeException("simulated exception on event " + event.getId()); - } - - success.add(event.getId()); - if (success.size() >= numEvents) { - gotAll.release(); - } - return Mono.just(Status.SUCCESS); + // Simulate an error + if ((success.size() == 4 /* some random entry */) && errorsToBeEmitted.decrementAndGet() >= 0) { + throw new RuntimeException("simulated exception on event " + event.getId()); } - dropCounter.incrementAndGet(); - return Mono.just(Status.DROP); + success.add(event.getId()); + if (success.size() >= numEvents) { + gotAll.release(); + } + return Mono.just(Status.SUCCESS); } - @Override - public void onError(RuntimeException exception) { - errors.add(exception.getMessage()); - } + dropCounter.incrementAndGet(); + return Mono.just(Status.DROP); + } + + @Override + public void onError(RuntimeException exception) { + errors.add(exception.getMessage()); + } - }, - TypeRef.STRING); + }, + TypeRef.STRING); gotAll.acquire(); subscription.close(); @@ -561,14 +561,14 @@ public void onError(RuntimeException exception) { @Test public void scheduleJobShouldSucceedWhenAllFieldsArePresentInRequest() { DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") - .withZone(ZoneOffset.UTC); + .withZone(ZoneOffset.UTC); ScheduleJobRequest expectedScheduleJobRequest = new ScheduleJobRequest("testJob", - JobSchedule.fromString("*/5 * * * *")) - .setData("testData".getBytes()) - .setTtl(Instant.now().plus(1, ChronoUnit.DAYS)) - .setRepeat(5) - .setDueTime(Instant.now().plus(10, ChronoUnit.MINUTES)); + JobSchedule.fromString("*/5 * * * *")) + .setData("testData".getBytes()) + .setTtl(Instant.now().plus(1, ChronoUnit.DAYS)) + .setRepeat(5) + .setDueTime(Instant.now().plus(10, ChronoUnit.MINUTES)); doAnswer(invocation -> { StreamObserver observer = invocation.getArgument(1); @@ -579,14 +579,14 @@ public void scheduleJobShouldSucceedWhenAllFieldsArePresentInRequest() { assertDoesNotThrow(() -> previewClient.scheduleJob(expectedScheduleJobRequest).block()); ArgumentCaptor captor = - ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); + ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any()); DaprProtos.ScheduleJobRequest actualScheduleJobReq = captor.getValue(); assertEquals("testJob", actualScheduleJobReq.getJob().getName()); assertEquals("testData", - new String(actualScheduleJobReq.getJob().getData().getValue().toByteArray(), StandardCharsets.UTF_8)); + new String(actualScheduleJobReq.getJob().getData().getValue().toByteArray(), StandardCharsets.UTF_8)); assertEquals("*/5 * * * *", actualScheduleJobReq.getJob().getSchedule()); assertEquals(iso8601Formatter.format(expectedScheduleJobRequest.getTtl()), actualScheduleJobReq.getJob().getTtl()); assertEquals(expectedScheduleJobRequest.getRepeats(), actualScheduleJobReq.getJob().getRepeats()); @@ -596,7 +596,7 @@ public void scheduleJobShouldSucceedWhenAllFieldsArePresentInRequest() { @Test public void scheduleJobShouldSucceedWhenRequiredFieldsNameAndDueTimeArePresentInRequest() { DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") - .withZone(ZoneOffset.UTC); + .withZone(ZoneOffset.UTC); doAnswer(invocation -> { StreamObserver observer = invocation.getArgument(1); @@ -605,11 +605,11 @@ public void scheduleJobShouldSucceedWhenRequiredFieldsNameAndDueTimeArePresentIn }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any()); ScheduleJobRequest expectedScheduleJobRequest = - new ScheduleJobRequest("testJob", Instant.now().plus(10, ChronoUnit.MINUTES)); + new ScheduleJobRequest("testJob", Instant.now().plus(10, ChronoUnit.MINUTES)); assertDoesNotThrow(() -> previewClient.scheduleJob(expectedScheduleJobRequest).block()); ArgumentCaptor captor = - ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); + ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any()); DaprProtos.ScheduleJobRequest actualScheduleJobRequest = captor.getValue(); @@ -620,13 +620,13 @@ public void scheduleJobShouldSucceedWhenRequiredFieldsNameAndDueTimeArePresentIn assertEquals(0, job.getRepeats()); assertFalse(job.hasTtl()); assertEquals(iso8601Formatter.format(expectedScheduleJobRequest.getDueTime()), - actualScheduleJobRequest.getJob().getDueTime()); + actualScheduleJobRequest.getJob().getDueTime()); } @Test public void scheduleJobShouldSucceedWhenRequiredFieldsNameAndScheduleArePresentInRequest() { DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") - .withZone(ZoneOffset.UTC); + .withZone(ZoneOffset.UTC); doAnswer(invocation -> { StreamObserver observer = invocation.getArgument(1); @@ -635,11 +635,11 @@ public void scheduleJobShouldSucceedWhenRequiredFieldsNameAndScheduleArePresentI }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any()); ScheduleJobRequest expectedScheduleJobRequest = new ScheduleJobRequest("testJob", - JobSchedule.fromString("* * * * * *")); + JobSchedule.fromString("* * * * * *")); assertDoesNotThrow(() -> previewClient.scheduleJob(expectedScheduleJobRequest).block()); ArgumentCaptor captor = - ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); + ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any()); DaprProtos.ScheduleJobRequest actualScheduleJobRequest = captor.getValue(); @@ -681,24 +681,24 @@ public void scheduleJobShouldThrowWhenNameInRequestIsEmpty() { @Test public void getJobShouldReturnResponseWhenAllFieldsArePresentInRequest() { DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") - .withZone(ZoneOffset.UTC); + .withZone(ZoneOffset.UTC); GetJobRequest getJobRequest = new GetJobRequest("testJob"); DaprProtos.Job job = DaprProtos.Job.newBuilder() - .setName("testJob") - .setTtl(OffsetDateTime.now().format(iso8601Formatter)) - .setData(Any.newBuilder().setValue(ByteString.copyFrom("testData".getBytes())).build()) - .setSchedule("*/5 * * * *") - .setRepeats(5) - .setDueTime(iso8601Formatter.format(Instant.now().plus(10, ChronoUnit.MINUTES))) - .build(); + .setName("testJob") + .setTtl(OffsetDateTime.now().format(iso8601Formatter)) + .setData(Any.newBuilder().setValue(ByteString.copyFrom("testData".getBytes())).build()) + .setSchedule("*/5 * * * *") + .setRepeats(5) + .setDueTime(iso8601Formatter.format(Instant.now().plus(10, ChronoUnit.MINUTES))) + .build(); doAnswer(invocation -> { StreamObserver observer = invocation.getArgument(1); observer.onNext(DaprProtos.GetJobResponse.newBuilder() - .setJob(job) - .build()); + .setJob(job) + .build()); observer.onCompleted(); return null; }).when(daprStub).getJobAlpha1(any(DaprProtos.GetJobRequest.class), any()); @@ -720,15 +720,15 @@ public void getJobShouldReturnResponseWithScheduleSetWhenResponseHasSchedule() { GetJobRequest getJobRequest = new GetJobRequest("testJob"); DaprProtos.Job job = DaprProtos.Job.newBuilder() - .setName("testJob") - .setSchedule("0 0 0 1 1 *") - .build(); + .setName("testJob") + .setSchedule("0 0 0 1 1 *") + .build(); doAnswer(invocation -> { StreamObserver observer = invocation.getArgument(1); observer.onNext(DaprProtos.GetJobResponse.newBuilder() - .setJob(job) - .build()); + .setJob(job) + .build()); observer.onCompleted(); return null; }).when(daprStub).getJobAlpha1(any(DaprProtos.GetJobRequest.class), any()); @@ -751,15 +751,15 @@ public void getJobShouldReturnResponseWithDueTimeSetWhenResponseHasDueTime() { String datetime = OffsetDateTime.now().toString(); DaprProtos.Job job = DaprProtos.Job.newBuilder() - .setName("testJob") - .setDueTime(datetime) - .build(); + .setName("testJob") + .setDueTime(datetime) + .build(); doAnswer(invocation -> { StreamObserver observer = invocation.getArgument(1); observer.onNext(DaprProtos.GetJobResponse.newBuilder() - .setJob(job) - .build()); + .setJob(job) + .build()); observer.onCompleted(); return null; }).when(daprStub).getJobAlpha1(any(DaprProtos.GetJobRequest.class), any()); @@ -846,15 +846,15 @@ public void deleteJobShouldThrowWhenNameIsEmptyRequest() { } private DaprProtos.QueryStateResponse buildQueryStateResponse(List> resp,String token) - throws JsonProcessingException { + throws JsonProcessingException { List items = new ArrayList<>(); for (QueryStateItem item: resp) { items.add(buildQueryStateItem(item)); } return DaprProtos.QueryStateResponse.newBuilder() - .addAllResults(items) - .setToken(token) - .build(); + .addAllResults(items) + .setToken(token) + .build(); } private DaprProtos.QueryStateItem buildQueryStateItem(QueryStateItem item) throws JsonProcessingException { From 17429d645d8ea8f23d98724272fea12696e4ceda Mon Sep 17 00:00:00 2001 From: siri-varma Date: Sat, 12 Apr 2025 09:42:25 +0530 Subject: [PATCH 23/30] Add examples Signed-off-by: siri-varma --- .github/workflows/validate.yml | 6 + .../io/dapr/examples/jobs/DemoJobsClient.java | 49 +++++++ .../jobs/DemoJobsSpringApplication.java | 31 +++++ .../io/dapr/examples/jobs/JobsController.java | 43 ++++++ .../main/java/io/dapr/examples/jobs/README.md | 123 ++++++++++++++++++ 5 files changed, 252 insertions(+) create mode 100644 examples/src/main/java/io/dapr/examples/jobs/DemoJobsClient.java create mode 100644 examples/src/main/java/io/dapr/examples/jobs/DemoJobsSpringApplication.java create mode 100644 examples/src/main/java/io/dapr/examples/jobs/JobsController.java create mode 100644 examples/src/main/java/io/dapr/examples/jobs/README.md diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index b8b478268c..1559f5aef4 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -115,6 +115,12 @@ jobs: run: ./mvnw install -q env: DOCKER_HOST: ${{steps.setup_docker.outputs.sock}} + - name: Validate Jobs example + working-directory: ./examples + run: | + mm.py ./src/main/java/io/dapr/examples/jobs/README.md + env: + DOCKER_HOST: ${{steps.setup_docker.outputs.sock}} - name: Validate invoke http example working-directory: ./examples run: | diff --git a/examples/src/main/java/io/dapr/examples/jobs/DemoJobsClient.java b/examples/src/main/java/io/dapr/examples/jobs/DemoJobsClient.java new file mode 100644 index 0000000000..4bafeb219a --- /dev/null +++ b/examples/src/main/java/io/dapr/examples/jobs/DemoJobsClient.java @@ -0,0 +1,49 @@ +/* + * Copyright 2021 The Dapr Authors + * 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 io.dapr.examples.jobs; + +import io.dapr.client.DaprClientBuilder; +import io.dapr.client.DaprPreviewClient; +import io.dapr.client.domain.GetJobRequest; +import io.dapr.client.domain.GetJobResponse; +import io.dapr.client.domain.JobSchedule; +import io.dapr.client.domain.ScheduleJobRequest; +import io.dapr.config.Properties; +import io.dapr.config.Property; + +import java.util.Map; + +public class DemoJobsClient { + + /** + * The main method of this app to register and fetch jobs. + */ + public static void main(String[] args) throws Exception { + Map, String> overrides = Map.of( + Properties.HTTP_PORT, "3500", + Properties.GRPC_PORT, "51439" + ); + + try (DaprPreviewClient client = new DaprClientBuilder().withPropertyOverrides(overrides).buildPreviewClient()) { + + // Schedule a job. + ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest("dapr-job-1", + JobSchedule.fromString("* * * * * *")).setData("Hello World!".getBytes()); + client.scheduleJob(scheduleJobRequest).block(); + + // Get a job. + GetJobResponse getJobResponse = client.getJob(new GetJobRequest("dapr-job-1")).block(); + } + } +} diff --git a/examples/src/main/java/io/dapr/examples/jobs/DemoJobsSpringApplication.java b/examples/src/main/java/io/dapr/examples/jobs/DemoJobsSpringApplication.java new file mode 100644 index 0000000000..74993c62e0 --- /dev/null +++ b/examples/src/main/java/io/dapr/examples/jobs/DemoJobsSpringApplication.java @@ -0,0 +1,31 @@ +/* + * Copyright 2021 The Dapr Authors + * 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 io.dapr.examples.jobs; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * Spring Boot application to demonstrate Dapr Jobs callback API. + *

+ * This application demonstrates how to use Dapr Jobs API with Spring Boot. + *

+ */ +@SpringBootApplication +public class DemoJobsSpringApplication { + + public static void main(String[] args) throws Exception { + SpringApplication.run(DemoJobsSpringApplication.class, args); + } +} diff --git a/examples/src/main/java/io/dapr/examples/jobs/JobsController.java b/examples/src/main/java/io/dapr/examples/jobs/JobsController.java new file mode 100644 index 0000000000..48548f9740 --- /dev/null +++ b/examples/src/main/java/io/dapr/examples/jobs/JobsController.java @@ -0,0 +1,43 @@ +/* + * Copyright 2021 The Dapr Authors + * 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 io.dapr.examples.jobs; + +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; + +/** + * SpringBoot Controller to handle jobs callback. + */ +@RestController +public class JobsController { + + /** + * Handles jobs callback from Dapr. + * + * @param jobName name of the job. + * @param payload data from the job if payload exists. + * @return Empty Mono. + */ + @PostMapping("/job/{jobName}") + public Mono handleJob(@PathVariable("jobName") String jobName, + @RequestBody(required = false) byte[] payload) { + System.out.println("Job Name: " + jobName); + System.out.println("Job Payload: " + new String(payload)); + + return Mono.empty(); + } +} diff --git a/examples/src/main/java/io/dapr/examples/jobs/README.md b/examples/src/main/java/io/dapr/examples/jobs/README.md new file mode 100644 index 0000000000..ed066db03d --- /dev/null +++ b/examples/src/main/java/io/dapr/examples/jobs/README.md @@ -0,0 +1,123 @@ +## Mange Dapr Jobs via the Jobs API + +This example provides the different capabilities provided by Dapr Java SDK for Jobs. For further information about Job APIs please refer to [this link](https://docs.dapr.io/developing-applications/building-blocks/jobs/jobs-overview/) + +### Using the JobsAPI + +The Java SDK exposes several methods for this - +* `client.scheduleJob(...)` for scheduling a job. +* `client.getJob(...)` for retrieving a scheduled job. +* `client.deleteJob(...)` for deleting a job. + +## Pre-requisites + +* [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/). +* Java JDK 11 (or greater): + * [Microsoft JDK 11](https://docs.microsoft.com/en-us/java/openjdk/download#openjdk-11) + * [Oracle JDK 11](https://www.oracle.com/technetwork/java/javase/downloads/index.html#JDK11) + * [OpenJDK 11](https://jdk.java.net/11/) +* [Apache Maven](https://maven.apache.org/install.html) version 3.x. + +### Checking out the code + +Clone this repository: + +```sh +git clone https://github.com/dapr/java-sdk.git +cd java-sdk +``` + +Then build the Maven project: + +```sh +# make sure you are in the `java-sdk` directory. +mvn install +``` + +Then get into the examples directory: + +```sh +cd examples +``` + +### Initialize Dapr + +Run `dapr init` to initialize Dapr in Self-Hosted Mode if it's not already initialized. + +### Running the example + +This example uses the Java SDK Dapr client in order to **Schedule and Get** Jobs. +`DemoJobsClient.java` is the example class demonstrating these features. +Kindly check [DaprPreviewClient.java](https://github.com/dapr/java-sdk/blob/master/sdk/src/main/java/io/dapr/client/DaprPreviewClient.java) for a detailed description of the supported APIs. + +```java +public class DemoJobsClient { + /** + * The main method of this app to register and fetch jobs. + */ + public static void main(String[] args) throws Exception { + Map, String> overrides = Map.of( + Properties.HTTP_PORT, "3500", + Properties.GRPC_PORT, "51439" + ); + + try (DaprPreviewClient client = new DaprClientBuilder().withPropertyOverrides(overrides).buildPreviewClient()) { + + // Schedule a job. + ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest("dapr-job-1", + JobSchedule.fromString("* * * * * *")).setData("Hello World!".getBytes()); + client.scheduleJob(scheduleJobRequest).block(); + + // Get a job. + GetJobResponse getJobResponse = client.getJob(new GetJobRequest("dapr-job-1")).block(); + } + } +} +``` + +Get into the examples' directory: +```sh +cd examples +``` + +Use the following command to run this example- + + + +```bash +dapr run --resources-path ./components/configuration --app-id myapp --app-port 8080 --dapr-http-port 3500 --dapr-grpc-port 51439 --log-level debug -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.jobs.DemoJobsSpringApplication +``` + +```bash +java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.jobs.DemoJobsClient +``` + + + +### Sample output +``` +== APP == Job Name: dapr-job-1 +== APP == Job Payload: Hello World! +``` +### Cleanup + +To stop the app, run (or press CTRL+C): + + + +```bash +dapr stop --app-id myapp +``` + + + From 25b236f9ecb47b159a928dc809195dc853915aa1 Mon Sep 17 00:00:00 2001 From: siri-varma Date: Sat, 12 Apr 2025 10:34:09 +0530 Subject: [PATCH 24/30] Cleanup Signed-off-by: siri-varma --- .../client/DaprPreviewClientGrpcTest.java | 196 +++++++++--------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java index 1959a1b266..bbb162bd59 100644 --- a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java @@ -3,7 +3,7 @@ * 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 + * 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. @@ -110,7 +110,7 @@ public void setup() throws IOException { daprHttp = mock(DaprHttp.class); when(daprStub.withInterceptors(any())).thenReturn(daprStub); previewClient = new DaprClientImpl( - channel, daprStub, daprHttp, new DefaultObjectSerializer(), new DefaultObjectSerializer()); + channel, daprStub, daprHttp, new DefaultObjectSerializer(), new DefaultObjectSerializer()); doNothing().when(channel).close(); } @@ -128,28 +128,28 @@ public void publishEventsExceptionThrownTest() { }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); assertThrowsDaprException( - StatusRuntimeException.class, - "INVALID_ARGUMENT", - "INVALID_ARGUMENT: bad bad argument", - () -> previewClient.publishEvents(new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.EMPTY_LIST)).block()); + StatusRuntimeException.class, + "INVALID_ARGUMENT", + "INVALID_ARGUMENT: bad bad argument", + () -> previewClient.publishEvents(new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, + Collections.EMPTY_LIST)).block()); } @Test public void publishEventsCallbackExceptionThrownTest() { doAnswer((Answer) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; observer.onError(newStatusRuntimeException("INVALID_ARGUMENT", "bad bad argument")); return null; }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); assertThrowsDaprException( - ExecutionException.class, - "INVALID_ARGUMENT", - "INVALID_ARGUMENT: bad bad argument", - () -> previewClient.publishEvents(new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.EMPTY_LIST)).block()); + ExecutionException.class, + "INVALID_ARGUMENT", + "INVALID_ARGUMENT: bad bad argument", + () -> previewClient.publishEvents(new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, + Collections.EMPTY_LIST)).block()); } @Test @@ -157,7 +157,7 @@ public void publishEventsContentTypeMismatchException() throws IOException { DaprObjectSerializer mockSerializer = mock(DaprObjectSerializer.class); doAnswer((Answer) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; observer.onNext(DaprProtos.BulkPublishResponse.getDefaultInstance()); observer.onCompleted(); return null; @@ -165,11 +165,11 @@ public void publishEventsContentTypeMismatchException() throws IOException { BulkPublishEntry entry = new BulkPublishEntry<>("1", "testEntry" - , "application/octet-stream", null); + , "application/octet-stream", null); BulkPublishRequest wrongReq = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.singletonList(entry)); + Collections.singletonList(entry)); - assertThrows(IllegalArgumentException.class, () -> previewClient.publishEvents(wrongReq).block()); + assertThrows(IllegalArgumentException.class, () -> previewClient.publishEvents(wrongReq).block()); } @Test @@ -178,30 +178,30 @@ public void publishEventsSerializeException() throws IOException { previewClient = new DaprClientImpl(channel, daprStub, daprHttp, mockSerializer, new DefaultObjectSerializer()); doAnswer((Answer) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; observer.onNext(DaprProtos.BulkPublishResponse.getDefaultInstance()); observer.onCompleted(); return null; }).when(daprStub).publishEvent(any(DaprProtos.PublishEventRequest.class), any()); BulkPublishEntry> entry = new BulkPublishEntry<>("1", new HashMap<>(), - "application/json", null); + "application/json", null); BulkPublishRequest> req = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.singletonList(entry)); + Collections.singletonList(entry)); when(mockSerializer.serialize(any())).thenThrow(IOException.class); Mono>> result = previewClient.publishEvents(req); assertThrowsDaprException( - IOException.class, - "UNKNOWN", - "UNKNOWN: ", - () -> result.block()); + IOException.class, + "UNKNOWN", + "UNKNOWN: ", + () -> result.block()); } @Test public void publishEventsTest() { doAnswer((Answer) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; DaprProtos.BulkPublishResponse.Builder builder = DaprProtos.BulkPublishResponse.newBuilder(); observer.onNext(builder.build()); observer.onCompleted(); @@ -209,9 +209,9 @@ public void publishEventsTest() { }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); BulkPublishEntry entry = new BulkPublishEntry<>("1", "test", - "text/plain", null); + "text/plain", null); BulkPublishRequest req = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.singletonList(entry)); + Collections.singletonList(entry)); Mono> result = previewClient.publishEvents(req); BulkPublishResponse res = result.block(); Assertions.assertNotNull(res); @@ -222,7 +222,7 @@ public void publishEventsTest() { public void publishEventsWithoutMetaTest() { doAnswer((Answer) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; DaprProtos.BulkPublishResponse.Builder builder = DaprProtos.BulkPublishResponse.newBuilder(); observer.onNext(builder.build()); observer.onCompleted(); @@ -230,7 +230,7 @@ public void publishEventsWithoutMetaTest() { }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); Mono> result = previewClient.publishEvents(PUBSUB_NAME, TOPIC_NAME, - "text/plain", Collections.singletonList("test")); + "text/plain", Collections.singletonList("test")); BulkPublishResponse res = result.block(); Assertions.assertNotNull(res); assertEquals( 0, res.getFailedEntries().size(), "expected no entries in failed entries list"); @@ -240,7 +240,7 @@ public void publishEventsWithoutMetaTest() { public void publishEventsWithRequestMetaTest() { doAnswer((Answer) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; DaprProtos.BulkPublishResponse.Builder builder = DaprProtos.BulkPublishResponse.newBuilder(); observer.onNext(builder.build()); observer.onCompleted(); @@ -248,9 +248,9 @@ public void publishEventsWithRequestMetaTest() { }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); Mono> result = previewClient.publishEvents(PUBSUB_NAME, TOPIC_NAME, - "text/plain", new HashMap(){{ - put("ttlInSeconds", "123"); - }}, Collections.singletonList("test")); + "text/plain", new HashMap(){{ + put("ttlInSeconds", "123"); + }}, Collections.singletonList("test")); BulkPublishResponse res = result.block(); Assertions.assertNotNull(res); assertEquals( 0, res.getFailedEntries().size(), "expected no entry in failed entries list"); @@ -260,7 +260,7 @@ public void publishEventsWithRequestMetaTest() { public void publishEventsObjectTest() { doAnswer((Answer) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; observer.onNext(DaprProtos.BulkPublishResponse.getDefaultInstance()); observer.onCompleted(); return null; @@ -271,7 +271,7 @@ public void publishEventsObjectTest() { } if (!"{\"id\":1,\"value\":\"Event\"}".equals(new String(entry.getEvent().toByteArray())) && - !"{\"value\":\"Event\",\"id\":1}".equals(new String(entry.getEvent().toByteArray()))) { + !"{\"value\":\"Event\",\"id\":1}".equals(new String(entry.getEvent().toByteArray()))) { return false; } return true; @@ -280,9 +280,9 @@ public void publishEventsObjectTest() { DaprClientGrpcTest.MyObject event = new DaprClientGrpcTest.MyObject(1, "Event"); BulkPublishEntry entry = new BulkPublishEntry<>("1", event, - "application/json", null); + "application/json", null); BulkPublishRequest req = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.singletonList(entry)); + Collections.singletonList(entry)); BulkPublishResponse result = previewClient.publishEvents(req).block(); Assertions.assertNotNull(result); Assertions.assertEquals(0, result.getFailedEntries().size(), "expected no entries to be failed"); @@ -292,7 +292,7 @@ public void publishEventsObjectTest() { public void publishEventsContentTypeOverrideTest() { doAnswer((Answer) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; observer.onNext(DaprProtos.BulkPublishResponse.getDefaultInstance()); observer.onCompleted(); return null; @@ -309,9 +309,9 @@ public void publishEventsContentTypeOverrideTest() { }), any()); BulkPublishEntry entry = new BulkPublishEntry<>("1", "hello", - "", null); + "", null); BulkPublishRequest req = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.singletonList(entry)); + Collections.singletonList(entry)); BulkPublishResponse result = previewClient.publishEvents(req).block(); Assertions.assertNotNull(result); Assertions.assertEquals( 0, result.getFailedEntries().size(), "expected no entries to be failed"); @@ -351,7 +351,7 @@ public void queryState() throws JsonProcessingException { assertEquals(0, req.getMetadataCount()); StreamObserver observer = (StreamObserver) - invocation.getArguments()[1]; + invocation.getArguments()[1]; observer.onNext(responseEnvelope); observer.onCompleted(); return null; @@ -378,14 +378,14 @@ public void queryStateMetadataError() throws JsonProcessingException { assertEquals(1, req.getMetadataCount()); StreamObserver observer = (StreamObserver) - invocation.getArguments()[1]; + invocation.getArguments()[1]; observer.onNext(responseEnvelope); observer.onCompleted(); return null; }).when(daprStub).queryStateAlpha1(any(DaprProtos.QueryStateRequest.class), any()); QueryStateResponse response = previewClient.queryState(QUERY_STORE_NAME, "query", - new HashMap(){{ put("key", "error"); }}, String.class).block(); + new HashMap(){{ put("key", "error"); }}, String.class).block(); assertNotNull(response); assertEquals(1, response.getResults().size(), "result size must be 1"); assertEquals( "1", response.getResults().get(0).getKey(), "result must be same"); @@ -396,7 +396,7 @@ public void queryStateMetadataError() throws JsonProcessingException { public void tryLock() { DaprProtos.TryLockResponse.Builder builder = DaprProtos.TryLockResponse.newBuilder() - .setSuccess(true); + .setSuccess(true); DaprProtos.TryLockResponse response = builder.build(); @@ -408,7 +408,7 @@ public void tryLock() { assertEquals(10, req.getExpiryInSeconds()); StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; observer.onNext(response); observer.onCompleted(); return null; @@ -422,7 +422,7 @@ public void tryLock() { public void unLock() { DaprProtos.UnlockResponse.Builder builder = DaprProtos.UnlockResponse.newBuilder() - .setStatus(DaprProtos.UnlockResponse.Status.SUCCESS); + .setStatus(DaprProtos.UnlockResponse.Status.SUCCESS); DaprProtos.UnlockResponse response = builder.build(); @@ -433,7 +433,7 @@ public void unLock() { assertEquals("owner", req.getLockOwner()); StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; + (StreamObserver) invocation.getArguments()[1]; observer.onNext(response); observer.onCompleted(); return null; @@ -457,37 +457,37 @@ public void subscribeEventTest() throws Exception { doAnswer((Answer>) invocation -> { StreamObserver observer = - (StreamObserver) invocation.getArguments()[0]; + (StreamObserver) invocation.getArguments()[0]; var emitterThread = new Thread(() -> { - try { - started.acquire(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.getDefaultInstance()); + try { + started.acquire(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.getDefaultInstance()); for (int i = 0; i < numEvents; i++) { observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.newBuilder() - .setEventMessage(DaprAppCallbackProtos.TopicEventRequest.newBuilder() - .setId(Integer.toString(i)) - .setPubsubName(pubsubName) - .setTopic(topicName) - .setData(ByteString.copyFromUtf8("\"" + data + "\"")) - .setDataContentType("application/json") - .build()) - .build()); + .setEventMessage(DaprAppCallbackProtos.TopicEventRequest.newBuilder() + .setId(Integer.toString(i)) + .setPubsubName(pubsubName) + .setTopic(topicName) + .setData(ByteString.copyFromUtf8("\"" + data + "\"")) + .setDataContentType("application/json") + .build()) + .build()); } for (int i = 0; i < numDrops; i++) { // Bad messages observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.newBuilder() - .setEventMessage(DaprAppCallbackProtos.TopicEventRequest.newBuilder() - .setId(UUID.randomUUID().toString()) - .setPubsubName("bad pubsub") - .setTopic("bad topic") - .setData(ByteString.copyFromUtf8("\"\"")) - .setDataContentType("application/json") - .build()) - .build()); + .setEventMessage(DaprAppCallbackProtos.TopicEventRequest.newBuilder() + .setId(UUID.randomUUID().toString()) + .setPubsubName("bad pubsub") + .setTopic("bad topic") + .setData(ByteString.copyFromUtf8("\"\"")) + .setDataContentType("application/json") + .build()) + .build()); } observer.onCompleted(); }); @@ -517,38 +517,38 @@ public void onCompleted() { final AtomicInteger errorsToBeEmitted = new AtomicInteger(numErrors); var subscription = previewClient.subscribeToEvents( - "pubsubname", - "topic", - new SubscriptionListener<>() { - @Override - public Mono onEvent(CloudEvent event) { - if (event.getPubsubName().equals(pubsubName) && + "pubsubname", + "topic", + new SubscriptionListener<>() { + @Override + public Mono onEvent(CloudEvent event) { + if (event.getPubsubName().equals(pubsubName) && event.getTopic().equals(topicName) && event.getData().equals(data)) { - // Simulate an error - if ((success.size() == 4 /* some random entry */) && errorsToBeEmitted.decrementAndGet() >= 0) { - throw new RuntimeException("simulated exception on event " + event.getId()); - } + // Simulate an error + if ((success.size() == 4 /* some random entry */) && errorsToBeEmitted.decrementAndGet() >= 0) { + throw new RuntimeException("simulated exception on event " + event.getId()); + } - success.add(event.getId()); - if (success.size() >= numEvents) { - gotAll.release(); + success.add(event.getId()); + if (success.size() >= numEvents) { + gotAll.release(); + } + return Mono.just(Status.SUCCESS); } - return Mono.just(Status.SUCCESS); - } - dropCounter.incrementAndGet(); - return Mono.just(Status.DROP); - } + dropCounter.incrementAndGet(); + return Mono.just(Status.DROP); + } - @Override - public void onError(RuntimeException exception) { - errors.add(exception.getMessage()); - } + @Override + public void onError(RuntimeException exception) { + errors.add(exception.getMessage()); + } - }, - TypeRef.STRING); + }, + TypeRef.STRING); gotAll.acquire(); subscription.close(); @@ -846,15 +846,15 @@ public void deleteJobShouldThrowWhenNameIsEmptyRequest() { } private DaprProtos.QueryStateResponse buildQueryStateResponse(List> resp,String token) - throws JsonProcessingException { + throws JsonProcessingException { List items = new ArrayList<>(); for (QueryStateItem item: resp) { items.add(buildQueryStateItem(item)); } return DaprProtos.QueryStateResponse.newBuilder() - .addAllResults(items) - .setToken(token) - .build(); + .addAllResults(items) + .setToken(token) + .build(); } private DaprProtos.QueryStateItem buildQueryStateItem(QueryStateItem item) throws JsonProcessingException { From 68568c5f682381f999bda134dcd37a2e83afa5cb Mon Sep 17 00:00:00 2001 From: siri-varma Date: Sat, 12 Apr 2025 10:41:39 +0530 Subject: [PATCH 25/30] indent to spaces Signed-off-by: siri-varma --- .../client/DaprPreviewClientGrpcTest.java | 1556 ++++++++--------- 1 file changed, 778 insertions(+), 778 deletions(-) diff --git a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java index bbb162bd59..aec0f287ae 100644 --- a/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprPreviewClientGrpcTest.java @@ -88,790 +88,790 @@ public class DaprPreviewClientGrpcTest { - private static final ObjectMapper MAPPER = new ObjectMapper(); - - private static final String QUERY_STORE_NAME = "testQueryStore"; - - private static final String PUBSUB_NAME = "testPubsub"; - - private static final String TOPIC_NAME = "testTopic"; - - private static final String LOCK_STORE_NAME = "MyLockStore"; - - private GrpcChannelFacade channel; - private DaprGrpc.DaprStub daprStub; - private DaprHttp daprHttp; - private DaprPreviewClient previewClient; - - @BeforeEach - public void setup() throws IOException { - channel = mock(GrpcChannelFacade.class); - daprStub = mock(DaprGrpc.DaprStub.class); - daprHttp = mock(DaprHttp.class); - when(daprStub.withInterceptors(any())).thenReturn(daprStub); - previewClient = new DaprClientImpl( - channel, daprStub, daprHttp, new DefaultObjectSerializer(), new DefaultObjectSerializer()); - doNothing().when(channel).close(); - } - - @AfterEach - public void tearDown() throws Exception { - previewClient.close(); - verify(channel).close(); - verifyNoMoreInteractions(channel); - } - - @Test - public void publishEventsExceptionThrownTest() { - doAnswer((Answer) invocation -> { - throw newStatusRuntimeException("INVALID_ARGUMENT", "bad bad argument"); - }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); - - assertThrowsDaprException( - StatusRuntimeException.class, - "INVALID_ARGUMENT", - "INVALID_ARGUMENT: bad bad argument", - () -> previewClient.publishEvents(new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.EMPTY_LIST)).block()); - } - - @Test - public void publishEventsCallbackExceptionThrownTest() { - doAnswer((Answer) invocation -> { - StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; - observer.onError(newStatusRuntimeException("INVALID_ARGUMENT", "bad bad argument")); - return null; - }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); - - assertThrowsDaprException( - ExecutionException.class, - "INVALID_ARGUMENT", - "INVALID_ARGUMENT: bad bad argument", - () -> previewClient.publishEvents(new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.EMPTY_LIST)).block()); - } - - @Test - public void publishEventsContentTypeMismatchException() throws IOException { - DaprObjectSerializer mockSerializer = mock(DaprObjectSerializer.class); - doAnswer((Answer) invocation -> { - StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; - observer.onNext(DaprProtos.BulkPublishResponse.getDefaultInstance()); - observer.onCompleted(); - return null; - }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); - - - BulkPublishEntry entry = new BulkPublishEntry<>("1", "testEntry" - , "application/octet-stream", null); - BulkPublishRequest wrongReq = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.singletonList(entry)); + private static final ObjectMapper MAPPER = new ObjectMapper(); + + private static final String QUERY_STORE_NAME = "testQueryStore"; + + private static final String PUBSUB_NAME = "testPubsub"; + + private static final String TOPIC_NAME = "testTopic"; + + private static final String LOCK_STORE_NAME = "MyLockStore"; + + private GrpcChannelFacade channel; + private DaprGrpc.DaprStub daprStub; + private DaprHttp daprHttp; + private DaprPreviewClient previewClient; + + @BeforeEach + public void setup() throws IOException { + channel = mock(GrpcChannelFacade.class); + daprStub = mock(DaprGrpc.DaprStub.class); + daprHttp = mock(DaprHttp.class); + when(daprStub.withInterceptors(any())).thenReturn(daprStub); + previewClient = new DaprClientImpl( + channel, daprStub, daprHttp, new DefaultObjectSerializer(), new DefaultObjectSerializer()); + doNothing().when(channel).close(); + } + + @AfterEach + public void tearDown() throws Exception { + previewClient.close(); + verify(channel).close(); + verifyNoMoreInteractions(channel); + } + + @Test + public void publishEventsExceptionThrownTest() { + doAnswer((Answer) invocation -> { + throw newStatusRuntimeException("INVALID_ARGUMENT", "bad bad argument"); + }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); + + assertThrowsDaprException( + StatusRuntimeException.class, + "INVALID_ARGUMENT", + "INVALID_ARGUMENT: bad bad argument", + () -> previewClient.publishEvents(new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, + Collections.EMPTY_LIST)).block()); + } + + @Test + public void publishEventsCallbackExceptionThrownTest() { + doAnswer((Answer) invocation -> { + StreamObserver observer = + (StreamObserver) invocation.getArguments()[1]; + observer.onError(newStatusRuntimeException("INVALID_ARGUMENT", "bad bad argument")); + return null; + }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); + + assertThrowsDaprException( + ExecutionException.class, + "INVALID_ARGUMENT", + "INVALID_ARGUMENT: bad bad argument", + () -> previewClient.publishEvents(new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, + Collections.EMPTY_LIST)).block()); + } + + @Test + public void publishEventsContentTypeMismatchException() throws IOException { + DaprObjectSerializer mockSerializer = mock(DaprObjectSerializer.class); + doAnswer((Answer) invocation -> { + StreamObserver observer = + (StreamObserver) invocation.getArguments()[1]; + observer.onNext(DaprProtos.BulkPublishResponse.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); + + + BulkPublishEntry entry = new BulkPublishEntry<>("1", "testEntry" + , "application/octet-stream", null); + BulkPublishRequest wrongReq = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, + Collections.singletonList(entry)); assertThrows(IllegalArgumentException.class, () -> previewClient.publishEvents(wrongReq).block()); - } - - @Test - public void publishEventsSerializeException() throws IOException { - DaprObjectSerializer mockSerializer = mock(DaprObjectSerializer.class); - previewClient = new DaprClientImpl(channel, daprStub, daprHttp, mockSerializer, new DefaultObjectSerializer()); - doAnswer((Answer) invocation -> { - StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; - observer.onNext(DaprProtos.BulkPublishResponse.getDefaultInstance()); - observer.onCompleted(); - return null; - }).when(daprStub).publishEvent(any(DaprProtos.PublishEventRequest.class), any()); - BulkPublishEntry> entry = new BulkPublishEntry<>("1", new HashMap<>(), - "application/json", null); - BulkPublishRequest> req = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.singletonList(entry)); - when(mockSerializer.serialize(any())).thenThrow(IOException.class); - Mono>> result = previewClient.publishEvents(req); - - assertThrowsDaprException( - IOException.class, - "UNKNOWN", - "UNKNOWN: ", - () -> result.block()); - } - - @Test - public void publishEventsTest() { - doAnswer((Answer) invocation -> { - StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; - DaprProtos.BulkPublishResponse.Builder builder = DaprProtos.BulkPublishResponse.newBuilder(); - observer.onNext(builder.build()); - observer.onCompleted(); - return null; - }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); - - BulkPublishEntry entry = new BulkPublishEntry<>("1", "test", - "text/plain", null); - BulkPublishRequest req = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.singletonList(entry)); - Mono> result = previewClient.publishEvents(req); - BulkPublishResponse res = result.block(); - Assertions.assertNotNull(res); - assertEquals( 0, res.getFailedEntries().size(), "expected no entry in failed entries list"); - } - - @Test - public void publishEventsWithoutMetaTest() { - doAnswer((Answer) invocation -> { - StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; - DaprProtos.BulkPublishResponse.Builder builder = DaprProtos.BulkPublishResponse.newBuilder(); - observer.onNext(builder.build()); - observer.onCompleted(); - return null; - }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); - - Mono> result = previewClient.publishEvents(PUBSUB_NAME, TOPIC_NAME, - "text/plain", Collections.singletonList("test")); - BulkPublishResponse res = result.block(); - Assertions.assertNotNull(res); - assertEquals( 0, res.getFailedEntries().size(), "expected no entries in failed entries list"); - } - - @Test - public void publishEventsWithRequestMetaTest() { - doAnswer((Answer) invocation -> { - StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; - DaprProtos.BulkPublishResponse.Builder builder = DaprProtos.BulkPublishResponse.newBuilder(); - observer.onNext(builder.build()); - observer.onCompleted(); - return null; - }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); - - Mono> result = previewClient.publishEvents(PUBSUB_NAME, TOPIC_NAME, - "text/plain", new HashMap(){{ - put("ttlInSeconds", "123"); - }}, Collections.singletonList("test")); - BulkPublishResponse res = result.block(); - Assertions.assertNotNull(res); - assertEquals( 0, res.getFailedEntries().size(), "expected no entry in failed entries list"); - } - - @Test - public void publishEventsObjectTest() { - doAnswer((Answer) invocation -> { - StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; - observer.onNext(DaprProtos.BulkPublishResponse.getDefaultInstance()); - observer.onCompleted(); - return null; - }).when(daprStub).bulkPublishEventAlpha1(ArgumentMatchers.argThat(bulkPublishRequest -> { - DaprProtos.BulkPublishRequestEntry entry = bulkPublishRequest.getEntries(0); - if (!"application/json".equals(bulkPublishRequest.getEntries(0).getContentType())) { - return false; - } - - if (!"{\"id\":1,\"value\":\"Event\"}".equals(new String(entry.getEvent().toByteArray())) && - !"{\"value\":\"Event\",\"id\":1}".equals(new String(entry.getEvent().toByteArray()))) { - return false; - } - return true; - }), any()); - - - DaprClientGrpcTest.MyObject event = new DaprClientGrpcTest.MyObject(1, "Event"); - BulkPublishEntry entry = new BulkPublishEntry<>("1", event, - "application/json", null); - BulkPublishRequest req = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.singletonList(entry)); - BulkPublishResponse result = previewClient.publishEvents(req).block(); - Assertions.assertNotNull(result); - Assertions.assertEquals(0, result.getFailedEntries().size(), "expected no entries to be failed"); - } - - @Test - public void publishEventsContentTypeOverrideTest() { - doAnswer((Answer) invocation -> { - StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; - observer.onNext(DaprProtos.BulkPublishResponse.getDefaultInstance()); - observer.onCompleted(); - return null; - }).when(daprStub).bulkPublishEventAlpha1(ArgumentMatchers.argThat(bulkPublishRequest -> { - DaprProtos.BulkPublishRequestEntry entry = bulkPublishRequest.getEntries(0); - if (!"application/json".equals(entry.getContentType())) { - return false; - } - - if (!"\"hello\"".equals(new String(entry.getEvent().toByteArray()))) { - return false; - } - return true; - }), any()); - - BulkPublishEntry entry = new BulkPublishEntry<>("1", "hello", - "", null); - BulkPublishRequest req = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, - Collections.singletonList(entry)); - BulkPublishResponse result = previewClient.publishEvents(req).block(); - Assertions.assertNotNull(result); - Assertions.assertEquals( 0, result.getFailedEntries().size(), "expected no entries to be failed"); - } - - @Test - public void queryStateExceptionsTest() { - assertThrows(IllegalArgumentException.class, () -> { - previewClient.queryState("", "query", String.class).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - previewClient.queryState("storeName", "", String.class).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - previewClient.queryState("storeName", (Query) null, String.class).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - previewClient.queryState("storeName", (String) null, String.class).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - previewClient.queryState(new QueryStateRequest("storeName"), String.class).block(); - }); - assertThrows(IllegalArgumentException.class, () -> { - previewClient.queryState(null, String.class).block(); - }); - } - - @Test - public void queryState() throws JsonProcessingException { - List> resp = new ArrayList<>(); - resp.add(new QueryStateItem("1", (Object)"testData", "6f54ad94-dfb9-46f0-a371-e42d550adb7d")); - DaprProtos.QueryStateResponse responseEnvelope = buildQueryStateResponse(resp, ""); - doAnswer(invocation -> { - DaprProtos.QueryStateRequest req = (DaprProtos.QueryStateRequest) invocation.getArgument(0); - assertEquals(QUERY_STORE_NAME, req.getStoreName()); - assertEquals("query", req.getQuery()); - assertEquals(0, req.getMetadataCount()); - - StreamObserver observer = (StreamObserver) - invocation.getArguments()[1]; - observer.onNext(responseEnvelope); - observer.onCompleted(); - return null; - }).when(daprStub).queryStateAlpha1(any(DaprProtos.QueryStateRequest.class), any()); - - QueryStateResponse response = previewClient.queryState(QUERY_STORE_NAME, "query", String.class).block(); - assertNotNull(response); - assertEquals(1, response.getResults().size(), "result size must be 1"); - assertEquals("1", response.getResults().get(0).getKey(), "result must be same"); - assertEquals("testData", response.getResults().get(0).getValue(), "result must be same"); - assertEquals("6f54ad94-dfb9-46f0-a371-e42d550adb7d", response.getResults().get(0).getEtag(), "result must be same"); - } - - @Test - public void queryStateMetadataError() throws JsonProcessingException { - List> resp = new ArrayList<>(); - resp.add(new QueryStateItem("1", null, "error data")); - DaprProtos.QueryStateResponse responseEnvelope = buildQueryStateResponse(resp, ""); - doAnswer(invocation -> { - DaprProtos.QueryStateRequest req = (DaprProtos.QueryStateRequest) invocation.getArgument(0); - assertEquals(QUERY_STORE_NAME, req.getStoreName()); - assertEquals("query", req.getQuery()); - assertEquals(1, req.getMetadataCount()); - assertEquals(1, req.getMetadataCount()); - - StreamObserver observer = (StreamObserver) - invocation.getArguments()[1]; - observer.onNext(responseEnvelope); - observer.onCompleted(); - return null; - }).when(daprStub).queryStateAlpha1(any(DaprProtos.QueryStateRequest.class), any()); - - QueryStateResponse response = previewClient.queryState(QUERY_STORE_NAME, "query", - new HashMap(){{ put("key", "error"); }}, String.class).block(); - assertNotNull(response); - assertEquals(1, response.getResults().size(), "result size must be 1"); - assertEquals( "1", response.getResults().get(0).getKey(), "result must be same"); - assertEquals( "error data", response.getResults().get(0).getError(), "result must be same"); - } - - @Test - public void tryLock() { - - DaprProtos.TryLockResponse.Builder builder = DaprProtos.TryLockResponse.newBuilder() - .setSuccess(true); - - DaprProtos.TryLockResponse response = builder.build(); - - doAnswer((Answer) invocation -> { - DaprProtos.TryLockRequest req = invocation.getArgument(0); - assertEquals(LOCK_STORE_NAME, req.getStoreName()); - assertEquals("1", req.getResourceId()); - assertEquals("owner", req.getLockOwner()); - assertEquals(10, req.getExpiryInSeconds()); - - StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; - observer.onNext(response); - observer.onCompleted(); - return null; - }).when(daprStub).tryLockAlpha1(any(DaprProtos.TryLockRequest.class), any()); - - Boolean result = previewClient.tryLock("MyLockStore", "1", "owner", 10).block(); - assertEquals(Boolean.TRUE, result); - } - - @Test - public void unLock() { - - DaprProtos.UnlockResponse.Builder builder = DaprProtos.UnlockResponse.newBuilder() - .setStatus(DaprProtos.UnlockResponse.Status.SUCCESS); - - DaprProtos.UnlockResponse response = builder.build(); - - doAnswer((Answer) invocation -> { - DaprProtos.UnlockRequest req = invocation.getArgument(0); - assertEquals(LOCK_STORE_NAME, req.getStoreName()); - assertEquals("1", req.getResourceId()); - assertEquals("owner", req.getLockOwner()); - - StreamObserver observer = - (StreamObserver) invocation.getArguments()[1]; - observer.onNext(response); - observer.onCompleted(); - return null; - }).when(daprStub).unlockAlpha1(any(DaprProtos.UnlockRequest.class), any()); - - UnlockResponseStatus result = previewClient.unlock("MyLockStore", "1", "owner").block(); - assertEquals(UnlockResponseStatus.SUCCESS, result); - } - - @Test - public void subscribeEventTest() throws Exception { - var numEvents = 100; - var numErrors = 3; - var numDrops = 2; - - var pubsubName = "pubsubName"; - var topicName = "topicName"; - var data = "my message"; - - var started = new Semaphore(0); - - doAnswer((Answer>) invocation -> { - StreamObserver observer = - (StreamObserver) invocation.getArguments()[0]; - var emitterThread = new Thread(() -> { + } + + @Test + public void publishEventsSerializeException() throws IOException { + DaprObjectSerializer mockSerializer = mock(DaprObjectSerializer.class); + previewClient = new DaprClientImpl(channel, daprStub, daprHttp, mockSerializer, new DefaultObjectSerializer()); + doAnswer((Answer) invocation -> { + StreamObserver observer = + (StreamObserver) invocation.getArguments()[1]; + observer.onNext(DaprProtos.BulkPublishResponse.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).publishEvent(any(DaprProtos.PublishEventRequest.class), any()); + BulkPublishEntry> entry = new BulkPublishEntry<>("1", new HashMap<>(), + "application/json", null); + BulkPublishRequest> req = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, + Collections.singletonList(entry)); + when(mockSerializer.serialize(any())).thenThrow(IOException.class); + Mono>> result = previewClient.publishEvents(req); + + assertThrowsDaprException( + IOException.class, + "UNKNOWN", + "UNKNOWN: ", + () -> result.block()); + } + + @Test + public void publishEventsTest() { + doAnswer((Answer) invocation -> { + StreamObserver observer = + (StreamObserver) invocation.getArguments()[1]; + DaprProtos.BulkPublishResponse.Builder builder = DaprProtos.BulkPublishResponse.newBuilder(); + observer.onNext(builder.build()); + observer.onCompleted(); + return null; + }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); + + BulkPublishEntry entry = new BulkPublishEntry<>("1", "test", + "text/plain", null); + BulkPublishRequest req = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, + Collections.singletonList(entry)); + Mono> result = previewClient.publishEvents(req); + BulkPublishResponse res = result.block(); + Assertions.assertNotNull(res); + assertEquals( 0, res.getFailedEntries().size(), "expected no entry in failed entries list"); + } + + @Test + public void publishEventsWithoutMetaTest() { + doAnswer((Answer) invocation -> { + StreamObserver observer = + (StreamObserver) invocation.getArguments()[1]; + DaprProtos.BulkPublishResponse.Builder builder = DaprProtos.BulkPublishResponse.newBuilder(); + observer.onNext(builder.build()); + observer.onCompleted(); + return null; + }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); + + Mono> result = previewClient.publishEvents(PUBSUB_NAME, TOPIC_NAME, + "text/plain", Collections.singletonList("test")); + BulkPublishResponse res = result.block(); + Assertions.assertNotNull(res); + assertEquals( 0, res.getFailedEntries().size(), "expected no entries in failed entries list"); + } + + @Test + public void publishEventsWithRequestMetaTest() { + doAnswer((Answer) invocation -> { + StreamObserver observer = + (StreamObserver) invocation.getArguments()[1]; + DaprProtos.BulkPublishResponse.Builder builder = DaprProtos.BulkPublishResponse.newBuilder(); + observer.onNext(builder.build()); + observer.onCompleted(); + return null; + }).when(daprStub).bulkPublishEventAlpha1(any(DaprProtos.BulkPublishRequest.class), any()); + + Mono> result = previewClient.publishEvents(PUBSUB_NAME, TOPIC_NAME, + "text/plain", new HashMap(){{ + put("ttlInSeconds", "123"); + }}, Collections.singletonList("test")); + BulkPublishResponse res = result.block(); + Assertions.assertNotNull(res); + assertEquals( 0, res.getFailedEntries().size(), "expected no entry in failed entries list"); + } + + @Test + public void publishEventsObjectTest() { + doAnswer((Answer) invocation -> { + StreamObserver observer = + (StreamObserver) invocation.getArguments()[1]; + observer.onNext(DaprProtos.BulkPublishResponse.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).bulkPublishEventAlpha1(ArgumentMatchers.argThat(bulkPublishRequest -> { + DaprProtos.BulkPublishRequestEntry entry = bulkPublishRequest.getEntries(0); + if (!"application/json".equals(bulkPublishRequest.getEntries(0).getContentType())) { + return false; + } + + if (!"{\"id\":1,\"value\":\"Event\"}".equals(new String(entry.getEvent().toByteArray())) && + !"{\"value\":\"Event\",\"id\":1}".equals(new String(entry.getEvent().toByteArray()))) { + return false; + } + return true; + }), any()); + + + DaprClientGrpcTest.MyObject event = new DaprClientGrpcTest.MyObject(1, "Event"); + BulkPublishEntry entry = new BulkPublishEntry<>("1", event, + "application/json", null); + BulkPublishRequest req = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, + Collections.singletonList(entry)); + BulkPublishResponse result = previewClient.publishEvents(req).block(); + Assertions.assertNotNull(result); + Assertions.assertEquals(0, result.getFailedEntries().size(), "expected no entries to be failed"); + } + + @Test + public void publishEventsContentTypeOverrideTest() { + doAnswer((Answer) invocation -> { + StreamObserver observer = + (StreamObserver) invocation.getArguments()[1]; + observer.onNext(DaprProtos.BulkPublishResponse.getDefaultInstance()); + observer.onCompleted(); + return null; + }).when(daprStub).bulkPublishEventAlpha1(ArgumentMatchers.argThat(bulkPublishRequest -> { + DaprProtos.BulkPublishRequestEntry entry = bulkPublishRequest.getEntries(0); + if (!"application/json".equals(entry.getContentType())) { + return false; + } + + if (!"\"hello\"".equals(new String(entry.getEvent().toByteArray()))) { + return false; + } + return true; + }), any()); + + BulkPublishEntry entry = new BulkPublishEntry<>("1", "hello", + "", null); + BulkPublishRequest req = new BulkPublishRequest<>(PUBSUB_NAME, TOPIC_NAME, + Collections.singletonList(entry)); + BulkPublishResponse result = previewClient.publishEvents(req).block(); + Assertions.assertNotNull(result); + Assertions.assertEquals( 0, result.getFailedEntries().size(), "expected no entries to be failed"); + } + + @Test + public void queryStateExceptionsTest() { + assertThrows(IllegalArgumentException.class, () -> { + previewClient.queryState("", "query", String.class).block(); + }); + assertThrows(IllegalArgumentException.class, () -> { + previewClient.queryState("storeName", "", String.class).block(); + }); + assertThrows(IllegalArgumentException.class, () -> { + previewClient.queryState("storeName", (Query) null, String.class).block(); + }); + assertThrows(IllegalArgumentException.class, () -> { + previewClient.queryState("storeName", (String) null, String.class).block(); + }); + assertThrows(IllegalArgumentException.class, () -> { + previewClient.queryState(new QueryStateRequest("storeName"), String.class).block(); + }); + assertThrows(IllegalArgumentException.class, () -> { + previewClient.queryState(null, String.class).block(); + }); + } + + @Test + public void queryState() throws JsonProcessingException { + List> resp = new ArrayList<>(); + resp.add(new QueryStateItem("1", (Object)"testData", "6f54ad94-dfb9-46f0-a371-e42d550adb7d")); + DaprProtos.QueryStateResponse responseEnvelope = buildQueryStateResponse(resp, ""); + doAnswer(invocation -> { + DaprProtos.QueryStateRequest req = (DaprProtos.QueryStateRequest) invocation.getArgument(0); + assertEquals(QUERY_STORE_NAME, req.getStoreName()); + assertEquals("query", req.getQuery()); + assertEquals(0, req.getMetadataCount()); + + StreamObserver observer = (StreamObserver) + invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).queryStateAlpha1(any(DaprProtos.QueryStateRequest.class), any()); + + QueryStateResponse response = previewClient.queryState(QUERY_STORE_NAME, "query", String.class).block(); + assertNotNull(response); + assertEquals(1, response.getResults().size(), "result size must be 1"); + assertEquals("1", response.getResults().get(0).getKey(), "result must be same"); + assertEquals("testData", response.getResults().get(0).getValue(), "result must be same"); + assertEquals("6f54ad94-dfb9-46f0-a371-e42d550adb7d", response.getResults().get(0).getEtag(), "result must be same"); + } + + @Test + public void queryStateMetadataError() throws JsonProcessingException { + List> resp = new ArrayList<>(); + resp.add(new QueryStateItem("1", null, "error data")); + DaprProtos.QueryStateResponse responseEnvelope = buildQueryStateResponse(resp, ""); + doAnswer(invocation -> { + DaprProtos.QueryStateRequest req = (DaprProtos.QueryStateRequest) invocation.getArgument(0); + assertEquals(QUERY_STORE_NAME, req.getStoreName()); + assertEquals("query", req.getQuery()); + assertEquals(1, req.getMetadataCount()); + assertEquals(1, req.getMetadataCount()); + + StreamObserver observer = (StreamObserver) + invocation.getArguments()[1]; + observer.onNext(responseEnvelope); + observer.onCompleted(); + return null; + }).when(daprStub).queryStateAlpha1(any(DaprProtos.QueryStateRequest.class), any()); + + QueryStateResponse response = previewClient.queryState(QUERY_STORE_NAME, "query", + new HashMap(){{ put("key", "error"); }}, String.class).block(); + assertNotNull(response); + assertEquals(1, response.getResults().size(), "result size must be 1"); + assertEquals( "1", response.getResults().get(0).getKey(), "result must be same"); + assertEquals( "error data", response.getResults().get(0).getError(), "result must be same"); + } + + @Test + public void tryLock() { + + DaprProtos.TryLockResponse.Builder builder = DaprProtos.TryLockResponse.newBuilder() + .setSuccess(true); + + DaprProtos.TryLockResponse response = builder.build(); + + doAnswer((Answer) invocation -> { + DaprProtos.TryLockRequest req = invocation.getArgument(0); + assertEquals(LOCK_STORE_NAME, req.getStoreName()); + assertEquals("1", req.getResourceId()); + assertEquals("owner", req.getLockOwner()); + assertEquals(10, req.getExpiryInSeconds()); + + StreamObserver observer = + (StreamObserver) invocation.getArguments()[1]; + observer.onNext(response); + observer.onCompleted(); + return null; + }).when(daprStub).tryLockAlpha1(any(DaprProtos.TryLockRequest.class), any()); + + Boolean result = previewClient.tryLock("MyLockStore", "1", "owner", 10).block(); + assertEquals(Boolean.TRUE, result); + } + + @Test + public void unLock() { + + DaprProtos.UnlockResponse.Builder builder = DaprProtos.UnlockResponse.newBuilder() + .setStatus(DaprProtos.UnlockResponse.Status.SUCCESS); + + DaprProtos.UnlockResponse response = builder.build(); + + doAnswer((Answer) invocation -> { + DaprProtos.UnlockRequest req = invocation.getArgument(0); + assertEquals(LOCK_STORE_NAME, req.getStoreName()); + assertEquals("1", req.getResourceId()); + assertEquals("owner", req.getLockOwner()); + + StreamObserver observer = + (StreamObserver) invocation.getArguments()[1]; + observer.onNext(response); + observer.onCompleted(); + return null; + }).when(daprStub).unlockAlpha1(any(DaprProtos.UnlockRequest.class), any()); + + UnlockResponseStatus result = previewClient.unlock("MyLockStore", "1", "owner").block(); + assertEquals(UnlockResponseStatus.SUCCESS, result); + } + + @Test + public void subscribeEventTest() throws Exception { + var numEvents = 100; + var numErrors = 3; + var numDrops = 2; + + var pubsubName = "pubsubName"; + var topicName = "topicName"; + var data = "my message"; + + var started = new Semaphore(0); + + doAnswer((Answer>) invocation -> { + StreamObserver observer = + (StreamObserver) invocation.getArguments()[0]; + var emitterThread = new Thread(() -> { try { started.acquire(); } catch (InterruptedException e) { throw new RuntimeException(e); } observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.getDefaultInstance()); - for (int i = 0; i < numEvents; i++) { - observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.newBuilder() - .setEventMessage(DaprAppCallbackProtos.TopicEventRequest.newBuilder() - .setId(Integer.toString(i)) - .setPubsubName(pubsubName) - .setTopic(topicName) - .setData(ByteString.copyFromUtf8("\"" + data + "\"")) - .setDataContentType("application/json") - .build()) - .build()); - } - - for (int i = 0; i < numDrops; i++) { - // Bad messages - observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.newBuilder() - .setEventMessage(DaprAppCallbackProtos.TopicEventRequest.newBuilder() - .setId(UUID.randomUUID().toString()) - .setPubsubName("bad pubsub") - .setTopic("bad topic") - .setData(ByteString.copyFromUtf8("\"\"")) - .setDataContentType("application/json") - .build()) - .build()); - } - observer.onCompleted(); - }); - emitterThread.start(); - return new StreamObserver<>() { - - @Override - public void onNext(DaprProtos.SubscribeTopicEventsRequestAlpha1 subscribeTopicEventsRequestAlpha1) { - started.release(); - } - - @Override - public void onError(Throwable throwable) { - } - - @Override - public void onCompleted() { - } - }; - }).when(daprStub).subscribeTopicEventsAlpha1(any(StreamObserver.class)); - - final Set success = Collections.synchronizedSet(new HashSet<>()); - final Set errors = Collections.synchronizedSet(new HashSet<>()); - final AtomicInteger dropCounter = new AtomicInteger(); - final Semaphore gotAll = new Semaphore(0); - - final AtomicInteger errorsToBeEmitted = new AtomicInteger(numErrors); - - var subscription = previewClient.subscribeToEvents( - "pubsubname", - "topic", - new SubscriptionListener<>() { - @Override - public Mono onEvent(CloudEvent event) { - if (event.getPubsubName().equals(pubsubName) && - event.getTopic().equals(topicName) && - event.getData().equals(data)) { - - // Simulate an error - if ((success.size() == 4 /* some random entry */) && errorsToBeEmitted.decrementAndGet() >= 0) { - throw new RuntimeException("simulated exception on event " + event.getId()); - } - - success.add(event.getId()); - if (success.size() >= numEvents) { - gotAll.release(); - } - return Mono.just(Status.SUCCESS); - } - - dropCounter.incrementAndGet(); - return Mono.just(Status.DROP); - } - - @Override - public void onError(RuntimeException exception) { - errors.add(exception.getMessage()); - } - - }, - TypeRef.STRING); - - gotAll.acquire(); - subscription.close(); - - assertEquals(numEvents, success.size()); - assertEquals(numDrops, dropCounter.get()); - assertEquals(numErrors, errors.size()); - } - - @Test - public void scheduleJobShouldSucceedWhenAllFieldsArePresentInRequest() { - DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") - .withZone(ZoneOffset.UTC); - - ScheduleJobRequest expectedScheduleJobRequest = new ScheduleJobRequest("testJob", - JobSchedule.fromString("*/5 * * * *")) - .setData("testData".getBytes()) - .setTtl(Instant.now().plus(1, ChronoUnit.DAYS)) - .setRepeat(5) - .setDueTime(Instant.now().plus(10, ChronoUnit.MINUTES)); - - doAnswer(invocation -> { - StreamObserver observer = invocation.getArgument(1); - observer.onCompleted(); // Simulate successful response - return null; - }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any()); - - assertDoesNotThrow(() -> previewClient.scheduleJob(expectedScheduleJobRequest).block()); - - ArgumentCaptor captor = - ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); - - verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any()); - DaprProtos.ScheduleJobRequest actualScheduleJobReq = captor.getValue(); - - assertEquals("testJob", actualScheduleJobReq.getJob().getName()); - assertEquals("testData", - new String(actualScheduleJobReq.getJob().getData().getValue().toByteArray(), StandardCharsets.UTF_8)); - assertEquals("*/5 * * * *", actualScheduleJobReq.getJob().getSchedule()); - assertEquals(iso8601Formatter.format(expectedScheduleJobRequest.getTtl()), actualScheduleJobReq.getJob().getTtl()); - assertEquals(expectedScheduleJobRequest.getRepeats(), actualScheduleJobReq.getJob().getRepeats()); - assertEquals(iso8601Formatter.format(expectedScheduleJobRequest.getDueTime()), actualScheduleJobReq.getJob().getDueTime()); - } - - @Test - public void scheduleJobShouldSucceedWhenRequiredFieldsNameAndDueTimeArePresentInRequest() { - DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") - .withZone(ZoneOffset.UTC); - - doAnswer(invocation -> { - StreamObserver observer = invocation.getArgument(1); - observer.onCompleted(); // Simulate successful response - return null; - }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any()); - - ScheduleJobRequest expectedScheduleJobRequest = - new ScheduleJobRequest("testJob", Instant.now().plus(10, ChronoUnit.MINUTES)); - assertDoesNotThrow(() -> previewClient.scheduleJob(expectedScheduleJobRequest).block()); - - ArgumentCaptor captor = - ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); - - verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any()); - DaprProtos.ScheduleJobRequest actualScheduleJobRequest = captor.getValue(); - DaprProtos.Job job = actualScheduleJobRequest.getJob(); - assertEquals("testJob", job.getName()); - assertFalse(job.hasData()); - assertFalse(job.hasSchedule()); - assertEquals(0, job.getRepeats()); - assertFalse(job.hasTtl()); - assertEquals(iso8601Formatter.format(expectedScheduleJobRequest.getDueTime()), - actualScheduleJobRequest.getJob().getDueTime()); - } - - @Test - public void scheduleJobShouldSucceedWhenRequiredFieldsNameAndScheduleArePresentInRequest() { - DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") - .withZone(ZoneOffset.UTC); - - doAnswer(invocation -> { - StreamObserver observer = invocation.getArgument(1); - observer.onCompleted(); // Simulate successful response - return null; - }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any()); - - ScheduleJobRequest expectedScheduleJobRequest = new ScheduleJobRequest("testJob", - JobSchedule.fromString("* * * * * *")); - assertDoesNotThrow(() -> previewClient.scheduleJob(expectedScheduleJobRequest).block()); - - ArgumentCaptor captor = - ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); - - verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any()); - DaprProtos.ScheduleJobRequest actualScheduleJobRequest = captor.getValue(); - DaprProtos.Job job = actualScheduleJobRequest.getJob(); - assertEquals("testJob", job.getName()); - assertFalse(job.hasData()); - assertEquals( "* * * * * *", job.getSchedule()); - assertEquals(0, job.getRepeats()); - assertFalse(job.hasTtl()); - } - - @Test - public void scheduleJobShouldThrowWhenRequestIsNull() { - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - previewClient.scheduleJob(null).block(); - }); - assertEquals("scheduleJobRequest cannot be null", exception.getMessage()); - } - - @Test - public void scheduleJobShouldThrowWhenInvalidRequest() { - ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest(null, Instant.now()); - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - previewClient.scheduleJob(scheduleJobRequest).block(); - }); - assertEquals("Name in the request cannot be null or empty", exception.getMessage()); - } - - @Test - public void scheduleJobShouldThrowWhenNameInRequestIsEmpty() { - ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest("", Instant.now()); - - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - previewClient.scheduleJob(scheduleJobRequest).block(); - }); - assertEquals("Name in the request cannot be null or empty", exception.getMessage()); - } - - @Test - public void getJobShouldReturnResponseWhenAllFieldsArePresentInRequest() { - DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") - .withZone(ZoneOffset.UTC); - - GetJobRequest getJobRequest = new GetJobRequest("testJob"); - - DaprProtos.Job job = DaprProtos.Job.newBuilder() - .setName("testJob") - .setTtl(OffsetDateTime.now().format(iso8601Formatter)) - .setData(Any.newBuilder().setValue(ByteString.copyFrom("testData".getBytes())).build()) - .setSchedule("*/5 * * * *") - .setRepeats(5) - .setDueTime(iso8601Formatter.format(Instant.now().plus(10, ChronoUnit.MINUTES))) - .build(); - - doAnswer(invocation -> { - StreamObserver observer = invocation.getArgument(1); - observer.onNext(DaprProtos.GetJobResponse.newBuilder() - .setJob(job) - .build()); - observer.onCompleted(); - return null; - }).when(daprStub).getJobAlpha1(any(DaprProtos.GetJobRequest.class), any()); - - Mono resultMono = previewClient.getJob(getJobRequest); - - GetJobResponse response = resultMono.block(); - assertNotNull(response); - assertEquals("testJob", response.getName()); - assertEquals("testData", new String(response.getData(), StandardCharsets.UTF_8)); - assertEquals("*/5 * * * *", response.getSchedule().getExpression()); - assertEquals(5, response.getRepeats()); - assertEquals(job.getTtl(), iso8601Formatter.format(response.getTtl())); - assertEquals(job.getDueTime(), iso8601Formatter.format(response.getDueTime())); - } - - @Test - public void getJobShouldReturnResponseWithScheduleSetWhenResponseHasSchedule() { - GetJobRequest getJobRequest = new GetJobRequest("testJob"); - - DaprProtos.Job job = DaprProtos.Job.newBuilder() - .setName("testJob") - .setSchedule("0 0 0 1 1 *") - .build(); - - doAnswer(invocation -> { - StreamObserver observer = invocation.getArgument(1); - observer.onNext(DaprProtos.GetJobResponse.newBuilder() - .setJob(job) - .build()); - observer.onCompleted(); - return null; - }).when(daprStub).getJobAlpha1(any(DaprProtos.GetJobRequest.class), any()); - - Mono resultMono = previewClient.getJob(getJobRequest); - - GetJobResponse response = resultMono.block(); - assertNotNull(response); - assertEquals("testJob", response.getName()); - assertNull(response.getData()); - assertEquals("0 0 0 1 1 *", response.getSchedule().getExpression()); - assertNull(response.getRepeats()); - assertNull(response.getTtl()); - assertNull(response.getDueTime()); - } - - @Test - public void getJobShouldReturnResponseWithDueTimeSetWhenResponseHasDueTime() { - GetJobRequest getJobRequest = new GetJobRequest("testJob"); - - String datetime = OffsetDateTime.now().toString(); - DaprProtos.Job job = DaprProtos.Job.newBuilder() - .setName("testJob") - .setDueTime(datetime) - .build(); - - doAnswer(invocation -> { - StreamObserver observer = invocation.getArgument(1); - observer.onNext(DaprProtos.GetJobResponse.newBuilder() - .setJob(job) - .build()); - observer.onCompleted(); - return null; - }).when(daprStub).getJobAlpha1(any(DaprProtos.GetJobRequest.class), any()); - - Mono resultMono = previewClient.getJob(getJobRequest); - - GetJobResponse response = resultMono.block(); - assertNotNull(response); - assertEquals("testJob", response.getName()); - assertNull(response.getData()); - assertNull(response.getSchedule()); - assertNull(response.getRepeats()); - assertNull(response.getTtl()); - assertEquals(job.getDueTime(), datetime); - } - - @Test - public void getJobShouldThrowWhenRequestIsNull() { - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - previewClient.getJob(null).block(); - }); - assertEquals("getJobRequest cannot be null", exception.getMessage()); - } - - @Test - public void getJobShouldThrowWhenNameIsNullRequest() { - GetJobRequest getJobRequest = new GetJobRequest(null); - - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - previewClient.getJob(getJobRequest).block(); - }); - assertEquals("Name in the request cannot be null or empty", exception.getMessage()); - } - - @Test - public void getJobShouldThrowWhenNameIsEmptyRequest() { - GetJobRequest getJobRequest =new GetJobRequest("");; - - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - previewClient.getJob(getJobRequest).block(); - }); - assertEquals("Name in the request cannot be null or empty", exception.getMessage()); - } - - @Test - public void deleteJobShouldSucceedWhenValidRequest() { - DeleteJobRequest deleteJobRequest = new DeleteJobRequest("testJob"); - - doAnswer(invocation -> { - StreamObserver observer = invocation.getArgument(1); - observer.onCompleted(); // Simulate successful response - return null; - }).when(daprStub).deleteJobAlpha1(any(DaprProtos.DeleteJobRequest.class), any()); - - Mono resultMono = previewClient.deleteJob(deleteJobRequest); - - assertDoesNotThrow(() -> resultMono.block()); - } - - @Test - public void deleteJobShouldThrowRequestIsNull() { - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - previewClient.deleteJob(null).block(); - }); - assertEquals("deleteJobRequest cannot be null", exception.getMessage()); - } - - @Test - public void deleteJobShouldThrowWhenNameIsNullRequest() { - DeleteJobRequest deleteJobRequest = new DeleteJobRequest(null); - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - previewClient.deleteJob(deleteJobRequest).block(); - }); - assertEquals("Name in the request cannot be null or empty", exception.getMessage()); - } - - @Test - public void deleteJobShouldThrowWhenNameIsEmptyRequest() { - DeleteJobRequest deleteJobRequest = new DeleteJobRequest(""); - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { - previewClient.deleteJob(deleteJobRequest).block(); - }); - assertEquals("Name in the request cannot be null or empty", exception.getMessage()); - } - - private DaprProtos.QueryStateResponse buildQueryStateResponse(List> resp,String token) - throws JsonProcessingException { - List items = new ArrayList<>(); - for (QueryStateItem item: resp) { - items.add(buildQueryStateItem(item)); - } - return DaprProtos.QueryStateResponse.newBuilder() - .addAllResults(items) - .setToken(token) - .build(); - } - - private DaprProtos.QueryStateItem buildQueryStateItem(QueryStateItem item) throws JsonProcessingException { - DaprProtos.QueryStateItem.Builder it = DaprProtos.QueryStateItem.newBuilder().setKey(item.getKey()); - if (item.getValue() != null) { - it.setData(ByteString.copyFrom(MAPPER.writeValueAsBytes(item.getValue()))); - } - if (item.getEtag() != null) { - it.setEtag(item.getEtag()); - } - if (item.getError() != null) { - it.setError(item.getError()); - } - return it.build(); - } - - private static StatusRuntimeException newStatusRuntimeException(String status, String message) { - return new StatusRuntimeException(Status.fromCode(Status.Code.valueOf(status)).withDescription(message)); - } + for (int i = 0; i < numEvents; i++) { + observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.newBuilder() + .setEventMessage(DaprAppCallbackProtos.TopicEventRequest.newBuilder() + .setId(Integer.toString(i)) + .setPubsubName(pubsubName) + .setTopic(topicName) + .setData(ByteString.copyFromUtf8("\"" + data + "\"")) + .setDataContentType("application/json") + .build()) + .build()); + } + + for (int i = 0; i < numDrops; i++) { + // Bad messages + observer.onNext(DaprProtos.SubscribeTopicEventsResponseAlpha1.newBuilder() + .setEventMessage(DaprAppCallbackProtos.TopicEventRequest.newBuilder() + .setId(UUID.randomUUID().toString()) + .setPubsubName("bad pubsub") + .setTopic("bad topic") + .setData(ByteString.copyFromUtf8("\"\"")) + .setDataContentType("application/json") + .build()) + .build()); + } + observer.onCompleted(); + }); + emitterThread.start(); + return new StreamObserver<>() { + + @Override + public void onNext(DaprProtos.SubscribeTopicEventsRequestAlpha1 subscribeTopicEventsRequestAlpha1) { + started.release(); + } + + @Override + public void onError(Throwable throwable) { + } + + @Override + public void onCompleted() { + } + }; + }).when(daprStub).subscribeTopicEventsAlpha1(any(StreamObserver.class)); + + final Set success = Collections.synchronizedSet(new HashSet<>()); + final Set errors = Collections.synchronizedSet(new HashSet<>()); + final AtomicInteger dropCounter = new AtomicInteger(); + final Semaphore gotAll = new Semaphore(0); + + final AtomicInteger errorsToBeEmitted = new AtomicInteger(numErrors); + + var subscription = previewClient.subscribeToEvents( + "pubsubname", + "topic", + new SubscriptionListener<>() { + @Override + public Mono onEvent(CloudEvent event) { + if (event.getPubsubName().equals(pubsubName) && + event.getTopic().equals(topicName) && + event.getData().equals(data)) { + + // Simulate an error + if ((success.size() == 4 /* some random entry */) && errorsToBeEmitted.decrementAndGet() >= 0) { + throw new RuntimeException("simulated exception on event " + event.getId()); + } + + success.add(event.getId()); + if (success.size() >= numEvents) { + gotAll.release(); + } + return Mono.just(Status.SUCCESS); + } + + dropCounter.incrementAndGet(); + return Mono.just(Status.DROP); + } + + @Override + public void onError(RuntimeException exception) { + errors.add(exception.getMessage()); + } + + }, + TypeRef.STRING); + + gotAll.acquire(); + subscription.close(); + + assertEquals(numEvents, success.size()); + assertEquals(numDrops, dropCounter.get()); + assertEquals(numErrors, errors.size()); + } + + @Test + public void scheduleJobShouldSucceedWhenAllFieldsArePresentInRequest() { + DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + .withZone(ZoneOffset.UTC); + + ScheduleJobRequest expectedScheduleJobRequest = new ScheduleJobRequest("testJob", + JobSchedule.fromString("*/5 * * * *")) + .setData("testData".getBytes()) + .setTtl(Instant.now().plus(1, ChronoUnit.DAYS)) + .setRepeat(5) + .setDueTime(Instant.now().plus(10, ChronoUnit.MINUTES)); + + doAnswer(invocation -> { + StreamObserver observer = invocation.getArgument(1); + observer.onCompleted(); // Simulate successful response + return null; + }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any()); + + assertDoesNotThrow(() -> previewClient.scheduleJob(expectedScheduleJobRequest).block()); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); + + verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any()); + DaprProtos.ScheduleJobRequest actualScheduleJobReq = captor.getValue(); + + assertEquals("testJob", actualScheduleJobReq.getJob().getName()); + assertEquals("testData", + new String(actualScheduleJobReq.getJob().getData().getValue().toByteArray(), StandardCharsets.UTF_8)); + assertEquals("*/5 * * * *", actualScheduleJobReq.getJob().getSchedule()); + assertEquals(iso8601Formatter.format(expectedScheduleJobRequest.getTtl()), actualScheduleJobReq.getJob().getTtl()); + assertEquals(expectedScheduleJobRequest.getRepeats(), actualScheduleJobReq.getJob().getRepeats()); + assertEquals(iso8601Formatter.format(expectedScheduleJobRequest.getDueTime()), actualScheduleJobReq.getJob().getDueTime()); + } + + @Test + public void scheduleJobShouldSucceedWhenRequiredFieldsNameAndDueTimeArePresentInRequest() { + DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + .withZone(ZoneOffset.UTC); + + doAnswer(invocation -> { + StreamObserver observer = invocation.getArgument(1); + observer.onCompleted(); // Simulate successful response + return null; + }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any()); + + ScheduleJobRequest expectedScheduleJobRequest = + new ScheduleJobRequest("testJob", Instant.now().plus(10, ChronoUnit.MINUTES)); + assertDoesNotThrow(() -> previewClient.scheduleJob(expectedScheduleJobRequest).block()); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); + + verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any()); + DaprProtos.ScheduleJobRequest actualScheduleJobRequest = captor.getValue(); + DaprProtos.Job job = actualScheduleJobRequest.getJob(); + assertEquals("testJob", job.getName()); + assertFalse(job.hasData()); + assertFalse(job.hasSchedule()); + assertEquals(0, job.getRepeats()); + assertFalse(job.hasTtl()); + assertEquals(iso8601Formatter.format(expectedScheduleJobRequest.getDueTime()), + actualScheduleJobRequest.getJob().getDueTime()); + } + + @Test + public void scheduleJobShouldSucceedWhenRequiredFieldsNameAndScheduleArePresentInRequest() { + DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + .withZone(ZoneOffset.UTC); + + doAnswer(invocation -> { + StreamObserver observer = invocation.getArgument(1); + observer.onCompleted(); // Simulate successful response + return null; + }).when(daprStub).scheduleJobAlpha1(any(DaprProtos.ScheduleJobRequest.class), any()); + + ScheduleJobRequest expectedScheduleJobRequest = new ScheduleJobRequest("testJob", + JobSchedule.fromString("* * * * * *")); + assertDoesNotThrow(() -> previewClient.scheduleJob(expectedScheduleJobRequest).block()); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(DaprProtos.ScheduleJobRequest.class); + + verify(daprStub, times(1)).scheduleJobAlpha1(captor.capture(), Mockito.any()); + DaprProtos.ScheduleJobRequest actualScheduleJobRequest = captor.getValue(); + DaprProtos.Job job = actualScheduleJobRequest.getJob(); + assertEquals("testJob", job.getName()); + assertFalse(job.hasData()); + assertEquals( "* * * * * *", job.getSchedule()); + assertEquals(0, job.getRepeats()); + assertFalse(job.hasTtl()); + } + + @Test + public void scheduleJobShouldThrowWhenRequestIsNull() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.scheduleJob(null).block(); + }); + assertEquals("scheduleJobRequest cannot be null", exception.getMessage()); + } + + @Test + public void scheduleJobShouldThrowWhenInvalidRequest() { + ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest(null, Instant.now()); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.scheduleJob(scheduleJobRequest).block(); + }); + assertEquals("Name in the request cannot be null or empty", exception.getMessage()); + } + + @Test + public void scheduleJobShouldThrowWhenNameInRequestIsEmpty() { + ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest("", Instant.now()); + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.scheduleJob(scheduleJobRequest).block(); + }); + assertEquals("Name in the request cannot be null or empty", exception.getMessage()); + } + + @Test + public void getJobShouldReturnResponseWhenAllFieldsArePresentInRequest() { + DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + .withZone(ZoneOffset.UTC); + + GetJobRequest getJobRequest = new GetJobRequest("testJob"); + + DaprProtos.Job job = DaprProtos.Job.newBuilder() + .setName("testJob") + .setTtl(OffsetDateTime.now().format(iso8601Formatter)) + .setData(Any.newBuilder().setValue(ByteString.copyFrom("testData".getBytes())).build()) + .setSchedule("*/5 * * * *") + .setRepeats(5) + .setDueTime(iso8601Formatter.format(Instant.now().plus(10, ChronoUnit.MINUTES))) + .build(); + + doAnswer(invocation -> { + StreamObserver observer = invocation.getArgument(1); + observer.onNext(DaprProtos.GetJobResponse.newBuilder() + .setJob(job) + .build()); + observer.onCompleted(); + return null; + }).when(daprStub).getJobAlpha1(any(DaprProtos.GetJobRequest.class), any()); + + Mono resultMono = previewClient.getJob(getJobRequest); + + GetJobResponse response = resultMono.block(); + assertNotNull(response); + assertEquals("testJob", response.getName()); + assertEquals("testData", new String(response.getData(), StandardCharsets.UTF_8)); + assertEquals("*/5 * * * *", response.getSchedule().getExpression()); + assertEquals(5, response.getRepeats()); + assertEquals(job.getTtl(), iso8601Formatter.format(response.getTtl())); + assertEquals(job.getDueTime(), iso8601Formatter.format(response.getDueTime())); + } + + @Test + public void getJobShouldReturnResponseWithScheduleSetWhenResponseHasSchedule() { + GetJobRequest getJobRequest = new GetJobRequest("testJob"); + + DaprProtos.Job job = DaprProtos.Job.newBuilder() + .setName("testJob") + .setSchedule("0 0 0 1 1 *") + .build(); + + doAnswer(invocation -> { + StreamObserver observer = invocation.getArgument(1); + observer.onNext(DaprProtos.GetJobResponse.newBuilder() + .setJob(job) + .build()); + observer.onCompleted(); + return null; + }).when(daprStub).getJobAlpha1(any(DaprProtos.GetJobRequest.class), any()); + + Mono resultMono = previewClient.getJob(getJobRequest); + + GetJobResponse response = resultMono.block(); + assertNotNull(response); + assertEquals("testJob", response.getName()); + assertNull(response.getData()); + assertEquals("0 0 0 1 1 *", response.getSchedule().getExpression()); + assertNull(response.getRepeats()); + assertNull(response.getTtl()); + assertNull(response.getDueTime()); + } + + @Test + public void getJobShouldReturnResponseWithDueTimeSetWhenResponseHasDueTime() { + GetJobRequest getJobRequest = new GetJobRequest("testJob"); + + String datetime = OffsetDateTime.now().toString(); + DaprProtos.Job job = DaprProtos.Job.newBuilder() + .setName("testJob") + .setDueTime(datetime) + .build(); + + doAnswer(invocation -> { + StreamObserver observer = invocation.getArgument(1); + observer.onNext(DaprProtos.GetJobResponse.newBuilder() + .setJob(job) + .build()); + observer.onCompleted(); + return null; + }).when(daprStub).getJobAlpha1(any(DaprProtos.GetJobRequest.class), any()); + + Mono resultMono = previewClient.getJob(getJobRequest); + + GetJobResponse response = resultMono.block(); + assertNotNull(response); + assertEquals("testJob", response.getName()); + assertNull(response.getData()); + assertNull(response.getSchedule()); + assertNull(response.getRepeats()); + assertNull(response.getTtl()); + assertEquals(job.getDueTime(), datetime); + } + + @Test + public void getJobShouldThrowWhenRequestIsNull() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.getJob(null).block(); + }); + assertEquals("getJobRequest cannot be null", exception.getMessage()); + } + + @Test + public void getJobShouldThrowWhenNameIsNullRequest() { + GetJobRequest getJobRequest = new GetJobRequest(null); + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.getJob(getJobRequest).block(); + }); + assertEquals("Name in the request cannot be null or empty", exception.getMessage()); + } + + @Test + public void getJobShouldThrowWhenNameIsEmptyRequest() { + GetJobRequest getJobRequest =new GetJobRequest("");; + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.getJob(getJobRequest).block(); + }); + assertEquals("Name in the request cannot be null or empty", exception.getMessage()); + } + + @Test + public void deleteJobShouldSucceedWhenValidRequest() { + DeleteJobRequest deleteJobRequest = new DeleteJobRequest("testJob"); + + doAnswer(invocation -> { + StreamObserver observer = invocation.getArgument(1); + observer.onCompleted(); // Simulate successful response + return null; + }).when(daprStub).deleteJobAlpha1(any(DaprProtos.DeleteJobRequest.class), any()); + + Mono resultMono = previewClient.deleteJob(deleteJobRequest); + + assertDoesNotThrow(() -> resultMono.block()); + } + + @Test + public void deleteJobShouldThrowRequestIsNull() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.deleteJob(null).block(); + }); + assertEquals("deleteJobRequest cannot be null", exception.getMessage()); + } + + @Test + public void deleteJobShouldThrowWhenNameIsNullRequest() { + DeleteJobRequest deleteJobRequest = new DeleteJobRequest(null); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.deleteJob(deleteJobRequest).block(); + }); + assertEquals("Name in the request cannot be null or empty", exception.getMessage()); + } + + @Test + public void deleteJobShouldThrowWhenNameIsEmptyRequest() { + DeleteJobRequest deleteJobRequest = new DeleteJobRequest(""); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + previewClient.deleteJob(deleteJobRequest).block(); + }); + assertEquals("Name in the request cannot be null or empty", exception.getMessage()); + } + + private DaprProtos.QueryStateResponse buildQueryStateResponse(List> resp,String token) + throws JsonProcessingException { + List items = new ArrayList<>(); + for (QueryStateItem item: resp) { + items.add(buildQueryStateItem(item)); + } + return DaprProtos.QueryStateResponse.newBuilder() + .addAllResults(items) + .setToken(token) + .build(); + } + + private DaprProtos.QueryStateItem buildQueryStateItem(QueryStateItem item) throws JsonProcessingException { + DaprProtos.QueryStateItem.Builder it = DaprProtos.QueryStateItem.newBuilder().setKey(item.getKey()); + if (item.getValue() != null) { + it.setData(ByteString.copyFrom(MAPPER.writeValueAsBytes(item.getValue()))); + } + if (item.getEtag() != null) { + it.setEtag(item.getEtag()); + } + if (item.getError() != null) { + it.setError(item.getError()); + } + return it.build(); + } + + private static StatusRuntimeException newStatusRuntimeException(String status, String message) { + return new StatusRuntimeException(Status.fromCode(Status.Code.valueOf(status)).withDescription(message)); + } } From 9504bfcc7ca293d2795789981c7a340670af3c12 Mon Sep 17 00:00:00 2001 From: Siri Varma Vegiraju Date: Sat, 12 Apr 2025 05:16:17 -0700 Subject: [PATCH 26/30] Update README.md Signed-off-by: Siri Varma Vegiraju --- examples/src/main/java/io/dapr/examples/jobs/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/src/main/java/io/dapr/examples/jobs/README.md b/examples/src/main/java/io/dapr/examples/jobs/README.md index ed066db03d..b78e46a346 100644 --- a/examples/src/main/java/io/dapr/examples/jobs/README.md +++ b/examples/src/main/java/io/dapr/examples/jobs/README.md @@ -1,8 +1,8 @@ -## Mange Dapr Jobs via the Jobs API +## Manage Dapr Jobs via the Jobs API This example provides the different capabilities provided by Dapr Java SDK for Jobs. For further information about Job APIs please refer to [this link](https://docs.dapr.io/developing-applications/building-blocks/jobs/jobs-overview/) -### Using the JobsAPI +### Using the Jobs API The Java SDK exposes several methods for this - * `client.scheduleJob(...)` for scheduling a job. From 09354ede24c233dde84c75cc9da7fa5a5bfdeebd Mon Sep 17 00:00:00 2001 From: Siri Varma Vegiraju Date: Tue, 15 Apr 2025 18:34:56 -0700 Subject: [PATCH 27/30] Update README.md Signed-off-by: Siri Varma Vegiraju --- examples/src/main/java/io/dapr/examples/jobs/README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/examples/src/main/java/io/dapr/examples/jobs/README.md b/examples/src/main/java/io/dapr/examples/jobs/README.md index b78e46a346..2877b31fba 100644 --- a/examples/src/main/java/io/dapr/examples/jobs/README.md +++ b/examples/src/main/java/io/dapr/examples/jobs/README.md @@ -75,11 +75,6 @@ public class DemoJobsClient { } ``` -Get into the examples' directory: -```sh -cd examples -``` - Use the following command to run this example-