Home | History | Annotate | Download | only in vogar
      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 
     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 
     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 
     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 
    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 
    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 
    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      */
    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