Fix user extract pattern for maxStartForTaskForUserForQueue

Fixes the user extract pattern in maxStartForTaskForUserForQueue
quota to use the updated logic in I69d2b4a1d.

Change-Id: Ifb0abb139e6dcd8d5c7424ffe709df33e4d4bbe4
diff --git a/src/main/java/com/googlesource/gerrit/plugins/quota/TaskParser.java b/src/main/java/com/googlesource/gerrit/plugins/quota/TaskParser.java
index 5944308..f70a34f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/quota/TaskParser.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/quota/TaskParser.java
@@ -20,10 +20,12 @@
 import java.util.regex.Pattern;
 
 public class TaskParser {
-  public static final Pattern USER_EXTRACT_PATTERN = Pattern.compile("\\(([\\-_A-Za-z0-9]+)\\)$");
+  public static final String USER_PATTERN = "([\\-_A-Za-z0-9]+)";
+  public static final Pattern USER_EXTRACT_PATTERN_FROM_TASK_STRING =
+      Pattern.compile("\\(" + USER_PATTERN + "\\)$");
 
   public static Optional<String> user(WorkQueue.Task<?> task) {
-    Matcher matcher = USER_EXTRACT_PATTERN.matcher(task.toString());
-    return matcher.find() ? Optional.of(matcher.group()) : Optional.empty();
+    Matcher matcher = USER_EXTRACT_PATTERN_FROM_TASK_STRING.matcher(task.toString());
+    return matcher.find() ? Optional.of(matcher.group(1)) : Optional.empty();
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/quota/TaskQuotaForTaskForQueueForUser.java b/src/main/java/com/googlesource/gerrit/plugins/quota/TaskQuotaForTaskForQueueForUser.java
index 751559e..01438ad 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/quota/TaskQuotaForTaskForQueueForUser.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/quota/TaskQuotaForTaskForQueueForUser.java
@@ -28,9 +28,9 @@
       Pattern.compile(
           "(\\d+)\\s+("
               + String.join("|", SUPPORTED_TASKS_BY_GROUP.keySet())
-              + ")\\s+([a-zA-Z0-9]+)"
+              + ")\\s+"
+              + TaskParser.USER_PATTERN
               + "\\s+(.+)");
-  public static final Pattern USER_EXTRACT_PATTERN = Pattern.compile("\\(([a-z0-9]+)\\)$");
   private final String user;
 
   public TaskQuotaForTaskForQueueForUser(
@@ -41,8 +41,7 @@
 
   @Override
   public boolean isApplicable(WorkQueue.Task<?> task) {
-    Matcher taskUser = USER_EXTRACT_PATTERN.matcher(task.toString());
-    return taskUser.find() && user.equals(taskUser.group(1)) && super.isApplicable(task);
+    return TaskParser.user(task).map(user::equals).orElse(false) && super.isApplicable(task);
   }
 
   public static Optional<TaskQuota> build(QuotaSection qs, String config) {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/quota/TaskQuotasTest.java b/src/test/java/com/googlesource/gerrit/plugins/quota/TaskQuotasTest.java
index 61614c8..75fc8d8 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/quota/TaskQuotasTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/quota/TaskQuotasTest.java
@@ -33,7 +33,7 @@
 @RunWith(MockitoJUnitRunner.class)
 public class TaskQuotasTest {
   private static final String PROJECT_X = "project-x";
-  private static final String USER_A = "USER_A";
+  private static final String USER_A = "USER-A";
   private static final String USER_B = "USER_B";
 
   @Test
@@ -42,7 +42,7 @@
         taskQuotas(
             2,
             2,
-            """
+"""
 [quota "%s"]
   maxStartForTaskForQueue = 1 uploadpack %s
 """
@@ -78,12 +78,44 @@
   }
 
   @Test
+  public void testMaxStartForTaskForUserForQueue() throws ConfigInvalidException {
+    TaskQuotas taskQuotas =
+        taskQuotas(
+            2,
+            2,
+"""
+[quota "%s"]
+  maxStartForTaskForUserForQueue = 1 uploadpack %s %s
+"""
+                .formatted(PROJECT_X, USER_A, INTERACTIVE.getName()));
+
+    Task<?> u_x_a_1 = task(INTERACTIVE.getName(), uploadPackTask(PROJECT_X, USER_A));
+    assertTrue(taskQuotas.isReadyToStart(u_x_a_1));
+    startAndCompleteTask(taskQuotas, u_x_a_1);
+
+    Task<?> u_x_a_2 = task(INTERACTIVE.getName(), uploadPackTask(PROJECT_X, USER_A));
+    assertTrue(taskQuotas.isReadyToStart(u_x_a_2));
+    taskQuotas.onStart(u_x_a_2);
+
+    Task<?> u_x_a_3 = task(INTERACTIVE.getName(), uploadPackTask(PROJECT_X, USER_A));
+    assertFalse(taskQuotas.isReadyToStart(u_x_a_3));
+
+    Task<?> u_x_b_1 = task(INTERACTIVE.getName(), uploadPackTask(PROJECT_X, USER_B));
+    assertTrue(taskQuotas.isReadyToStart(u_x_b_1));
+    startAndCompleteTask(taskQuotas, u_x_b_1);
+
+    taskQuotas.onStop(u_x_a_2);
+    assertTrue(taskQuotas.isReadyToStart(u_x_a_3));
+    startAndCompleteTask(taskQuotas, u_x_a_3);
+  }
+
+  @Test
   public void testSoftMaxPerUserForQueue() throws ConfigInvalidException {
     TaskQuotas taskQuotas =
         taskQuotas(
             5,
             5,
-            """
+"""
 [quota "%s"]
   softMaxStartPerUserForQueue = 2 %s
 """