View Javadoc
1   /*
2    * Copyright (C) 2011, GitHub Inc. and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  package org.eclipse.jgit.submodule;
11  
12  import static org.junit.Assert.assertEquals;
13  import static org.junit.Assert.assertNotNull;
14  import static org.junit.Assert.assertTrue;
15  import static org.junit.Assert.fail;
16  
17  import java.io.File;
18  import java.text.MessageFormat;
19  
20  import org.eclipse.jgit.api.Git;
21  import org.eclipse.jgit.api.Status;
22  import org.eclipse.jgit.api.SubmoduleAddCommand;
23  import org.eclipse.jgit.api.errors.GitAPIException;
24  import org.eclipse.jgit.api.errors.JGitInternalException;
25  import org.eclipse.jgit.dircache.DirCache;
26  import org.eclipse.jgit.dircache.DirCacheEditor;
27  import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
28  import org.eclipse.jgit.dircache.DirCacheEntry;
29  import org.eclipse.jgit.internal.JGitText;
30  import org.eclipse.jgit.junit.RepositoryTestCase;
31  import org.eclipse.jgit.lib.ConfigConstants;
32  import org.eclipse.jgit.lib.Constants;
33  import org.eclipse.jgit.lib.FileMode;
34  import org.eclipse.jgit.lib.ObjectId;
35  import org.eclipse.jgit.lib.Repository;
36  import org.eclipse.jgit.revwalk.RevCommit;
37  import org.eclipse.jgit.storage.file.FileBasedConfig;
38  import org.junit.Test;
39  
40  /**
41   * Unit tests of {@link org.eclipse.jgit.api.SubmoduleAddCommand}
42   */
43  public class SubmoduleAddTest extends RepositoryTestCase {
44  
45  	@Test
46  	public void commandWithNullPath() throws GitAPIException {
47  		try {
48  			new SubmoduleAddCommand(db).setURI("uri").call().close();
49  			fail("Exception not thrown");
50  		} catch (IllegalArgumentException e) {
51  			assertEquals(JGitText.get().pathNotConfigured, e.getMessage());
52  		}
53  	}
54  
55  	@Test
56  	public void commandWithEmptyPath() throws GitAPIException {
57  		try {
58  			new SubmoduleAddCommand(db).setPath("").setURI("uri").call()
59  					.close();
60  			fail("Exception not thrown");
61  		} catch (IllegalArgumentException e) {
62  			assertEquals(JGitText.get().pathNotConfigured, e.getMessage());
63  		}
64  	}
65  
66  	@Test
67  	public void commandWithNullUri() throws GitAPIException {
68  		try {
69  			new SubmoduleAddCommand(db).setPath("sub").call().close();
70  			fail("Exception not thrown");
71  		} catch (IllegalArgumentException e) {
72  			assertEquals(JGitText.get().uriNotConfigured, e.getMessage());
73  		}
74  	}
75  
76  	@Test
77  	public void commandWithEmptyUri() throws GitAPIException {
78  		try {
79  			new SubmoduleAddCommand(db).setPath("sub").setURI("").call()
80  					.close();
81  			fail("Exception not thrown");
82  		} catch (IllegalArgumentException e) {
83  			assertEquals(JGitText.get().uriNotConfigured, e.getMessage());
84  		}
85  	}
86  
87  	@Test
88  	public void addSubmodule() throws Exception {
89  		try (Git git = new Git(db)) {
90  			writeTrashFile("file.txt", "content");
91  			git.add().addFilepattern("file.txt").call();
92  			RevCommit commit = git.commit().setMessage("create file").call();
93  
94  			SubmoduleAddCommand command = new SubmoduleAddCommand(db);
95  			String path = "sub";
96  			command.setPath(path);
97  			String uri = db.getDirectory().toURI().toString();
98  			command.setURI(uri);
99  			ObjectId subCommit;
100 			try (Repository repo = command.call()) {
101 				assertNotNull(repo);
102 				subCommit = repo.resolve(Constants.HEAD);
103 			}
104 
105 			try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) {
106 				generator.loadModulesConfig();
107 				assertTrue(generator.next());
108 				assertEquals(path, generator.getModuleName());
109 				assertEquals(path, generator.getPath());
110 				assertEquals(commit, generator.getObjectId());
111 				assertEquals(uri, generator.getModulesUrl());
112 				assertEquals(path, generator.getModulesPath());
113 				assertEquals(uri, generator.getConfigUrl());
114 				try (Repository subModRepo = generator.getRepository()) {
115 					assertNotNull(subModRepo);
116 					assertEquals(subCommit, commit);
117 				}
118 			}
119 			Status status = Git.wrap(db).status().call();
120 			assertTrue(status.getAdded().contains(Constants.DOT_GIT_MODULES));
121 			assertTrue(status.getAdded().contains(path));
122 		}
123 	}
124 
125 	@Test
126 	public void addSubmoduleWithName() throws Exception {
127 		try (Git git = new Git(db)) {
128 			writeTrashFile("file.txt", "content");
129 			git.add().addFilepattern("file.txt").call();
130 			RevCommit commit = git.commit().setMessage("create file").call();
131 
132 			SubmoduleAddCommand command = new SubmoduleAddCommand(db);
133 			String name = "testsub";
134 			command.setName(name);
135 			String path = "sub";
136 			command.setPath(path);
137 			String uri = db.getDirectory().toURI().toString();
138 			command.setURI(uri);
139 			ObjectId subCommit;
140 			try (Repository repo = command.call()) {
141 				assertNotNull(repo);
142 				subCommit = repo.resolve(Constants.HEAD);
143 			}
144 
145 			try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) {
146 				generator.loadModulesConfig();
147 				assertTrue(generator.next());
148 				assertEquals(name, generator.getModuleName());
149 				assertEquals(path, generator.getPath());
150 				assertEquals(commit, generator.getObjectId());
151 				assertEquals(uri, generator.getModulesUrl());
152 				assertEquals(path, generator.getModulesPath());
153 				assertEquals(uri, generator.getConfigUrl());
154 				try (Repository subModRepo = generator.getRepository()) {
155 					assertNotNull(subModRepo);
156 					assertEquals(subCommit, commit);
157 				}
158 			}
159 			Status status = Git.wrap(db).status().call();
160 			assertTrue(status.getAdded().contains(Constants.DOT_GIT_MODULES));
161 			assertTrue(status.getAdded().contains(path));
162 		}
163 	}
164 
165 	@Test
166 	public void addExistentSubmodule() throws Exception {
167 		final ObjectId id = ObjectId
168 				.fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
169 		final String path = "sub";
170 		DirCache cache = db.lockDirCache();
171 		DirCacheEditor editor = cache.editor();
172 		editor.add(new PathEdit(path) {
173 
174 			@Override
175 			public void apply(DirCacheEntry ent) {
176 				ent.setFileMode(FileMode.GITLINK);
177 				ent.setObjectId(id);
178 			}
179 		});
180 		editor.commit();
181 
182 		SubmoduleAddCommand command = new SubmoduleAddCommand(db);
183 		command.setPath(path);
184 		command.setURI("git://server/repo.git");
185 		try {
186 			command.call().close();
187 			fail("Exception not thrown");
188 		} catch (JGitInternalException e) {
189 			assertEquals(
190 					MessageFormat.format(JGitText.get().submoduleExists, path),
191 					e.getMessage());
192 		}
193 	}
194 
195 	@Test
196 	public void addSubmoduleWithInvalidPath() throws Exception {
197 		SubmoduleAddCommand command = new SubmoduleAddCommand(db);
198 		command.setPath("-invalid-path");
199 		command.setName("sub");
200 		command.setURI("http://example.com/repo/x.git");
201 		try {
202 			command.call().close();
203 			fail("Exception not thrown");
204 		} catch (IllegalArgumentException e) {
205 			assertEquals("Invalid submodule path '-invalid-path'",
206 					e.getMessage());
207 		}
208 	}
209 
210 	@Test
211 	public void addSubmoduleWithInvalidUri() throws Exception {
212 		SubmoduleAddCommand command = new SubmoduleAddCommand(db);
213 		command.setPath("valid-path");
214 		command.setURI("-upstream");
215 		try {
216 			command.call().close();
217 			fail("Exception not thrown");
218 		} catch (IllegalArgumentException e) {
219 			assertEquals("Invalid submodule URL '-upstream'", e.getMessage());
220 		}
221 	}
222 
223 	@Test
224 	public void addSubmoduleWithRelativeUri() throws Exception {
225 		try (Git git = new Git(db)) {
226 			writeTrashFile("file.txt", "content");
227 			git.add().addFilepattern("file.txt").call();
228 			RevCommit commit = git.commit().setMessage("create file").call();
229 
230 			SubmoduleAddCommand command = new SubmoduleAddCommand(db);
231 			String path = "sub";
232 			String uri = "./.git";
233 			command.setPath(path);
234 			command.setURI(uri);
235 			Repository repo = command.call();
236 			assertNotNull(repo);
237 			addRepoToClose(repo);
238 
239 			try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) {
240 				assertTrue(generator.next());
241 				assertEquals(path, generator.getPath());
242 				assertEquals(commit, generator.getObjectId());
243 				assertEquals(uri, generator.getModulesUrl());
244 				assertEquals(path, generator.getModulesPath());
245 				String fullUri = db.getDirectory().getAbsolutePath();
246 				if (File.separatorChar == '\\') {
247 					fullUri = fullUri.replace('\\', '/');
248 				}
249 				assertEquals(fullUri, generator.getConfigUrl());
250 				try (Repository subModRepo = generator.getRepository()) {
251 					assertNotNull(subModRepo);
252 					assertEquals(fullUri,
253 							subModRepo.getConfig().getString(
254 									ConfigConstants.CONFIG_REMOTE_SECTION,
255 									Constants.DEFAULT_REMOTE_NAME,
256 									ConfigConstants.CONFIG_KEY_URL));
257 				}
258 			}
259 			assertEquals(commit, repo.resolve(Constants.HEAD));
260 
261 			Status status = Git.wrap(db).status().call();
262 			assertTrue(status.getAdded().contains(Constants.DOT_GIT_MODULES));
263 			assertTrue(status.getAdded().contains(path));
264 		}
265 	}
266 
267 	@Test
268 	public void addSubmoduleWithExistingSubmoduleDefined() throws Exception {
269 		String path1 = "sub1";
270 		String url1 = "git://server/repo1.git";
271 		String path2 = "sub2";
272 
273 		FileBasedConfig modulesConfig = new FileBasedConfig(new File(
274 				db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
275 		modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
276 				path1, ConfigConstants.CONFIG_KEY_PATH, path1);
277 		modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
278 				path1, ConfigConstants.CONFIG_KEY_URL, url1);
279 		modulesConfig.save();
280 
281 		try (Git git = new Git(db)) {
282 			writeTrashFile("file.txt", "content");
283 			git.add().addFilepattern("file.txt").call();
284 			assertNotNull(git.commit().setMessage("create file").call());
285 
286 			SubmoduleAddCommand command = new SubmoduleAddCommand(db);
287 			command.setPath(path2);
288 			String url2 = db.getDirectory().toURI().toString();
289 			command.setURI(url2);
290 			Repository r = command.call();
291 			assertNotNull(r);
292 			addRepoToClose(r);
293 
294 			modulesConfig.load();
295 			assertEquals(path1, modulesConfig.getString(
296 					ConfigConstants.CONFIG_SUBMODULE_SECTION, path1,
297 					ConfigConstants.CONFIG_KEY_PATH));
298 			assertEquals(url1, modulesConfig.getString(
299 					ConfigConstants.CONFIG_SUBMODULE_SECTION, path1,
300 					ConfigConstants.CONFIG_KEY_URL));
301 			assertEquals(path2, modulesConfig.getString(
302 					ConfigConstants.CONFIG_SUBMODULE_SECTION, path2,
303 					ConfigConstants.CONFIG_KEY_PATH));
304 			assertEquals(url2, modulesConfig.getString(
305 					ConfigConstants.CONFIG_SUBMODULE_SECTION, path2,
306 					ConfigConstants.CONFIG_KEY_URL));
307 		}
308 	}
309 
310 	@Test
311 	public void denySubmoduleWithDotDot() throws Exception {
312 		SubmoduleAddCommand command = new SubmoduleAddCommand(db);
313 		command.setName("dir/../");
314 		command.setPath("sub");
315 		command.setURI(db.getDirectory().toURI().toString());
316 		try {
317 			command.call();
318 			fail();
319 		} catch (IllegalArgumentException e) {
320 			// Expected
321 		}
322 	}
323 }