AudienceManager { @NonNull @WorkerThread public synchronized TagGroupResult getTags(@NonNull Map<String, Set<String>> tags) { if (requestTagsCallback == null) { throw new IllegalStateException("RequestTagsCallback not set"); } if (!isEnabled()) { return new TagGroupResult(false, null); } if (tags.isEmpty()) { return new TagGroupResult(true, tags); } if (tags.size() == 1 && tags.containsKey(DEVICE_GROUP) && airshipChannel.getChannelTagRegistrationEnabled()) { Map<String, Set<String>> deviceTags = new HashMap<>(); deviceTags.put(DEVICE_GROUP, airshipChannel.getTags()); return new TagGroupResult(true, deviceTags); } if (airshipChannel.getId() == null) { return new TagGroupResult(false, null); } long cacheStaleReadTime = getCacheStaleReadTimeMilliseconds(); long cacheMaxAgeTime = getCacheMaxAgeTimeMilliseconds(); TagGroupResponse cachedResponse = null; if (TagGroupUtils.containsAll(getCachedRequestTags(), tags)) { cachedResponse = getCachedResponse(); } long cacheCreateDate = getCacheCreateDate(); if (cachedResponse != null && cacheMaxAgeTime > clock.currentTimeMillis() - cacheCreateDate) { return new TagGroupResult(true, generateTags(tags, cachedResponse, cacheCreateDate)); } try { refreshCache(tags, cachedResponse); cachedResponse = getCachedResponse(); cacheCreateDate = getCacheCreateDate(); } catch (Exception e) { Logger.error(e, "Failed to refresh tags."); } if (cachedResponse == null) { return new TagGroupResult(false, null); } if (cacheStaleReadTime <= 0 || cacheStaleReadTime > clock.currentTimeMillis() - cacheCreateDate) { return new TagGroupResult(true, generateTags(tags, cachedResponse, cacheCreateDate)); } return new TagGroupResult(false, null); } AudienceManager(@NonNull AirshipRuntimeConfig runtimeConfig,
                           @NonNull AirshipChannel airshipChannel,
                           @NonNull NamedUser namedUser,
                           @NonNull PreferenceDataStore dataStore); @VisibleForTesting  AudienceManager(@NonNull TagGroupLookupApiClient client, @NonNull AirshipChannel airshipChannel,
                    @NonNull NamedUser namedUser, @NonNull AudienceHistorian historian,
                    @NonNull PreferenceDataStore dataStore, @NonNull Clock clock); void setEnabled(boolean enabled); boolean isEnabled(); void setCacheMaxAgeTime(@IntRange(from = 0) long duration, @NonNull TimeUnit unit); long getCacheMaxAgeTimeMilliseconds(); void setCacheStaleReadTime(@IntRange(from = MIN_CACHE_MAX_AGE_TIME_MS) long duration, @NonNull TimeUnit unit); long getCacheStaleReadTimeMilliseconds(); void setRequestTagsCallback(@Nullable RequestTagsCallback callback); long getPreferLocalTagDataTime(); void setPreferLocalTagDataTime(@IntRange(from = 0) long duration, @NonNull TimeUnit unit); @NonNull @WorkerThread synchronized TagGroupResult getTags(@NonNull Map<String, Set<String>> tags); @NonNull List<TagGroupsMutation> getTagOverrides(); @NonNull List<AttributeMutation> getAttributeOverrides(); static final long MIN_CACHE_MAX_AGE_TIME_MS; static final long DEFAULT_CACHE_MAX_AGE_TIME_MS; static final long DEFAULT_CACHE_STALE_READ_TIME_MS; static final long DEFAULT_PREFER_LOCAL_DATA_TIME_MS; }
