diff --git a/src/main/java/org/wikitolearn/wikirating/service/MaintenanceService.java b/src/main/java/org/wikitolearn/wikirating/service/MaintenanceService.java index 02ba1ce..e8332c6 100644 --- a/src/main/java/org/wikitolearn/wikirating/service/MaintenanceService.java +++ b/src/main/java/org/wikitolearn/wikirating/service/MaintenanceService.java @@ -1,256 +1,241 @@ package org.wikitolearn.wikirating.service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.wikitolearn.wikirating.exception.*; import org.wikitolearn.wikirating.model.graph.Process; import org.wikitolearn.wikirating.util.enums.ProcessStatus; import org.wikitolearn.wikirating.util.enums.ProcessType; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; /** * @author aletundo * @author valsdav */ @Service public class MaintenanceService { private static final Logger LOG = LoggerFactory.getLogger(MaintenanceService.class); @Autowired private UserService userService; @Autowired private PageService pageService; @Autowired private RevisionService revisionService; @Autowired private MetadataService metadataService; @Autowired private ProcessService processService; @Autowired private VoteService voteService; @Value("#{'${mediawiki.langs}'.split(',')}") private List langs; @Value("${mediawiki.protocol}") private String protocol; @Value("${mediawiki.api.url}") private String apiUrl; @Value("${mediawiki.namespace}") private String namespace; /** * Initialize the graph for the first time using parallel threads for each domain language * @return true if initialization succeed */ public boolean initializeGraph() { // Initialize Metadata service metadataService.initMetadata(); // Start a new Process Process initProcess = processService.addProcess(ProcessType.INIT); metadataService.addFirstProcess(initProcess); CompletableFuture initFuture = CompletableFuture // Users and pages .allOf(buildUsersAndPagesFuturesList().toArray(new CompletableFuture[langs.size() + 1])) // CourseStructure .thenCompose(result -> CompletableFuture - .allOf(buildInitCourseStructureFuturesList().toArray(new CompletableFuture[langs.size()]))) + .allOf(buildApplyCourseStructureFuturesList().toArray(new CompletableFuture[langs.size()]))) // Revisions .thenCompose(result -> CompletableFuture .allOf(buildRevisionsFuturesList().toArray(new CompletableFuture[langs.size()]))) // Change Coefficients .thenCompose(result -> CompletableFuture .allOf(buildChangeCoefficientFuturesList().toArray(new CompletableFuture[langs.size()]))) // Users authorship .thenCompose(result -> userService.initAuthorship()); try { boolean result = initFuture.get(); // Save the result of the process if (result){ processService.closeCurrentProcess(ProcessStatus.DONE); }else{ processService.closeCurrentProcess(ProcessStatus.EXCEPTION); } return result; } catch (InterruptedException | ExecutionException e) { LOG.error("Something went wrong. {}", e.getMessage()); return false; } } /** * Entry point for the scheduled graph updated * @return true if the update succeed */ @Scheduled(cron = "${maintenance.update.cron}") public void updateGraph() { Process currentFetchProcess; Date startTimestampCurrentFetch, startTimestampLatestFetch; // Get start timestamp of the latest FETCH Process before opening a new process startTimestampLatestFetch = (processService.getLastProcessStartDateByType(ProcessType.FETCH) != null) ? processService.getLastProcessStartDateByType(ProcessType.FETCH) : processService.getLastProcessStartDateByType(ProcessType.INIT); // Create a new FETCH process try { currentFetchProcess = processService.addProcess(ProcessType.FETCH); metadataService.updateLatestProcess(); startTimestampCurrentFetch = currentFetchProcess.getStartOfProcess(); } catch (PreviousProcessOngoingException e){ LOG.error("Cannot start Update process because the previous process is still ONGOING." + "The update will be aborted."); return; } try { CompletableFuture updateFuture = CompletableFuture .allOf(userService.updateUsers(protocol + langs.get(0) + "." + apiUrl, startTimestampLatestFetch, startTimestampCurrentFetch)) .thenCompose(result -> CompletableFuture .allOf(buildUpdatePagesFuturesList(startTimestampLatestFetch, startTimestampCurrentFetch) .toArray(new CompletableFuture[langs.size()]))) .thenCompose(result -> CompletableFuture - .allOf(buildUpdateCourseStructureFuturesList().toArray(new CompletableFuture[langs.size()]))) + .allOf(buildApplyCourseStructureFuturesList().toArray(new CompletableFuture[langs.size()]))) .thenCompose(result -> voteService.validateTemporaryVotes(startTimestampCurrentFetch)); boolean result = updateFuture.get(); // Save the result of the process, closing the current one if (result) { processService.closeCurrentProcess(ProcessStatus.DONE); } else { processService.closeCurrentProcess(ProcessStatus.ERROR); } } catch (TemporaryVoteValidationException | UpdateUsersException | UpdatePagesAndRevisionsException | InterruptedException | ExecutionException e) { processService.closeCurrentProcess(ProcessStatus.EXCEPTION); LOG.error("An error occurred during a scheduled graph update procedure"); throw new UpdateGraphException(); } } /** * Build a list of CompletableFuture. * * @return a list of CompletableFuture */ - private List> buildInitCourseStructureFuturesList() { - List> parallelInitCourseStructureFutures = new ArrayList<>(); - // Add course structure for each domain language - for (String lang : langs) { - String url = protocol + lang + "." + apiUrl; - parallelInitCourseStructureFutures.add(pageService.updateCourseStructure(lang, url)); - } - return parallelInitCourseStructureFutures; - } - - /** - * Build a list of CompletableFuture. - * - * @return a list of CompletableFuture - */ - private List> buildUpdateCourseStructureFuturesList() { + private List> buildApplyCourseStructureFuturesList() { List> parallelUpdateCourseStructureFutures = new ArrayList<>(); // Add course structure for each domain language for (String lang : langs) { String url = protocol + lang + "." + apiUrl; - parallelUpdateCourseStructureFutures.add(pageService.updateCourseStructure(lang, url)); + parallelUpdateCourseStructureFutures.add(pageService.applyCourseStructure(lang, url)); } return parallelUpdateCourseStructureFutures; } /** * * @param start * @param end * @return */ private List> buildUpdatePagesFuturesList(Date start, Date end) { List> futures = new ArrayList<>(); // Add update pages for each domain language for (String lang : langs) { String url = protocol + lang + "." + apiUrl; futures.add(pageService.updatePages(lang, url, start, end)); } return futures; } /** * Build a list of CompletableFuture. The elements are the fetches of pages' * revisions from each domain language. * * @return a list of CompletableFuture */ private List> buildRevisionsFuturesList() { List> parallelRevisionsFutures = new ArrayList<>(); // Add revisions fetch for each domain language for (String lang : langs) { String url = protocol + lang + "." + apiUrl; parallelRevisionsFutures.add(revisionService.initRevisions(lang, url)); } return parallelRevisionsFutures; } private List> buildChangeCoefficientFuturesList(){ List> parallelCCFutures = new ArrayList<>(); // Add revisions fetch for each domain language for (String lang : langs) { String url = protocol + lang + "." + apiUrl; parallelCCFutures.add(revisionService.calculateChangeCoefficientAllRevisions(lang, url)); } return parallelCCFutures; } /** * Build a list of CompletableFuture. The first one is the fetch of the * users from the first domain in mediawiki.langs list. The rest of the * elements are the fetches of the pages for each language. This * implementation assumes that the users are shared among domains. * * @return a list of CompletableFuture */ private List> buildUsersAndPagesFuturesList() { List> usersAndPagesInsertion = new ArrayList<>(); // Add users fetch as fist operation usersAndPagesInsertion.add(userService.initUsers(protocol + langs.get(0) + "." + apiUrl)); // Add pages fetch for each domain language for (String lang : langs) { String url = protocol + lang + "." + apiUrl; usersAndPagesInsertion.add(pageService.initPages(lang, url)); } return usersAndPagesInsertion; } /*@SuppressWarnings("unchecked") private List> buildFuturesList(Object obj, String methodPrefix) { List> futures = new ArrayList<>(); for (String lang : langs) { String url = protocol + lang + "." + apiUrl; Method[] methods = obj.getClass().getMethods(); for (int i = 0; i < methods.length; i++) { try { if (methods[i].getName().startsWith(methodPrefix) && methods[i].getParameterCount() == 1) { futures.add((CompletableFuture) methods[i].invoke(obj, url)); } else if (methods[i].getName().startsWith(methodPrefix) && methods[i].getParameterCount() == 2) { futures.add((CompletableFuture) methods[i].invoke(obj, lang, url)); } } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } return futures; }*/ } diff --git a/src/main/java/org/wikitolearn/wikirating/service/PageService.java b/src/main/java/org/wikitolearn/wikirating/service/PageService.java index a4bf3ea..0ea5945 100644 --- a/src/main/java/org/wikitolearn/wikirating/service/PageService.java +++ b/src/main/java/org/wikitolearn/wikirating/service/PageService.java @@ -1,402 +1,380 @@ /** * */ package org.wikitolearn.wikirating.service; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.wikitolearn.wikirating.exception.GetPagesUpdateInfoException; import org.wikitolearn.wikirating.exception.PageNotFoundException; import org.wikitolearn.wikirating.exception.UpdatePagesAndRevisionsException; import org.wikitolearn.wikirating.model.CourseTree; import org.wikitolearn.wikirating.model.UpdateInfo; import org.wikitolearn.wikirating.model.graph.*; import org.wikitolearn.wikirating.repository.CourseLevelThreeRepository; import org.wikitolearn.wikirating.repository.CourseLevelTwoRepository; import org.wikitolearn.wikirating.repository.CourseRootRepository; import org.wikitolearn.wikirating.repository.PageRepository; import org.wikitolearn.wikirating.service.mediawiki.PageMediaWikiService; import org.wikitolearn.wikirating.service.mediawiki.UpdateMediaWikiService; import org.wikitolearn.wikirating.util.enums.CourseLevel; +import com.google.common.base.CaseFormat; + /** * * @author aletundo, valsdav * */ @Service public class PageService { private static final Logger LOG = LoggerFactory.getLogger(PageService.class); @Autowired private PageMediaWikiService pageMediaWikiService; @Autowired private RevisionService revisionService; @Autowired private UpdateMediaWikiService updateMediaWikiService; @Autowired private UserService userService; @Autowired private PageRepository pageRepository; @Autowired private CourseRootRepository courseRootRepository; @Autowired private CourseLevelTwoRepository courseLevelTwoRepository; @Autowired private CourseLevelThreeRepository courseLevelThreeRepository; @Value("${mediawiki.namespace}") private String namespace; /** * This methods inserts all the pages inside the DB querying the MediaWiki API. * @param lang String * @param apiUrl String The MediaWiki API url * @return CompletableFuture */ @Async public CompletableFuture initPages( String lang, String apiUrl ){ List pages = pageMediaWikiService.getAll(apiUrl); pages.forEach(page -> { page.setLang(lang); page.setLangPageId(lang + "_" +page.getPageId()); //Now we check the level of the page to set the right // additional laber for the Course Structure. CourseLevel levelLabel = getPageLevelFromTitle(page.getTitle()); if (levelLabel != CourseLevel.UNCATEGORIZED){ - page.addLabel(levelLabel.name()); + String label = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, levelLabel.name()); + page.addLabel(label); } }); pageRepository.save(pages); LOG.info("Inserted all {} pages", lang); return CompletableFuture.completedFuture(true); } /** * * @param lang * @param apiUrl * @param start * @param end * @return * @throws UpdatePagesAndRevisionsException */ @Async public CompletableFuture updatePages(String lang, String apiUrl, Date start, Date end) throws UpdatePagesAndRevisionsException{ try{ List updates = updateMediaWikiService.getPagesUpdateInfo(apiUrl, namespace, start, end); for(UpdateInfo update : updates){ if(!namespace.equals(update.getNs())) continue; switch (update.getType()) { case "new": // Add the new page with the right Course level Page newPage = addCoursePage(update.getPageLevelFromTitle(),update.getPageid(), update.getTitle(), lang); - if (update.getPageLevelFromTitle() == CourseLevel.CourseLevelThree) { + if (update.getPageLevelFromTitle() == CourseLevel.COURSE_LEVEL_THREE) { // Create the new revision. The change coefficient for the new revision is set to 0 by default. Revision newRev = revisionService.addRevision(update.getRevid(), lang, update.getUserid(), update.getOld_revid(), update.getNewlen(), update.getTimestamp()); // Add the first revision to the page ((CourseLevelThree) newPage).initFirstRevision(newRev); // It's necessary to save the page again courseLevelThreeRepository.save((CourseLevelThree) newPage); userService.setAuthorship(newRev); } break; case "edit": // Act only on CourseLevelThree pages - if (update.getPageLevelFromTitle() == CourseLevel.CourseLevelThree){ + if (update.getPageLevelFromTitle() == CourseLevel.COURSE_LEVEL_THREE){ // Create a new revision Revision updateRev = revisionService.addRevision(update.getRevid(), lang, update.getUserid(), update.getOld_revid(), update.getNewlen(), update.getTimestamp()); // Then add it to the page addRevisionToPage(lang + "_" + update.getPageid(), updateRev); // Then calculate the changeCoefficient revisionService.setChangeCoefficient(apiUrl, updateRev); // Finally set the authorship userService.setAuthorship(updateRev); } break; case "move": // We have to change the label in case the Course level is changed // Move the page to the new title movePage(update.getTitle(), update.getNewTitle(), lang); break; case "delete": // Delete the page and all its revisions deletePage(update.getTitle(), lang); break; default: break; } } }catch(GetPagesUpdateInfoException | PageNotFoundException e){ LOG.error("An error occurred while updating pages and revisions: {}", e.getMessage()); throw new UpdatePagesAndRevisionsException(); } return CompletableFuture.completedFuture(true); } /** * Create a new generic Page entity. * @param pageid * @param title * @param lang * @return the added page */ public Page addPage(int pageid, String title, String lang){ Page page = new Page(pageid, title, lang, lang + "_" + pageid); pageRepository.save(page); return page; } /** * Add a page entity distinguishing between the different Course levels. * @param level * @param pageid * @param title * @param lang * @return */ public Page addCoursePage(CourseLevel level, int pageid, String title, String lang){ switch(level){ - case CourseRoot: + case COURSE_ROOT: CourseRoot pageRoot = new CourseRoot(pageid, title, lang, lang + "_" + pageid); courseRootRepository.save(pageRoot); return pageRoot; - case CourseLevelTwo: + case COURSE_LEVEL_TWO: CourseLevelTwo pageTwo = new CourseLevelTwo(pageid, title, lang, lang + "_" + pageid); courseLevelTwoRepository.save(pageTwo); return pageTwo; - case CourseLevelThree: + case COURSE_LEVEL_THREE: CourseLevelThree pageThree = new CourseLevelThree(pageid, title, lang, lang + "_" + pageid); courseLevelThreeRepository.save(pageThree); return pageThree; default: return addPage(pageid, title, lang); } } - - /** - * Create a new CourseLevelThree page. It requires the firstRevision of the Page in order - * to create the initial relationships. - * @param pageid - * @param title - * @param lang - * @param firstRevision - * @return the added page - */ - public CourseLevelThree addCourseLevelThreePage(int pageid, String title, String lang, Revision firstRevision){ - CourseLevelThree page = new CourseLevelThree(pageid, title, lang, lang + "_" + pageid, firstRevision); - courseLevelThreeRepository.save(page); - return page; - } /** * Get the page with the given pageId and language * @param pageId the id of the page * @param lang the language of the page * @return the requested page * @throws PageNotFoundException */ public Page getPage(int pageId, String lang) throws PageNotFoundException{ Page page = pageRepository.findByLangPageId(lang + "_" + pageId); if(page == null){ LOG.error("Page with pageId {} and lang {} not found.", pageId, lang); throw new PageNotFoundException(); } return page; } /** * Get the page with the given langePageId * @param langPageId the langPageId of the page * @return the requested page * @throws PageNotFoundException */ public Page getPage(String langPageId) throws PageNotFoundException{ Page page = pageRepository.findByLangPageId(langPageId); if(page == null){ LOG.error("Page with langPageId: {} not found.", langPageId); throw new PageNotFoundException(); } return page; } /** * Add a new revision to a CourseLevelThree page. It links the page to the new revision via * LAST_REVISION link. Moreover it create the PREVIOUS_REVISION link. * @param langPageId * @param rev */ public void addRevisionToPage(String langPageId, Revision rev) throws PageNotFoundException{ CourseLevelThree page = courseLevelThreeRepository.findByLangPageId(langPageId); if(page == null){ throw new PageNotFoundException(); } //TODO Check if the page has no previous revisions // Add PREVIOUS_REVISION relationship rev.setPreviousRevision(page.getLastRevision()); //page.setLastRevision(rev); //Maybe this is not necessary // The changes on the revision will be automatically persisted courseLevelThreeRepository.save(page); //Update the LAST_REVISION edge with a query courseLevelThreeRepository.updateLastRevision(page.getLangPageId()); } /** * Change title of a page. The method is prefixed by move to follow MediaWiki naming. * The method checks also the new page title to set the right Course level label - * in case of changes. + * in case of changes * @param oldTitle the old title of the page * @param newTitle the new title to set * @param lang the language of the page * @return the updated page * @throws PageNotFoundException */ public Page movePage(String oldTitle, String newTitle, String lang) throws PageNotFoundException{ Page page = pageRepository.findByTitleAndLang(oldTitle, lang); if(page == null){ throw new PageNotFoundException(); } page.setTitle(newTitle); // Check if the Course level has changed if (getPageLevelFromTitle(oldTitle) != getPageLevelFromTitle(newTitle)){ page.removeLabel(getPageLevelFromTitle(oldTitle).name()); page.addLabel(getPageLevelFromTitle(newTitle).name()); } pageRepository.save(page); return page; } /** - * Delete a page from the graph given its title and domain language. + * Delete a page from the graph given its title and domain language * @param title the title of the page * @param lang the language of the page * @throws PageNotFoundException */ public void deletePage(String title, String lang) throws PageNotFoundException{ Page page = pageRepository.findByTitleAndLang(title, lang); if(page == null){ throw new PageNotFoundException(); } // Delete the revisions of the page if it's CourseLevelThree if (page.hasLabel("CourseLevelThree")){ revisionService.deleteRevisionsOfPage(page.getLangPageId()); } // Delete finally the page itself pageRepository.delete(page); } - /*** + /** * Get the level of a Page in the Course Structure - * anaylizing the number of slashes in the title. - * @param title - * @return null if the page has more that 2 slashes. + * analyzing the number of slashes in the title + * @param title the title of the page + * @return the course level */ public static CourseLevel getPageLevelFromTitle(String title){ - int nslash = StringUtils.countMatches(title, "/"); - switch (nslash){ + int slashesNumber = StringUtils.countMatches(title, "/"); + switch (slashesNumber){ case 0: - return CourseLevel.CourseRoot; + return CourseLevel.COURSE_ROOT; case 1: - return CourseLevel.CourseLevelTwo; + return CourseLevel.COURSE_LEVEL_TWO; case 2: - return CourseLevel.CourseLevelThree; + return CourseLevel.COURSE_LEVEL_THREE; default: //The page remains generic. return CourseLevel.UNCATEGORIZED; } } /** * Get the pages labeled by :CourseRoot label * @return the list of course root pages */ public List getCourseRootPages(String lang){ return courseRootRepository.findByLang(lang); } /** * Get the page labeled only by :Page label * @return the list of the uncategorized pages */ public List getUncategorizedPages(String lang){ return pageRepository.findAllUncategorizedPages(lang); } - - /** - * - * @param lang the language of the domain - * @param apiUrl the MediaWiki API url - * @return - */ - public CompletableFuture updateCourseStructure(String lang, String apiUrl) { - List courseRootPages = getCourseRootPages(lang); - applyCourseStructure(lang, apiUrl, courseRootPages); - - return CompletableFuture.completedFuture(true); - } - /** * @param lang the language of the domain * @param apiUrl the MediaWiki API url * @param courseRootPages */ - private void applyCourseStructure(String lang, String apiUrl, List courseRootPages) { + @Async + public CompletableFuture applyCourseStructure(String lang, String apiUrl) { + List courseRootPages = getCourseRootPages(lang); for (CourseRoot pageRoot : courseRootPages) { // Get course tree and prepare relationship set CourseTree tree = pageMediaWikiService.getCourseTree(apiUrl, pageRoot.getTitle()); Set levelsTwo = (pageRoot.getLevelsTwo() == null) ? new HashSet<>() : pageRoot.getLevelsTwo(); int index = 0; for (String levelTwo : tree.getLevelsTwo()) { String levelTwoTitle = (tree.getRoot() + "/" + levelTwo).trim(); CourseLevelTwo levelTwoPage = courseLevelTwoRepository.findByTitleAndLang(levelTwoTitle, lang); // Skip malformed page if (levelTwoPage == null) continue; - // Add levelstwo to the set to be saved + // Add levels two to the set to be saved if(!levelsTwo.contains(levelTwoPage)){ levelsTwo.add(levelTwoPage); } Set levelsThree = (levelTwoPage.getLevelsThree() == null) ? new HashSet<>() : levelTwoPage.getLevelsThree(); // Add levels three to the set to be saved for (String levelThree : tree.getLevelsTree().get(index)) { String levelThreeTitle = (levelTwoTitle + "/" + levelThree).trim(); CourseLevelThree levelThreePage = courseLevelThreeRepository.findByTitleAndLang(levelThreeTitle, lang); // Skip malformed page if (levelThreePage == null) continue; if(!levelsThree.contains(levelThreePage)){ levelsThree.add(levelThreePage); } } // Set LEVEL_THREE relationships levelTwoPage.setLevelsThree(levelsThree); courseLevelThreeRepository.save(levelsThree); index++; } - // Set LEVEL_TWO relationships and CourseRoot label + // Set LEVEL_TWO relationships pageRoot.setLevelsTwo(levelsTwo); courseLevelTwoRepository.save(levelsTwo); courseRootRepository.save(pageRoot); } + + return CompletableFuture.completedFuture(true); } } diff --git a/src/main/java/org/wikitolearn/wikirating/util/enums/CourseLevel.java b/src/main/java/org/wikitolearn/wikirating/util/enums/CourseLevel.java index 5c1fdd0..daa6f3a 100644 --- a/src/main/java/org/wikitolearn/wikirating/util/enums/CourseLevel.java +++ b/src/main/java/org/wikitolearn/wikirating/util/enums/CourseLevel.java @@ -1,9 +1,10 @@ package org.wikitolearn.wikirating.util.enums; /** - * Possible levels for Course pages. - * Created by valsdav on 05/05/17. + * Possible levels for Course pages + * @author valsdav + * @author aletundo */ public enum CourseLevel { - CourseRoot, CourseLevelTwo, CourseLevelThree, UNCATEGORIZED; + COURSE_ROOT, COURSE_LEVEL_TWO, COURSE_LEVEL_THREE, UNCATEGORIZED; } diff --git a/src/test/java/org/wikitolearn/wikirating/service/PageServiceTest.java b/src/test/java/org/wikitolearn/wikirating/service/PageServiceTest.java index 045a9f7..03464b8 100644 --- a/src/test/java/org/wikitolearn/wikirating/service/PageServiceTest.java +++ b/src/test/java/org/wikitolearn/wikirating/service/PageServiceTest.java @@ -1,131 +1,148 @@ /** * */ package org.wikitolearn.wikirating.service; import static org.junit.Assert.assertEquals; - +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.wikitolearn.wikirating.exception.PageNotFoundException; -import org.wikitolearn.wikirating.model.graph.CourseRoot; import org.wikitolearn.wikirating.model.graph.Page; -import org.wikitolearn.wikirating.model.graph.Revision; import org.wikitolearn.wikirating.repository.PageRepository; +import org.wikitolearn.wikirating.service.mediawiki.PageMediaWikiService; /** * @author aletundo * */ @RunWith(SpringJUnit4ClassRunner.class) public class PageServiceTest { @Mock private PageRepository pageRepository; + @Mock + private PageMediaWikiService pageMediaWikiService; + @InjectMocks private PageService pageService; @Before public void setup(){ MockitoAnnotations.initMocks(this); } + @Test + public void testInitPages() throws InterruptedException, ExecutionException{ + List pages = new ArrayList(); + pages.add(new Page(1, "Title", "en", "en_1")); + pages.add(new Page(2, "Title2/Subtitle2", "en", "en_2")); + pages.add(new Page(3, "Title3/Subtitle3/Subsubtitle3", "en", "en_4")); + when(pageMediaWikiService.getAll("https://en.domain.org/api.php")).thenReturn(pages); + CompletableFuture result = pageService.initPages("en", "https://en.domain.org/api.php"); + assertTrue(result.get()); + verify(pageRepository, times(1)).save(pages); + + } + @Test public void testGetPageByLangPageId(){ Page page = new Page(1, "Title", "en", "en_1"); when(pageRepository.findByLangPageId("en_1")).thenReturn(page); Page result = pageService.getPage("en_1"); assertEquals(1, result.getPageId()); assertEquals("Title", result.getTitle()); assertEquals("en", result.getLang()); assertEquals("en_1", result.getLangPageId()); } @Test public void testGetPageByPageIdAndLang(){ Page page = new Page(1, "Title", "en", "en_1"); when(pageRepository.findByLangPageId("en_1")).thenReturn(page); Page result = pageService.getPage(1, "en"); assertEquals(1, result.getPageId()); assertEquals("Title", result.getTitle()); assertEquals("en", result.getLang()); assertEquals("en_1", result.getLangPageId()); } @Test(expected = PageNotFoundException.class) public void testGetPageByPageIdAndLangNotFound(){ when(pageRepository.findByLangPageId("en_1")).thenReturn(null); pageService.getPage(1, "en"); } @Test(expected = PageNotFoundException.class) public void testGetPageByLangPageIdNotFound(){ when(pageRepository.findByLangPageId("en_1")).thenReturn(null); pageService.getPage("en_1"); } @Test(expected = PageNotFoundException.class) public void testDeletePageNotFound(){ when(pageRepository.findByTitleAndLang("Title", "en")).thenReturn(null); pageService.deletePage("Title", "en"); } @Test public void testDeletePage(){ Page page = new Page(1, "Title", "en", "en_1"); when(pageRepository.findByTitleAndLang("Title", "en")).thenReturn(page); pageService.deletePage("Title", "en"); verify(pageRepository, times(1)).delete(page); } @Test(expected = PageNotFoundException.class) public void testMovePageNotFound(){ when(pageRepository.findByLangPageId("en_1")).thenReturn(null); pageService.movePage("Title", "NewTitle", "en"); } @Test public void testMovePage(){ Page page = new Page(1, "Title", "en", "en_1"); when(pageRepository.findByTitleAndLang("Title", "en")).thenReturn(page); Page result = pageService.movePage("Title", "NewTitle", "en"); assertEquals("NewTitle", result.getTitle()); } @Test public void testAddPage(){ Page page = new Page(1, "Title", "en", "en_1"); when(pageRepository.save(page)).thenReturn(page); Page result = pageService.addPage(1, "Title", "en"); assertEquals(1, result.getPageId()); assertEquals("Title", result.getTitle()); assertEquals("en", result.getLang()); assertEquals("en_1", result.getLangPageId()); } @Test public void testGetUncategorizedPages(){ List uncategorizedPages = new ArrayList(); uncategorizedPages.add(new Page(1, "Title", "en", "en_1")); uncategorizedPages.add(new Page(2, "Title2", "en", "en_2")); uncategorizedPages.add(new Page(3, "Title3", "en", "en_4")); when(pageRepository.findAllUncategorizedPages("en")).thenReturn(uncategorizedPages); List result = pageService.getUncategorizedPages("en"); assertEquals(3, result.size()); } }