Loading services/autofill/java/com/android/server/autofill/RequestId.java 0 → 100644 +94 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.android.server.autofill; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; // Helper class containing various methods to deal with FillRequest Ids. // For authentication flows, there needs to be a way to know whether to retrieve the Fill // Response from the primary provider or the secondary provider from the requestId. A simple // way to achieve this is by assigning odd number request ids to secondary provider and // even numbers to primary provider. public class RequestId { private AtomicInteger sIdCounter; // Mainly used for tests RequestId(int start) { sIdCounter = new AtomicInteger(start); } public RequestId() { this((int) (Math.floor(Math.random() * 0xFFFF))); } public static int getLastRequestIdIndex(List<Integer> requestIds) { int lastId = -1; int indexOfBiggest = -1; // Biggest number is usually the latest request, since IDs only increase // The only exception is when the request ID wraps around back to 0 for (int i = requestIds.size() - 1; i >= 0; i--) { if (requestIds.get(i) > lastId) { lastId = requestIds.get(i); indexOfBiggest = i; } } // 0xFFFE + 2 == 0x1 (for secondary) // 0xFFFD + 2 == 0x0 (for primary) // Wrap has occurred if (lastId >= 0xFFFD) { // Calculate the biggest size possible // If list only has one kind of request ids - we need to multiple by 2 // (since they skip odd ints) // Also subtract one from size because at least one integer exists pre-wrap int calcSize = (requestIds.size()) * 2; //Biggest possible id after wrapping int biggestPossible = (lastId + calcSize) % 0xFFFF; lastId = -1; indexOfBiggest = -1; for (int i = 0; i < requestIds.size(); i++) { int currentId = requestIds.get(i); if (currentId <= biggestPossible && currentId > lastId) { lastId = currentId; indexOfBiggest = i; } } } return indexOfBiggest; } public int nextId(boolean isSecondary) { // For authentication flows, there needs to be a way to know whether to retrieve the Fill // Response from the primary provider or the secondary provider from the requestId. A simple // way to achieve this is by assigning odd number request ids to secondary provider and // even numbers to primary provider. int requestId; do { requestId = sIdCounter.incrementAndGet() % 0xFFFF; sIdCounter.set(requestId); } while (isSecondaryProvider(requestId) != isSecondary); return requestId; } public static boolean isSecondaryProvider(int requestId) { return requestId % 2 == 1; } } services/autofill/java/com/android/server/autofill/Session.java +17 −46 Original line number Diff line number Diff line Loading @@ -263,7 +263,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState static final int AUGMENTED_AUTOFILL_REQUEST_ID = 1; private static AtomicInteger sIdCounter = new AtomicInteger(2); private static RequestId mRequestId = new RequestId(); private static AtomicInteger sIdCounterForPcc = new AtomicInteger(2); Loading Loading @@ -1333,7 +1333,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } viewState.setState(newState); int requestId = getRequestId(isSecondary); int requestId = mRequestId.nextId(isSecondary); // Create a metrics log for the request final int ordinal = mRequestLogs.size() + 1; Loading Loading @@ -1415,25 +1415,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState requestAssistStructureLocked(requestId, flags); } private static int getRequestId(boolean isSecondary) { // For authentication flows, there needs to be a way to know whether to retrieve the Fill // Response from the primary provider or the secondary provider from the requestId. A simple // way to achieve this is by assigning odd number request ids to secondary provider and // even numbers to primary provider. int requestId; // TODO(b/158623971): Update this to prevent possible overflow if (isSecondary) { do { requestId = sIdCounter.getAndIncrement(); } while (!isSecondaryProviderRequestId(requestId)); } else { do { requestId = sIdCounter.getAndIncrement(); } while (requestId == INVALID_REQUEST_ID || isSecondaryProviderRequestId(requestId)); } return requestId; } private boolean isRequestSupportFillDialog(int flags) { return (flags & FLAG_SUPPORTS_FILL_DIALOG) != 0; } Loading @@ -1441,7 +1422,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @GuardedBy("mLock") private void requestAssistStructureForPccLocked(int flags) { if (!mClassificationState.shouldTriggerRequest()) return; mFillRequestIdSnapshot = sIdCounter.get(); mFillRequestIdSnapshot = sIdCounterForPcc.get(); mClassificationState.updatePendingRequest(); // Get request id int requestId; Loading Loading @@ -2884,7 +2865,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState removeFromService(); return; } final FillResponse authenticatedResponse = isSecondaryProviderRequestId(requestId) final FillResponse authenticatedResponse = mRequestId.isSecondaryProvider(requestId) ? mSecondaryResponses.get(requestId) : mResponses.get(requestId); if (authenticatedResponse == null || data == null) { Loading Loading @@ -2982,7 +2963,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mPresentationStatsEventLogger.maybeSetAuthenticationResult( AUTHENTICATION_RESULT_SUCCESS); if (newClientState != null) { if (sDebug) Slog.d(TAG, "Updating client state from auth dataset"); if (sDebug) Slog.d(TAG, "Updating client state from auth dataset"); mClientState = newClientState; } Dataset datasetFromResult = getEffectiveDatasetForAuthentication((Dataset) result); Loading Loading @@ -3011,10 +2993,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } private static boolean isSecondaryProviderRequestId(int requestId) { return requestId % 2 == 1; } private Dataset getDatasetFromCredentialResponse(GetCredentialResponse result) { if (result == null) { return null; Loading Loading @@ -6929,22 +6907,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @GuardedBy("mLock") private int getLastResponseIndexLocked() { // The response ids are monotonically increasing so // we just find the largest id which is the last. We // do not rely on the internal ordering in sparse // array to avoid - wow this stopped working!? int lastResponseIdx = -1; int lastResponseId = -1; if (mResponses != null) { List<Integer> requestIdList = new ArrayList<>(); final int responseCount = mResponses.size(); for (int i = 0; i < responseCount; i++) { if (mResponses.keyAt(i) > lastResponseId) { lastResponseIdx = i; lastResponseId = mResponses.keyAt(i); } requestIdList.add(mResponses.keyAt(i)); } return mRequestId.getLastRequestIdIndex(requestIdList); } return lastResponseIdx; return -1; } private LogMaker newLogMaker(int category) { Loading services/tests/servicestests/src/com/android/server/autofill/RequestIdTest.java 0 → 100644 +185 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.android.server.autofill; import static com.google.common.truth.Truth.assertThat; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.util.ArrayList; import java.util.List; @RunWith(JUnit4.class) public class RequestIdTest { List<Integer> datasetPrimaryNoWrap = new ArrayList<>(); List<Integer> datasetPrimaryWrap = new ArrayList<>(); List<Integer> datasetSecondaryNoWrap = new ArrayList<>(); List<Integer> datasetSecondaryWrap = new ArrayList<>(); List<Integer> datasetMixedNoWrap = new ArrayList<>(); List<Integer> datasetMixedWrap = new ArrayList<>(); @Before public void setup() throws Exception { int datasetSize = 300; { // Generate primary only ids that do not wrap RequestId requestId = new RequestId(0); for (int i = 0; i < datasetSize; i++) { datasetPrimaryNoWrap.add(requestId.nextId(false)); } } { // Generate primary only ids that wrap RequestId requestId = new RequestId(0xff00); for (int i = 0; i < datasetSize; i++) { datasetPrimaryWrap.add(requestId.nextId(false)); } } { // Generate SECONDARY only ids that do not wrap RequestId requestId = new RequestId(0); for (int i = 0; i < datasetSize; i++) { datasetSecondaryNoWrap.add(requestId.nextId(true)); } } { // Generate SECONDARY only ids that wrap RequestId requestId = new RequestId(0xff00); for (int i = 0; i < datasetSize; i++) { datasetSecondaryWrap.add(requestId.nextId(true)); } } { // Generate MIXED only ids that do not wrap RequestId requestId = new RequestId(0); for (int i = 0; i < datasetSize; i++) { datasetMixedNoWrap.add(requestId.nextId(i % 2 != 0)); } } { // Generate MIXED only ids that wrap RequestId requestId = new RequestId(0xff00); for (int i = 0; i < datasetSize; i++) { datasetMixedWrap.add(requestId.nextId(i % 2 != 0)); } } } @Test public void testRequestIdLists() { for (int id : datasetPrimaryNoWrap) { assertThat(RequestId.isSecondaryProvider(id)).isFalse(); assertThat(id >= 0).isTrue(); assertThat(id < 0xffff).isTrue(); } for (int id : datasetPrimaryWrap) { assertThat(RequestId.isSecondaryProvider(id)).isFalse(); assertThat(id >= 0).isTrue(); assertThat(id < 0xffff).isTrue(); } for (int id : datasetSecondaryNoWrap) { assertThat(RequestId.isSecondaryProvider(id)).isTrue(); assertThat(id >= 0).isTrue(); assertThat(id < 0xffff).isTrue(); } for (int id : datasetSecondaryWrap) { assertThat(RequestId.isSecondaryProvider(id)).isTrue(); assertThat(id >= 0).isTrue(); assertThat(id < 0xffff).isTrue(); } } @Test public void testRequestIdGeneration() { RequestId requestId = new RequestId(0); // Large Primary for (int i = 0; i < 100000; i++) { int y = requestId.nextId(false); assertThat(RequestId.isSecondaryProvider(y)).isFalse(); assertThat(y >= 0).isTrue(); assertThat(y < 0xffff).isTrue(); } // Large Secondary requestId = new RequestId(0); for (int i = 0; i < 100000; i++) { int y = requestId.nextId(true); assertThat(RequestId.isSecondaryProvider(y)).isTrue(); assertThat(y >= 0).isTrue(); assertThat(y < 0xffff).isTrue(); } // Large Mixed requestId = new RequestId(0); for (int i = 0; i < 50000; i++) { int y = requestId.nextId(i % 2 != 0); assertThat(RequestId.isSecondaryProvider(y)).isEqualTo(i % 2 == 0); assertThat(y >= 0).isTrue(); assertThat(y < 0xffff).isTrue(); } } @Test public void testGetLastRequestId() { // In this test, request ids are generated FIFO, so the last entry is also the last // request { // Primary no wrap int lastIdIndex = datasetPrimaryNoWrap.size() - 1; int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetPrimaryNoWrap); assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex); } { // Primary wrap int lastIdIndex = datasetPrimaryWrap.size() - 1; int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetPrimaryWrap); assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex); } { // Secondary no wrap int lastIdIndex = datasetSecondaryNoWrap.size() - 1; int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetSecondaryNoWrap); assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex); } { // Secondary wrap int lastIdIndex = datasetSecondaryWrap.size() - 1; int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetSecondaryWrap); assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex); } { // Mixed no wrap int lastIdIndex = datasetMixedNoWrap.size() - 1; int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetMixedNoWrap); assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex); } { // Mixed wrap int lastIdIndex = datasetMixedWrap.size() - 1; int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetMixedWrap); assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex); } } } Loading
services/autofill/java/com/android/server/autofill/RequestId.java 0 → 100644 +94 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.android.server.autofill; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; // Helper class containing various methods to deal with FillRequest Ids. // For authentication flows, there needs to be a way to know whether to retrieve the Fill // Response from the primary provider or the secondary provider from the requestId. A simple // way to achieve this is by assigning odd number request ids to secondary provider and // even numbers to primary provider. public class RequestId { private AtomicInteger sIdCounter; // Mainly used for tests RequestId(int start) { sIdCounter = new AtomicInteger(start); } public RequestId() { this((int) (Math.floor(Math.random() * 0xFFFF))); } public static int getLastRequestIdIndex(List<Integer> requestIds) { int lastId = -1; int indexOfBiggest = -1; // Biggest number is usually the latest request, since IDs only increase // The only exception is when the request ID wraps around back to 0 for (int i = requestIds.size() - 1; i >= 0; i--) { if (requestIds.get(i) > lastId) { lastId = requestIds.get(i); indexOfBiggest = i; } } // 0xFFFE + 2 == 0x1 (for secondary) // 0xFFFD + 2 == 0x0 (for primary) // Wrap has occurred if (lastId >= 0xFFFD) { // Calculate the biggest size possible // If list only has one kind of request ids - we need to multiple by 2 // (since they skip odd ints) // Also subtract one from size because at least one integer exists pre-wrap int calcSize = (requestIds.size()) * 2; //Biggest possible id after wrapping int biggestPossible = (lastId + calcSize) % 0xFFFF; lastId = -1; indexOfBiggest = -1; for (int i = 0; i < requestIds.size(); i++) { int currentId = requestIds.get(i); if (currentId <= biggestPossible && currentId > lastId) { lastId = currentId; indexOfBiggest = i; } } } return indexOfBiggest; } public int nextId(boolean isSecondary) { // For authentication flows, there needs to be a way to know whether to retrieve the Fill // Response from the primary provider or the secondary provider from the requestId. A simple // way to achieve this is by assigning odd number request ids to secondary provider and // even numbers to primary provider. int requestId; do { requestId = sIdCounter.incrementAndGet() % 0xFFFF; sIdCounter.set(requestId); } while (isSecondaryProvider(requestId) != isSecondary); return requestId; } public static boolean isSecondaryProvider(int requestId) { return requestId % 2 == 1; } }
services/autofill/java/com/android/server/autofill/Session.java +17 −46 Original line number Diff line number Diff line Loading @@ -263,7 +263,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState static final int AUGMENTED_AUTOFILL_REQUEST_ID = 1; private static AtomicInteger sIdCounter = new AtomicInteger(2); private static RequestId mRequestId = new RequestId(); private static AtomicInteger sIdCounterForPcc = new AtomicInteger(2); Loading Loading @@ -1333,7 +1333,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } viewState.setState(newState); int requestId = getRequestId(isSecondary); int requestId = mRequestId.nextId(isSecondary); // Create a metrics log for the request final int ordinal = mRequestLogs.size() + 1; Loading Loading @@ -1415,25 +1415,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState requestAssistStructureLocked(requestId, flags); } private static int getRequestId(boolean isSecondary) { // For authentication flows, there needs to be a way to know whether to retrieve the Fill // Response from the primary provider or the secondary provider from the requestId. A simple // way to achieve this is by assigning odd number request ids to secondary provider and // even numbers to primary provider. int requestId; // TODO(b/158623971): Update this to prevent possible overflow if (isSecondary) { do { requestId = sIdCounter.getAndIncrement(); } while (!isSecondaryProviderRequestId(requestId)); } else { do { requestId = sIdCounter.getAndIncrement(); } while (requestId == INVALID_REQUEST_ID || isSecondaryProviderRequestId(requestId)); } return requestId; } private boolean isRequestSupportFillDialog(int flags) { return (flags & FLAG_SUPPORTS_FILL_DIALOG) != 0; } Loading @@ -1441,7 +1422,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @GuardedBy("mLock") private void requestAssistStructureForPccLocked(int flags) { if (!mClassificationState.shouldTriggerRequest()) return; mFillRequestIdSnapshot = sIdCounter.get(); mFillRequestIdSnapshot = sIdCounterForPcc.get(); mClassificationState.updatePendingRequest(); // Get request id int requestId; Loading Loading @@ -2884,7 +2865,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState removeFromService(); return; } final FillResponse authenticatedResponse = isSecondaryProviderRequestId(requestId) final FillResponse authenticatedResponse = mRequestId.isSecondaryProvider(requestId) ? mSecondaryResponses.get(requestId) : mResponses.get(requestId); if (authenticatedResponse == null || data == null) { Loading Loading @@ -2982,7 +2963,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mPresentationStatsEventLogger.maybeSetAuthenticationResult( AUTHENTICATION_RESULT_SUCCESS); if (newClientState != null) { if (sDebug) Slog.d(TAG, "Updating client state from auth dataset"); if (sDebug) Slog.d(TAG, "Updating client state from auth dataset"); mClientState = newClientState; } Dataset datasetFromResult = getEffectiveDatasetForAuthentication((Dataset) result); Loading Loading @@ -3011,10 +2993,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } private static boolean isSecondaryProviderRequestId(int requestId) { return requestId % 2 == 1; } private Dataset getDatasetFromCredentialResponse(GetCredentialResponse result) { if (result == null) { return null; Loading Loading @@ -6929,22 +6907,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @GuardedBy("mLock") private int getLastResponseIndexLocked() { // The response ids are monotonically increasing so // we just find the largest id which is the last. We // do not rely on the internal ordering in sparse // array to avoid - wow this stopped working!? int lastResponseIdx = -1; int lastResponseId = -1; if (mResponses != null) { List<Integer> requestIdList = new ArrayList<>(); final int responseCount = mResponses.size(); for (int i = 0; i < responseCount; i++) { if (mResponses.keyAt(i) > lastResponseId) { lastResponseIdx = i; lastResponseId = mResponses.keyAt(i); } requestIdList.add(mResponses.keyAt(i)); } return mRequestId.getLastRequestIdIndex(requestIdList); } return lastResponseIdx; return -1; } private LogMaker newLogMaker(int category) { Loading
services/tests/servicestests/src/com/android/server/autofill/RequestIdTest.java 0 → 100644 +185 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.android.server.autofill; import static com.google.common.truth.Truth.assertThat; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.util.ArrayList; import java.util.List; @RunWith(JUnit4.class) public class RequestIdTest { List<Integer> datasetPrimaryNoWrap = new ArrayList<>(); List<Integer> datasetPrimaryWrap = new ArrayList<>(); List<Integer> datasetSecondaryNoWrap = new ArrayList<>(); List<Integer> datasetSecondaryWrap = new ArrayList<>(); List<Integer> datasetMixedNoWrap = new ArrayList<>(); List<Integer> datasetMixedWrap = new ArrayList<>(); @Before public void setup() throws Exception { int datasetSize = 300; { // Generate primary only ids that do not wrap RequestId requestId = new RequestId(0); for (int i = 0; i < datasetSize; i++) { datasetPrimaryNoWrap.add(requestId.nextId(false)); } } { // Generate primary only ids that wrap RequestId requestId = new RequestId(0xff00); for (int i = 0; i < datasetSize; i++) { datasetPrimaryWrap.add(requestId.nextId(false)); } } { // Generate SECONDARY only ids that do not wrap RequestId requestId = new RequestId(0); for (int i = 0; i < datasetSize; i++) { datasetSecondaryNoWrap.add(requestId.nextId(true)); } } { // Generate SECONDARY only ids that wrap RequestId requestId = new RequestId(0xff00); for (int i = 0; i < datasetSize; i++) { datasetSecondaryWrap.add(requestId.nextId(true)); } } { // Generate MIXED only ids that do not wrap RequestId requestId = new RequestId(0); for (int i = 0; i < datasetSize; i++) { datasetMixedNoWrap.add(requestId.nextId(i % 2 != 0)); } } { // Generate MIXED only ids that wrap RequestId requestId = new RequestId(0xff00); for (int i = 0; i < datasetSize; i++) { datasetMixedWrap.add(requestId.nextId(i % 2 != 0)); } } } @Test public void testRequestIdLists() { for (int id : datasetPrimaryNoWrap) { assertThat(RequestId.isSecondaryProvider(id)).isFalse(); assertThat(id >= 0).isTrue(); assertThat(id < 0xffff).isTrue(); } for (int id : datasetPrimaryWrap) { assertThat(RequestId.isSecondaryProvider(id)).isFalse(); assertThat(id >= 0).isTrue(); assertThat(id < 0xffff).isTrue(); } for (int id : datasetSecondaryNoWrap) { assertThat(RequestId.isSecondaryProvider(id)).isTrue(); assertThat(id >= 0).isTrue(); assertThat(id < 0xffff).isTrue(); } for (int id : datasetSecondaryWrap) { assertThat(RequestId.isSecondaryProvider(id)).isTrue(); assertThat(id >= 0).isTrue(); assertThat(id < 0xffff).isTrue(); } } @Test public void testRequestIdGeneration() { RequestId requestId = new RequestId(0); // Large Primary for (int i = 0; i < 100000; i++) { int y = requestId.nextId(false); assertThat(RequestId.isSecondaryProvider(y)).isFalse(); assertThat(y >= 0).isTrue(); assertThat(y < 0xffff).isTrue(); } // Large Secondary requestId = new RequestId(0); for (int i = 0; i < 100000; i++) { int y = requestId.nextId(true); assertThat(RequestId.isSecondaryProvider(y)).isTrue(); assertThat(y >= 0).isTrue(); assertThat(y < 0xffff).isTrue(); } // Large Mixed requestId = new RequestId(0); for (int i = 0; i < 50000; i++) { int y = requestId.nextId(i % 2 != 0); assertThat(RequestId.isSecondaryProvider(y)).isEqualTo(i % 2 == 0); assertThat(y >= 0).isTrue(); assertThat(y < 0xffff).isTrue(); } } @Test public void testGetLastRequestId() { // In this test, request ids are generated FIFO, so the last entry is also the last // request { // Primary no wrap int lastIdIndex = datasetPrimaryNoWrap.size() - 1; int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetPrimaryNoWrap); assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex); } { // Primary wrap int lastIdIndex = datasetPrimaryWrap.size() - 1; int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetPrimaryWrap); assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex); } { // Secondary no wrap int lastIdIndex = datasetSecondaryNoWrap.size() - 1; int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetSecondaryNoWrap); assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex); } { // Secondary wrap int lastIdIndex = datasetSecondaryWrap.size() - 1; int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetSecondaryWrap); assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex); } { // Mixed no wrap int lastIdIndex = datasetMixedNoWrap.size() - 1; int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetMixedNoWrap); assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex); } { // Mixed wrap int lastIdIndex = datasetMixedWrap.size() - 1; int lastComputedIdIndex = RequestId.getLastRequestIdIndex(datasetMixedWrap); assertThat(lastIdIndex).isEqualTo(lastComputedIdIndex); } } }