1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.tradefed.result.skipped;
17 
18 import java.util.regex.Matcher;
19 import java.util.regex.Pattern;
20 
21 /** Provide a reason and its metadata for skipping a test. */
22 public class SkipReason {
23 
24     private final String reason;
25     private final String trigger;
26     private final String bugId;
27 
28     // Limit the possibilities for reported trigger type, but store as a string.
29     public static enum DemotionTrigger {
30         UNKNOWN_TRIGGER, // Unspecified trigger
31         MANUAL, // Inserted directly via API
32         LATENCY, // Test is out of SLO on latency
33         ERROR_RATE, // Test is out of SLO on error rate
34         FLAKINESS; // Test is out of SLO on flakiness score
35     }
36 
SkipReason(String message, String trigger)37     public SkipReason(String message, String trigger) {
38         this(message, trigger, "");
39     }
40 
SkipReason(String message, DemotionTrigger trigger)41     public SkipReason(String message, DemotionTrigger trigger) {
42         this(message, trigger, "");
43     }
44 
SkipReason(String message, DemotionTrigger trigger, String bugId)45     public SkipReason(String message, DemotionTrigger trigger, String bugId) {
46         this(
47                 message,
48                 trigger == null ? DemotionTrigger.UNKNOWN_TRIGGER.name() : trigger.name(),
49                 bugId);
50     }
51 
SkipReason(String message, String trigger, String bugId)52     public SkipReason(String message, String trigger, String bugId) {
53         this.reason = message;
54         this.trigger = trigger;
55         this.bugId = bugId;
56     }
57 
58     /** Returns the reason associated with the skip status. */
getReason()59     public String getReason() {
60         return reason;
61     }
62 
63     /** Returns the trigger associated with the skip status. */
getTrigger()64     public String getTrigger() {
65         return trigger;
66     }
67 
68     /** Returns the bug id associated with skip status. Optional. */
getBugId()69     public String getBugId() {
70         return bugId;
71     }
72 
73     @Override
toString()74     public String toString() {
75         return "SkipReason[reason=" + reason + ", trigger=" + trigger + ", bugId=" + bugId + "]";
76     }
77 
78     /** Parses {@link #toString()} into a {@link SkipReason}. */
fromString(String skipReasonMessage)79     public static SkipReason fromString(String skipReasonMessage) {
80         Pattern p = Pattern.compile("SkipReason\\[reason=(.*), trigger=(.*), bugId=(.*)\\]");
81         Matcher m = p.matcher(skipReasonMessage);
82         if (m.find()) {
83             String reason = m.group(1);
84             String trigger = m.group(2);
85             String bugId = m.group(3);
86             return new SkipReason(reason, DemotionTrigger.valueOf(trigger), bugId);
87         }
88         throw new RuntimeException(
89                 String.format("Cannot parse '%s' as SkipReason.", skipReasonMessage));
90     }
91 }
92