From b76631d7c1df4c2b146d6835bbbc6fbf83451528 Mon Sep 17 00:00:00 2001 From: Tim Liang Date: Sun, 16 Nov 2025 16:14:12 -0500 Subject: [PATCH 1/5] Implement WindmillNotificationClient and unit tests. Also added a manual test script for sending actual webhooks to Windmill --- .../WindmillNotificationClient.java | 112 ++++++++++++++++++ .../WindmillNotificationClientTest.java | 48 ++++++++ .../WindmillWebhookManualTest.java | 21 ++++ 3 files changed, 181 insertions(+) create mode 100644 src/main/Notification/WindmillNotificationClient.java create mode 100644 src/test/NotificationTest/WindmillNotificationClientTest.java create mode 100644 src/test/NotificationTest/WindmillWebhookManualTest.java diff --git a/src/main/Notification/WindmillNotificationClient.java b/src/main/Notification/WindmillNotificationClient.java new file mode 100644 index 00000000..eae2c1c1 --- /dev/null +++ b/src/main/Notification/WindmillNotificationClient.java @@ -0,0 +1,112 @@ +package Notification; + +import okhttp3.*; +import com.google.gson.Gson; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; + +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; + +@Slf4j +public class WindmillNotificationClient { + private final OkHttpClient client; + private final Gson gson; + private final String WINDMILL_URL; + private final String WINDMILL_TOKEN; + private final String TWILIO_PHONE_NUMBER; + private final Map twilioResource; + private final Pattern PHONE_PATTERN = Pattern.compile("\\+1\\d{10}"); // +1 followed by 10 digits + + public WindmillNotificationClient() { + this.client = new OkHttpClient.Builder() + .connectTimeout(30, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .build(); + this.gson = new Gson(); + this.WINDMILL_URL = System.getenv("WINDMILL_URL"); + this.WINDMILL_TOKEN = System.getenv("WINDMILL_TOKEN"); + this.TWILIO_PHONE_NUMBER = System.getenv("TWILIO_PHONE_NUMBER"); + this.twilioResource = new HashMap<>(); + String TWILIO_ACCOUNT_SID = System.getenv("ACCOUNT_SID"); + String TWILIO_AUTH_TOKEN = System.getenv("AUTH_TOKEN_TWILIO"); + this.twilioResource.put("accountSid", TWILIO_ACCOUNT_SID); + this.twilioResource.put("token", TWILIO_AUTH_TOKEN); + } + + // Constructor for testing + public WindmillNotificationClient(String windmillUrl, String windmillToken, String twilioPhoneNumber, + String twilioAccountSid, String twilioAuthToken) { + this.client = new OkHttpClient(); + this.gson = new Gson(); + this.WINDMILL_URL = windmillUrl; + this.WINDMILL_TOKEN = windmillToken; + this.TWILIO_PHONE_NUMBER = twilioPhoneNumber; + this.twilioResource = new HashMap<>(); + this.twilioResource.put("accountSid", twilioAccountSid); + this.twilioResource.put("token", twilioAuthToken); + } + + public boolean isValidPhoneNumber(String phoneNumber) { + return phoneNumber != null && this.PHONE_PATTERN.matcher(phoneNumber).matches(); + } + + public void executeRequest(Request request, Callback callback) { + client.newCall(request).enqueue(callback); + } + + public void sendSms(String to, String message) { + if (!isValidPhoneNumber(to)) { + log.error("sendSms failed: invalid phone number provided: {}", to); + return; + } + if (message == null || message.isBlank()) { + log.error("sendSms failed: empty message provided: {}", message); + return; + } + + Map payload = Map.of( + "method", "sms", + "message", message, + "sms_config", Map.of( + "twilio_auth", twilioResource, + "to_phone_number", to, + "from_phone_number", this.TWILIO_PHONE_NUMBER + ), + "email_config", Map.of() + ); + + Request request = new Request.Builder() + .url(this.WINDMILL_URL) + .post(RequestBody.create(gson.toJson(payload), MediaType.parse("application/json"))) + .addHeader("Authorization", "Bearer " + this.WINDMILL_TOKEN) + .build(); + + log.info("Sending SMS to {} with message: {}", to, message); + + Callback callback = new Callback() { + public void onFailure(@NotNull Call call, @NotNull java.io.IOException e) { + log.error("sendSms failed: " + e.getMessage()); + } + + public void onResponse(@NotNull Call call, @NotNull Response response) { + try (response) { + if (response.isSuccessful()) { + log.info("sent SMS successfully. Status: {}", response.code()); + } else { + log.warn("SMS request completed but failed. Status: {}, Body: {}", + response.code(), response.body() != null ? response.body().string() : ""); + } + } catch (IOException e) { + log.error("caught error reading SMS response: " + e.getMessage()); + } + } + }; + executeRequest(request, callback); + } +} diff --git a/src/test/NotificationTest/WindmillNotificationClientTest.java b/src/test/NotificationTest/WindmillNotificationClientTest.java new file mode 100644 index 00000000..c1d31bd6 --- /dev/null +++ b/src/test/NotificationTest/WindmillNotificationClientTest.java @@ -0,0 +1,48 @@ +package NotificationTest; + +import Notification.WindmillNotificationClient; +import lombok.extern.slf4j.Slf4j; +import okhttp3.Callback; +import okhttp3.Request; +import org.junit.Test; + +import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +@Slf4j +public class WindmillNotificationClientTest { + + WindmillNotificationClient client = new WindmillNotificationClient("http://localhost", + "test_windmill_token", "test_twilio_phone_number", + "test_twilio_account_sid", "test_twilio_auth_token"); + @Test + public void sendSMSSuccess() { + var testClient = new WindmillNotificationClient("http://localhost", + "test_windmill_token", "test_twilio_phone_number", + "test_twilio_account_sid", "test_twilio_auth_token") { + @Override + public void executeRequest(Request request, Callback callback) { + // Don't actually send, just verify the request looks right + assertNotNull(request); + assertEquals("POST", request.method()); + } + }; + + assertDoesNotThrow(() -> client.sendSms("+12025551234", "Test")); + } + + @Test + public void testValidPhoneNumbers() { + assertTrue(client.isValidPhoneNumber("+12025551234")); + assertTrue(client.isValidPhoneNumber("+19999999999")); + } + + @Test + public void testInvalidPhoneNumbers() { + assertFalse(client.isValidPhoneNumber("12025551234")); // missing + + assertFalse(client.isValidPhoneNumber("+44123456789")); // wrong country code + assertFalse(client.isValidPhoneNumber("+1202555123")); // too few digits + assertFalse(client.isValidPhoneNumber("+120255512345")); // too many digits + assertFalse(client.isValidPhoneNumber(null)); + } +} diff --git a/src/test/NotificationTest/WindmillWebhookManualTest.java b/src/test/NotificationTest/WindmillWebhookManualTest.java new file mode 100644 index 00000000..8c238012 --- /dev/null +++ b/src/test/NotificationTest/WindmillWebhookManualTest.java @@ -0,0 +1,21 @@ +package NotificationTest; + +import Notification.WindmillNotificationClient; +import org.junit.jupiter.api.Test; + +// Sends actual webhooks to windmill +// Need to set environment variables in run configuration in Intellij (look at WindmillNotificationClient.java) +class WindmillWebhookManualTest { + + @Test + void sendSms() throws InterruptedException { + WindmillNotificationClient client = new WindmillNotificationClient(); + + System.out.println("Sending webhook..."); + client.sendSms("TEST_PHONE_NUMBER_HERE", "Test payload"); + System.out.println("Done! Check the webhook dashboard to verify receipt."); + + // wait for callback + Thread.sleep(10000); + } +} From a7dbca026bbfc6fb51d124c8cf7c7f9a33d1eee2 Mon Sep 17 00:00:00 2001 From: Tim Liang Date: Sun, 16 Nov 2025 17:11:18 -0500 Subject: [PATCH 2/5] fix static code analysis issues --- src/main/Notification/WindmillNotificationClient.java | 2 +- .../NotificationTest/WindmillNotificationClientTest.java | 2 +- src/test/NotificationTest/WindmillWebhookManualTest.java | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/Notification/WindmillNotificationClient.java b/src/main/Notification/WindmillNotificationClient.java index eae2c1c1..aeb9182f 100644 --- a/src/main/Notification/WindmillNotificationClient.java +++ b/src/main/Notification/WindmillNotificationClient.java @@ -90,7 +90,7 @@ public void sendSms(String to, String message) { log.info("Sending SMS to {} with message: {}", to, message); Callback callback = new Callback() { - public void onFailure(@NotNull Call call, @NotNull java.io.IOException e) { + public void onFailure(@NotNull Call call, @NotNull IOException e) { log.error("sendSms failed: " + e.getMessage()); } diff --git a/src/test/NotificationTest/WindmillNotificationClientTest.java b/src/test/NotificationTest/WindmillNotificationClientTest.java index c1d31bd6..ee9ebb87 100644 --- a/src/test/NotificationTest/WindmillNotificationClientTest.java +++ b/src/test/NotificationTest/WindmillNotificationClientTest.java @@ -28,7 +28,7 @@ public void executeRequest(Request request, Callback callback) { } }; - assertDoesNotThrow(() -> client.sendSms("+12025551234", "Test")); + assertDoesNotThrow(() -> testClient.sendSms("+12025551234", "Test")); } @Test diff --git a/src/test/NotificationTest/WindmillWebhookManualTest.java b/src/test/NotificationTest/WindmillWebhookManualTest.java index 8c238012..6caf821c 100644 --- a/src/test/NotificationTest/WindmillWebhookManualTest.java +++ b/src/test/NotificationTest/WindmillWebhookManualTest.java @@ -3,6 +3,8 @@ import Notification.WindmillNotificationClient; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + // Sends actual webhooks to windmill // Need to set environment variables in run configuration in Intellij (look at WindmillNotificationClient.java) class WindmillWebhookManualTest { @@ -12,7 +14,9 @@ void sendSms() throws InterruptedException { WindmillNotificationClient client = new WindmillNotificationClient(); System.out.println("Sending webhook..."); - client.sendSms("TEST_PHONE_NUMBER_HERE", "Test payload"); + assertDoesNotThrow(() -> { + client.sendSms("TEST_PHONE_NUMBER_HERE", "Test payload"); + }); System.out.println("Done! Check the webhook dashboard to verify receipt."); // wait for callback From 92b49dc13255740fae700d21a894b4a9d5d99724 Mon Sep 17 00:00:00 2001 From: Tim Liang Date: Fri, 13 Feb 2026 15:03:49 -0500 Subject: [PATCH 3/5] implement id pickup notification endpoint --- .../UserActivity/NotifyIdPickupActivity.java | 21 +++ src/main/Config/AppConfig.java | 7 + .../Notification/NotificationController.java | 59 ++++++++ .../Services/NotifyIdPickupService.java | 73 ++++++++++ .../NotifyIdPickupServiceTest.java | 132 ++++++++++++++++++ 5 files changed, 292 insertions(+) create mode 100644 src/main/Activity/UserActivity/NotifyIdPickupActivity.java create mode 100644 src/main/Notification/NotificationController.java create mode 100644 src/main/Notification/Services/NotifyIdPickupService.java create mode 100644 src/test/NotificationTest/NotifyIdPickupServiceTest.java diff --git a/src/main/Activity/UserActivity/NotifyIdPickupActivity.java b/src/main/Activity/UserActivity/NotifyIdPickupActivity.java new file mode 100644 index 00000000..42743635 --- /dev/null +++ b/src/main/Activity/UserActivity/NotifyIdPickupActivity.java @@ -0,0 +1,21 @@ +package Activity.UserActivity; + +import Activity.Activity; +import java.util.ArrayList; +import java.util.List; + +public class NotifyIdPickupActivity extends UserActivity { + @Override + public List construct() { + List a = new ArrayList<>(); + a.add(Activity.class.getSimpleName()); + a.add(UserActivity.class.getSimpleName()); + a.add(NotifyIdPickupActivity.class.getSimpleName()); + return a; + } + + public NotifyIdPickupActivity( + String workerUsername, String clientUsername, String idToPickup) { + super(workerUsername, clientUsername, idToPickup); + } +} diff --git a/src/main/Config/AppConfig.java b/src/main/Config/AppConfig.java index c6e83aac..3c8c4819 100644 --- a/src/main/Config/AppConfig.java +++ b/src/main/Config/AppConfig.java @@ -22,6 +22,8 @@ import Issue.IssueController; import Mail.FileBackfillController; import Mail.MailController; +import Notification.NotificationController; +import Notification.WindmillNotificationClient; import Organization.Organization; import Organization.OrganizationController; import PDF.PdfController; @@ -98,6 +100,8 @@ public static Javalin appFactory(DeploymentLevel deploymentLevel) { FileBackfillController backfillController = new FileBackfillController(db, fileDao, userDao); PdfControllerV2 pdfControllerV2 = new PdfControllerV2(fileDao, formDao, activityDao, userDao, encryptionController); + WindmillNotificationClient notificationClient = new WindmillNotificationClient(); + NotificationController notificationController = new NotificationController(activityDao, notificationClient); // try { do not recommend this block of code, this will delete and regenerate our encryption // key // System.out.println("generating keyset"); @@ -200,6 +204,9 @@ public static Javalin appFactory(DeploymentLevel deploymentLevel) { app.post("/get-all-activities", activityController.findMyActivities); app.post("/get-org-activities", activityController.findOrganizationActivities); + /* --------------- NOTIFICATION ROUTES ------------- */ + app.post("/notify-id-pickup", notificationController.notifyIdPickup); + /* --------------- FILE BACKFILL ROUTE ------------- */ // app.get("/backfill", backfillController.backfillSingleFile); diff --git a/src/main/Notification/NotificationController.java b/src/main/Notification/NotificationController.java new file mode 100644 index 00000000..6b96da0a --- /dev/null +++ b/src/main/Notification/NotificationController.java @@ -0,0 +1,59 @@ +package Notification; + +import Config.Message; +import Database.Activity.ActivityDao; +import Notification.Services.NotifyIdPickupService; +import User.UserMessage; +import io.javalin.http.Handler; +import lombok.extern.slf4j.Slf4j; +import org.json.JSONObject; + +@Slf4j +public class NotificationController { + private ActivityDao activityDao; + private WindmillNotificationClient notificationClient; + + public NotificationController( + ActivityDao activityDao, WindmillNotificationClient notificationClient) { + this.activityDao = activityDao; + this.notificationClient = notificationClient; + } + + public Handler notifyIdPickup = + ctx -> { + JSONObject req = new JSONObject(ctx.body()); + + String sessionUsername = ctx.sessionAttribute("username"); + if (sessionUsername == null) { + ctx.result(UserMessage.SESSION_TOKEN_FAILURE.toResponseString()); + return; + } + + String workerUsername = req.getString("workerUsername"); + + if (!sessionUsername.equals(workerUsername)) { + ctx.result( + UserMessage.INVALID_PARAMETER + .withMessage("Worker username does not match authenticated session") + .toResponseString()); + return; + } + + String clientUsername = req.getString("clientUsername"); + String idToPickup = req.getString("idToPickup"); + String clientPhoneNumber = req.getString("clientPhoneNumber"); + String message = req.getString("message"); + + NotifyIdPickupService service = + new NotifyIdPickupService( + activityDao, + notificationClient, + workerUsername, + clientUsername, + idToPickup, + clientPhoneNumber, + message); + Message responseMessage = service.executeAndGetResponse(); + ctx.result(responseMessage.toResponseString()); + }; +} diff --git a/src/main/Notification/Services/NotifyIdPickupService.java b/src/main/Notification/Services/NotifyIdPickupService.java new file mode 100644 index 00000000..8dfd8f54 --- /dev/null +++ b/src/main/Notification/Services/NotifyIdPickupService.java @@ -0,0 +1,73 @@ +package Notification.Services; + +import Activity.UserActivity.NotifyIdPickupActivity; +import Config.Message; +import Config.Service; +import Database.Activity.ActivityDao; +import Notification.WindmillNotificationClient; +import User.UserMessage; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class NotifyIdPickupService implements Service { + private final ActivityDao activityDao; + private final WindmillNotificationClient notificationClient; + private final String workerUsername; + private final String clientUsername; + private final String idToPickup; + private final String clientPhoneNumber; + private final String message; + + public NotifyIdPickupService( + ActivityDao activityDao, + WindmillNotificationClient notificationClient, + String workerUsername, + String clientUsername, + String idToPickup, + String clientPhoneNumber, + String message) { + this.activityDao = activityDao; + this.notificationClient = notificationClient; + this.workerUsername = workerUsername; + this.clientUsername = clientUsername; + this.idToPickup = idToPickup; + this.clientPhoneNumber = clientPhoneNumber; + this.message = message; + } + + @Override + public Message executeAndGetResponse() { + if (workerUsername == null || workerUsername.isBlank()) { + return UserMessage.INVALID_PARAMETER.withMessage("Worker username is required"); + } + if (clientUsername == null || clientUsername.isBlank()) { + return UserMessage.INVALID_PARAMETER.withMessage("Client username is required"); + } + if (idToPickup == null || idToPickup.isBlank()) { + return UserMessage.INVALID_PARAMETER.withMessage("ID to pickup is required"); + } + if (!notificationClient.isValidPhoneNumber(clientPhoneNumber)) { + return UserMessage.INVALID_PARAMETER.withMessage( + "Invalid phone number format. Expected +1XXXXXXXXXX"); + } + if (message == null || message.isBlank()) { + return UserMessage.INVALID_PARAMETER.withMessage("Message is required"); + } + + notificationClient.sendSms(clientPhoneNumber, message); + recordNotifyIdPickupActivity(); + + log.info( + "ID pickup notification sent from {} to {} for ID: {}", + workerUsername, + clientUsername, + idToPickup); + return UserMessage.SUCCESS; + } + + private void recordNotifyIdPickupActivity() { + NotifyIdPickupActivity activity = + new NotifyIdPickupActivity(workerUsername, clientUsername, idToPickup); + activityDao.save(activity); + } +} diff --git a/src/test/NotificationTest/NotifyIdPickupServiceTest.java b/src/test/NotificationTest/NotifyIdPickupServiceTest.java new file mode 100644 index 00000000..495a6104 --- /dev/null +++ b/src/test/NotificationTest/NotifyIdPickupServiceTest.java @@ -0,0 +1,132 @@ +package NotificationTest; + +import static org.junit.Assert.*; + +import Activity.Activity; +import Config.DeploymentLevel; +import Config.Message; +import Database.Activity.ActivityDao; +import Database.Activity.ActivityDaoFactory; +import Notification.Services.NotifyIdPickupService; +import Notification.WindmillNotificationClient; +import User.UserMessage; +import java.util.List; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class NotifyIdPickupServiceTest { + private ActivityDao activityDao; + private WindmillNotificationClient notificationClient; + + @Before + public void setUp() { + activityDao = ActivityDaoFactory.create(DeploymentLevel.IN_MEMORY); + notificationClient = + new WindmillNotificationClient( + "http://localhost:9999", "fake-token", "+10000000000", "fake-sid", "fake-auth"); + } + + @After + public void tearDown() { + activityDao.clear(); + } + + @Test + public void successfulNotification_savesActivity() { + NotifyIdPickupService service = + new NotifyIdPickupService( + activityDao, + notificationClient, + "worker1", + "client1", + "drivers-license", + "+12125551234", + "Your ID is ready for pickup!"); + Message result = service.executeAndGetResponse(); + + assertEquals(UserMessage.SUCCESS, result); + assertEquals(1, activityDao.size()); + + List activities = activityDao.getAllFromUser("worker1"); + assertEquals(1, activities.size()); + Activity activity = activities.get(0); + assertEquals("worker1", activity.getInvokerUsername()); + assertEquals("client1", activity.getTargetUsername()); + assertEquals("drivers-license", activity.getObjectName()); + assertEquals( + "NotifyIdPickupActivity", activity.getType().get(activity.getType().size() - 1)); + } + + @Test + public void invalidPhoneNumber_returnsError() { + NotifyIdPickupService service = + new NotifyIdPickupService( + activityDao, + notificationClient, + "worker1", + "client1", + "drivers-license", + "not-a-phone", + "Your ID is ready!"); + Message result = service.executeAndGetResponse(); + + assertNotEquals(UserMessage.SUCCESS, result); + assertEquals(0, activityDao.size()); + } + + @Test + public void blankMessage_returnsError() { + NotifyIdPickupService service = + new NotifyIdPickupService( + activityDao, + notificationClient, + "worker1", + "client1", + "drivers-license", + "+12125551234", + ""); + Message result = service.executeAndGetResponse(); + + assertNotEquals(UserMessage.SUCCESS, result); + assertEquals(0, activityDao.size()); + } + + @Test + public void nullWorkerUsername_returnsError() { + NotifyIdPickupService service = + new NotifyIdPickupService( + activityDao, + notificationClient, + null, + "client1", + "drivers-license", + "+12125551234", + "Your ID is ready!"); + Message result = service.executeAndGetResponse(); + + assertNotEquals(UserMessage.SUCCESS, result); + assertEquals(0, activityDao.size()); + } + + @Test + public void activityRecordedWithCorrectTypeChain() { + NotifyIdPickupService service = + new NotifyIdPickupService( + activityDao, + notificationClient, + "worker1", + "client1", + "state-id", + "+12125551234", + "Your state ID is ready"); + service.executeAndGetResponse(); + + Activity activity = activityDao.getAll().get(0); + List type = activity.getType(); + assertEquals(3, type.size()); + assertEquals("Activity", type.get(0)); + assertEquals("UserActivity", type.get(1)); + assertEquals("NotifyIdPickupActivity", type.get(2)); + } +} From 293c0771c59c44f943d96bb2d263e458c0f4d4e2 Mon Sep 17 00:00:00 2001 From: Tim Liang Date: Sun, 15 Feb 2026 20:22:47 -0500 Subject: [PATCH 4/5] remove manual windmill webhook test --- .../WindmillWebhookManualTest.java | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 src/test/NotificationTest/WindmillWebhookManualTest.java diff --git a/src/test/NotificationTest/WindmillWebhookManualTest.java b/src/test/NotificationTest/WindmillWebhookManualTest.java deleted file mode 100644 index 6caf821c..00000000 --- a/src/test/NotificationTest/WindmillWebhookManualTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package NotificationTest; - -import Notification.WindmillNotificationClient; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; - -// Sends actual webhooks to windmill -// Need to set environment variables in run configuration in Intellij (look at WindmillNotificationClient.java) -class WindmillWebhookManualTest { - - @Test - void sendSms() throws InterruptedException { - WindmillNotificationClient client = new WindmillNotificationClient(); - - System.out.println("Sending webhook..."); - assertDoesNotThrow(() -> { - client.sendSms("TEST_PHONE_NUMBER_HERE", "Test payload"); - }); - System.out.println("Done! Check the webhook dashboard to verify receipt."); - - // wait for callback - Thread.sleep(10000); - } -} From 1ad8c4bcb8d061af458d8287053e876e2862d9df Mon Sep 17 00:00:00 2001 From: Tim Liang Date: Sun, 15 Feb 2026 21:56:00 -0500 Subject: [PATCH 5/5] fix test names --- src/test/NotificationTest/NotifyIdPickupServiceTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/NotificationTest/NotifyIdPickupServiceTest.java b/src/test/NotificationTest/NotifyIdPickupServiceTest.java index 495a6104..6972e49c 100644 --- a/src/test/NotificationTest/NotifyIdPickupServiceTest.java +++ b/src/test/NotificationTest/NotifyIdPickupServiceTest.java @@ -33,7 +33,7 @@ public void tearDown() { } @Test - public void successfulNotification_savesActivity() { + public void successfulNotificationSavesActivity() { NotifyIdPickupService service = new NotifyIdPickupService( activityDao, @@ -59,7 +59,7 @@ public void successfulNotification_savesActivity() { } @Test - public void invalidPhoneNumber_returnsError() { + public void invalidPhoneNumberReturnsError() { NotifyIdPickupService service = new NotifyIdPickupService( activityDao, @@ -76,7 +76,7 @@ public void invalidPhoneNumber_returnsError() { } @Test - public void blankMessage_returnsError() { + public void blankMessageReturnsError() { NotifyIdPickupService service = new NotifyIdPickupService( activityDao, @@ -93,7 +93,7 @@ public void blankMessage_returnsError() { } @Test - public void nullWorkerUsername_returnsError() { + public void nullWorkerUsernameReturnsError() { NotifyIdPickupService service = new NotifyIdPickupService( activityDao,