blob: 6bcb37b84d8d1777a6ffe20399954650a6cddaa6 [file] [log] [blame]
/*
* Copyright (C) 2021 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.android.chre.test.stress;
import android.hardware.location.ContextHubClient;
import android.hardware.location.ContextHubClientCallback;
import android.hardware.location.ContextHubInfo;
import android.hardware.location.ContextHubManager;
import android.hardware.location.ContextHubTransaction;
import android.hardware.location.NanoAppBinary;
import android.hardware.location.NanoAppMessage;
import android.util.Log;
import com.google.android.chre.nanoapp.proto.ChreStressTest;
import com.google.android.chre.nanoapp.proto.ChreTestCommon;
import com.google.android.utils.chre.ChreTestUtil;
import com.google.protobuf.InvalidProtocolBufferException;
import org.junit.Assert;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
/**
* A class that can execute the CHRE Stress test.
*/
public class ContextHubStressTestExecutor extends ContextHubClientCallback {
private static final String TAG = "ContextHubStressTestExecutor";
private final NanoAppBinary mNanoAppBinary;
private final long mNanoAppId;
private ContextHubClient mContextHubClient;
private final AtomicReference<ChreTestCommon.TestResult> mTestResult =
new AtomicReference<>();
private final AtomicBoolean mChreReset = new AtomicBoolean(false);
private final ContextHubManager mContextHubManager;
private final ContextHubInfo mContextHubInfo;
private CountDownLatch mCountDownLatch;
// Set to true to have the test suite only load the nanoapp and start the test.
// This can be useful for long-running stress tests, where we do not want to wait a fixed
// time to wait for successful completion.
private boolean mLoadAndStartOnly = false;
public ContextHubStressTestExecutor(ContextHubManager manager, ContextHubInfo info,
NanoAppBinary binary) {
mNanoAppBinary = binary;
mNanoAppId = mNanoAppBinary.getNanoAppId();
mContextHubManager = manager;
mContextHubInfo = info;
}
@Override
public void onMessageFromNanoApp(ContextHubClient client, NanoAppMessage message) {
if (message.getNanoAppId() == mNanoAppId) {
boolean valid = false;
switch (message.getMessageType()) {
case ChreStressTest.MessageType.TEST_RESULT_VALUE: {
try {
mTestResult.set(
ChreTestCommon.TestResult.parseFrom(message.getMessageBody()));
valid = true;
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "Failed to parse message: " + e.getMessage());
}
break;
}
default: {
Log.e(TAG, "Unknown message type " + message.getMessageType());
}
}
if (valid && mCountDownLatch != null) {
mCountDownLatch.countDown();
}
}
}
@Override
public void onHubReset(ContextHubClient client) {
mChreReset.set(true);
if (mCountDownLatch != null) {
mCountDownLatch.countDown();
}
}
/**
* Should be invoked before run() is invoked to set up the test, e.g. in a @Before method.
*/
public void init() {
init(false /* loadAndStartOnly */);
}
/**
* Same version of init, but specifies mLoadAndStartOnly.
*
* @param loadAndStartOnly Sets mLoadAndStartOnly.
*/
public void init(boolean loadAndStartOnly) {
mLoadAndStartOnly = loadAndStartOnly;
ChreTestUtil.loadNanoAppAssertSuccess(mContextHubManager, mContextHubInfo, mNanoAppBinary);
mContextHubClient = mContextHubManager.createClient(mContextHubInfo, this);
Assert.assertTrue(mContextHubClient != null);
}
/**
* @param timeout The amount of time to run the stress test.
* @param unit The unit for timeout.
*/
public void runStressTest(long timeout, TimeUnit unit) {
ChreStressTest.TestCommand.Feature[] features = {
ChreStressTest.TestCommand.Feature.WIFI,
ChreStressTest.TestCommand.Feature.GNSS_LOCATION,
ChreStressTest.TestCommand.Feature.GNSS_MEASUREMENT,
ChreStressTest.TestCommand.Feature.WWAN,
};
mTestResult.set(null);
mCountDownLatch = new CountDownLatch(1);
for (ChreStressTest.TestCommand.Feature feature : features) {
sendTestMessage(feature, true /* start */);
}
if (!mLoadAndStartOnly) {
try {
mCountDownLatch.await(timeout, unit);
} catch (InterruptedException e) {
Assert.fail(e.getMessage());
}
if (mTestResult.get() != null
&& mTestResult.get().getCode() == ChreTestCommon.TestResult.Code.FAILED) {
if (mTestResult.get().hasErrorMessage()) {
Assert.fail(new String(mTestResult.get().getErrorMessage().toByteArray(),
StandardCharsets.UTF_8));
} else {
Assert.fail("Stress test failed");
}
}
for (ChreStressTest.TestCommand.Feature feature : features) {
sendTestMessage(feature, false /* start */);
}
try {
// Add a short delay to make sure the stop command did not cause issues.
Thread.sleep(10000);
} catch (InterruptedException e) {
Assert.fail(e.getMessage());
}
}
}
/**
* Cleans up the test, should be invoked in e.g. @After method.
*/
public void deinit() {
if (!mLoadAndStartOnly) {
ChreTestUtil.unloadNanoApp(mContextHubManager, mContextHubInfo, mNanoAppId);
}
if (mContextHubClient != null) {
mContextHubClient.close();
}
if (mChreReset.get()) {
Assert.fail("CHRE reset during the test");
}
}
/**
* @param feature The feature to start testing for.
* @param start true to start the test, false to stop.
*/
private void sendTestMessage(ChreStressTest.TestCommand.Feature feature, boolean start) {
ChreStressTest.TestCommand testCommand = ChreStressTest.TestCommand.newBuilder()
.setFeature(feature).setStart(start).build();
NanoAppMessage message = NanoAppMessage.createMessageToNanoApp(
mNanoAppId, ChreStressTest.MessageType.TEST_COMMAND_VALUE,
testCommand.toByteArray());
int result = mContextHubClient.sendMessageToNanoApp(message);
if (result != ContextHubTransaction.RESULT_SUCCESS) {
Assert.fail("Failed to send message: result = " + result);
}
}
}