Skip to content

Commit

Permalink
Merge pull request #36 from IABTechLab/aaq-UID2-2022-opt-out-status-api
Browse files Browse the repository at this point in the history
[UID2-2022] Add tests for opt out status API
  • Loading branch information
asloobq authored Jun 12, 2024
2 parents c742914 + 95928b1 commit e230b21
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 19 deletions.
6 changes: 6 additions & 0 deletions src/test/java/app/component/Operator.java
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,12 @@ public JsonNode v2IdentityBuckets(String payload) throws Exception {
return v2DecryptEncryptedResponse(encryptedResponse, envelope.nonce(), CLIENT_API_SECRET);
}

public JsonNode v2OptOutStatus(String payload) throws Exception {
V2Envelope envelope = v2CreateEnvelope(payload, CLIENT_API_SECRET);
String encryptedResponse = HttpClient.post(getBaseUrl() + "/v2/optout/status", envelope.envelope(), CLIENT_API_KEY);
return v2DecryptEncryptedResponse(encryptedResponse, envelope.nonce(), CLIENT_API_SECRET);
}

public JsonNode v2KeySharing() throws Exception {
V2Envelope envelope = v2CreateEnvelope("", CLIENT_API_SECRET);
String encryptedResponse = HttpClient.post(getBaseUrl() + "/v2/key/sharing", envelope.envelope(), CLIENT_API_KEY);
Expand Down
73 changes: 69 additions & 4 deletions src/test/java/suite/optout/OptoutTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.awaitility.Awaitility.*;

import java.time.Instant;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assumptions.assumeThat;
import static org.awaitility.Awaitility.await;
import static org.awaitility.Awaitility.with;

@SuppressWarnings("unused")
Expand All @@ -29,10 +28,12 @@ public class OptoutTest {
private static final int OPTOUT_WAIT_SECONDS = 300;

private static Set<Arguments> outputArgs;
private static Set<Arguments> outputAdvertisingIdArgs;

@BeforeAll
public static void setupAll() {
outputArgs = new HashSet<>();
outputAdvertisingIdArgs = new HashSet<>();
}

@ParameterizedTest(name = "/v2/token/logout with /v0/token/generate - {0} - {2}")
Expand Down Expand Up @@ -120,7 +121,26 @@ public void testV2LogoutWithV2TokenGenerateOldParticipant(String label, Operator
);
}

@ParameterizedTest(name = "/v2/token/logout with /v2/identity/map - DII {0} - toOptOut {5} - {2}")
@MethodSource({
"suite.optout.TestData#identityMapEmailArgs",
"suite.optout.TestData#identityMapPhoneArgs"
})
@Order(5)
public void testV2LogoutWithV2IdentityMap(String label, Operator operator, String operatorName, String type, String emailOrPhone, boolean toOptOut) throws Exception {
JsonNode identityMapResponseNode = operator.v2IdentityMap("{\""+ type + "\":[\"" + emailOrPhone + "\"]}", false);
assertThat(identityMapResponseNode.at("/status").asText()).isEqualTo("success");
String rawUID = identityMapResponseNode.get("body").get("mapped").get(0).get(TestData.ADVERTISING_ID).asText();
long beforeOptOutTimestamp = Instant.now().toEpochMilli();
if (toOptOut) {
Thread.sleep(OPTOUT_DELAY_MS);
JsonNode logoutResponse = operator.v2TokenLogout(type, emailOrPhone);
assertThat(logoutResponse).isEqualTo(Mapper.OBJECT_MAPPER.readTree("{\"body\":{\"optout\":\"OK\"},\"status\":\"success\"}"));
}
outputAdvertisingIdArgs.add(Arguments.of(label, operator, operatorName, rawUID, toOptOut, beforeOptOutTimestamp));
}

@Order(6)
@ParameterizedTest(name = "/v0/token/refresh after {2} generate and {3} logout - {0} - {1}")
@MethodSource({
"afterOptoutTokenArgs"
Expand All @@ -130,7 +150,7 @@ public void testV0TokenRefreshAfterOptOut(String label, Operator operator, Strin
this.waitForOptOutResponse(operator::v0CheckedTokenRefresh, refreshToken, "{\"advertisement_token\":\"\",\"advertising_token\":\"\",\"refresh_token\":\"\"}");
}

@Order(6)
@Order(7)
@ParameterizedTest(name = "/v1/token/refresh after {2} generate and {3} logout - {0} - {1}")
@MethodSource({
"afterOptoutTokenArgs"
Expand All @@ -140,7 +160,7 @@ public void testV1TokenRefreshAfterOptOut(String label, Operator operator, Strin
this.waitForOptOutResponse(operator::v1CheckedTokenRefresh, refreshToken, "{\"status\":\"optout\"}");
}

@Order(7)
@Order(8)
@ParameterizedTest(name = "/v2/token/refresh after {2} generate and {3} logout - {0} - {1}")
@MethodSource({
"afterOptoutTokenArgs"
Expand All @@ -151,10 +171,55 @@ public void testV2TokenRefreshAfterOptOut(String label, Operator operator, Strin
with().pollInterval(5, TimeUnit.SECONDS).await("Get V2 Token Response").atMost(OPTOUT_WAIT_SECONDS, TimeUnit.SECONDS).until(() -> operator.v2TokenRefresh(refreshToken, refreshResponseKey).equals(Mapper.OBJECT_MAPPER.readTree("{\"status\":\"optout\"}")));
}

@Order(9)
@ParameterizedTest(name = "/v2/optout/status after v2/identity/map and v2/token/logout - DII {0} - expecting {4} - {2}")
@MethodSource({"afterOptoutAdvertisingIdArgs"})
public void testV2OptOutStatus(String label, Operator operator, String operatorName, String rawUID,
boolean isOptedOut, long optedOutTimestamp) throws Exception {
String payload = "{\"advertising_ids\":[\"" + rawUID + "\"]}";
with().pollInterval(5, TimeUnit.SECONDS)
.await("Get Opt out status response")
.atMost(OPTOUT_WAIT_SECONDS, TimeUnit.SECONDS)
.until(() -> {
JsonNode response = operator.v2OptOutStatus(payload);
JsonNode body = response.get("body");
JsonNode optedOutJsonNode = body.get("opted_out");
if (isOptedOut) {
return optedOutJsonNode.size() == 1;

} else {
return optedOutJsonNode.isEmpty();
}
});
JsonNode response = operator.v2OptOutStatus(payload);
assertThat(response.at("/status").asText()).isEqualTo("success");
JsonNode body = response.get("body");
assertThat(body).isNotNull();
JsonNode optedOutJsonNode = body.get("opted_out");
assertThat(optedOutJsonNode).isNotNull();
if (isOptedOut) {
assertThat(optedOutJsonNode.size()).isEqualTo(1);
JsonNode optedOutRecord = optedOutJsonNode.get(0);
assertThat(optedOutRecord).isNotNull();
assertThat(optedOutRecord.has(TestData.ADVERTISING_ID)).isTrue();
String advertisingId = optedOutRecord.get(TestData.ADVERTISING_ID).asText();
assertThat(advertisingId).isEqualTo(rawUID);
assertThat(optedOutRecord.has(TestData.OPTED_OUT_SINCE)).isTrue();
long optedOutSinceMilliseconds = optedOutRecord.get(TestData.OPTED_OUT_SINCE).asLong();
assertThat(optedOutSinceMilliseconds).isGreaterThanOrEqualTo(optedOutTimestamp);
} else {
assertThat(optedOutJsonNode.size()).isEqualTo(0);
}
}

private static Set<Arguments> afterOptoutTokenArgs() {
return outputArgs;
}

private static Set<Arguments> afterOptoutAdvertisingIdArgs() {
return outputAdvertisingIdArgs;
}

private void addToken(String label, Operator operator, String tokenGenerateVersion, String tokenLogoutVersion, String refreshToken, String refreshResponseKey) {
outputArgs.add(Arguments.of(label, operator, tokenGenerateVersion, tokenLogoutVersion, refreshToken, refreshResponseKey));
}
Expand Down
73 changes: 58 additions & 15 deletions src/test/java/suite/optout/TestData.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import java.util.stream.Collectors;

public final class TestData {
public static final String ADVERTISING_ID = "advertising_id";
public static final String OPTED_OUT_SINCE = "opted_out_since";
private static final boolean PHONE_SUPPORT = Boolean.parseBoolean(EnvUtil.getEnv("UID2_E2E_PHONE_SUPPORT"));

private TestData() {
Expand All @@ -34,12 +36,8 @@ public static Set<Arguments> tokenEmailArgs() {

public static Set<Arguments> optoutTokenEmailArgs() {
Set<Operator> operators = getPublicOperators();
Random random = new Random();
int number = random.nextInt(100000000);
String email = "test.email" + number + "@" + getRandomString(2, 10) + "." + getRandomString(2, 10);
Set<List<String>> inputs = Set.of(
List.of("good email", "email", email)
);

Set<List<String>> inputs = generateEmailSet(1);

Set<Arguments> args = new HashSet<>();
for (Operator operator : operators) {
Expand Down Expand Up @@ -69,15 +67,7 @@ public static Set<Arguments> tokenPhoneArgs() {

public static Set<Arguments> optoutTokenPhoneArgs() {
Set<Operator> operators = getPublicOperators();
Random random = new Random();
StringBuilder phone = new StringBuilder(String.valueOf(random.nextLong((10000000000L - 1000000000L) +1) + 1000000000L));
while (phone.length() < 10) {
phone.insert(0, "0");
}
phone.insert(0, "+0");
Set<List<String>> inputs = Set.of(
List.of("good phone", "phone", phone.toString())
);
Set<List<String>> inputs = generatePhoneSet(1);

Set<Arguments> args = new HashSet<>();
if (PHONE_SUPPORT) {
Expand All @@ -90,6 +80,59 @@ public static Set<Arguments> optoutTokenPhoneArgs() {
return args;
}

public static Set<Arguments> identityMapEmailArgs() {
Set<Operator> operators = getPublicOperators();
Set<List<String>> inputs = generateEmailSet(4);

Set<Arguments> args = new HashSet<>();
for (Operator operator : operators) {
for (List<String> input : inputs) {
args.add(Arguments.of(input.get(0), operator, operator.getName(), input.get(1), input.get(2), Boolean.parseBoolean(input.get(3))));
}
}
return args;
}

public static Set<Arguments> identityMapPhoneArgs() {
Set<Operator> operators = getPublicOperators();
Set<List<String>> inputs = generatePhoneSet(4);

Set<Arguments> args = new HashSet<>();
for (Operator operator : operators) {
for (List<String> input : inputs) {
args.add(Arguments.of(input.get(0), operator, operator.getName(), input.get(1), input.get(2), Boolean.parseBoolean(input.get(3))));
}
}
return args;
}

private static Set<List<String>> generateEmailSet(int count) {
Random random = new Random();
Set<List<String>> inputs = new HashSet<>(count);
for (int i = 0; i < count; ++i) {
int number = random.nextInt(100000000);
String email = "test.email" + number + "@" + getRandomString(2, 10) + "." + getRandomString(2, 10);
inputs.add(List.of("good email " + (i + 1), "email", email, i % 2 == 0 ? "true" : "false"));
}

return inputs;
}

private static Set<List<String>> generatePhoneSet(int count) {
Random random = new Random();
Set<List<String>> inputs = new HashSet<>();
final long bound = (10000000000L - 1000000000L) + 1;
for (int i = 0; i < count; ++i) {
StringBuilder phone = new StringBuilder(String.valueOf(random.nextLong(bound) + 1000000000L));
while (phone.length() < 10) {
phone.insert(0, "0");
}
phone.insert(0, "+0");
inputs.add(List.of("good phone " + (i + 1), "phone", phone.toString(), i % 2 == 0 ? "true" : "false"));
}
return inputs;
}

private static String getRandomString(int minLength, int maxLength) {
String alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
StringBuilder s = new StringBuilder();
Expand Down

0 comments on commit e230b21

Please sign in to comment.