Skip to content

Commit da59df3

Browse files
authored
[FFM-5471] - Target identifier set in the target builder function in the Java SDK is not used (#125)
What Targets reported by Java SDK are incorrectly showing in the UI Target Management -> Targets as the global target Why We're sending the global target identifier in the targetData when we shouldn't be. Also global target is not correctly applied to metricsData when isGlobalTargetEnabled is set Testing Tested manually with sample app to confirm changes are reflected in the UI. Also added a new unit test to capture and assert on the posted MetricsData object.
1 parent 98f8f3e commit da59df3

File tree

2 files changed

+79
-20
lines changed

2 files changed

+79
-20
lines changed

src/main/java/io/harness/cf/client/api/MetricsProcessor.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ class MetricsProcessor extends AbstractScheduledService {
3131
private static final String SDK_LANGUAGE = "SDK_LANGUAGE";
3232
private static final String SDK_VERSION = "SDK_VERSION";
3333

34+
private static final Target globalTarget =
35+
Target.builder().name(GLOBAL_TARGET_NAME).identifier(GLOBAL_TARGET).build();
36+
3437
private final Connector connector;
3538
private final BaseConfig config;
3639
private final AtomicLongMap<MetricEvent> frequencyMap;
@@ -70,11 +73,12 @@ public synchronized void pushToQueue(Target target, String featureName, Variatio
7073

7174
uniqueTargetSet.add(target);
7275

73-
if (config.isGlobalTargetEnabled()) {
74-
target.setIdentifier(GLOBAL_TARGET);
76+
Target metricTarget = globalTarget;
77+
if (!config.isGlobalTargetEnabled()) {
78+
metricTarget = target;
7579
}
7680

77-
frequencyMap.incrementAndGet(new MetricEvent(featureName, target, variation));
81+
frequencyMap.incrementAndGet(new MetricEvent(featureName, metricTarget, variation));
7882
}
7983

8084
/** This method sends the metrics data to the analytics server and resets the cache */
@@ -117,10 +121,8 @@ protected Metrics prepareSummaryMetricsBody(Map<MetricEvent, Long> data, Set<Tar
117121
final Metrics metrics = new Metrics(new ArrayList<>(), new ArrayList<>());
118122
final Map<SummaryMetrics, Long> summaryMetricsData = new HashMap<>();
119123

120-
addTargetData(
121-
metrics, Target.builder().name(GLOBAL_TARGET_NAME).identifier(GLOBAL_TARGET).build());
122-
123124
targets.forEach(target -> addTargetData(metrics, target));
125+
124126
data.forEach(
125127
(target, count) ->
126128
summaryMetricsData.put(

src/test/java/io/harness/cf/client/api/MetricsProcessorTest.java

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
package io.harness.cf.client.api;
22

3-
import static org.junit.jupiter.api.Assertions.assertEquals;
4-
import static org.junit.jupiter.api.Assertions.fail;
3+
import static org.junit.jupiter.api.Assertions.*;
4+
import static org.mockito.Mockito.doNothing;
5+
import static org.mockito.Mockito.when;
56

67
import com.google.common.collect.Maps;
78
import io.harness.cf.client.connector.Connector;
9+
import io.harness.cf.client.connector.ConnectorException;
810
import io.harness.cf.client.dto.Target;
9-
import io.harness.cf.model.FeatureConfig;
10-
import io.harness.cf.model.Metrics;
11-
import io.harness.cf.model.Variation;
12-
import java.util.HashSet;
13-
import java.util.Map;
14-
import java.util.Set;
11+
import io.harness.cf.model.*;
12+
import java.util.*;
1513
import java.util.concurrent.*;
1614
import lombok.NonNull;
1715
import lombok.extern.slf4j.Slf4j;
1816
import org.junit.jupiter.api.BeforeEach;
1917
import org.junit.jupiter.api.Test;
18+
import org.junit.jupiter.params.ParameterizedTest;
19+
import org.junit.jupiter.params.provider.ValueSource;
2020
import org.mockito.*;
2121

2222
@Slf4j
@@ -141,7 +141,7 @@ public void onMetricsFailure() {
141141
}
142142

143143
@Test
144-
public void testPrepareSummaryMetricsBody() {
144+
void testPrepareSummaryMetricsBody() {
145145
Target target = Target.builder().identifier("harness").build();
146146
FeatureConfig feature = FeatureConfig.builder().feature("bool-flag").build();
147147
Variation variation = Variation.builder().identifier("true").value("true").build();
@@ -150,12 +150,69 @@ public void testPrepareSummaryMetricsBody() {
150150
Set<Target> uniqueTargets = new HashSet<>();
151151
uniqueTargets.add(target);
152152

153-
Map<MetricEvent, Long> map = Maps.newHashMap();
154-
map.put(event, 6L);
153+
Map<MetricEvent, Long> freqMap = Maps.newHashMap();
154+
freqMap.put(event, 6L);
155155

156-
Metrics metrics = metricsProcessor.prepareSummaryMetricsBody(map, uniqueTargets);
156+
Metrics metrics = metricsProcessor.prepareSummaryMetricsBody(freqMap, uniqueTargets);
157157

158-
assert metrics.getTargetData() != null;
159-
assert metrics.getTargetData().get(1).getIdentifier().equals(target.getIdentifier());
158+
assertNotNull(metrics);
159+
assertNotNull(metrics.getTargetData());
160+
assertNotNull(metrics.getMetricsData());
161+
162+
assertEquals(target.getIdentifier(), metrics.getTargetData().get(0).getIdentifier());
163+
assertEquals(6, metrics.getMetricsData().get(0).getCount());
164+
}
165+
166+
@ParameterizedTest
167+
@ValueSource(booleans = {true, false})
168+
void shouldPostCorrectMetrics_WhenGlobalTargetEnabledOrDisabled(boolean globalTargetEnabled)
169+
throws ConnectorException {
170+
final Connector mockConnector = Mockito.mock(Connector.class);
171+
final BaseConfig mockConfig = Mockito.mock(BaseConfig.class);
172+
final ArgumentCaptor<Metrics> metricsArgumentCaptor = ArgumentCaptor.forClass(Metrics.class);
173+
174+
when(mockConfig.isGlobalTargetEnabled()).thenReturn(globalTargetEnabled);
175+
when(mockConfig.getBufferSize()).thenReturn(10);
176+
doNothing().when(mockConnector).postMetrics(metricsArgumentCaptor.capture());
177+
178+
final MetricsProcessor processor =
179+
new MetricsProcessor(mockConnector, mockConfig, Mockito.mock(MetricsCallback.class));
180+
181+
final Target target = Target.builder().identifier("target123").build();
182+
final Variation variation = Variation.builder().identifier("true").value("true").build();
183+
processor.pushToQueue(target, "feature1", variation);
184+
processor.pushToQueue(target, "feature1", variation);
185+
processor.pushToQueue(target, "feature2", variation);
186+
processor.pushToQueue(target, "feature2", variation);
187+
processor.pushToQueue(target, "feature3", variation);
188+
processor.pushToQueue(target, "feature3", variation);
189+
processor.runOneIteration(); // Mimic scheduled job
190+
191+
final Metrics sentMetrics = metricsArgumentCaptor.getValue();
192+
193+
assertNotNull(sentMetrics.getMetricsData());
194+
assertNotNull(sentMetrics.getTargetData());
195+
196+
assertEquals(1, sentMetrics.getTargetData().size());
197+
assertEquals("target123", sentMetrics.getTargetData().get(0).getIdentifier());
198+
199+
assertEquals(3, sentMetrics.getMetricsData().size());
200+
for (MetricsData md : sentMetrics.getMetricsData()) {
201+
final Map<String, String> map = keyValueArrayToMap(md.getAttributes());
202+
assertEquals(2, md.getCount());
203+
if (globalTargetEnabled) {
204+
assertEquals("__global__cf_target", map.get("target"));
205+
} else {
206+
assertEquals("target123", map.get("target"));
207+
}
208+
}
209+
}
210+
211+
private Map<String, String> keyValueArrayToMap(List<KeyValue> keyValueList) {
212+
final Map<String, String> map = new HashMap<>();
213+
for (KeyValue kv : keyValueList) {
214+
map.put(kv.getKey(), kv.getValue());
215+
}
216+
return map;
160217
}
161218
}

0 commit comments

Comments
 (0)