Merge "Add support for testing counter metrics that have fields"
diff --git a/java/com/google/gerrit/acceptance/TestMetricMaker.java b/java/com/google/gerrit/acceptance/TestMetricMaker.java
index 85c5b6d..647eb9d 100644
--- a/java/com/google/gerrit/acceptance/TestMetricMaker.java
+++ b/java/com/google/gerrit/acceptance/TestMetricMaker.java
@@ -14,20 +14,26 @@
 
 package com.google.gerrit.acceptance;
 
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
 import com.google.gerrit.metrics.Counter0;
+import com.google.gerrit.metrics.Counter1;
+import com.google.gerrit.metrics.Counter2;
+import com.google.gerrit.metrics.Counter3;
 import com.google.gerrit.metrics.Description;
 import com.google.gerrit.metrics.DisabledMetricMaker;
+import com.google.gerrit.metrics.Field;
 import com.google.inject.Singleton;
+import java.util.Arrays;
 import java.util.concurrent.ConcurrentHashMap;
 import org.apache.commons.lang3.mutable.MutableLong;
 
 /**
  * {@link com.google.gerrit.metrics.MetricMaker} to be bound in tests.
  *
- * <p>Records how often {@link Counter0} metrics are invoked. Metrics of other types are not
- * recorded.
+ * <p>Records how often counter metrics are invoked. Metrics of other types are not recorded.
  *
- * <p>Allows test to check how much a {@link Counter0} metrics is increased by an operation.
+ * <p>Allows test to check how much a counter metrics is increased by an operation.
  *
  * <p>Example:
  *
@@ -48,18 +54,18 @@
  */
 @Singleton
 public class TestMetricMaker extends DisabledMetricMaker {
-  private final ConcurrentHashMap<String, MutableLong> counts = new ConcurrentHashMap<>();
+  private final ConcurrentHashMap<CounterKey, MutableLong> counts = new ConcurrentHashMap<>();
 
-  public long getCount(String counter0Name) {
-    return get(counter0Name).longValue();
+  public long getCount(String counterName, Object... fieldValues) {
+    return get(CounterKey.create(counterName, fieldValues)).longValue();
   }
 
   public void reset() {
     counts.clear();
   }
 
-  private MutableLong get(String counter0Name) {
-    return counts.computeIfAbsent(counter0Name, name -> new MutableLong(0));
+  private MutableLong get(CounterKey counterKey) {
+    return counts.computeIfAbsent(counterKey, key -> new MutableLong(0));
   }
 
   @Override
@@ -67,11 +73,64 @@
     return new Counter0() {
       @Override
       public void incrementBy(long value) {
-        get(name).add(value);
+        get(CounterKey.create(name)).add(value);
       }
 
       @Override
       public void remove() {}
     };
   }
+
+  @Override
+  public <F1> Counter1<F1> newCounter(String name, Description desc, Field<F1> field1) {
+    return new Counter1<>() {
+      @Override
+      public void incrementBy(F1 field1, long value) {
+        get(CounterKey.create(name, field1)).add(value);
+      }
+
+      @Override
+      public void remove() {}
+    };
+  }
+
+  @Override
+  public <F1, F2> Counter2<F1, F2> newCounter(
+      String name, Description desc, Field<F1> field1, Field<F2> field2) {
+    return new Counter2<>() {
+      @Override
+      public void incrementBy(F1 field1, F2 field2, long value) {
+        get(CounterKey.create(name, field1, field2)).add(value);
+      }
+
+      @Override
+      public void remove() {}
+    };
+  }
+
+  @Override
+  public <F1, F2, F3> Counter3<F1, F2, F3> newCounter(
+      String name, Description desc, Field<F1> field1, Field<F2> field2, Field<F3> field3) {
+    return new Counter3<>() {
+      @Override
+      public void incrementBy(F1 field1, F2 field2, F3 field3, long value) {
+        get(CounterKey.create(name, field1, field2, field3)).add(value);
+      }
+
+      @Override
+      public void remove() {}
+    };
+  }
+
+  @AutoValue
+  abstract static class CounterKey {
+    abstract String name();
+
+    abstract ImmutableList<Object> fieldValues();
+
+    static CounterKey create(String name, Object... fieldValues) {
+      return new AutoValue_TestMetricMaker_CounterKey(
+          name, ImmutableList.copyOf(Arrays.asList(fieldValues)));
+    }
+  }
 }
diff --git a/javatests/com/google/gerrit/acceptance/TestMetricMakerTest.java b/javatests/com/google/gerrit/acceptance/TestMetricMakerTest.java
new file mode 100644
index 0000000..3464d21
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/TestMetricMakerTest.java
@@ -0,0 +1,202 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// 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 com.google.gerrit.acceptance;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.metrics.Counter0;
+import com.google.gerrit.metrics.Counter1;
+import com.google.gerrit.metrics.Counter2;
+import com.google.gerrit.metrics.Counter3;
+import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.Field;
+import org.junit.Before;
+import org.junit.Test;
+
+/** Tests for {@link TestMetricMaker}. */
+public class TestMetricMakerTest {
+  private TestMetricMaker testMetricMaker = new TestMetricMaker();
+
+  @Before
+  public void setUp() {
+    testMetricMaker.reset();
+  }
+
+  @Test
+  public void counter0() throws Exception {
+    String counterName = "test_counter";
+    Counter0 counter = testMetricMaker.newCounter(counterName, new Description("Test Counter"));
+    assertThat(testMetricMaker.getCount(counterName)).isEqualTo(0);
+
+    counter.increment();
+    assertThat(testMetricMaker.getCount(counterName)).isEqualTo(1);
+
+    counter.incrementBy(/* value= */ 3);
+    assertThat(testMetricMaker.getCount(counterName)).isEqualTo(4);
+  }
+
+  @Test
+  public void counter1_booleanField() throws Exception {
+    String counterName = "test_counter";
+    Counter1<Boolean> counter =
+        testMetricMaker.newCounter(
+            counterName,
+            new Description("Test Counter"),
+            Field.ofBoolean("boolean_field", (metadataBuilder, booleanField) -> {}).build());
+    assertThat(testMetricMaker.getCount(counterName, true)).isEqualTo(0);
+    assertThat(testMetricMaker.getCount(counterName, false)).isEqualTo(0);
+
+    counter.increment(/* field1= */ true);
+    assertThat(testMetricMaker.getCount(counterName, true)).isEqualTo(1);
+    assertThat(testMetricMaker.getCount(counterName, false)).isEqualTo(0);
+
+    counter.incrementBy(/* field1= */ true, /* value= */ 3);
+    assertThat(testMetricMaker.getCount(counterName, true)).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, false)).isEqualTo(0);
+
+    counter.increment(/* field1= */ false);
+    assertThat(testMetricMaker.getCount(counterName, true)).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, false)).isEqualTo(1);
+
+    counter.incrementBy(/* field1= */ false, /* value= */ 4);
+    assertThat(testMetricMaker.getCount(counterName, true)).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, false)).isEqualTo(5);
+
+    assertThat(testMetricMaker.getCount(counterName)).isEqualTo(0);
+  }
+
+  @Test
+  public void counter1_stringField() throws Exception {
+    String counterName = "test_counter";
+    Counter1<String> counter =
+        testMetricMaker.newCounter(
+            counterName,
+            new Description("Test Counter"),
+            Field.ofString("string_field", (metadataBuilder, stringField) -> {}).build());
+    assertThat(testMetricMaker.getCount(counterName, "foo")).isEqualTo(0);
+    assertThat(testMetricMaker.getCount(counterName, "bar")).isEqualTo(0);
+
+    counter.increment(/* field1= */ "foo");
+    assertThat(testMetricMaker.getCount(counterName, "foo")).isEqualTo(1);
+    assertThat(testMetricMaker.getCount(counterName, "bar")).isEqualTo(0);
+
+    counter.incrementBy(/* field1= */ "foo", /* value= */ 3);
+    assertThat(testMetricMaker.getCount(counterName, "foo")).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, "bar")).isEqualTo(0);
+
+    counter.increment(/* field1= */ "bar");
+    assertThat(testMetricMaker.getCount(counterName, "foo")).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, "bar")).isEqualTo(1);
+
+    counter.incrementBy(/* field1= */ "bar", /* value= */ 4);
+    assertThat(testMetricMaker.getCount(counterName, "foo")).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, "bar")).isEqualTo(5);
+
+    assertThat(testMetricMaker.getCount(counterName)).isEqualTo(0);
+  }
+
+  @Test
+  public void counter2() throws Exception {
+    String counterName = "test_counter";
+    Counter2<Boolean, String> counter =
+        testMetricMaker.newCounter(
+            counterName,
+            new Description("Test Counter"),
+            Field.ofBoolean("boolean_field", (metadataBuilder, booleanField) -> {}).build(),
+            Field.ofString("string_field", (metadataBuilder, stringField) -> {}).build());
+    assertThat(testMetricMaker.getCount(counterName, true, "foo")).isEqualTo(0);
+    assertThat(testMetricMaker.getCount(counterName, false, "foo")).isEqualTo(0);
+
+    counter.increment(/* field1= */ true, /* field2= */ "foo");
+    assertThat(testMetricMaker.getCount(counterName, true, "foo")).isEqualTo(1);
+    assertThat(testMetricMaker.getCount(counterName, false, "foo")).isEqualTo(0);
+
+    counter.incrementBy(/* field1= */ true, /* field2= */ "foo", /* value= */ 3);
+    assertThat(testMetricMaker.getCount(counterName, true, "foo")).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, false, "foo")).isEqualTo(0);
+
+    counter.increment(/* field1= */ false, /* field2= */ "foo");
+    assertThat(testMetricMaker.getCount(counterName, true, "foo")).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, false, "foo")).isEqualTo(1);
+
+    counter.incrementBy(/* field1= */ false, /* field2= */ "foo", /* value= */ 4);
+    assertThat(testMetricMaker.getCount(counterName, true, "foo")).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, false, "foo")).isEqualTo(5);
+
+    counter.increment(/* field1= */ true, /* field2= */ "bar");
+    assertThat(testMetricMaker.getCount(counterName, true, "foo")).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, true, "bar")).isEqualTo(1);
+
+    counter.incrementBy(/* field1= */ true, /* field2= */ "bar", /* value= */ 5);
+    assertThat(testMetricMaker.getCount(counterName, true, "foo")).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, true, "bar")).isEqualTo(6);
+
+    assertThat(testMetricMaker.getCount(counterName)).isEqualTo(0);
+    assertThat(testMetricMaker.getCount(counterName, true)).isEqualTo(0);
+    assertThat(testMetricMaker.getCount(counterName, false)).isEqualTo(0);
+  }
+
+  @Test
+  public void counter3() throws Exception {
+    String counterName = "test_counter";
+    Counter3<Boolean, String, Integer> counter =
+        testMetricMaker.newCounter(
+            counterName,
+            new Description("Test Counter"),
+            Field.ofBoolean("boolean_field", (metadataBuilder, booleanField) -> {}).build(),
+            Field.ofString("string_field", (metadataBuilder, stringField) -> {}).build(),
+            Field.ofInteger("integer_field", (metadataBuilder, stringField) -> {}).build());
+    assertThat(testMetricMaker.getCount(counterName, true, "foo", 0)).isEqualTo(0);
+    assertThat(testMetricMaker.getCount(counterName, false, "foo", 0)).isEqualTo(0);
+
+    counter.increment(/* field1= */ true, /* field2= */ "foo", /* field3= */ 0);
+    assertThat(testMetricMaker.getCount(counterName, true, "foo", 0)).isEqualTo(1);
+    assertThat(testMetricMaker.getCount(counterName, false, "foo", 0)).isEqualTo(0);
+
+    counter.incrementBy(/* field1= */ true, /* field2= */ "foo", /* field3= */ 0, /* value= */ 3);
+    assertThat(testMetricMaker.getCount(counterName, true, "foo", 0)).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, false, "foo", 0)).isEqualTo(0);
+
+    counter.increment(/* field1= */ false, /* field2= */ "foo", /* field3= */ 0);
+    assertThat(testMetricMaker.getCount(counterName, true, "foo", 0)).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, false, "foo", 0)).isEqualTo(1);
+
+    counter.incrementBy(/* field1= */ false, /* field2= */ "foo", /* field3= */ 0, /* value= */ 4);
+    assertThat(testMetricMaker.getCount(counterName, true, "foo", 0)).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, false, "foo", 0)).isEqualTo(5);
+
+    counter.increment(/* field1= */ true, /* field2= */ "bar", /* field3= */ 0);
+    assertThat(testMetricMaker.getCount(counterName, true, "foo", 0)).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, true, "bar", 0)).isEqualTo(1);
+
+    counter.incrementBy(/* field1= */ true, /* field2= */ "bar", /* field3= */ 0, /* value= */ 5);
+    assertThat(testMetricMaker.getCount(counterName, true, "foo", 0)).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, true, "bar", 0)).isEqualTo(6);
+
+    counter.increment(/* field1= */ false, /* field2= */ "foo", /* field3= */ 1);
+    assertThat(testMetricMaker.getCount(counterName, true, "foo", 0)).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, false, "foo", 1)).isEqualTo(1);
+
+    counter.incrementBy(/* field1= */ false, /* field2= */ "foo", /* field3= */ 1, /* value= */ 6);
+    assertThat(testMetricMaker.getCount(counterName, true, "foo", 0)).isEqualTo(4);
+    assertThat(testMetricMaker.getCount(counterName, false, "foo", 1)).isEqualTo(7);
+
+    assertThat(testMetricMaker.getCount(counterName)).isEqualTo(0);
+    assertThat(testMetricMaker.getCount(counterName, true)).isEqualTo(0);
+    assertThat(testMetricMaker.getCount(counterName, false)).isEqualTo(0);
+    assertThat(testMetricMaker.getCount(counterName, true, "foo")).isEqualTo(0);
+    assertThat(testMetricMaker.getCount(counterName, false, "foo")).isEqualTo(0);
+  }
+}