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