1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * See LICENSE.txt included in this distribution for the specific
9  * language governing permissions and limitations under the License.
10  *
11  * When distributing Covered Code, include this CDDL HEADER in each
12  * file and include the License file at LICENSE.txt.
13  * If applicable, add the following below this CDDL HEADER, with the
14  * fields enclosed by brackets "[]" replaced with your own identifying
15  * information: Portions Copyright [yyyy] [name of copyright owner]
16  *
17  * CDDL HEADER END
18  */
19 
20 /*
21  * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
22  * Portions Copyright (c) 2018-2019, Chris Fraire <cfraire@me.com>.
23  */
24 package org.opengrok.indexer.history;
25 
26 import java.io.ByteArrayInputStream;
27 import java.io.File;
28 import java.io.FileOutputStream;
29 import java.io.FileWriter;
30 import java.io.IOException;
31 import java.io.Reader;
32 import java.io.StringReader;
33 import java.nio.channels.FileChannel;
34 import java.util.ArrayList;
35 import java.util.List;
36 import org.junit.After;
37 import static org.junit.Assert.assertEquals;
38 import static org.junit.Assert.assertNotNull;
39 import static org.junit.Assert.assertTrue;
40 import static org.junit.Assert.fail;
41 import org.junit.Before;
42 import org.junit.Rule;
43 import org.junit.Test;
44 import org.opengrok.indexer.condition.ConditionalRun;
45 import org.opengrok.indexer.condition.ConditionalRunRule;
46 import org.opengrok.indexer.condition.RepositoryInstalled;
47 import org.opengrok.indexer.util.Executor;
48 import org.opengrok.indexer.util.IOUtils;
49 import org.opengrok.indexer.util.TestRepository;
50 
51 /**
52  *
53  * @author austvik
54  */
55 @ConditionalRun(RepositoryInstalled.CvsInstalled.class)
56 public class CVSRepositoryTest {
57 
58     @Rule
59     public ConditionalRunRule rule = new ConditionalRunRule();
60 
61     CVSRepository instance;
62 
63     private TestRepository repository;
64 
65     /**
66      * Set up a test repository. Should be called by the tests that need it. The
67      * test repository will be destroyed automatically when the test finishes.
68      */
setUpTestRepository()69     private void setUpTestRepository() throws IOException {
70         repository = new TestRepository();
71         repository.create(getClass().getResourceAsStream("repositories.zip"));
72 
73         // Checkout cvsrepo anew in order to get the CVS/Root files point to
74         // the temporary directory rather than the OpenGrok workspace directory
75         // it was created from. This is necessary since 'cvs update' changes
76         // the CVS parent directory after branch has been created.
77         File root = new File(repository.getSourceRoot(), "cvs_test");
78         File cvsrepodir = new File(root, "cvsrepo");
79         IOUtils.removeRecursive(cvsrepodir.toPath());
80         File cvsroot = new File(root, "cvsroot");
81         runCvsCommand(root, "-d", cvsroot.getAbsolutePath(), "checkout", "cvsrepo");
82     }
83 
84     @After
tearDown()85     public void tearDown() {
86         instance = null;
87 
88         if (repository != null) {
89             repository.destroy();
90             repository = null;
91         }
92     }
93 
94     @Before
setUp()95     public void setUp() {
96         instance = new CVSRepository();
97     }
98 
99     /**
100      * Run the 'cvs' command with some arguments.
101      *
102      * @param reposRoot directory of the repository root
103      * @param args arguments to use for the command
104      */
runCvsCommand(File reposRoot, String ... args)105     public static void runCvsCommand(File reposRoot, String ... args) {
106         List<String> cmdargs = new ArrayList<>();
107         CVSRepository repo = new CVSRepository();
108         cmdargs.add(repo.getRepoCommand());
109         for (String arg: args) {
110             cmdargs.add(arg);
111         }
112         Executor exec = new Executor(cmdargs, reposRoot);
113         int exitCode = exec.exec();
114         if (exitCode != 0) {
115             fail("cvs command '" + cmdargs.toString() + "'failed."
116                     + "\nexit code: " + exitCode
117                     + "\nstdout:\n" + exec.getOutputString()
118                     + "\nstderr:\n" + exec.getErrorString());
119         }
120     }
121 
122     /**
123      * Get the CVS repository, test that getBranch() returns null if there is
124      * no branch.
125      * @throws Exception
126      */
127     @Test
testGetBranchNoBranch()128     public void testGetBranchNoBranch() throws Exception {
129         setUpTestRepository();
130         File root = new File(repository.getSourceRoot(), "cvs_test/cvsrepo");
131         CVSRepository cvsrepo
132                 = (CVSRepository) RepositoryFactory.getRepository(root);
133         assertEquals(null, cvsrepo.getBranch());
134     }
135 
136     /**
137      * Get the CVS repository, create new branch, change a file and verify that
138      * getBranch() returns the branch and check newly added commits annotate
139      * with branch revision numbers.
140      * Last, check that history entries of the file follow through before the
141      * branch was created.
142      * @throws Exception
143      */
144     @Test
testNewBranch()145     public void testNewBranch() throws Exception {
146         setUpTestRepository();
147         File root = new File(repository.getSourceRoot(), "cvs_test/cvsrepo");
148 
149         // Create new branch and switch to it.
150         runCvsCommand(root, "tag", "-b", "mybranch");
151         // Note that the 'update' command will change the entries in 'cvsroot' directory.
152         runCvsCommand(root, "update", "-r", "mybranch");
153 
154         // Now the repository object can be instantiated so that determineBranch()
155         // will be called.
156         CVSRepository cvsrepo
157             = (CVSRepository) RepositoryFactory.getRepository(root);
158 
159         assertEquals("mybranch", cvsrepo.getBranch());
160 
161         // Change the content and commit.
162         File mainC = new File(root, "main.c");
163         FileChannel outChan = new FileOutputStream(mainC, true).getChannel();
164         outChan.truncate(0);
165         outChan.close();
166         FileWriter fw = new FileWriter(mainC);
167         fw.write("#include <foo.h>\n");
168         fw.close();
169         runCvsCommand(root, "commit", "-m", "change on a branch", "main.c");
170 
171         // Check that annotation for the changed line has branch revision.
172         Annotation annotation = cvsrepo.annotate(mainC, null);
173         assertEquals("1.2.2.1", annotation.getRevision(1));
174 
175         History mainCHistory = cvsrepo.getHistory(mainC);
176         assertEquals(3, mainCHistory.getHistoryEntries().size());
177         assertEquals("1.2.2.1", mainCHistory.getHistoryEntries().get(0).getRevision());
178         assertEquals("1.2", mainCHistory.getHistoryEntries().get(1).getRevision());
179         assertEquals("1.1", mainCHistory.getHistoryEntries().get(2).getRevision());
180     }
181 
182     /**
183      * Test of fileHasAnnotation method, of class CVSRepository.
184      */
185     @Test
testFileHasAnnotation()186     public void testFileHasAnnotation() {
187         boolean result = instance.fileHasAnnotation(null);
188         assertTrue(result);
189     }
190 
191     /**
192      * Test of fileHasHistory method, of class CVSRepository.
193      */
194     @Test
testFileHasHistory()195     public void testFileHasHistory() {
196         boolean result = instance.fileHasHistory(null);
197         assertTrue(result);
198     }
199 
200     /**
201      * Test of parseAnnotation method, of class CVSRepository.
202      * @throws java.lang.Exception
203      */
204     @Test
testParseAnnotation()205     public void testParseAnnotation() throws Exception {
206         String revId1 = "1.1";
207         String revId2 = "1.2.3";
208         String revId3 = "1.0";
209         String author1 = "author1";
210         String author2 = "author_long2";
211         String author3 = "author3";
212         String output = "just jibberish in output\n\n" + revId1 + "     (" + author1 + " 01-Mar-07) \n" +
213                 revId2 + "    (" + author2 + " 02-Mar-08)   if (some code)\n" +
214                 revId3 + "       (" + author3 + " 30-Apr-07)           call_function(i);\n";
215 
216         String fileName = "something.ext";
217 
218         CVSAnnotationParser parser = new CVSAnnotationParser(fileName);
219         parser.processStream(new ByteArrayInputStream(output.getBytes()));
220         Annotation result = parser.getAnnotation();
221 
222         assertNotNull(result);
223         assertEquals(3, result.size());
224         for (int i = 1; i <= 3; i++) {
225             assertEquals(true, result.isEnabled(i));
226         }
227         assertEquals(revId1, result.getRevision(1));
228         assertEquals(revId2, result.getRevision(2));
229         assertEquals(revId3, result.getRevision(3));
230         assertEquals(author1, result.getAuthor(1));
231         assertEquals(author2, result.getAuthor(2));
232         assertEquals(author3, result.getAuthor(3));
233         assertEquals(author2.length(), result.getWidestAuthor());
234         assertEquals(revId2.length(), result.getWidestRevision());
235         assertEquals(fileName, result.getFilename());
236     }
237 
238 }
239