aboutsummaryrefslogtreecommitdiff
path: root/tests/snapshot/src/com/android/cuttlefish/tests/SnapshotTest.java
blob: 19b36ecdadd53f894c2c072479af52b487491efe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*
 * Copyright (C) 2023 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.cuttlefish.tests;

import static org.junit.Assert.assertTrue;

import com.android.tradefed.config.Option;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.internal.DeviceResetHandler;
import com.android.tradefed.device.internal.DeviceSnapshotHandler;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import java.io.File;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
 * Test snapshot/restore function.
 *
 * <p>* This test resets the device thus it should not run with other tests in the same test suite
 * to avoid unexpected behavior.
 *
 * <p>* The test logic relies on cvd and snapshot_util_cvd tools, so it can only run in a test lab
 * setup.
 */
@RunWith(DeviceJUnit4ClassRunner.class)
public class SnapshotTest extends BaseHostJUnit4Test {

  @Option(
      name = "test-count",
      description = "Number of times to restore the device back to snapshot state.")
  private int mTestCount = 1;

  @Test
  public void testSnapshot() throws Exception {
    // Snapshot the device
    boolean snapshotRes = false;
    snapshotRes =
        new DeviceSnapshotHandler()
            .snapshotDevice(getDevice(), String.format("snapshot_img%d", mTestCount));

    if (!snapshotRes) {
      Assert.fail("failed to snapshot.");
    }

    // Create a file in tmp directory
    final String tmpFile = "/data/local/tmp/snapshot_tmp";
    getDevice().executeShellCommand("touch " + tmpFile);

    // Reboot the device to make sure the file persits.
    getDevice().reboot();
    File file = getDevice().pullFile(tmpFile);
    if (file == null) {
      Assert.fail("Setup failed: tmp file failed to persist after device reboot.");
    }

    long startAllRuns = System.currentTimeMillis();
    for (int i = 0; i < mTestCount; i++) {
      CLog.d("Restore snapshot attempt #%d", i);
      long start = System.currentTimeMillis();
      // We don't usually expect tests to use our feature server, but in this case we are
      // validating the feature itself so it's fine
      boolean restoreRes = false;
      try {
        restoreRes =
            new DeviceSnapshotHandler()
                .restoreSnapshotDevice(
                    getDevice(), String.format("snapshot_img%d", mTestCount));
      } catch (DeviceNotAvailableException e) {
        CLog.e(e);
      }
      assertTrue(
          String.format("Restore snapshot for device reset failed during attempt #%d", i), restoreRes);
      long duration = System.currentTimeMillis() - start;
      CLog.d("Restore snapshot took %dms to finish", duration);
    }
    CLog.d(
        "%d Restore snapshot runs finished successfully, with average time of %dms",
        mTestCount, (System.currentTimeMillis() - startAllRuns) / mTestCount);

    // Verify that the device is back online and pre-existing file is gone.
    file = getDevice().pullFile(tmpFile);
    if (file != null) {
      Assert.fail("Restore snapshot failed: pre-existing file still exists.");
    }
  }

  // Make sure reboots work correctly after a restore.
  //
  // There is some overlap between the cuttleifsh's support for restore and
  // reboot and so it can be easy for change to one to break the other.
  @Test
  public void testSnapshotReboot() throws Exception {
    // Snapshot the device>
    boolean snapshotRes =
        new DeviceSnapshotHandler().snapshotDevice(getDevice(), "snapshot_img");
    assertTrue("failed to snapshot", snapshotRes);
    // Restore the device.
    boolean restoreRes =
        new DeviceSnapshotHandler().restoreSnapshotDevice(getDevice(), "snapshot_img");
    assertTrue("Restore snapshot for device reset failed", restoreRes);
    // Reboot the device.
    getDevice().reboot();
    // Verify that the device is back online.
    getDevice().executeShellCommand("echo test");
  }

  // Test powerwash after restoring
  @Test
  public void testSnapshotPowerwash() throws Exception {
    // Snapshot the device>
    boolean snapshotRes =
        new DeviceSnapshotHandler().snapshotDevice(getDevice(), "snapshot_img");
    assertTrue("failed to snapshot", snapshotRes);
    // Restore the device.
    boolean restoreRes =
        new DeviceSnapshotHandler().restoreSnapshotDevice(getDevice(), "snapshot_img");
    assertTrue("Restore snapshot for device reset failed before powerwash", restoreRes);
    CLog.d("Powerwash attempt after restore");
    long start = System.currentTimeMillis();
    boolean success = new DeviceResetHandler(getInvocationContext()).resetDevice(getDevice());
    assertTrue(String.format("Powerwash reset failed during attempt after restore"), success);
    long duration = System.currentTimeMillis() - start;
    CLog.d("Powerwash took %dms to finish", duration);
    // Verify that the device is back online.
    getDevice().executeShellCommand("echo test");
  }

  // Test powerwash the device, then snapshot and restore
  @Test
  public void testPowerwashSnapshot() throws Exception {
    CLog.d("Powerwash attempt before restore");
    long start = System.currentTimeMillis();
    boolean success = new DeviceResetHandler(getInvocationContext()).resetDevice(getDevice());
    assertTrue(String.format("Powerwash reset failed during attempt before snapshot"), success);
    long duration = System.currentTimeMillis() - start;
    CLog.d("Powerwash took %dms to finish", duration);
    // Verify that the device is back online.
    getDevice().executeShellCommand("echo test");
    // Snapshot the device>
    boolean snapshotRes =
        new DeviceSnapshotHandler().snapshotDevice(getDevice(), "snapshot_img");
    assertTrue("failed to snapshot", snapshotRes);
    // Restore the device.
    boolean restoreRes =
        new DeviceSnapshotHandler().restoreSnapshotDevice(getDevice(), "snapshot_img");
    assertTrue("Restore snapshot after powerwash for device reset failed", restoreRes);
    // Verify that the device is back online.
    getDevice().executeShellCommand("echo test");
  }
}