Skip to content

Commit 504158e

Browse files
authored
LlamaDemo Android UI workflow automated test (#143)
1 parent 3d1dbcf commit 504158e

5 files changed

Lines changed: 324 additions & 118 deletions

File tree

llm/android/LlamaDemo/README.md

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -189,32 +189,55 @@ Ensure you have the following functions in your callback class that you provided
189189

190190
```
191191

192-
## Instrumentation Test
193-
You can run the instrumentation test for a sanity check. The test loads a model .pte file and tokenizer.bin file
194-
under `/data/local/tmp/llama`.
192+
## Instrumentation Tests
193+
194+
The app includes instrumentation tests for sanity checking and UI workflow validation.
195+
196+
### Available Tests
197+
198+
1. **SanityCheck** - Basic model loading and generation test that verifies the LLM module can load a model and generate tokens.
199+
200+
2. **UIWorkflowTest** - UI-based tests that simulate user interactions:
201+
- `testModelLoadingWorkflow`: Tests the complete flow of selecting a model/tokenizer and loading it
202+
- `testSendMessageAndReceiveResponse`: Tests sending a message and receiving a response from the model
203+
204+
### Model Preparation
205+
206+
The test model (`stories110M.pte`) and tokenizer (`tokenizer.model`) are **automatically downloaded** when you run the tests via Gradle. The download task runs before the instrumentation tests execute.
207+
208+
If you want to manually prepare the model files, you can use the following commands:
195209

196-
### Model preparation
197-
You need to install [executorch python package](https://docs.pytorch.org/executorch/stable/getting-started.html#installation) first.
198210
```sh
211+
# Install executorch python package first: https://docs.pytorch.org/executorch/stable/getting-started.html#installation
212+
199213
curl -C - -Ls "https://huggingface.co/karpathy/tinyllamas/resolve/main/stories110M.pt" --output stories110M.pt
200214
curl -C - -Ls "https://raw.githubusercontent.com/karpathy/llama2.c/master/tokenizer.model" --output tokenizer.model
215+
201216
# Create params.json file
202217
touch params.json
203218
echo '{"dim": 768, "multiple_of": 32, "n_heads": 12, "n_layers": 12, "norm_eps": 1e-05, "vocab_size": 32000}' > params.json
204-
python -m executorch.extension.llm.export.export_llm base.checkpoint=stories110M.pt base.params=params.json model.dtype_override="fp16" export.output_name=stories110m_h.pte model.use_kv_cache=True
205-
python -m pytorch_tokenizers.tools.llama2c.convert -t tokenizer.model -o tokenizer.bin
206-
```
207-
### Push model
208-
```sh
219+
220+
# Export the model
221+
python -m executorch.extension.llm.export.export_llm base.checkpoint=stories110M.pt base.params=params.json model.dtype_override="fp16" export.output_name=stories110M.pte model.use_kv_cache=True
222+
223+
# Push to device
209224
adb shell mkdir -p /data/local/tmp/llama
210-
adb push stories110m_h.pte /data/local/tmp/llama
211-
adb push tokenizer.bin /data/local/tmp/llama
225+
adb push stories110M.pte /data/local/tmp/llama
226+
adb push tokenizer.model /data/local/tmp/llama
212227
```
213228

214-
### Run test
229+
### Running Tests
230+
231+
Run all instrumentation tests:
215232
```sh
216233
./gradlew connectedAndroidTest
217234
```
218235

236+
Run a specific test class:
237+
```sh
238+
./gradlew connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.example.executorchllamademo.SanityCheck
239+
./gradlew connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.example.executorchllamademo.UIWorkflowTest
240+
```
241+
219242
## Reporting Issues
220243
If you encountered any bugs or issues following this tutorial, please file a bug/issue here on [GitHub](https://github.com/pytorch/executorch/issues/new), or join our Discord [here](https://lnkd.in/gWCM4ViK).

llm/android/LlamaDemo/app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ dependencies {
196196
testImplementation("junit:junit:4.13.2")
197197
androidTestImplementation("androidx.test.ext:junit:1.1.5")
198198
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
199+
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.2.0")
199200
androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
200201
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
201202
debugImplementation("androidx.compose.ui:ui-tooling")

llm/android/LlamaDemo/app/src/androidTest/java/com/example/executorchllamademo/PerfTest.java

Lines changed: 0 additions & 105 deletions
This file was deleted.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
package com.example.executorchllamademo;
10+
11+
import static org.junit.Assert.assertEquals;
12+
import static org.junit.Assert.assertFalse;
13+
14+
import androidx.test.ext.junit.runners.AndroidJUnit4;
15+
import java.io.File;
16+
import java.util.ArrayList;
17+
import java.util.List;
18+
import org.junit.Test;
19+
import org.junit.runner.RunWith;
20+
import org.pytorch.executorch.extension.llm.LlmCallback;
21+
import org.pytorch.executorch.extension.llm.LlmModule;
22+
23+
@RunWith(AndroidJUnit4.class)
24+
public class SanityCheck implements LlmCallback {
25+
26+
private static final String RESOURCE_PATH = "/data/local/tmp/llama/";
27+
private static final String TOKENIZER_PATH = "tokenizer.model";
28+
private static final String MODEL_PATH = "stories110M.pte";
29+
30+
private final List<String> results = new ArrayList<>();
31+
32+
@Test
33+
public void testLoadAndGenerate() {
34+
String tokenizerPath = RESOURCE_PATH + TOKENIZER_PATH;
35+
File model = new File(RESOURCE_PATH + MODEL_PATH);
36+
LlmModule mModule = new LlmModule(model.getPath(), tokenizerPath, 0.8f);
37+
38+
int loadResult = mModule.load();
39+
// Check that the model can be loaded successfully
40+
assertEquals(0, loadResult);
41+
42+
// Run a testing prompt
43+
mModule.generate("How do you do! I'm testing llm on mobile device", SanityCheck.this);
44+
45+
// Verify we got some response
46+
assertFalse("Should receive at least one result token", results.isEmpty());
47+
}
48+
49+
@Override
50+
public void onResult(String result) {
51+
results.add(result);
52+
}
53+
54+
@Override
55+
public void onStats(String result) {
56+
// Not measuring performance for now
57+
}
58+
}

0 commit comments

Comments
 (0)