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.forge.PullRequest; 27 import org.openjdk.skara.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.*; 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.title(), 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.forge().currentUser().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.forge().currentUser().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 URIBuilder.base("http://issues.test/browse/").build(), 76 Map.of(), Duration.ZERO); 77 78 // The mailing list as well 79 var mailmanServer = MailingListServerFactory.createMailmanServer(listServer.getArchive(), listServer.getSMTP(), 80 Duration.ZERO); 81 var mailmanList = mailmanServer.getList(listAddress.address()); 82 var readerBot = new MailingListArchiveReaderBot(from, Set.of(mailmanList), Set.of(archive)); 83 84 // Populate the projects repository 85 var localRepo = CheckableRepository.init(tempFolder.path(), author.repositoryType()); 86 var masterHash = localRepo.resolve("master").orElseThrow(); 87 localRepo.push(masterHash, author.url(), "master", true); 88 localRepo.push(masterHash, archive.url(), "webrev", true); 89 90 // Make a change with a corresponding PR 91 var editHash = CheckableRepository.appendAndCommit(localRepo, "A simple change", 92 "Change msg\n\nWith several lines"); 93 localRepo.push(editHash, author.url(), "edit", true); 94 var pr = credentials.createPullRequest(archive, "master", "edit", "This is a pull request"); 95 pr.setBody("This should now be ready"); 96 97 // Run an archive pass 98 TestBotRunner.runPeriodicItems(mlBot); 99 listServer.processIncoming(); 100 101 // Run an archive pass 102 TestBotRunner.runPeriodicItems(readerBot); 103 TestBotRunner.runPeriodicItems(readerBot); 104 105 // Post a reply directly to the list 106 var conversations = mailmanList.conversations(Duration.ofDays(1)); 107 assertEquals(1, conversations.size()); 108 addReply(conversations.get(0), mailmanList, pr); 109 listServer.processIncoming(); 110 111 // Another archive reader pass - has to be done twice 112 TestBotRunner.runPeriodicItems(readerBot); 113 TestBotRunner.runPeriodicItems(readerBot); 114 115 // The bridge should now have processed the reply 116 var updated = pr.comments(); 117 assertEquals(2, updated.size()); 118 assertTrue(updated.get(1).body().contains("Mailing list message from")); 119 assertTrue(updated.get(1).body().contains("[Commenter](mailto:c@test.test)")); 120 assertTrue(updated.get(1).body().contains("[test](mailto:test@" + listAddress.domain() + ")")); 121 } 122 } 123 124 @Test 125 void rememberBridged(TestInfo testInfo) throws IOException { 126 try (var credentials = new HostCredentials(testInfo); 127 var tempFolder = new TemporaryDirectory(); 128 var listServer = new TestMailmanServer()) { 129 var author = credentials.getHostedRepository(); 130 var archive = credentials.getHostedRepository(); 131 var ignored = credentials.getHostedRepository(); 132 var listAddress = EmailAddress.parse(listServer.createList("test")); 133 var censusBuilder = credentials.getCensusBuilder() 134 .addAuthor(author.forge().currentUser().id()); 135 var from = EmailAddress.from("test", "test@test.mail"); 136 var mlBot = new MailingListBridgeBot(from, author, archive, censusBuilder.build(), "master", 137 listAddress, 138 Set.of(ignored.forge().currentUser().userName()), 139 Set.of(), 140 listServer.getArchive(), listServer.getSMTP(), 141 archive, "webrev", Path.of("test"), 142 URIBuilder.base("http://www.test.test/").build(), 143 Set.of(), Map.of(), 144 URIBuilder.base("http://issues.test/browse/").build(), 145 Map.of(), Duration.ZERO); 146 147 // The mailing list as well 148 var mailmanServer = MailingListServerFactory.createMailmanServer(listServer.getArchive(), listServer.getSMTP(), 149 Duration.ZERO); 150 var mailmanList = mailmanServer.getList(listAddress.address()); 151 var readerBot = new MailingListArchiveReaderBot(from, Set.of(mailmanList), Set.of(archive)); 152 153 // Populate the projects repository 154 var localRepo = CheckableRepository.init(tempFolder.path(), author.repositoryType()); 155 var masterHash = localRepo.resolve("master").orElseThrow(); 156 localRepo.push(masterHash, author.url(), "master", true); 157 localRepo.push(masterHash, archive.url(), "webrev", true); 158 159 // Make a change with a corresponding PR 160 var editHash = CheckableRepository.appendAndCommit(localRepo, "A simple change", 161 "Change msg\n\nWith several lines"); 162 localRepo.push(editHash, author.url(), "edit", true); 163 var pr = credentials.createPullRequest(archive, "master", "edit", "This is a pull request"); 164 pr.setBody("This should now be ready"); 165 166 // Run an archive pass 167 TestBotRunner.runPeriodicItems(mlBot); 168 listServer.processIncoming(); 169 170 // Post a reply directly to the list 171 var conversations = mailmanList.conversations(Duration.ofDays(1)); 172 assertEquals(1, conversations.size()); 173 addReply(conversations.get(0), mailmanList, pr); 174 listServer.processIncoming(); 175 176 // Another archive reader pass - has to be done twice 177 TestBotRunner.runPeriodicItems(readerBot); 178 TestBotRunner.runPeriodicItems(readerBot); 179 180 // The bridge should now have processed the reply 181 var updated = pr.comments(); 182 assertEquals(2, updated.size()); 183 184 var newReaderBot = new MailingListArchiveReaderBot(from, Set.of(mailmanList), Set.of(archive)); 185 TestBotRunner.runPeriodicItems(newReaderBot); 186 TestBotRunner.runPeriodicItems(newReaderBot); 187 188 // The new bridge should not have made duplicate posts 189 var notUpdated = pr.comments(); 190 assertEquals(2, notUpdated.size()); 191 } 192 } 193 }