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 }