1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.openjdk.skara.bots.mlbridge; 24 25 import org.openjdk.skara.email.*; 26 import org.openjdk.skara.host.PullRequest; 27 import org.openjdk.skara.host.network.URIBuilder; 28 import org.openjdk.skara.mailinglist.*; 29 import org.openjdk.skara.test.*; 30 31 import org.junit.jupiter.api.*; 32 33 import java.io.IOException; 34 import java.nio.file.Path; 35 import java.time.Duration; 36 import java.util.*; 37 38 import static org.junit.jupiter.api.Assertions.assertEquals; 39 40 class MailingListArchiveReaderBotTests { 41 private void addReply(Conversation conversation, MailingList mailingList, PullRequest pr) { 42 var first = conversation.first(); 43 44 var reply = "Looks good"; 45 var references = first.id().toString(); 46 var email = Email.create(EmailAddress.from("Commenter", "<c@test.test>"), "Re: RFR: " + pr.getTitle(), reply) 47 .recipient(first.author()) 48 .id(EmailAddress.from(UUID.randomUUID() + "@id.id")) 49 .header("In-Reply-To", first.id().toString()) 50 .header("References", references) 51 .build(); 52 mailingList.post(email); 53 } 54 55 @Test 56 void simpleArchive(TestInfo testInfo) throws IOException { 57 try (var credentials = new HostCredentials(testInfo); 58 var tempFolder = new TemporaryDirectory(); 59 var listServer = new TestMailmanServer()) { 60 var author = credentials.getHostedRepository(); 61 var archive = credentials.getHostedRepository(); 62 var ignored = credentials.getHostedRepository(); 63 var listAddress = EmailAddress.parse(listServer.createList("test")); 64 var censusBuilder = credentials.getCensusBuilder() 65 .addAuthor(author.host().getCurrentUserDetails().id()); 66 var from = EmailAddress.from("test", "test@test.mail"); 67 var mlBot = new MailingListBridgeBot(from, author, archive, censusBuilder.build(), "master", 68 listAddress, 69 Set.of(ignored.host().getCurrentUserDetails().userName()), 70 Set.of(), 71 listServer.getArchive(), listServer.getSMTP(), 72 archive, "webrev", Path.of("test"), 73 URIBuilder.base("http://www.test.test/").build(), 74 Set.of(), Map.of()); 75 76 // The mailing list as well 77 var mailmanServer = MailingListServerFactory.createMailmanServer(listServer.getArchive(), listServer.getSMTP()); 78 var mailmanList = mailmanServer.getList(listAddress.address()); 79 var readerBot = new MailingListArchiveReaderBot(from, Set.of(mailmanList), Set.of(archive)); 80 81 // Populate the projects repository 82 var localRepo = CheckableRepository.init(tempFolder.path(), author.getRepositoryType()); 83 var masterHash = localRepo.resolve("master").orElseThrow(); 84 localRepo.push(masterHash, author.getUrl(), "master", true); 85 localRepo.push(masterHash, archive.getUrl(), "webrev", true); 86 87 // Make a change with a corresponding PR 88 var editHash = CheckableRepository.appendAndCommit(localRepo, "A simple change", 89 "Change msg\n\nWith several lines"); 90 localRepo.push(editHash, author.getUrl(), "edit", true); 91 var pr = credentials.createPullRequest(archive, "master", "edit", "This is a pull request"); 92 pr.setBody("This should now be ready"); 93 94 // Run an archive pass 95 TestBotRunner.runPeriodicItems(mlBot); 96 listServer.processIncoming(); 97 98 // Run an archive pass 99 TestBotRunner.runPeriodicItems(readerBot); 100 TestBotRunner.runPeriodicItems(readerBot); 101 102 // Post a reply directly to the list 103 var conversations = mailmanList.conversations(Duration.ofDays(1)); 104 assertEquals(1, conversations.size()); 105 addReply(conversations.get(0), mailmanList, pr); 106 listServer.processIncoming(); 107 108 // Another archive reader pass - has to be done twice 109 TestBotRunner.runPeriodicItems(readerBot); 110 TestBotRunner.runPeriodicItems(readerBot); 111 112 // The bridge should now have processed the reply 113 var updated = pr.getComments(); 114 assertEquals(2, updated.size()); 115 } 116 } 117 118 @Test 119 void rememberBridged(TestInfo testInfo) throws IOException { 120 try (var credentials = new HostCredentials(testInfo); 121 var tempFolder = new TemporaryDirectory(); 122 var listServer = new TestMailmanServer()) { 123 var author = credentials.getHostedRepository(); 124 var archive = credentials.getHostedRepository(); 125 var ignored = credentials.getHostedRepository(); 126 var listAddress = EmailAddress.parse(listServer.createList("test")); 127 var censusBuilder = credentials.getCensusBuilder() 128 .addAuthor(author.host().getCurrentUserDetails().id()); 129 var from = EmailAddress.from("test", "test@test.mail"); 130 var mlBot = new MailingListBridgeBot(from, author, archive, censusBuilder.build(), "master", 131 listAddress, 132 Set.of(ignored.host().getCurrentUserDetails().userName()), 133 Set.of(), 134 listServer.getArchive(), listServer.getSMTP(), 135 archive, "webrev", Path.of("test"), 136 URIBuilder.base("http://www.test.test/").build(), 137 Set.of(), Map.of()); 138 139 // The mailing list as well 140 var mailmanServer = MailingListServerFactory.createMailmanServer(listServer.getArchive(), listServer.getSMTP()); 141 var mailmanList = mailmanServer.getList(listAddress.address()); 142 var readerBot = new MailingListArchiveReaderBot(from, Set.of(mailmanList), Set.of(archive)); 143 144 // Populate the projects repository 145 var localRepo = CheckableRepository.init(tempFolder.path(), author.getRepositoryType()); 146 var masterHash = localRepo.resolve("master").orElseThrow(); 147 localRepo.push(masterHash, author.getUrl(), "master", true); 148 localRepo.push(masterHash, archive.getUrl(), "webrev", true); 149 150 // Make a change with a corresponding PR 151 var editHash = CheckableRepository.appendAndCommit(localRepo, "A simple change", 152 "Change msg\n\nWith several lines"); 153 localRepo.push(editHash, author.getUrl(), "edit", true); 154 var pr = credentials.createPullRequest(archive, "master", "edit", "This is a pull request"); 155 pr.setBody("This should now be ready"); 156 157 // Run an archive pass 158 TestBotRunner.runPeriodicItems(mlBot); 159 listServer.processIncoming(); 160 161 // Post a reply directly to the list 162 var conversations = mailmanList.conversations(Duration.ofDays(1)); 163 assertEquals(1, conversations.size()); 164 addReply(conversations.get(0), mailmanList, pr); 165 listServer.processIncoming(); 166 167 // Another archive reader pass - has to be done twice 168 TestBotRunner.runPeriodicItems(readerBot); 169 TestBotRunner.runPeriodicItems(readerBot); 170 171 // The bridge should now have processed the reply 172 var updated = pr.getComments(); 173 assertEquals(2, updated.size()); 174 175 var newReaderBot = new MailingListArchiveReaderBot(from, Set.of(mailmanList), Set.of(archive)); 176 TestBotRunner.runPeriodicItems(newReaderBot); 177 TestBotRunner.runPeriodicItems(newReaderBot); 178 179 // The new bridge should not have made duplicate posts 180 var notUpdated = pr.getComments(); 181 assertEquals(2, notUpdated.size()); 182 } 183 } 184 }