1 /*
2  * Copyright (c) 2016 Google Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you
5  * may not use this file except in compliance with the License. You may
6  * 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
13  * implied. See the License for the specific language governing
14  * permissions and limitations under the License.
15  */
16 
17 package com.android.vts.servlet;
18 
19 import com.android.vts.entity.TestEntity;
20 import com.android.vts.entity.TestStatusEntity;
21 import com.android.vts.entity.UserFavoriteEntity;
22 import com.google.appengine.api.datastore.DatastoreService;
23 import com.google.appengine.api.datastore.DatastoreServiceFactory;
24 import com.google.appengine.api.datastore.Entity;
25 import com.google.appengine.api.datastore.Key;
26 import com.google.appengine.api.datastore.KeyFactory;
27 import com.google.appengine.api.datastore.PropertyProjection;
28 import com.google.appengine.api.datastore.Query;
29 import com.google.appengine.api.datastore.Query.Filter;
30 import com.google.appengine.api.datastore.Query.FilterOperator;
31 import com.google.appengine.api.datastore.Query.FilterPredicate;
32 import com.google.appengine.api.users.User;
33 import com.google.appengine.api.users.UserService;
34 import com.google.appengine.api.users.UserServiceFactory;
35 import com.google.gson.Gson;
36 import java.io.IOException;
37 import java.util.ArrayList;
38 import java.util.Comparator;
39 import java.util.HashMap;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.logging.Level;
43 import java.util.stream.Collectors;
44 import javax.servlet.RequestDispatcher;
45 import javax.servlet.ServletException;
46 import javax.servlet.http.HttpServletRequest;
47 import javax.servlet.http.HttpServletResponse;
48 import javax.servlet.http.HttpSession;
49 
50 import static com.googlecode.objectify.ObjectifyService.ofy;
51 
52 /** Represents the servlet that is invoked on loading the first page of dashboard. */
53 public class DashboardMainServlet extends BaseServlet {
54     private static final String DASHBOARD_MAIN_JSP = "WEB-INF/jsp/dashboard_main.jsp";
55     private static final String NO_TESTS_ERROR = "No test results available.";
56 
57     @Override
getNavParentType()58     public PageType getNavParentType() {
59         return PageType.TOT;
60     }
61 
62     @Override
getBreadcrumbLinks(HttpServletRequest request)63     public List<Page> getBreadcrumbLinks(HttpServletRequest request) {
64         return null;
65     }
66 
67     /** Helper class for displaying test entries on the main dashboard. */
68     public class TestDisplay implements Comparable<TestDisplay> {
69         private final Key testKey;
70         private final int passCount;
71         private final int failCount;
72         private boolean muteNotifications;
73         private boolean isFavorite;
74 
75         /**
76          * Test display constructor.
77          *
78          * @param testKey The key of the test.
79          * @param passCount The number of tests passing.
80          * @param failCount The number of tests failing.
81          * @param muteNotifications The flag for user notification in case of test failure.
82          * @param isFavorite The flag for showing favorite mark on All Tests Tab page.
83          */
TestDisplay( Key testKey, int passCount, int failCount, boolean muteNotifications, boolean isFavorite)84         public TestDisplay(
85                 Key testKey,
86                 int passCount,
87                 int failCount,
88                 boolean muteNotifications,
89                 boolean isFavorite) {
90             this.testKey = testKey;
91             this.passCount = passCount;
92             this.failCount = failCount;
93             this.muteNotifications = muteNotifications;
94             this.isFavorite = isFavorite;
95         }
96 
97         /**
98          * Get the key of the test.
99          *
100          * @return The key of the test.
101          */
getName()102         public String getName() {
103             return this.testKey.getName();
104         }
105 
106         /**
107          * Get the number of passing test cases.
108          *
109          * @return The number of passing test cases.
110          */
getPassCount()111         public int getPassCount() {
112             return this.passCount;
113         }
114 
115         /**
116          * Get the number of failing test cases.
117          *
118          * @return The number of failing test cases.
119          */
getFailCount()120         public int getFailCount() {
121             return this.failCount;
122         }
123 
124         /**
125          * Get the notification mute status.
126          *
127          * @return True if the subscriber has muted notifications, false otherwise.
128          */
getMuteNotifications()129         public boolean getMuteNotifications() {
130             return this.muteNotifications;
131         }
132 
133         /** Set the notification mute status. */
setMuteNotifications(boolean muteNotifications)134         public void setMuteNotifications(boolean muteNotifications) {
135             this.muteNotifications = muteNotifications;
136         }
137 
138         /**
139          * Get the favorate status.
140          *
141          * @return True if an user set favorate for the test, false otherwise.
142          */
getIsFavorite()143         public boolean getIsFavorite() {
144             return this.isFavorite;
145         }
146 
147         /** Set the favorite status. */
setIsFavorite(boolean isFavorite)148         public void setIsFavorite(boolean isFavorite) {
149             this.isFavorite = isFavorite;
150         }
151 
152         @Override
compareTo(TestDisplay test)153         public int compareTo(TestDisplay test) {
154             return this.testKey.getName().compareTo(test.getName());
155         }
156     }
157 
158     @Override
doGetHandler(HttpServletRequest request, HttpServletResponse response)159     public void doGetHandler(HttpServletRequest request, HttpServletResponse response)
160             throws IOException {
161         UserService userService = UserServiceFactory.getUserService();
162         User currentUser = userService.getCurrentUser();
163         RequestDispatcher dispatcher = null;
164         DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
165         HttpSession session = request.getSession(true);
166         PageType referTo = PageType.TREE;
167         if (session.getAttribute("treeDefault") != null) {
168             boolean treeDefault = (boolean) session.getAttribute("treeDefault");
169             if (!treeDefault) {
170                 referTo = PageType.TABLE;
171             }
172         }
173 
174         List<TestDisplay> displayedTests = new ArrayList<>();
175         List<Key> unprocessedTestKeys = new ArrayList<>();
176 
177         Map<Key, TestDisplay> testMap = new HashMap<>(); // map from table key to TestDisplay
178         Map<String, String> subscriptionMap = new HashMap<>();
179 
180         boolean showAll = request.getParameter("showAll") != null;
181         String error = null;
182 
183         List<String> allTestNames = TestEntity.getAllTestNames();
184 
185         List<Key> favoriteKeyList = new ArrayList<Key>();
186         Filter userFilter =
187                 new FilterPredicate(UserFavoriteEntity.USER, FilterOperator.EQUAL, currentUser);
188         Query filterQuery = new Query(UserFavoriteEntity.KIND).setFilter(userFilter);
189         Iterable<Entity> favoriteIter = datastore.prepare(filterQuery).asIterable();
190         favoriteIter.forEach(
191                 fe -> {
192                     Key testKey = UserFavoriteEntity.fromEntity(fe).testKey;
193                     favoriteKeyList.add(testKey);
194                     subscriptionMap.put(testKey.getName(), KeyFactory.keyToString(fe.getKey()));
195                 });
196 
197         Query query =
198                 new Query(TestStatusEntity.KIND)
199                         .addProjection(
200                                 new PropertyProjection(TestStatusEntity.PASS_COUNT, Long.class))
201                         .addProjection(
202                                 new PropertyProjection(TestStatusEntity.FAIL_COUNT, Long.class));
203         for (Entity status : datastore.prepare(query).asIterable()) {
204             TestStatusEntity statusEntity = TestStatusEntity.fromEntity(status);
205             if (statusEntity == null) continue;
206             Key testKey = KeyFactory.createKey(TestEntity.KIND, statusEntity.getTestName());
207             boolean isFavorite = favoriteKeyList.contains(testKey);
208             TestDisplay display = new TestDisplay(testKey, -1, -1, false, isFavorite);
209             if (!unprocessedTestKeys.contains(testKey)) {
210                 display =
211                         new TestDisplay(
212                                 testKey,
213                                 statusEntity.getPassCount(),
214                                 statusEntity.getFailCount(),
215                                 false,
216                                 isFavorite);
217             }
218             testMap.put(testKey, display);
219         }
220 
221         if (testMap.size() == 0) {
222             error = NO_TESTS_ERROR;
223         }
224 
225         if (showAll) {
226             for (Key testKey : testMap.keySet()) {
227                 displayedTests.add(testMap.get(testKey));
228             }
229         } else {
230             if (testMap.size() > 0) {
231                 for (Entity favoriteEntity : favoriteIter) {
232                     UserFavoriteEntity favorite = UserFavoriteEntity.fromEntity(favoriteEntity);
233                     Key testKey = favorite.testKey;
234                     if (!testMap.containsKey(testKey)) {
235                         continue;
236                     }
237                     TestDisplay display = testMap.get(testKey);
238                     display.setMuteNotifications(favorite.muteNotifications);
239                     displayedTests.add(display);
240                 }
241             }
242         }
243         displayedTests.sort(Comparator.naturalOrder());
244 
245         response.setStatus(HttpServletResponse.SC_OK);
246         request.setAttribute("allTestsJson", new Gson().toJson(allTestNames));
247         request.setAttribute("subscriptionMapJson", new Gson().toJson(subscriptionMap));
248         request.setAttribute("testNames", displayedTests);
249         request.setAttribute("showAll", showAll);
250         request.setAttribute("error", error);
251         request.setAttribute("resultsUrl", referTo.defaultUrl);
252         dispatcher = request.getRequestDispatcher(DASHBOARD_MAIN_JSP);
253         try {
254             dispatcher.forward(request, response);
255         } catch (ServletException e) {
256             logger.log(Level.SEVERE, "Servlet Excpetion caught : ", e);
257         }
258     }
259 }
260