@Test public void getTagsUsesCache() { when(mockClient.lookupTagGroups(channelId, getExpectedClientRequestTags(), null)) .thenReturn(new TagGroupResponse(200, clientResponseTags, "lastModifiedTime")); TagGroupResult result = manager.getTags(requestTags); TagGroupResult cachedResult = manager.getTags(requestTags); verify(mockClient).lookupTagGroups(channelId, getExpectedClientRequestTags(), null); verifyNoMoreInteractions(mockClient); assertEquals(result.success, cachedResult.success); assertEquals(result.tagGroups, cachedResult.tagGroups); }
@Test public void getTagsUsesLocalData() { when(mockClient.lookupTagGroups(channelId, getExpectedClientRequestTags(), null)) .thenReturn(new TagGroupResponse(200, clientResponseTags, "lastModifiedTime")); List<TagGroupsMutation> mutations = new ArrayList<>(); mutations.add(TagGroupsMutation.newSetTagsMutation("some-group", Collections.singleton("story"))); when(mockHistorian.getTagGroupHistory(anyLong())).thenReturn(mutations); pendingChannelMutations.add(TagGroupsMutation.newAddTagsMutation("some-group", Collections.singleton("cool"))); TagGroupResult result = manager.getTags(requestTags); assertTrue(result.success); assertEquals(1, result.tagGroups.size()); assertNotNull(result.tagGroups.get("some-group")); assertEquals(2, result.tagGroups.get("some-group").size()); assertTrue(result.tagGroups.get("some-group").contains("cool")); assertTrue(result.tagGroups.get("some-group").contains("story")); }
@Test public void getTagsDeviceGroup() { Set<String> deviceTags = tagSet("local tag"); when(mockChannel.getTags()).thenReturn(deviceTags); when(mockChannel.getChannelTagRegistrationEnabled()).thenReturn(true); clientResponseTags.put("device", tagSet("server tag")); requestTags.put("device", tagSet("server tag", "local tag")); when(mockClient.lookupTagGroups(channelId, getExpectedClientRequestTags(), null)) .thenReturn(new TagGroupResponse(200, clientResponseTags, "lastModifiedTime")); TagGroupResult result = manager.getTags(requestTags); assertTrue(result.success); assertEquals(2, result.tagGroups.size()); assertEquals(1, result.tagGroups.get("device").size()); assertTrue(result.tagGroups.get("device").contains("local tag")); }
@Test public void getTagsDeviceGroupPushManagerTagsDisabled() { when(mockChannel.getChannelTagRegistrationEnabled()).thenReturn(false); clientResponseTags.put("device", tagSet("server tag")); requestTags.put("device", tagSet("server tag")); when(mockClient.lookupTagGroups(channelId, getExpectedClientRequestTags(), null)) .thenReturn(new TagGroupResponse(200, clientResponseTags, "lastModifiedTime")); TagGroupResult result = manager.getTags(requestTags); assertTrue(result.success); assertEquals(2, result.tagGroups.size()); assertEquals(1, result.tagGroups.get("device").size()); assertTrue(result.tagGroups.get("device").contains("server tag")); }
@Test public void getTagsOnlyDeviceTags() { Set<String> deviceTags = tagSet("local tag"); when(mockChannel.getTags()).thenReturn(deviceTags); when(mockChannel.getChannelTagRegistrationEnabled()).thenReturn(true); requestTags.clear(); requestTags.put("device", tagSet("local tag")); TagGroupResult result = manager.getTags(requestTags); assertTrue(result.success); assertEquals(1, result.tagGroups.size()); assertEquals(1, result.tagGroups.get("device").size()); assertTrue(result.tagGroups.get("device").contains("local tag")); verifyZeroInteractions(mockClient); }
@Test public void getTagsEmptyRequest() { requestTags.clear(); TagGroupResult result = manager.getTags(requestTags); assertTrue(result.success); assertTrue(result.tagGroups.isEmpty()); verifyZeroInteractions(mockClient); }
@Test public void getTagsNoChannel() { channelId = null; TagGroupResult result = manager.getTags(requestTags); assertFalse(result.success); verifyZeroInteractions(mockClient); }
@Test public void getTagsBadResponse() { when(mockClient.lookupTagGroups(channelId, getExpectedClientRequestTags(), null)) .thenReturn(new TagGroupResponse(400, null, null)); TagGroupResult result = manager.getTags(requestTags); assertFalse(result.success); }
@Test public void getTagsNewTags() { when(mockClient.lookupTagGroups(channelId, getExpectedClientRequestTags(), null)) .thenReturn(new TagGroupResponse(200, clientResponseTags, "lastModifiedTime")); manager.getTags(requestTags); verify(mockClient, times(1)) .lookupTagGroups(channelId, getExpectedClientRequestTags(), null); requestTags.get("some-group").add("new-tag"); manager.getTags(requestTags); verify(mockClient, times(1)) .lookupTagGroups(channelId, getExpectedClientRequestTags(), null); verifyNoMoreInteractions(mockClient); }
@Test public void getTags() { when(mockClient.lookupTagGroups(channelId, getExpectedClientRequestTags(), null)) .thenReturn(new TagGroupResponse(200, clientResponseTags, "lastModifiedTime")); TagGroupResult result = manager.getTags(requestTags); verify(mockHistorian).getTagGroupHistory(clock.currentTimeMillis - manager.getPreferLocalTagDataTime()); assertTrue(result.success); assertEquals(1, result.tagGroups.size()); assertNotNull(result.tagGroups.get("some-group")); assertEquals(1, result.tagGroups.get("some-group").size()); assertTrue(result.tagGroups.get("some-group").contains("cool")); }