[RESTRICT AUTOMERGE] Add tests and add AutoValue.
- Add BugStorageUtilsTest
- Migrate MetaBugReport pojo to AutoValue.
This removed 40 lines of extra code.
It is useful for testing and debugging,
it automatically creates equals(), toString(),
hash() methods.
- Add completeDelete - destructively deletes the bugreport from db.
- Add expire bugreport - set status to expired and
delete zip file.
Test: atest packages/services/Car/tests/BugReportApp/tests
Test: manually on a hawk bench
Bug: 144523228
Change-Id: Ice23b105a71ed2021d28943d31e26ec5c839f637
(cherry picked from commit 08d0edea03bd94a9abcb79f947824b452a8b946a)
diff --git a/tests/BugReportApp/Android.mk b/tests/BugReportApp/Android.mk
index f948b82..186fe4b 100644
--- a/tests/BugReportApp/Android.mk
+++ b/tests/BugReportApp/Android.mk
@@ -37,7 +37,8 @@
LOCAL_DEX_PREOPT := false
LOCAL_JAVA_LIBRARIES += \
- android.car
+ android.car \
+ br_google_auto_value_target
LOCAL_STATIC_JAVA_LIBRARIES := \
androidx.recyclerview_recyclerview \
@@ -56,6 +57,11 @@
LOCAL_REQUIRED_MODULES := privapp_whitelist_com.google.android.car.bugreport
+# Explicitly define annotation processors even if javac can find them from
+# LOCAL_STATIC_JAVA_LIBRARIES.
+LOCAL_ANNOTATION_PROCESSORS := br_google_auto_value
+LOCAL_ANNOTATION_PROCESSOR_CLASSES := com.google.auto.value.processor.AutoValueProcessor
+
include $(BUILD_PACKAGE)
# ==== prebuilt library ========================
@@ -76,3 +82,28 @@
br_apache_commons:$(COMMON_LIBS_PATH)/org/eclipse/tycho/tycho-bundles-external/0.18.1/eclipse/plugins/org.apache.commons.codec_1.4.0.v201209201156.jar
include $(BUILD_MULTI_PREBUILT)
+
+# Following shenanigans are needed for LOCAL_ANNOTATION_PROCESSORS.
+
+# ==== prebuilt host libraries ========================
+include $(CLEAR_VARS)
+
+LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
+ br_google_auto_value:../../../../../prebuilts/tools/common/m2/repository/com/google/auto/value/auto-value/1.5.2/auto-value-1.5.2.jar
+
+include $(BUILD_HOST_PREBUILT)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_MODULE := br_google_auto_value_target
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := ../../../../../prebuilts/tools/common/m2/repository/com/google/auto/value/auto-value/1.5.2/auto-value-1.5.2.jar
+LOCAL_UNINSTALLABLE_MODULE := true
+
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportActivity.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportActivity.java
index 5d60672..5463813 100644
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportActivity.java
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportActivity.java
@@ -48,8 +48,6 @@
import java.io.File;
import java.io.IOException;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Random;
@@ -77,9 +75,6 @@
private static final int VOICE_MESSAGE_MAX_DURATION_MILLIS = 60 * 1000;
private static final int AUDIO_PERMISSIONS_REQUEST_ID = 1;
- private static final DateFormat BUG_REPORT_TIMESTAMP_DATE_FORMAT =
- new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
-
private final Handler mHandler = new Handler(Looper.getMainLooper());
private TextView mInProgressTitleText;
@@ -323,7 +318,7 @@
// Delete the bugreport from database, otherwise pressing "Show Bugreports" button will
// create unnecessary cancelled bugreports.
if (mMetaBugReport != null) {
- BugStorageUtils.deleteBugReport(this, mMetaBugReport.getId());
+ BugStorageUtils.completeDeleteBugReport(this, mMetaBugReport.getId());
}
Intent intent = new Intent(this, BugReportInfoActivity.class);
startActivity(intent);
@@ -456,10 +451,9 @@
* @param type bug report type, {@link MetaBugReport.BugReportType}.
*/
private static MetaBugReport createBugReport(Context context, int type) {
- Date initiatedAt = new Date();
- String timestamp = BUG_REPORT_TIMESTAMP_DATE_FORMAT.format(initiatedAt);
+ String timestamp = MetaBugReport.toBugReportTimestamp(new Date());
String username = getCurrentUserName(context);
- String title = BugReportTitleGenerator.generateBugReportTitle(initiatedAt, username);
+ String title = BugReportTitleGenerator.generateBugReportTitle(timestamp, username);
return BugStorageUtils.createBugReport(context, title, timestamp, username, type);
}
@@ -477,10 +471,9 @@
*
* <p>Example: "[A45E8] Feedback from user Driver at 2019-09-21_12:00:00"
*/
- static String generateBugReportTitle(Date initiatedAt, String username) {
+ static String generateBugReportTitle(String timestamp, String username) {
// Lookup string is used to search a bug in Buganizer (see b/130915969).
String lookupString = generateRandomString(LOOKUP_STRING_LENGTH);
- String timestamp = BUG_REPORT_TIMESTAMP_DATE_FORMAT.format(initiatedAt);
return "[" + lookupString + "] Feedback from user " + username + " at " + timestamp;
}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportService.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportService.java
index ceba655..341ab6b 100644
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportService.java
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/BugReportService.java
@@ -372,11 +372,13 @@
private void zipDirectoryAndScheduleForUpload() {
try {
+ // All the generated zip files, images and audio messages are located in this dir.
+ // This is located under the current user.
+ File bugReportTempDir = FileUtils.createTempDir(this, mMetaBugReport.getTimestamp());
// When OutputStream from openBugReportFile is closed, BugStorageProvider automatically
// schedules an upload job.
zipDirectoryToOutputStream(
- FileUtils.createTempDir(this, mMetaBugReport.getTimestamp()),
- BugStorageUtils.openBugReportFile(this, mMetaBugReport));
+ bugReportTempDir, BugStorageUtils.openBugReportFile(this, mMetaBugReport));
showBugReportFinishedNotification();
} catch (IOException e) {
Log.e(TAG, "Failed to zip files", e);
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageProvider.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageProvider.java
index 2809495..51d5a4c 100644
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageProvider.java
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageProvider.java
@@ -52,6 +52,7 @@
private static final String AUTHORITY = "com.google.android.car.bugreport";
private static final String BUG_REPORTS_TABLE = "bugreports";
private static final String URL_SEGMENT_DELETE_ZIP_FILE = "deleteZipFile";
+ private static final String URL_SEGMENT_COMPLETE_DELETE = "completeDelete";
static final Uri BUGREPORT_CONTENT_URI =
Uri.parse("content://" + AUTHORITY + "/" + BUG_REPORTS_TABLE);
@@ -71,6 +72,7 @@
private static final int URL_MATCHED_BUG_REPORTS_URI = 1;
private static final int URL_MATCHED_BUG_REPORT_ID_URI = 2;
private static final int URL_MATCHED_DELETE_ZIP_FILE = 3;
+ private static final int URL_MATCHED_COMPLETE_DELETE = 4;
private Handler mHandler;
@@ -131,6 +133,12 @@
return Uri.parse("content://" + AUTHORITY + "/" + BUG_REPORTS_TABLE + "/" + bugReportId);
}
+ /** Builds {@link Uri} that completely deletes the bugreport from DB and files. */
+ static Uri buildUriCompleteDelete(int bugReportId) {
+ return Uri.parse("content://" + AUTHORITY + "/" + BUG_REPORTS_TABLE + "/"
+ + URL_SEGMENT_COMPLETE_DELETE + "/" + bugReportId);
+ }
+
/** Builds {@link Uri} that deletes a zip file for given bugreport id. */
static Uri buildUriDeleteZipFile(int bugReportId) {
return Uri.parse("content://" + AUTHORITY + "/" + BUG_REPORTS_TABLE + "/"
@@ -144,6 +152,9 @@
mUriMatcher.addURI(
AUTHORITY, BUG_REPORTS_TABLE + "/" + URL_SEGMENT_DELETE_ZIP_FILE + "/#",
URL_MATCHED_DELETE_ZIP_FILE);
+ mUriMatcher.addURI(
+ AUTHORITY, BUG_REPORTS_TABLE + "/" + URL_SEGMENT_COMPLETE_DELETE + "/#",
+ URL_MATCHED_COMPLETE_DELETE);
}
@Override
@@ -244,18 +255,6 @@
@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
switch (mUriMatcher.match(uri)) {
- // returns the bugreport that match the id.
- case URL_MATCHED_BUG_REPORT_ID_URI:
- if (selection != null || selectionArgs != null) {
- throw new IllegalArgumentException("selection is not allowed for "
- + URL_MATCHED_BUG_REPORT_ID_URI);
- }
- selection = COLUMN_ID + " = ?";
- selectionArgs = new String[]{uri.getLastPathSegment()};
- // Ignore the results of zip file deletion, likelihood of failure is too small.
- deleteZipFile(Integer.parseInt(uri.getLastPathSegment()));
- getContext().getContentResolver().notifyChange(uri, null);
- return db.delete(BUG_REPORTS_TABLE, selection, selectionArgs);
case URL_MATCHED_DELETE_ZIP_FILE:
if (selection != null || selectionArgs != null) {
throw new IllegalArgumentException("selection is not allowed for "
@@ -266,6 +265,17 @@
return 1;
}
return 0;
+ case URL_MATCHED_COMPLETE_DELETE:
+ if (selection != null || selectionArgs != null) {
+ throw new IllegalArgumentException("selection is not allowed for "
+ + URL_MATCHED_COMPLETE_DELETE);
+ }
+ selection = COLUMN_ID + " = ?";
+ selectionArgs = new String[]{uri.getLastPathSegment()};
+ // Ignore the results of zip file deletion, possibly it wasn't even created.
+ deleteZipFile(Integer.parseInt(uri.getLastPathSegment()));
+ getContext().getContentResolver().notifyChange(uri, null);
+ return db.delete(BUG_REPORTS_TABLE, selection, selectionArgs);
default:
throw new IllegalArgumentException("Unknown URL " + uri);
}
@@ -334,7 +344,7 @@
Log.e(TAG, "Only read-only or write-only mode supported; mode=" + mode);
return;
}
- Log.i(TAG, "File " + path + " opened in write-only mode.");
+ Log.i(TAG, "File " + path + " opened in write-only mode, scheduling for upload.");
Status status;
if (e == null) {
// success writing the file. Update the field to indicate bugreport
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageUtils.java b/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageUtils.java
index 4cdc7cd..6069a8e 100644
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageUtils.java
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/BugStorageUtils.java
@@ -34,11 +34,13 @@
import android.util.Log;
import com.google.api.client.auth.oauth2.TokenResponseException;
+import com.google.common.base.Strings;
import java.io.FileNotFoundException;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -88,20 +90,7 @@
ContentResolver r = context.getContentResolver();
Uri uri = r.insert(BugStorageProvider.BUGREPORT_CONTENT_URI, values);
-
- Cursor c = r.query(uri, new String[]{COLUMN_ID}, null, null, null);
- int count = (c == null) ? 0 : c.getCount();
- if (count != 1) {
- throw new RuntimeException("Could not create a bug report entry.");
- }
- c.moveToFirst();
- int id = getInt(c, COLUMN_ID);
- c.close();
- return new MetaBugReport.Builder(id, timestamp)
- .setTitle(title)
- .setUserName(username)
- .setType(type)
- .build();
+ return findBugReport(context, Integer.parseInt(uri.getLastPathSegment())).get();
}
/**
@@ -125,16 +114,17 @@
}
/**
- * Deletes {@link MetaBugReport} record from a local database. Returns true if the record was
- * deleted.
+ * Deletes {@link MetaBugReport} record from a local database and deletes the associated file.
+ *
+ * <p>WARNING: destructive operation.
*
* @param context - an application context.
* @param bugReportId - a bug report id.
* @return true if the record was deleted.
*/
- static boolean deleteBugReport(@NonNull Context context, int bugReportId) {
+ static boolean completeDeleteBugReport(@NonNull Context context, int bugReportId) {
ContentResolver r = context.getContentResolver();
- return r.delete(BugStorageProvider.buildUriWithBugId(bugReportId), null, null) == 1;
+ return r.delete(BugStorageProvider.buildUriCompleteDelete(bugReportId), null, null) == 1;
}
/** Deletes zip file for given bugreport id; doesn't delete sqlite3 record. */
@@ -144,10 +134,10 @@
}
/**
- * Returns bugreports that are waiting to be uploaded.
+ * Returns all the bugreports that are waiting to be uploaded.
*/
@NonNull
- public static List<MetaBugReport> getPendingBugReports(@NonNull Context context) {
+ public static List<MetaBugReport> getUploadPendingBugReports(@NonNull Context context) {
String selection = COLUMN_STATUS + "=?";
String[] selectionArgs = new String[]{
Integer.toString(Status.STATUS_UPLOAD_PENDING.getValue())};
@@ -195,11 +185,12 @@
if (count > 0) c.moveToFirst();
for (int i = 0; i < count; i++) {
- MetaBugReport meta = new MetaBugReport.Builder(getInt(c, COLUMN_ID),
- getString(c, COLUMN_TIMESTAMP))
+ MetaBugReport meta = MetaBugReport.builder()
+ .setId(getInt(c, COLUMN_ID))
+ .setTimestamp(getString(c, COLUMN_TIMESTAMP))
.setUserName(getString(c, COLUMN_USERNAME))
.setTitle(getString(c, COLUMN_TITLE))
- .setFilepath(getString(c, COLUMN_FILEPATH))
+ .setFilePath(getString(c, COLUMN_FILEPATH))
.setStatus(getInt(c, COLUMN_STATUS))
.setStatusMessage(getString(c, COLUMN_STATUS_MESSAGE))
.setType(getInt(c, COLUMN_TYPE))
@@ -232,7 +223,7 @@
Log.w(TAG, "Column " + colName + " not found.");
return "";
}
- return c.getString(colIndex);
+ return Strings.nullToEmpty(c.getString(colIndex));
}
/**
@@ -262,6 +253,22 @@
setBugReportStatus(context, bugReport, Status.STATUS_UPLOAD_PENDING, msg);
}
+ /**
+ * Sets {@link MetaBugReport} status {@link Status#STATUS_EXPIRED}.
+ * Deletes the associated zip file from disk.
+ *
+ * @return true if succeeded.
+ */
+ static boolean expireBugReport(@NonNull Context context,
+ @NonNull MetaBugReport metaBugReport, @NonNull Instant expiredAt) {
+ metaBugReport = setBugReportStatus(
+ context, metaBugReport, Status.STATUS_EXPIRED, "Expired on " + expiredAt);
+ if (metaBugReport.getStatus() != Status.STATUS_EXPIRED.getValue()) {
+ return false;
+ }
+ return deleteBugReportZipfile(context, metaBugReport.getId());
+ }
+
/** Gets the root cause of the error. */
@NonNull
private static String getRootCauseMessage(@Nullable Throwable t) {
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/JobSchedulingUtils.java b/tests/BugReportApp/src/com/google/android/car/bugreport/JobSchedulingUtils.java
index a20c6c6..eac8b9a 100644
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/JobSchedulingUtils.java
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/JobSchedulingUtils.java
@@ -31,7 +31,7 @@
private static final int RETRY_DELAY_IN_MS = 5_000;
/**
- * Schedules an upload job under the current user.
+ * Schedules {@link UploadJob} under the current user.
*
* <p>Make sure this method is called under the primary user.
*
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/MetaBugReport.java b/tests/BugReportApp/src/com/google/android/car/bugreport/MetaBugReport.java
index 6d5e89b..5157d38 100644
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/MetaBugReport.java
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/MetaBugReport.java
@@ -20,13 +20,22 @@
import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
-import com.google.common.base.Strings;
+import com.google.auto.value.AutoValue;
import java.lang.annotation.Retention;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
/** Represents the information that a bugreport can contain. */
-public final class MetaBugReport implements Parcelable {
+@AutoValue
+abstract class MetaBugReport implements Parcelable {
+
+ private static final DateFormat BUG_REPORT_TIMESTAMP_DATE_FORMAT =
+ new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
/** Contains {@link #TYPE_SILENT} and audio message. */
static final int TYPE_INTERACTIVE = 0;
@@ -44,109 +53,91 @@
@IntDef({TYPE_INTERACTIVE, TYPE_SILENT})
@interface BugReportType {};
- private final int mId;
- private final String mTimestamp;
- private final String mTitle;
- private final String mUsername;
- private final String mFilePath;
- private final int mStatus;
- private final String mStatusMessage;
- /** One of {@link BugReportType}. */
- private final int mType;
-
- private MetaBugReport(Builder builder) {
- mId = builder.mId;
- mTimestamp = builder.mTimestamp;
- mTitle = builder.mTitle;
- mUsername = builder.mUsername;
- mFilePath = builder.mFilePath;
- mStatus = builder.mStatus;
- mStatusMessage = builder.mStatusMessage;
- mType = builder.mType;
- }
-
/**
* @return Id of the bug report. Bug report id monotonically increases and is unique.
*/
- public int getId() {
- return mId;
- }
+ public abstract int getId();
/**
* @return Username (LDAP) that created this bugreport
*/
- public String getUsername() {
- return Strings.nullToEmpty(mUsername);
- }
+ public abstract String getUserName();
/**
* @return Title of the bug.
*/
- public String getTitle() {
- return Strings.nullToEmpty(mTitle);
- }
+ public abstract String getTitle();
/**
* @return Timestamp when the bug report is initialized.
*/
- public String getTimestamp() {
- return Strings.nullToEmpty(mTimestamp);
+ public abstract String getTimestamp();
+
+ /**
+ * @return Timestamp converted to {@link Date}.
+ */
+ public Date getTimestampDate() {
+ try {
+ return BUG_REPORT_TIMESTAMP_DATE_FORMAT.parse(getTimestamp());
+ } catch (ParseException e) {
+ Log.e(this.getClass().getSimpleName(), "Failed to parse timestamp", e);
+ return new Date(0); // Return "January 1, 1970, 00:00:00 GMT".
+ }
}
/**
* @return path to the zip file
*/
- public String getFilePath() {
- return Strings.nullToEmpty(mFilePath);
- }
+ public abstract String getFilePath();
/**
* @return {@link Status} of the bug upload.
*/
- public int getStatus() {
- return mStatus;
- }
+ public abstract int getStatus();
/**
* @return StatusMessage of the bug upload.
*/
- public String getStatusMessage() {
- return Strings.nullToEmpty(mStatusMessage);
- }
+ public abstract String getStatusMessage();
/**
* @return {@link BugReportType}.
*/
- public int getType() {
- return mType;
- }
+ public abstract int getType();
+
+ /** @return {@link Builder} from the meta bug report. */
+ public abstract Builder toBuilder();
@Override
public int describeContents() {
return 0;
}
- /** Returns {@link Builder} from the meta bug report. */
- public Builder toBuilder() {
- return new Builder(mId, mTimestamp)
- .setFilepath(mFilePath)
- .setStatus(mStatus)
- .setStatusMessage(mStatusMessage)
- .setTitle(mTitle)
- .setUserName(mUsername)
- .setType(mType);
- }
-
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mId);
- dest.writeString(mTimestamp);
- dest.writeString(mTitle);
- dest.writeString(mUsername);
- dest.writeString(mFilePath);
- dest.writeInt(mStatus);
- dest.writeString(mStatusMessage);
- dest.writeInt(mType);
+ dest.writeInt(getId());
+ dest.writeString(getTimestamp());
+ dest.writeString(getTitle());
+ dest.writeString(getUserName());
+ dest.writeString(getFilePath());
+ dest.writeInt(getStatus());
+ dest.writeString(getStatusMessage());
+ dest.writeInt(getType());
+ }
+
+ /** Converts {@link Date} to bugreport timestamp. */
+ static String toBugReportTimestamp(Date date) {
+ return BUG_REPORT_TIMESTAMP_DATE_FORMAT.format(date);
+ }
+
+ /** Creates a {@link Builder} with default, non-null values. */
+ static Builder builder() {
+ return new AutoValue_MetaBugReport.Builder()
+ .setTimestamp("")
+ .setFilePath("")
+ .setStatusMessage("")
+ .setTitle("")
+ .setUserName("");
}
/** A creator that's used by Parcelable. */
@@ -161,10 +152,12 @@
int status = in.readInt();
String statusMessage = in.readString();
int type = in.readInt();
- return new Builder(id, timestamp)
+ return MetaBugReport.builder()
+ .setId(id)
+ .setTimestamp(timestamp)
.setTitle(title)
.setUserName(username)
- .setFilepath(filePath)
+ .setFilePath(filePath)
.setStatus(status)
.setStatusMessage(statusMessage)
.setType(type)
@@ -177,66 +170,32 @@
};
/** Builder for MetaBugReport. */
- public static class Builder {
- private final int mId;
- private final String mTimestamp;
- private String mTitle;
- private String mUsername;
- private String mFilePath;
- private int mStatus;
- private String mStatusMessage;
- private int mType;
+ @AutoValue.Builder
+ abstract static class Builder {
+ /** Sets id. */
+ public abstract Builder setId(int id);
- /**
- * Initializes MetaBugReport.Builder.
- *
- * @param id - mandatory bugreport id
- * @param timestamp - mandatory timestamp when bugreport initialized.
- */
- public Builder(int id, String timestamp) {
- mId = id;
- mTimestamp = timestamp;
- }
+ /** Sets timestamp. */
+ public abstract Builder setTimestamp(String timestamp);
/** Sets title. */
- public Builder setTitle(String title) {
- mTitle = title;
- return this;
- }
+ public abstract Builder setTitle(String title);
/** Sets username. */
- public Builder setUserName(String username) {
- mUsername = username;
- return this;
- }
+ public abstract Builder setUserName(String username);
/** Sets filepath. */
- public Builder setFilepath(String filePath) {
- mFilePath = filePath;
- return this;
- }
+ public abstract Builder setFilePath(String filePath);
/** Sets {@link Status}. */
- public Builder setStatus(int status) {
- mStatus = status;
- return this;
- }
+ public abstract Builder setStatus(int status);
/** Sets statusmessage. */
- public Builder setStatusMessage(String statusMessage) {
- mStatusMessage = statusMessage;
- return this;
- }
+ public abstract Builder setStatusMessage(String statusMessage);
/** Sets the {@link BugReportType}. */
- public Builder setType(@BugReportType int type) {
- mType = type;
- return this;
- }
+ public abstract Builder setType(@BugReportType int type);
- /** Returns a {@link MetaBugReport}. */
- public MetaBugReport build() {
- return new MetaBugReport(this);
- }
+ public abstract MetaBugReport build();
}
}
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/SimpleUploaderAsyncTask.java b/tests/BugReportApp/src/com/google/android/car/bugreport/SimpleUploaderAsyncTask.java
index 779750c..82c573f 100644
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/SimpleUploaderAsyncTask.java
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/SimpleUploaderAsyncTask.java
@@ -131,7 +131,7 @@
/** Returns true is there are more files to upload. */
@Override
protected Boolean doInBackground(Void... voids) {
- List<MetaBugReport> bugReports = BugStorageUtils.getPendingBugReports(mContext);
+ List<MetaBugReport> bugReports = BugStorageUtils.getUploadPendingBugReports(mContext);
for (MetaBugReport bugReport : bugReports) {
try {
diff --git a/tests/BugReportApp/src/com/google/android/car/bugreport/Status.java b/tests/BugReportApp/src/com/google/android/car/bugreport/Status.java
index 67aa0ca..30179a1 100644
--- a/tests/BugReportApp/src/com/google/android/car/bugreport/Status.java
+++ b/tests/BugReportApp/src/com/google/android/car/bugreport/Status.java
@@ -45,7 +45,10 @@
STATUS_MOVE_FAILED(8),
// Bugreport is moving to USB drive.
- STATUS_MOVE_IN_PROGRESS(9);
+ STATUS_MOVE_IN_PROGRESS(9),
+
+ // Bugreport is expired. Associated file is deleted from the disk.
+ STATUS_EXPIRED(10);
private final int mValue;
@@ -81,6 +84,8 @@
return "Move failed";
case 9:
return "Move in progress";
+ case 10:
+ return "Expired";
}
return "unknown";
}
diff --git a/tests/BugReportApp/tests/Android.mk b/tests/BugReportApp/tests/Android.mk
new file mode 100644
index 0000000..2a6ab88
--- /dev/null
+++ b/tests/BugReportApp/tests/Android.mk
@@ -0,0 +1,40 @@
+# Copyright (C) 2019 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := BugReportAppTest
+LOCAL_INSTRUMENTATION_FOR := BugReportApp
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_CERTIFICATE := platform
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
+LOCAL_JAVA_LIBRARIES := \
+ android.test.base \
+ android.test.mock \
+ android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-test \
+ truth-prebuilt
+
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
diff --git a/tests/BugReportApp/tests/AndroidManifest.xml b/tests/BugReportApp/tests/AndroidManifest.xml
new file mode 100644
index 0000000..e6a8537
--- /dev/null
+++ b/tests/BugReportApp/tests/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.car.bugreport.tests" >
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:label="BugReportAppTest"
+ android:targetPackage="com.google.android.car.bugreport" />
+</manifest>
diff --git a/tests/BugReportApp/tests/src/com/google/android/car/bugreport/BugStorageUtilsTest.java b/tests/BugReportApp/tests/src/com/google/android/car/bugreport/BugStorageUtilsTest.java
new file mode 100644
index 0000000..6c4a805
--- /dev/null
+++ b/tests/BugReportApp/tests/src/com/google/android/car/bugreport/BugStorageUtilsTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2019 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.car.bugreport;
+
+import static com.google.android.car.bugreport.MetaBugReport.TYPE_INTERACTIVE;
+import static com.google.android.car.bugreport.Status.STATUS_PENDING_USER_ACTION;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.time.Instant;
+import java.util.Date;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class BugStorageUtilsTest {
+ private static final String TIMESTAMP_TODAY = MetaBugReport.toBugReportTimestamp(new Date());
+ private static final int BUGREPORT_ZIP_FILE_CONTENT = 1;
+
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getContext();
+ }
+
+ @Test
+ public void test_createBugReport_createsAndReturnsMetaBugReport() throws Exception {
+ MetaBugReport bug = createBugReportWithStatus(TIMESTAMP_TODAY,
+ STATUS_PENDING_USER_ACTION, TYPE_INTERACTIVE, /* createFile= */ true);
+
+ assertThat(BugStorageUtils.findBugReport(mContext, bug.getId()).get()).isEqualTo(bug);
+ }
+
+ @Test
+ public void test_deleteBugreport_marksBugReportDeletedAndDeletesZip() throws Exception {
+ MetaBugReport bug = createBugReportWithStatus(TIMESTAMP_TODAY,
+ STATUS_PENDING_USER_ACTION, TYPE_INTERACTIVE, /* createFile= */ true);
+ try (InputStream in = mContext.getContentResolver()
+ .openInputStream(BugStorageProvider.buildUriWithBugId(bug.getId()))) {
+ assertThat(in).isNotNull();
+ }
+ Instant now = Instant.now();
+
+ boolean deleteResult = BugStorageUtils.expireBugReport(mContext, bug, now);
+
+ assertThat(deleteResult).isTrue();
+ assertThat(BugStorageUtils.findBugReport(mContext, bug.getId()).get())
+ .isEqualTo(bug.toBuilder()
+ .setStatus(Status.STATUS_EXPIRED.getValue())
+ .setStatusMessage("Expired on " + now).build());
+ try (InputStream in = mContext.getContentResolver()
+ .openInputStream(BugStorageProvider.buildUriWithBugId(bug.getId()))) {
+ assertThat(in).isNull();
+ }
+ }
+
+ @Test
+ public void test_completeDeleteBugReport_removesBugReportRecordFromDb() throws Exception {
+ MetaBugReport bug = createBugReportWithStatus(TIMESTAMP_TODAY,
+ STATUS_PENDING_USER_ACTION, TYPE_INTERACTIVE, /* createFile= */ true);
+ try (InputStream in = mContext.getContentResolver()
+ .openInputStream(BugStorageProvider.buildUriWithBugId(bug.getId()))) {
+ assertThat(in).isNotNull();
+ }
+
+ boolean deleteResult = BugStorageUtils.completeDeleteBugReport(mContext, bug.getId());
+
+ assertThat(deleteResult).isTrue();
+ assertThat(BugStorageUtils.findBugReport(mContext, bug.getId()).isPresent()).isFalse();
+ assertThrows(FileNotFoundException.class, () -> {
+ mContext.getContentResolver()
+ .openInputStream(BugStorageProvider.buildUriWithBugId(bug.getId()));
+ });
+ }
+
+ private MetaBugReport createBugReportWithStatus(
+ String timestamp, Status status, int type, boolean createFile) throws IOException {
+ MetaBugReport bugReport = BugStorageUtils.createBugReport(
+ mContext, "sample title", timestamp, "driver", type);
+ if (createFile) {
+ try (OutputStream out = BugStorageUtils.openBugReportFile(mContext, bugReport)) {
+ out.write(BUGREPORT_ZIP_FILE_CONTENT);
+ }
+ }
+ return BugStorageUtils.setBugReportStatus(mContext, bugReport, status, "");
+ }
+
+ private static void assertThrows(Class<? extends Throwable> exceptionClass,
+ ExceptionRunnable r) {
+ try {
+ r.run();
+ } catch (Throwable e) {
+ assertTrue("Expected exception type " + exceptionClass.getName() + " but got "
+ + e.getClass().getName(), exceptionClass.isAssignableFrom(e.getClass()));
+ return;
+ }
+ fail("Expected exception type " + exceptionClass.getName()
+ + ", but no exception was thrown");
+ }
+
+ private interface ExceptionRunnable {
+ void run() throws Exception;
+ }
+}