001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.maven.scm;
020
021import java.io.File;
022import java.util.ArrayList;
023import java.util.Iterator;
024import java.util.List;
025import java.util.Map;
026import java.util.TreeMap;
027
028import org.apache.commons.lang3.StringUtils;
029import org.apache.maven.scm.command.add.AddScmResult;
030import org.apache.maven.scm.command.checkin.CheckInScmResult;
031import org.apache.maven.scm.command.checkout.CheckOutScmResult;
032import org.apache.maven.scm.command.edit.EditScmResult;
033import org.apache.maven.scm.command.remove.RemoveScmResult;
034import org.apache.maven.scm.provider.ScmProvider;
035import org.apache.maven.scm.repository.ScmRepository;
036import org.junit.After;
037import org.junit.Before;
038
039import static org.junit.Assert.assertEquals;
040import static org.junit.Assert.assertTrue;
041import static org.junit.Assume.assumeTrue;
042
043/**
044 * Base class for all TcK tests.
045 * <p>
046 * Basically all it does is to setup a default test enviroment
047 * common for all tck tests. The default setup includes:
048 * <ol>
049 * <li>Delete all default locations (working copy, updating copy etc)</li>
050 * <li>Initialize the repository</li>
051 * <li>Check out the repository to the working copy</li>
052 * </ol>
053 *
054 * @author <a href="mailto:torbjorn@smorgrav.org">Torbj�rn Eikli Sm�rgrav</a>
055 *
056 */
057public abstract class ScmTckTestCase extends ScmTestCase {
058    private ScmRepository scmRepository;
059
060    private List<String> scmFileNames;
061
062    /**
063     * Some tests can only run if the appropriate application has been installed.
064     * If the provided name is not a runnable application all tests in the class are skipped.
065     * @return The commandline command for the specific scm provider. Or null if none is needed.
066     */
067    public String getScmProviderCommand() {
068        return null;
069    }
070
071    /**
072     * @return A provider specific and valid url for the repository
073     * @throws Exception if any
074     */
075    public abstract String getScmUrl() throws Exception;
076
077    /**
078     * <p>
079     * Get the list of file names that is supposed to be in the test repo.
080     * </p>
081     * <ul>
082     * <li>/pom.xml</li>
083     * <li>/readme.txt</li>
084     * <li>/src/main/java/Application.java</li>
085     * <li>/src/test/java/Test.java</li>
086     * </ul>
087     *
088     * @return {@link List} of {@link String} objects
089     */
090    protected List<String> getScmFileNames() {
091        return scmFileNames;
092    }
093
094    /**
095     * <p>
096     * Initialize repository at the {@link #getScmUrl()} location with the files in {@link #getScmFileNames()}
097     * </p>
098     * <p>
099     * The setup is also asserting on the existence of these files. <br>
100     * This should only be used by this class (thus do not call this method from derived classes)
101     * </p>
102     * <b>Note</b>: 'svnadmin' should be a system command.
103     *
104     * @throws Exception if any
105     */
106    public abstract void initRepo() throws Exception;
107
108    public void checkScmPresence() {
109        String scmProviderCommand = getScmProviderCommand();
110        if (scmProviderCommand != null) {
111            assumeTrue(
112                    "Skipping tests because the required command '" + scmProviderCommand + "' is not available.",
113                    ScmTestCase.isSystemCmd(scmProviderCommand));
114        }
115    }
116
117    /**
118     * {@inheritDoc}
119     */
120    @Before
121    @Override
122    public void setUp() throws Exception {
123        checkScmPresence();
124        super.setUp();
125
126        scmRepository = null;
127
128        scmFileNames = new ArrayList<>(4);
129        scmFileNames.add("/pom.xml");
130        scmFileNames.add("/readme.txt");
131        scmFileNames.add("/src/main/java/Application.java");
132        scmFileNames.add("/src/test/java/Test.java");
133
134        initRepo();
135
136        checkOut(getWorkingCopy(), getScmRepository());
137
138        Iterator<String> it = getScmFileNames().iterator();
139        while (it.hasNext()) {
140            assertFile(getWorkingCopy(), it.next());
141        }
142    }
143
144    /**
145     * This method is available to those SCM clients that need to perform
146     * a cleanup at the end of the tests. It is needed when server side
147     * operations are performed, or the check out dirs are outside
148     * of the normal target directory.
149     */
150    public void removeRepo() throws Exception {}
151
152    /**
153     * Provided to allow removeRepo() to be called.
154     */
155    @After
156    @Override
157    public void tearDown() throws Exception {
158        super.tearDown();
159        removeRepo();
160    }
161
162    /**
163     * Convenience method to get the ScmRepository for this provider
164     */
165    protected ScmRepository getScmRepository() throws Exception {
166        if (scmRepository == null) {
167            scmRepository = getScmManager().makeScmRepository(getScmUrl());
168        }
169
170        return scmRepository;
171    }
172
173    /**
174     * Convenience method to check out files from the repository
175     */
176    protected CheckOutScmResult checkOut(File workingDirectory, ScmRepository repository) throws Exception {
177        CheckOutScmResult result = getScmManager()
178                .getProviderByUrl(getScmUrl())
179                .checkOut(repository, new ScmFileSet(workingDirectory), (ScmVersion) null);
180
181        assertTrue("Check result was successful, output: " + result.getCommandOutput(), result.isSuccess());
182
183        return result;
184    }
185
186    /**
187     * Convenience method to check in files to the repository
188     */
189    protected CheckInScmResult checkIn(File workingDirectory, ScmRepository repository) throws Exception {
190        CheckInScmResult result = getScmManager()
191                .getProviderByUrl(getScmUrl())
192                .checkIn(repository, new ScmFileSet(workingDirectory), (ScmVersion) null, "Initial Checkin");
193
194        assertTrue("Check result was successful, output: " + result.getCommandOutput(), result.isSuccess());
195
196        return result;
197    }
198
199    /**
200     * Convenience method to remove files from the repository
201     */
202    protected RemoveScmResult remove(File workingDirectory, ScmRepository repository) throws Exception {
203        RemoveScmResult result = getScmManager()
204                .getProviderByUrl(getScmUrl())
205                .remove(repository, new ScmFileSet(workingDirectory), "Initial Checkin");
206
207        assertTrue("Remove result was successful, output: " + result.getCommandOutput(), result.isSuccess());
208
209        return result;
210    }
211
212    /**
213     * Convenience method to add a file to the working tree at the working directory
214     */
215    protected void addToWorkingTree(File workingDirectory, File file, ScmRepository repository) throws Exception {
216        ScmProvider provider = getScmManager().getProviderByUrl(getScmUrl());
217
218        CommandParameters commandParameters = new CommandParameters();
219        commandParameters.setString(CommandParameter.FORCE_ADD, Boolean.TRUE.toString());
220
221        AddScmResult result = provider.add(repository, new ScmFileSet(workingDirectory, file), commandParameters);
222
223        assertTrue("Check result was successful, output: " + result.getCommandOutput(), result.isSuccess());
224
225        List<ScmFile> addedFiles = result.getAddedFiles();
226
227        if (new File(workingDirectory, file.getPath()).isFile()) {
228            // Don't check directory add because some SCM tools ignore it
229            assertEquals("Expected 1 file in the added files list " + addedFiles, 1, addedFiles.size());
230        }
231    }
232
233    /**
234     * take the files of the given list, add them to a TreeMap and
235     * use the pathName String as key for the Map.
236     * This function is useful for every TCK which has to check for the
237     * existence of more than 1 file of the returned ScmResult, regardless
238     * of their order in the list.
239     * All backslashes in the path will be replaced by forward slashes
240     * for Windows compatibility.
241     *
242     * @param files List with {@code ScmFile}s
243     * @return Map key=pathName, value=ScmFile
244     */
245    protected Map<String, ScmFile> mapFilesByPath(List<ScmFile> files) {
246        if (files == null) {
247            return null;
248        }
249
250        Map<String, ScmFile> mappedFiles = new TreeMap<>();
251        for (ScmFile scmFile : files) {
252            String path = StringUtils.replace(scmFile.getPath(), "\\", "/");
253            mappedFiles.put(path, scmFile);
254        }
255
256        return mappedFiles;
257    }
258
259    protected EditScmResult edit(File basedir, String includes, String excludes, ScmRepository repository)
260            throws Exception {
261        if (this.getScmManager()
262                .getProviderByRepository(this.getScmRepository())
263                .requiresEditMode()) {
264            ScmFileSet fileSet = new ScmFileSet(basedir, includes, excludes);
265            return getScmManager().edit(getScmRepository(), fileSet);
266        }
267        return new EditScmResult("", "", "", true);
268    }
269}