@Override public Object read(JsonReader in) throws IOException { JsonToken token = in.peek(); switch (token) { case BEGIN_ARRAY: List<Object> list = new ArrayList<Object>(); in.beginArray(); while (in.hasNext()) { list.add(read(in)); } in.endArray(); return list; case BEGIN_OBJECT: Map<String, Object> map = new LinkedHashTreeMap<String, Object>(); in.beginObject(); while (in.hasNext()) { map.put(in.nextName(), read(in)); } in.endObject(); return map; case STRING: return in.nextString(); case NUMBER: return in.nextDouble(); case BOOLEAN: return in.nextBoolean(); case NULL: in.nextNull(); return null; default: throw new IllegalStateException(); } }
private void fetchHeadSkin(File file, byte[] headArray) { try { HttpURLConnection connection = (HttpURLConnection) new URL("http://skinservice.codecrafter47.dyndns.eu/api/customhead").openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/json"); connection.setUseCaches(false); connection.setDoInput(true); connection.setDoOutput(true); try (DataOutputStream out = new DataOutputStream(connection. getOutputStream())) { out.write((Base64.getEncoder().encodeToString(headArray)).getBytes(Charsets.UTF_8)); out.flush(); } BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), Charsets.UTF_8)); LinkedHashTreeMap map = gson.fromJson(reader, LinkedHashTreeMap.class); if (map.get("state").equals("ERROR")) { plugin.getLogger().warning("An server side error occurred while preparing head " + file.getName()); fileSkinCache.put(file, missingSkinTexture); } else if (map.get("state").equals("QUEUED")) { plugin.getLogger().info("Preparing head " + file.getName() + " approx. " + map.get("timeLeft") + " minutes remaining."); ProxyServer.getInstance().getScheduler().schedule(plugin, () -> fetchHeadSkin(file, headArray), 30, TimeUnit.SECONDS); } else if (map.get("state").equals("SUCCESS")) { Icon skin = new Icon(null, new String[][]{{"textures", (String) map.get("skin"), (String) map.get("signature")}}); fileSkinCache.put(file, skin); headCache.put(Head.of(headArray), skin); plugin.getLogger().info("Head " + file.getName() + " is now ready for use."); // we received a new skin -> update tab to all players BungeeTabListPlus.getInstance().resendTabLists(); // save to cache File cacheFile = new File(headsFolder, "cache.txt"); if (!cacheFile.exists()) { cacheFile.createNewFile(); } BufferedWriter writer = new BufferedWriter(new FileWriter(cacheFile, true)); writer.write(Base64.getEncoder().encodeToString(headArray)); writer.write(' '); writer.write(skin.getProperties()[0][1]); writer.write(' '); writer.write(skin.getProperties()[0][2]); writer.newLine(); writer.close(); } else { plugin.getLogger().severe("Unexpected response from server: " + map.get("state")); fileSkinCache.put(file, missingSkinTexture); } } catch (IOException ex) { plugin.getLogger().log(Level.WARNING, "An error occurred while trying to contact skinservice.codecrafter47.dyndns.eu", ex); plugin.getLogger().warning("Unable to prepare head " + file.getName()); fileSkinCache.put(file, missingSkinTexture); ProxyServer.getInstance().getScheduler().schedule(plugin, () -> fileSkinCache.remove(file, missingSkinTexture), 30, TimeUnit.SECONDS); } }
@Override public void createIcon(BufferedImage image, Consumer<Icon> callback) { if (image.getWidth() != 8 || image.getHeight() != 8) { throw new IllegalArgumentException("Image must be 8x8 px."); } int[] rgb = image.getRGB(0, 0, 8, 8, null, 0, 8); ByteBuffer byteBuffer = ByteBuffer.allocate(rgb.length * 4); byteBuffer.asIntBuffer().put(rgb); byte[] headArray = byteBuffer.array(); if (headCache.containsKey(Head.of(headArray))) { Icon skin1 = headCache.get(Head.of(headArray)); callback.accept(new Icon(skin1.getPlayer(), skin1.getProperties())); return; } try { HttpURLConnection connection = (HttpURLConnection) new URL("http://skinservice.codecrafter47.dyndns.eu/api/customhead").openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/json"); connection.setUseCaches(false); connection.setDoInput(true); connection.setDoOutput(true); try (DataOutputStream out = new DataOutputStream(connection. getOutputStream())) { out.write((Base64.getEncoder().encodeToString(headArray)).getBytes(Charsets.UTF_8)); out.flush(); } BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), Charsets.UTF_8)); LinkedHashTreeMap map = gson.fromJson(reader, LinkedHashTreeMap.class); if (map.get("state").equals("SUCCESS")) { Icon skin = new Icon(null, new String[][]{{"textures", (String) map.get("skin"), (String) map.get("signature")}}); headCache.put(Head.of(headArray), skin); // save to cache File cacheFile = new File(headsFolder, "cache.txt"); if (!cacheFile.exists()) { cacheFile.createNewFile(); } BufferedWriter writer = new BufferedWriter(new FileWriter(cacheFile, true)); writer.write(Base64.getEncoder().encodeToString(headArray)); writer.write(' '); writer.write(skin.getProperties()[0][1]); writer.write(' '); writer.write(skin.getProperties()[0][2]); writer.newLine(); writer.close(); callback.accept(new Icon(skin.getPlayer(), skin.getProperties())); } else { ProxyServer.getInstance().getScheduler().schedule(plugin, () -> createIcon(image, callback), 5, TimeUnit.SECONDS); } } catch (IOException ex) { plugin.getLogger().log(Level.WARNING, "An error occurred while trying to contact skinservice.codecrafter47.dyndns.eu", ex); ProxyServer.getInstance().getScheduler().schedule(plugin, () -> createIcon(image, callback), 1, TimeUnit.MINUTES); } }
/** * 10個 story,沒有 task * filter 條件 * - 第1個 sprint * - 所有人 ALL */ public void testGetTaskBoardStoryTaskList_2() throws Exception { // Sprint 加入10個 Story int storyCount = 10; AddStoryToSprint ASTS = new AddStoryToSprint(storyCount, 1, mCS, mCP, "EST"); ASTS.exe(); // ================ set request info ======================== String projectName = mProject.getName(); request.setHeader("Referer", "?PID=" + projectName); addRequestParameter("UserID", "ALL"); addRequestParameter("sprintID", "1"); // ================ set session info ======================== request.getSession().setAttribute("UserSession", mConfig.getUserSession()); // ================ 執行 action ====================== actionPerform(); // ================ assert ====================== verifyNoActionErrors(); verifyNoActionMessages(); String result = response.getWriterBuffer().toString(); HashMap<String, Object> resultMap = mGson.fromJson(result, HashMap.class); ArrayList<LinkedHashTreeMap<String, Object>> storyList = (ArrayList<LinkedHashTreeMap<String, Object>>) resultMap.get("Stories"); Number total = (Number) resultMap.get("Total"); ArrayList<StoryObject> expectedStories = ASTS.getStories(); assertEquals(true, resultMap.get("success")); assertEquals(storyCount, total.intValue()); for (int i = 0; i < storyCount; i++) { StoryObject story; story = expectedStories.get(i); assertEquals(String.valueOf(story.getId()), storyList.get(i).get("Id")); assertEquals(story.getName(), storyList.get(i).get("Name")); assertEquals(String.valueOf(story.getValue()), storyList.get(i).get("Value")); assertEquals(String.valueOf(story.getEstimate()), storyList.get(i).get("Estimate")); assertEquals(String.valueOf(story.getImportance()), storyList.get(i).get("Importance")); assertEquals("", storyList.get(i).get("Tag")); assertEquals(story.getStatusString(), storyList.get(i).get("Status")); assertEquals(story.getNotes(), storyList.get(i).get("Notes")); assertEquals(story.getHowToDemo(), storyList.get(i).get("HowToDemo")); assertEquals(String.valueOf(mCS.getSprintsId().get(0)), storyList.get(i).get("Sprint")); assertEquals(false, storyList.get(i).get("Attach")); assertEquals(story.getAttachFiles(), storyList.get(i).get("AttachFileList")); assertEquals(new ArrayList<LinkedHashTreeMap>(), storyList.get(i).get("Tasks")); } }
/** * 測試 Story 的 burndown chart 在都沒有 done 的情況下的圖資料是否正確 */ public void testGetSprintBurndownChartData_Story_1() throws Exception { final int STORY_COUNT = 2, STORY_EST = 5; // Sprint加入2個Story AddStoryToSprint ASTS = new AddStoryToSprint(STORY_COUNT, STORY_EST, mCS, mCP, CreateProductBacklog.COLUMN_TYPE_EST); ASTS.exe(); // 拿出 sprint 的每一天日期放在 idealPointArray 當 expecte 天數 SprintBacklogLogic sprintBacklogLogic = new SprintBacklogLogic(mProject, mCS.getSprintsId().get(0)); SprintBacklogMapper SprintBacklogMapper = sprintBacklogLogic.getSprintBacklogMapper(); TaskBoard taskBoard = new TaskBoard(sprintBacklogLogic, SprintBacklogMapper); LinkedHashMap<Date, Double> ideal = taskBoard.getStoryIdealPointMap(); DateFormat formatter = new SimpleDateFormat("yyyy/MM/dd"); Object[] idealPointArray = ideal.keySet().toArray(); // ================ set request info ======================== request.setHeader("Referer", "?PID=" + mProject.getName()); addRequestParameter("SprintID", String.valueOf(mCS.getSprintsId().get(0))); addRequestParameter("Type", "story"); // ================ set session info ========================s request.getSession().setAttribute("UserSession", mConfig.getUserSession()); // ================ 執行 action ====================== actionPerform(); // ================ assert ====================== verifyNoActionErrors(); verifyNoActionMessages(); String result = response.getWriterBuffer().toString(); HashMap resultMap = mGson.fromJson(result, HashMap.class); ArrayList<LinkedHashTreeMap<String, Object>> points = (ArrayList<LinkedHashTreeMap<String, Object>>) resultMap.get("Points"); Double totalStoryPoint = new Integer(STORY_COUNT * STORY_EST).doubleValue(); // 算出每一天ideal point的遞減值 Double periodPoint = totalStoryPoint / (points.size() - 1); assertEquals(true, resultMap.get("success")); for (int i = 0; i < points.size(); i++) { assertEquals(formatter.format(idealPointArray[i]), points.get(i).get("Date")); assertEquals(totalStoryPoint - periodPoint * i, points.get(i).get("IdealPoint")); // 只有第一天有real point其他因為時間尚未到,所以不會有real point if (i == 0) { assertEquals(totalStoryPoint, points.get(i).get("RealPoint")); } else { assertEquals("null", points.get(i).get("RealPoint")); } } }
/** * 測試Story的burndown chart當有story拉到done時,資料是否正確 */ public void testGetSprintBurndownChartData_Story_2() throws Exception { final int STORY_COUNT = 2, STORY_EST = 5; // Sprint加入2個Story AddStoryToSprint ASTS = new AddStoryToSprint(STORY_COUNT, STORY_EST, mCS, mCP, CreateProductBacklog.COLUMN_TYPE_EST); ASTS.exe(); // 拿出sprint的每一天日期 SprintBacklogLogic sprintBacklogLogic = new SprintBacklogLogic(mProject, mCS.getSprintsId().get(0)); SprintBacklogMapper SprintBacklogMapper = sprintBacklogLogic.getSprintBacklogMapper(); TaskBoard taskBoard = new TaskBoard(sprintBacklogLogic, SprintBacklogMapper); LinkedHashMap<Date, Double> ideal = taskBoard.getStoryIdealPointMap(); DateFormat formatter = new SimpleDateFormat("yyyy/MM/dd"); Object[] idealPointArray = ideal.keySet().toArray(); // 將story移到done sprintBacklogLogic.closeStory(ASTS.getStories().get(0).getId(), ASTS.getStories().get(0).getName(), "", ""); // ================ set request info ======================== request.setHeader("Referer", "?PID=" + mProject.getName()); addRequestParameter("SprintID", String.valueOf(mCS.getSprintsId().get(0))); addRequestParameter("Type", "story"); // ================ set session info ========================s request.getSession().setAttribute("UserSession", mConfig.getUserSession()); // ================ 執行 action ====================== actionPerform(); // ================ assert ====================== verifyNoActionErrors(); verifyNoActionMessages(); String result = response.getWriterBuffer().toString(); HashMap resultMap = mGson.fromJson(result, HashMap.class); ArrayList<LinkedHashTreeMap<String, Object>> points = (ArrayList<LinkedHashTreeMap<String, Object>>) resultMap.get("Points"); // 由於done了一個story因此減掉一個story的est Double totalStoryPoint = new Integer(STORY_COUNT * STORY_EST).doubleValue() - STORY_EST; Double periodPoint = totalStoryPoint / (points.size() - 1); assertEquals(true, resultMap.get("success")); for (int i = 0; i < points.size(); i++) { assertEquals(formatter.format(idealPointArray[i]), points.get(i).get("Date")); assertEquals(totalStoryPoint - periodPoint * i, points.get(i).get("IdealPoint")); if (i == 0) { assertEquals(totalStoryPoint, points.get(i).get("RealPoint")); } else { assertEquals("null", points.get(i).get("RealPoint")); } } }
/** * 測試Task的burndown chart在都沒有done的情況下的圖資料是否正確 */ public void testGetSprintBurndownChartData_Task_1() throws Exception { final int STORY_COUNT = 2, TASK_COUNT = 2, STORY_EST = 5, TASK_EST = 5; // Sprint加入2個Story AddStoryToSprint ASTS = new AddStoryToSprint(STORY_COUNT, STORY_EST, mCS, mCP, CreateProductBacklog.COLUMN_TYPE_EST); ASTS.exe(); // 每個Story加入2個task AddTaskToStory ATTS = new AddTaskToStory(TASK_COUNT, TASK_EST, ASTS, mCP); ATTS.exe(); // ================ set request info ======================== request.setHeader("Referer", "?PID=" + mProject.getName()); addRequestParameter("SprintID", String.valueOf(mCS.getSprintsId().get(0))); addRequestParameter("Type", "task"); // ================ set session info ========================s request.getSession().setAttribute("UserSession", mConfig.getUserSession()); // ================ 執行 action ====================== actionPerform(); // 拿出sprint的每一天日期放在idealPointArray當expecte 天數 SprintBacklogLogic sprintBacklogLogic = new SprintBacklogLogic(mProject, mCS.getSprintsId().get(0)); SprintBacklogMapper SprintBacklogMapper = sprintBacklogLogic.getSprintBacklogMapper(); TaskBoard taskBoard = new TaskBoard(sprintBacklogLogic, SprintBacklogMapper); LinkedHashMap<Date, Double> ideal = taskBoard.getStoryIdealPointMap(); DateFormat formatter = new SimpleDateFormat("yyyy/MM/dd"); Object[] idealPointArray = ideal.keySet().toArray(); // ================ assert ====================== verifyNoActionErrors(); verifyNoActionMessages(); String result = response.getWriterBuffer().toString(); HashMap resultMap = mGson.fromJson(result, HashMap.class); ArrayList<LinkedHashTreeMap<String, Object>> points = (ArrayList<LinkedHashTreeMap<String, Object>>) resultMap.get("Points"); Double totalTaskPoint = new Integer(STORY_COUNT * TASK_COUNT * TASK_EST).doubleValue(); // 算出每一天ideal point的遞減值 Double periodPoint = totalTaskPoint / (points.size() - 1); assertEquals(true, resultMap.get("success")); for (int i = 0; i < points.size(); i++) { assertEquals(formatter.format(idealPointArray[i]), points.get(i).get("Date")); assertEquals(totalTaskPoint - periodPoint * i, points.get(i).get("IdealPoint")); // 只有第一天有real point其他因為時間尚未到,所以不會有real point if (i == 0) { assertEquals(totalTaskPoint, points.get(i).get("RealPoint")); } else { assertEquals("null", points.get(i).get("RealPoint")); } } }
/** * 測試Story的burndown chart當有story拉到done時,資料是否正確 */ public void testGetSprintBurndownChartData_Task_2() throws Exception { final int STORY_COUNT = 2, TASK_COUNT = 2, STORY_EST = 5, TASK_EST = 5; // Sprint加入2個Story AddStoryToSprint ASTS = new AddStoryToSprint(STORY_COUNT, STORY_EST, mCS, mCP, CreateProductBacklog.COLUMN_TYPE_EST); ASTS.exe(); // 每個Story加入2個task AddTaskToStory ATTS = new AddTaskToStory(TASK_COUNT, TASK_EST, ASTS, mCP); ATTS.exe(); // 拿出sprint的每一天日期 SprintBacklogLogic sprintBacklogLogic = new SprintBacklogLogic(mProject, mCS.getSprintsId().get(0)); SprintBacklogMapper SprintBacklogMapper = sprintBacklogLogic.getSprintBacklogMapper(); TaskBoard taskBoard = new TaskBoard(sprintBacklogLogic, SprintBacklogMapper); LinkedHashMap<Date, Double> ideal = taskBoard.getStoryIdealPointMap(); DateFormat formatter = new SimpleDateFormat("yyyy/MM/dd"); Object[] idealPointArray = ideal.keySet().toArray(); // 將task拉到done sprintBacklogLogic.closeTask(ATTS.getTasksId().get(0), ATTS.getTasks().get(0).getName(), "", 0, ""); // ================ set request info ======================== request.setHeader("Referer", "?PID=" + mProject.getName()); addRequestParameter("SprintID", String.valueOf(mCS.getSprintsId().get(0))); addRequestParameter("Type", "task"); // ================ set session info ========================s request.getSession().setAttribute("UserSession", mConfig.getUserSession()); // ================ 執行 action ====================== actionPerform(); // ================ assert ====================== verifyNoActionErrors(); verifyNoActionMessages(); String result = response.getWriterBuffer().toString(); HashMap resultMap = mGson.fromJson(result, HashMap.class); ArrayList<LinkedHashTreeMap<String, Object>> points = (ArrayList<LinkedHashTreeMap<String, Object>>) resultMap.get("Points"); assertEquals(true, resultMap.get("success")); // 由於done了一個task因此減掉一個task的est Double totalTaskPoint = new Integer(STORY_COUNT * TASK_COUNT * TASK_EST).doubleValue() - TASK_EST; Double periodPoint = totalTaskPoint / (points.size() - 1); for (int i = 0; i < points.size(); i++) { assertEquals(formatter.format(idealPointArray[i]), points.get(i).get("Date")); assertEquals(totalTaskPoint - periodPoint * i, points.get(i).get("IdealPoint")); if (i == 0) { assertEquals(totalTaskPoint, points.get(i).get("RealPoint")); } else { assertEquals("null", points.get(i).get("RealPoint")); } } }