Test calls are rejected in invalid states

Incidentally this exercises VirtualMachineException (not that that's a big risk).

Bug: 261089785
Bug: 244561836
Test: atest MicrodroidTests
Change-Id: I91106ff08877e4a6b3f368633ca0c8c8f9d790f8
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
index 25f2310..d2cad2e 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -53,6 +53,7 @@
 import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.function.ThrowingRunnable;
 import org.junit.rules.Timeout;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -212,6 +213,62 @@
     }
 
     @Test
+    @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+    public void vmLifecycleChecks() throws Exception {
+        assumeSupportedKernel();
+
+        VirtualMachineConfig config =
+                newVmConfigBuilder()
+                        .setPayloadBinaryPath("MicrodroidTestNativeLib.so")
+                        .setMemoryMib(minMemoryRequired())
+                        .setDebugLevel(DEBUG_LEVEL_FULL)
+                        .build();
+
+        VirtualMachine vm = forceCreateNewVirtualMachine("test_vm", config);
+        assertThat(vm.getStatus()).isEqualTo(STATUS_STOPPED);
+
+        // These methods require a running VM
+        assertThrowsVmExceptionContaining(
+                () -> vm.connectVsock(VirtualMachine.MIN_VSOCK_PORT), "not in running state");
+        assertThrowsVmExceptionContaining(
+                () -> vm.connectToVsockServer(VirtualMachine.MIN_VSOCK_PORT),
+                "not in running state");
+
+        vm.run();
+        assertThat(vm.getStatus()).isEqualTo(STATUS_RUNNING);
+
+        // These methods require a stopped VM
+        assertThrowsVmExceptionContaining(() -> vm.run(), "not in stopped state");
+        assertThrowsVmExceptionContaining(() -> vm.setConfig(config), "not in stopped state");
+        assertThrowsVmExceptionContaining(() -> vm.toDescriptor(), "not in stopped state");
+        assertThrowsVmExceptionContaining(
+                () -> getVirtualMachineManager().delete("test_vm"), "not in stopped state");
+
+        vm.stop();
+        getVirtualMachineManager().delete("test_vm");
+        assertThat(vm.getStatus()).isEqualTo(STATUS_DELETED);
+
+        // None of these should work for a deleted VM
+        assertThrowsVmExceptionContaining(
+                () -> vm.connectVsock(VirtualMachine.MIN_VSOCK_PORT), "deleted");
+        assertThrowsVmExceptionContaining(
+                () -> vm.connectToVsockServer(VirtualMachine.MIN_VSOCK_PORT), "deleted");
+        assertThrowsVmExceptionContaining(() -> vm.run(), "deleted");
+        assertThrowsVmExceptionContaining(() -> vm.setConfig(config), "deleted");
+        assertThrowsVmExceptionContaining(() -> vm.toDescriptor(), "deleted");
+        // This is indistinguishable from the VM having never existed, so the message
+        // is non-specific.
+        assertThrows(
+                VirtualMachineException.class, () -> getVirtualMachineManager().delete("test_vm"));
+    }
+
+    private void assertThrowsVmExceptionContaining(
+            ThrowingRunnable runnable, String expectedContents) {
+        Exception e = assertThrows(VirtualMachineException.class, runnable);
+        assertThat(e).hasMessageThat().contains(expectedContents);
+    }
+
+    @Test
     @CddTest(requirements = {"9.17/C-1-1"})
     public void connectVsock() throws Exception {
         assumeSupportedKernel();