1 /* 2 * Copyright (C) 2011 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 17 package vogar; 18 19 import com.google.gson.stream.JsonReader; 20 import com.google.gson.stream.JsonWriter; 21 import java.io.File; 22 import java.io.FileReader; 23 import java.io.FileWriter; 24 import java.io.IOException; 25 import java.text.SimpleDateFormat; 26 import java.util.Arrays; 27 import java.util.Collections; 28 import java.util.Comparator; 29 import java.util.Date; 30 import java.util.LinkedHashMap; 31 import java.util.Map; 32 import java.util.TimeZone; 33 import vogar.commands.Mkdir; 34 import vogar.commands.Rm; 35 36 public final class OutcomeStore { 37 private static final String FILE_NAME_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssz"; 38 private static final int PRESERVE_TOTAL = 10; 39 40 private static final Comparator<File> ORDER_BY_LAST_MODIFIED = new Comparator<File>() { 41 @Override public int compare(File a, File b) { 42 if (a.lastModified() != b.lastModified()) { 43 return a.lastModified() < b.lastModified() ? -1 : 1; 44 } 45 return 0; 46 } 47 }; 48 49 private final Log log; 50 private final Mkdir mkdir; 51 private final Rm rm; 52 private final File resultsDir; 53 private final boolean recordResults; 54 private final ExpectationStore expectationStore; 55 private final Date date; 56 OutcomeStore(Log log, Mkdir mkdir, Rm rm, File resultsDir, boolean recordResults, ExpectationStore expectationStore, Date date)57 public OutcomeStore(Log log, Mkdir mkdir, Rm rm, File resultsDir, boolean recordResults, 58 ExpectationStore expectationStore, Date date) { 59 this.log = log; 60 this.mkdir = mkdir; 61 this.rm = rm; 62 this.resultsDir = resultsDir; 63 this.recordResults = recordResults; 64 this.expectationStore = expectationStore; 65 this.date = date; 66 } 67 read(Map<String, Outcome> outcomes)68 public Map<String, AnnotatedOutcome> read(Map<String, Outcome> outcomes) { 69 Map<String, AnnotatedOutcome> result = new LinkedHashMap<String, AnnotatedOutcome>(); 70 for (Map.Entry<String, Outcome> entry : outcomes.entrySet()) { 71 Outcome outcome = entry.getValue(); 72 Expectation expectation = expectationStore.get(outcome); 73 result.put(entry.getKey(), new AnnotatedOutcome(outcome, expectation)); 74 } 75 76 try { 77 File[] oldOutcomes = getOutcomeFiles(); 78 log.verbose("parsing outcomes from " + oldOutcomes.length + " files"); 79 for (File file : oldOutcomes) { 80 if (!file.getName().endsWith(".json")) { 81 continue; 82 } 83 84 loadOutcomes(result, file, file.lastModified()); 85 } 86 } catch (IOException e) { 87 log.info("Failed to read outcomes from " + resultsDir, e); 88 } 89 90 return result; 91 } 92 loadOutcomes(Map<String, AnnotatedOutcome> map, File file, long fileDate)93 private void loadOutcomes(Map<String, AnnotatedOutcome> map, File file, long fileDate) 94 throws IOException { 95 JsonReader in = new JsonReader(new FileReader(file)); 96 in.beginObject(); 97 while (in.hasNext()) { 98 String outcomeName = in.nextName(); 99 AnnotatedOutcome annotatedOutcome = map.get(outcomeName); 100 if (annotatedOutcome == null) { 101 in.skipValue(); 102 continue; 103 } 104 105 Result result = null; 106 in.beginObject(); 107 while (in.hasNext()) { 108 String fieldName = in.nextName(); 109 if (fieldName.equals("result")) { 110 result = Result.valueOf(in.nextString()); 111 } else { 112 in.skipValue(); 113 } 114 } 115 in.endObject(); 116 117 annotatedOutcome.add(fileDate, new Outcome(outcomeName, result, 118 Collections.<String>emptyList())); 119 } 120 in.endObject(); 121 in.close(); 122 } 123 write(Map<String, Outcome> outcomes)124 public void write(Map<String, Outcome> outcomes) { 125 if (!recordResults) { 126 return; 127 } 128 129 makeRoom(); 130 File outputFile = getOutputFile(); 131 try { 132 mkdir.mkdirs(outputFile.getParentFile()); 133 JsonWriter out = new JsonWriter(new FileWriter(outputFile)); 134 out.setIndent(" "); 135 out.beginObject(); 136 for (Map.Entry<String, Outcome> entry : outcomes.entrySet()) { 137 out.name(entry.getKey()); 138 out.beginObject(); 139 out.name("result"); 140 out.value(entry.getValue().getResult().toString()); 141 out.endObject(); 142 } 143 out.endObject(); 144 out.close(); 145 } catch (IOException e) { 146 log.info("Failed to write outcomes to " + outputFile, e); 147 } 148 } 149 getOutcomeFiles()150 private File[] getOutcomeFiles() { 151 File[] result = resultsDir.listFiles(); 152 if (result == null) { 153 return new File[0]; 154 } 155 Arrays.sort(result, ORDER_BY_LAST_MODIFIED); 156 return result; 157 } 158 getOutputFile()159 private File getOutputFile() { 160 SimpleDateFormat dateFormat = new SimpleDateFormat(FILE_NAME_DATE_FORMAT); 161 dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); 162 dateFormat.setLenient(true); 163 String timestamp = dateFormat.format(date); 164 return new File(resultsDir, timestamp + ".json"); 165 } 166 167 /** 168 * Removes the oldest result files until only (PRESERVE_TOTAL - 1) remain. 169 */ makeRoom()170 private void makeRoom() { 171 File[] outcomeFiles = getOutcomeFiles(); 172 for (int i = 0; i <= (outcomeFiles.length - PRESERVE_TOTAL); i++) { 173 rm.file(outcomeFiles[i]); 174 log.verbose("garbage collected results file: " + outcomeFiles[i]); 175 } 176 } 177 } 178