001 package org.hackystat.telemetry.analyzer.reducer.impl; 002 003 import java.util.List; 004 005 import org.hackystat.dailyprojectdata.client.DailyProjectDataClient; 006 import org.hackystat.dailyprojectdata.resource.unittest.jaxb.MemberData; 007 import org.hackystat.dailyprojectdata.resource.unittest.jaxb.UnitTestDailyProjectData; 008 import org.hackystat.sensorbase.resource.projects.jaxb.Project; 009 import org.hackystat.telemetry.analyzer.model.TelemetryDataPoint; 010 import org.hackystat.telemetry.analyzer.model.TelemetryStream; 011 import org.hackystat.telemetry.analyzer.model.TelemetryStreamCollection; 012 import org.hackystat.telemetry.analyzer.reducer.TelemetryReducer; 013 import org.hackystat.telemetry.analyzer.reducer.TelemetryReducerException; 014 import org.hackystat.telemetry.analyzer.reducer.util.IntervalUtility; 015 import org.hackystat.telemetry.service.server.ServerProperties; 016 import org.hackystat.utilities.time.interval.Interval; 017 import org.hackystat.utilities.time.period.Day; 018 import org.hackystat.utilities.tstamp.Tstamp; 019 020 021 /** 022 * Returns a single stream providing UnitTest data. 023 * <p> 024 * Options: 025 * <ol> 026 * <li> mode: One of 'TotalCount', 'SuccessCount', or 'FailureCount'. Default is 'TotalCount'. 027 * <li> member: The project member whose unit test data is to be returned, or "*" for all members. 028 * <li> isCumulative: True or false. Default is false. 029 * </ol> 030 * 031 * @author Hongbing Kou, Philip Johnson 032 */ 033 public class UnitTestReducer implements TelemetryReducer { 034 035 /** Possible mode values. */ 036 public enum Mode { TOTALCOUNT, SUCCESSCOUNT, FAILURECOUNT } 037 038 /** 039 * Computes and returns the required telemetry streams object. 040 * 041 * @param project The project. 042 * @param dpdClient The DPD Client. 043 * @param interval The interval. 044 * @param options The optional parameters. 045 * 046 * @return Telemetry stream collection. 047 * @throws TelemetryReducerException If there is any error. 048 */ 049 public TelemetryStreamCollection compute(Project project, DailyProjectDataClient dpdClient, 050 Interval interval, String[] options) throws TelemetryReducerException { 051 Mode mode = Mode.TOTALCOUNT; 052 String member = null; 053 boolean isCumulative = false; 054 //process options 055 if (options.length > 3) { 056 throw new TelemetryReducerException("UnitTest reducer takes 3 optional parameters."); 057 } 058 if (options.length >= 1) { 059 try { 060 mode = Mode.valueOf(options[0].toUpperCase()); 061 } 062 catch (Exception e) { 063 throw new TelemetryReducerException("Illegal mode value.", e); 064 } 065 } 066 067 if (options.length >= 2) { 068 member = options[1]; 069 } 070 071 if (options.length >= 3) { 072 try { 073 isCumulative = Boolean.valueOf(options[2]); 074 } 075 catch (Exception e) { 076 throw new TelemetryReducerException("Illegal cumulative value.", e); 077 } 078 } 079 080 // Find out the DailyProjectData host, throw error if not found. 081 String dpdHost = System.getProperty(ServerProperties.DAILYPROJECTDATA_FULLHOST_KEY); 082 if (dpdHost == null) { 083 throw new TelemetryReducerException("Null DPD host in UnitTestReducer"); 084 } 085 086 // now get the telemetry stream. 087 try { 088 TelemetryStream telemetryStream = this.getStream(dpdClient, project, interval, 089 mode, member, isCumulative, null); 090 TelemetryStreamCollection streams = new TelemetryStreamCollection(null, project, interval); 091 streams.add(telemetryStream); 092 return streams; 093 } 094 catch (Exception e) { 095 throw new TelemetryReducerException(e); 096 } 097 } 098 099 /** 100 * Gets the telemetry stream. 101 * 102 * @param dpdClient The DailyProjectData client we will contact for the data. 103 * @param project The project. 104 * @param interval The interval. 105 * @param mode The mode (TOTALCOUNT, SUCCESSCOUNT, or FAILURECOUNT). 106 * @param member The member, or "*" for all members. 107 * @param isCumulative True for cumulative measure. 108 * @param streamTagValue The tag for the generated telemetry stream. 109 * 110 * @return The telemetry stream as required. 111 * 112 * @throws Exception If there is any error. 113 */ 114 TelemetryStream getStream(DailyProjectDataClient dpdClient, 115 Project project, Interval interval, Mode mode, 116 String member, boolean isCumulative, Object streamTagValue) 117 throws Exception { 118 TelemetryStream telemetryStream = new TelemetryStream(streamTagValue); 119 List<IntervalUtility.Period> periods = IntervalUtility.getPeriods(interval); 120 double cumulativeTestCount = 0; 121 122 for (IntervalUtility.Period period : periods) { 123 Long value = this.getData(dpdClient, project, period.getStartDay(), period.getEndDay(), 124 mode, member); 125 126 if (value != null) { 127 cumulativeTestCount += value; 128 } 129 130 if (isCumulative) { 131 telemetryStream.addDataPoint(new TelemetryDataPoint(period.getTimePeriod(), 132 cumulativeTestCount)); 133 } 134 else { 135 telemetryStream.addDataPoint(new TelemetryDataPoint(period.getTimePeriod(), value)); 136 } 137 } 138 return telemetryStream; 139 } 140 141 /** 142 * Returns a UnitTest value for the specified time interval, or null if no SensorData. 143 * 144 * @param dpdClient The DailyProjectData client we will use to get this data. 145 * @param project The project. 146 * @param startDay The start day (inclusive). 147 * @param endDay The end day (inclusive). 148 * @param mode The mode. 149 * @param member The member email, or "*" for all members. 150 * @throws TelemetryReducerException If anything goes wrong. 151 * 152 * @return The UnitTest count, or null if there is no UnitTest SensorData for that time period. 153 */ 154 Long getData(DailyProjectDataClient dpdClient, Project project, Day startDay, Day endDay, 155 Mode mode, String member) throws TelemetryReducerException { 156 long count = 0; 157 boolean hasData = false; 158 try { 159 // For each day in the interval... 160 for (Day day = startDay; day.compareTo(endDay) <= 0; day = day.inc(1) ) { 161 // Get the DPD... 162 UnitTestDailyProjectData data = 163 dpdClient.getUnitTest(project.getOwner(), project.getName(), Tstamp.makeTimestamp(day)); 164 // Go through the DPD per-member data... 165 for (MemberData memberData : data.getMemberData()) { 166 if ((member == null) || "*".equals(member) || 167 (memberData.getMemberUri().endsWith(member))) { 168 hasData = true; 169 switch (mode) { 170 case TOTALCOUNT: 171 count += memberData.getFailure().longValue() + memberData.getSuccess().longValue(); 172 break; 173 case SUCCESSCOUNT: 174 count += memberData.getSuccess().longValue(); 175 break; 176 case FAILURECOUNT: 177 count += memberData.getFailure().longValue(); 178 break; 179 default: 180 throw new TelemetryReducerException("Unknown mode: " + mode); 181 } 182 } 183 } 184 } 185 } 186 catch (Exception ex) { 187 throw new TelemetryReducerException(ex); 188 } 189 190 //Return null if no data, the UnitTest data otherwise. 191 return (hasData) ? Long.valueOf(count) : null; 192 } 193 194 }