/* * Copyright (C) 2020, Lee Worrall and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at * https://www.eclipse.org/org/documents/edl-v10.php. * * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.transport; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThrows; import java.io.ByteArrayInputStream; import java.io.EOFException; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import org.eclipse.jgit.errors.NoRemoteRepositoryException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectIdRef; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.SymbolicRef; import org.junit.Test; public class BasePackConnectionTest { @Test public void testReadAdvertisedRefsShouldThrowExceptionWithOriginalCause() { try (FailingBasePackConnection basePackConnection = new FailingBasePackConnection()) { Exception result = assertThrows(NoRemoteRepositoryException.class, basePackConnection::readAdvertisedRefs); assertEquals(EOFException.class, result.getCause().getClass()); } } @Test public void testUpdateWithSymRefsAdds() { final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/main", ObjectId.fromString( "0000000000000000000000000000000000000001")); final Map refMap = new HashMap<>(); refMap.put(mainRef.getName(), mainRef); refMap.put("refs/heads/other", new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other", ObjectId.fromString( "0000000000000000000000000000000000000002"))); final Map symRefs = new HashMap<>(); symRefs.put("HEAD", "refs/heads/main"); BasePackConnection.updateWithSymRefs(refMap, symRefs); assertThat(refMap, hasKey("HEAD")); final Ref headRef = refMap.get("HEAD"); assertThat(headRef, instanceOf(SymbolicRef.class)); final SymbolicRef headSymRef = (SymbolicRef) headRef; assertEquals("HEAD", headSymRef.getName()); assertSame(mainRef, headSymRef.getTarget()); } @Test public void testUpdateWithSymRefsReplaces() { final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/main", ObjectId.fromString( "0000000000000000000000000000000000000001")); final Map refMap = new HashMap<>(); refMap.put(mainRef.getName(), mainRef); refMap.put("HEAD", new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "HEAD", mainRef.getObjectId())); refMap.put("refs/heads/other", new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other", ObjectId.fromString( "0000000000000000000000000000000000000002"))); final Map symRefs = new HashMap<>(); symRefs.put("HEAD", "refs/heads/main"); BasePackConnection.updateWithSymRefs(refMap, symRefs); assertThat(refMap, hasKey("HEAD")); final Ref headRef = refMap.get("HEAD"); assertThat(headRef, instanceOf(SymbolicRef.class)); final SymbolicRef headSymRef = (SymbolicRef) headRef; assertEquals("HEAD", headSymRef.getName()); assertSame(mainRef, headSymRef.getTarget()); } @Test public void testUpdateWithSymRefsWithIndirectsAdds() { final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/main", ObjectId.fromString( "0000000000000000000000000000000000000001")); final Map refMap = new HashMap<>(); refMap.put(mainRef.getName(), mainRef); refMap.put("refs/heads/other", new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other", ObjectId.fromString( "0000000000000000000000000000000000000002"))); final Map symRefs = new LinkedHashMap<>(); // Ordered symRefs.put("refs/heads/sym3", "refs/heads/sym2"); // Forward reference symRefs.put("refs/heads/sym1", "refs/heads/main"); symRefs.put("refs/heads/sym2", "refs/heads/sym1"); // Backward reference BasePackConnection.updateWithSymRefs(refMap, symRefs); assertThat(refMap, hasKey("refs/heads/sym1")); final Ref sym1Ref = refMap.get("refs/heads/sym1"); assertThat(sym1Ref, instanceOf(SymbolicRef.class)); final SymbolicRef sym1SymRef = (SymbolicRef) sym1Ref; assertEquals("refs/heads/sym1", sym1SymRef.getName()); assertSame(mainRef, sym1SymRef.getTarget()); assertThat(refMap, hasKey("refs/heads/sym2")); final Ref sym2Ref = refMap.get("refs/heads/sym2"); assertThat(sym2Ref, instanceOf(SymbolicRef.class)); final SymbolicRef sym2SymRef = (SymbolicRef) sym2Ref; assertEquals("refs/heads/sym2", sym2SymRef.getName()); assertSame(sym1SymRef, sym2SymRef.getTarget()); assertThat(refMap, hasKey("refs/heads/sym3")); final Ref sym3Ref = refMap.get("refs/heads/sym3"); assertThat(sym3Ref, instanceOf(SymbolicRef.class)); final SymbolicRef sym3SymRef = (SymbolicRef) sym3Ref; assertEquals("refs/heads/sym3", sym3SymRef.getName()); assertSame(sym2SymRef, sym3SymRef.getTarget()); } @Test public void testUpdateWithSymRefsWithIndirectsReplaces() { final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/main", ObjectId.fromString( "0000000000000000000000000000000000000001")); final Map refMap = new HashMap<>(); refMap.put(mainRef.getName(), mainRef); refMap.put("refs/heads/sym1", new ObjectIdRef.Unpeeled( Ref.Storage.LOOSE, "refs/heads/sym1", mainRef.getObjectId())); refMap.put("refs/heads/sym2", new ObjectIdRef.Unpeeled( Ref.Storage.LOOSE, "refs/heads/sym2", mainRef.getObjectId())); refMap.put("refs/heads/sym3", new ObjectIdRef.Unpeeled( Ref.Storage.LOOSE, "refs/heads/sym3", mainRef.getObjectId())); refMap.put("refs/heads/other", new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other", ObjectId.fromString( "0000000000000000000000000000000000000002"))); final Map symRefs = new LinkedHashMap<>(); // Ordered symRefs.put("refs/heads/sym3", "refs/heads/sym2"); // Forward reference symRefs.put("refs/heads/sym1", "refs/heads/main"); symRefs.put("refs/heads/sym2", "refs/heads/sym1"); // Backward reference BasePackConnection.updateWithSymRefs(refMap, symRefs); assertThat(refMap, hasKey("refs/heads/sym1")); final Ref sym1Ref = refMap.get("refs/heads/sym1"); assertThat(sym1Ref, instanceOf(SymbolicRef.class)); final SymbolicRef sym1SymRef = (SymbolicRef) sym1Ref; assertEquals("refs/heads/sym1", sym1SymRef.getName()); assertSame(mainRef, sym1SymRef.getTarget()); assertThat(refMap, hasKey("refs/heads/sym2")); final Ref sym2Ref = refMap.get("refs/heads/sym2"); assertThat(sym2Ref, instanceOf(SymbolicRef.class)); final SymbolicRef sym2SymRef = (SymbolicRef) sym2Ref; assertEquals("refs/heads/sym2", sym2SymRef.getName()); assertSame(sym1SymRef, sym2SymRef.getTarget()); assertThat(refMap, hasKey("refs/heads/sym3")); final Ref sym3Ref = refMap.get("refs/heads/sym3"); assertThat(sym3Ref, instanceOf(SymbolicRef.class)); final SymbolicRef sym3SymRef = (SymbolicRef) sym3Ref; assertEquals("refs/heads/sym3", sym3SymRef.getName()); assertSame(sym2SymRef, sym3SymRef.getTarget()); } @Test public void testUpdateWithSymRefsIgnoresSelfReference() { final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/main", ObjectId.fromString( "0000000000000000000000000000000000000001")); final Map refMap = new HashMap<>(); refMap.put(mainRef.getName(), mainRef); refMap.put("refs/heads/other", new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other", ObjectId.fromString( "0000000000000000000000000000000000000002"))); final Map symRefs = new LinkedHashMap<>(); symRefs.put("refs/heads/sym1", "refs/heads/sym1"); BasePackConnection.updateWithSymRefs(refMap, symRefs); assertEquals(2, refMap.size()); assertThat(refMap, not(hasKey("refs/heads/sym1"))); } @Test public void testUpdateWithSymRefsIgnoreCircularReference() { final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/main", ObjectId.fromString( "0000000000000000000000000000000000000001")); final Map refMap = new HashMap<>(); refMap.put(mainRef.getName(), mainRef); refMap.put("refs/heads/other", new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other", ObjectId.fromString( "0000000000000000000000000000000000000002"))); final Map symRefs = new LinkedHashMap<>(); symRefs.put("refs/heads/sym2", "refs/heads/sym1"); symRefs.put("refs/heads/sym1", "refs/heads/sym2"); BasePackConnection.updateWithSymRefs(refMap, symRefs); assertEquals(2, refMap.size()); assertThat(refMap, not(hasKey("refs/heads/sym1"))); assertThat(refMap, not(hasKey("refs/heads/sym2"))); } @Test public void testUpdateWithSymRefsFillInHead() { final String oidName = "0000000000000000000000000000000000000001"; final Ref advertised = new ObjectIdRef.PeeledNonTag(Ref.Storage.NETWORK, Constants.HEAD, ObjectId.fromString(oidName)); final Map refMap = new HashMap<>(); refMap.put(advertised.getName(), advertised); final Map symRefs = new HashMap<>(); symRefs.put("HEAD", "refs/heads/main"); BasePackConnection.updateWithSymRefs(refMap, symRefs); assertThat(refMap, hasKey("HEAD")); assertThat(refMap, hasKey("refs/heads/main")); final Ref headRef = refMap.get("HEAD"); final Ref mainRef = refMap.get("refs/heads/main"); assertThat(headRef, instanceOf(SymbolicRef.class)); final SymbolicRef headSymRef = (SymbolicRef) headRef; assertEquals(Constants.HEAD, headSymRef.getName()); assertSame(mainRef, headSymRef.getTarget()); assertEquals(oidName, headRef.getObjectId().name()); assertEquals(oidName, mainRef.getObjectId().name()); } private static class FailingBasePackConnection extends BasePackConnection { FailingBasePackConnection() { super(new TransportLocal(new URIish(), new java.io.File(""))); pckIn = new PacketLineIn(new ByteArrayInputStream(new byte[0])); } } }