123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947 |
- /*
- * Copyright (C) 2017, Google Inc.
- * and other copyright owners as documented in the project's IP log.
- *
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Distribution License v1.0 which
- * accompanies this distribution, is reproduced below, and is
- * available at http://www.eclipse.org/org/documents/edl-v10.php
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * - Neither the name of the Eclipse Foundation, Inc. nor the
- * names of its contributors may be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
- package org.eclipse.jgit.internal.storage.reftable;
-
- import static org.eclipse.jgit.lib.Constants.HEAD;
- import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
- import static org.eclipse.jgit.lib.Constants.R_HEADS;
- import static org.eclipse.jgit.lib.MoreAsserts.assertThrows;
- import static org.eclipse.jgit.lib.Ref.Storage.NEW;
- import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
- import static org.hamcrest.CoreMatchers.containsString;
- import static org.junit.Assert.assertEquals;
- import static org.junit.Assert.assertFalse;
- import static org.junit.Assert.assertNotNull;
- import static org.junit.Assert.assertNull;
- import static org.junit.Assert.assertSame;
- import static org.junit.Assert.assertThat;
- import static org.junit.Assert.assertTrue;
- import static org.junit.Assert.fail;
-
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.List;
- import java.util.concurrent.locks.ReentrantLock;
- import java.util.stream.Collectors;
-
- import org.eclipse.jgit.internal.JGitText;
- import org.eclipse.jgit.internal.storage.io.BlockSource;
- import org.eclipse.jgit.internal.storage.reftable.ReftableWriter.Stats;
- import org.eclipse.jgit.lib.ObjectId;
- import org.eclipse.jgit.lib.ObjectIdRef;
- import org.eclipse.jgit.lib.PersonIdent;
- import org.eclipse.jgit.lib.Ref;
- import org.eclipse.jgit.lib.ReflogEntry;
- import org.eclipse.jgit.lib.SymbolicRef;
- import org.hamcrest.Matchers;
- import org.junit.Test;
-
- public class ReftableTest {
- private static final String MASTER = "refs/heads/master";
- private static final String NEXT = "refs/heads/next";
- private static final String V1_0 = "refs/tags/v1.0";
-
- private Stats stats;
-
- @Test
- public void emptyTable() throws IOException {
- byte[] table = write();
- assertEquals(92 /* header, footer */, table.length);
- assertEquals('R', table[0]);
- assertEquals('E', table[1]);
- assertEquals('F', table[2]);
- assertEquals('T', table[3]);
- assertEquals(0x01, table[4]);
- assertTrue(ReftableConstants.isFileHeaderMagic(table, 0, 8));
- assertTrue(ReftableConstants.isFileHeaderMagic(table, 24, 92));
-
- Reftable t = read(table);
- try (RefCursor rc = t.allRefs()) {
- assertFalse(rc.next());
- }
- try (RefCursor rc = t.seekRef(HEAD)) {
- assertFalse(rc.next());
- }
- try (RefCursor rc = t.seekRefsWithPrefix(R_HEADS)) {
- assertFalse(rc.next());
- }
- try (LogCursor rc = t.allLogs()) {
- assertFalse(rc.next());
- }
- }
-
- @Test
- public void emptyVirtualTableFromRefs() throws IOException {
- Reftable t = Reftable.from(Collections.emptyList());
- try (RefCursor rc = t.allRefs()) {
- assertFalse(rc.next());
- }
- try (RefCursor rc = t.seekRef(HEAD)) {
- assertFalse(rc.next());
- }
- try (LogCursor rc = t.allLogs()) {
- assertFalse(rc.next());
- }
- }
-
- @Test
- public void estimateCurrentBytesOneRef() throws IOException {
- Ref exp = ref(MASTER, 1);
- int expBytes = 24 + 4 + 5 + 4 + MASTER.length() + 20 + 68;
-
- byte[] table;
- ReftableConfig cfg = new ReftableConfig();
- cfg.setIndexObjects(false);
- try (ByteArrayOutputStream buf = new ByteArrayOutputStream()) {
- ReftableWriter writer = new ReftableWriter(buf).setConfig(cfg);
- writer.begin();
- assertEquals(92, writer.estimateTotalBytes());
- writer.writeRef(exp);
- assertEquals(expBytes, writer.estimateTotalBytes());
- writer.finish();
- table = buf.toByteArray();
- }
- assertEquals(expBytes, table.length);
- }
-
- @SuppressWarnings("boxing")
- @Test
- public void estimateCurrentBytesWithIndex() throws IOException {
- List<Ref> refs = new ArrayList<>();
- for (int i = 1; i <= 5670; i++) {
- refs.add(ref(String.format("refs/heads/%04d", i), i));
- }
-
- ReftableConfig cfg = new ReftableConfig();
- cfg.setIndexObjects(false);
- cfg.setMaxIndexLevels(1);
-
- int expBytes = 147860;
- byte[] table;
- try (ByteArrayOutputStream buf = new ByteArrayOutputStream()) {
- ReftableWriter writer = new ReftableWriter(buf).setConfig(cfg);
- writer.begin();
- writer.sortAndWriteRefs(refs);
- assertEquals(expBytes, writer.estimateTotalBytes());
- writer.finish();
- stats = writer.getStats();
- table = buf.toByteArray();
- }
- assertEquals(1, stats.refIndexLevels());
- assertEquals(expBytes, table.length);
- }
-
- @Test
- public void oneIdRef() throws IOException {
- Ref exp = ref(MASTER, 1);
- byte[] table = write(exp);
- assertEquals(24 + 4 + 5 + 4 + MASTER.length() + 20 + 68, table.length);
-
- ReftableReader t = read(table);
- try (RefCursor rc = t.allRefs()) {
- assertTrue(rc.next());
- Ref act = rc.getRef();
- assertNotNull(act);
- assertEquals(PACKED, act.getStorage());
- assertTrue(act.isPeeled());
- assertFalse(act.isSymbolic());
- assertEquals(exp.getName(), act.getName());
- assertEquals(exp.getObjectId(), act.getObjectId());
- assertEquals(0, act.getUpdateIndex());
- assertNull(act.getPeeledObjectId());
- assertFalse(rc.wasDeleted());
- assertFalse(rc.next());
- }
- try (RefCursor rc = t.seekRef(MASTER)) {
- assertTrue(rc.next());
- Ref act = rc.getRef();
- assertNotNull(act);
- assertEquals(exp.getName(), act.getName());
- assertEquals(0, act.getUpdateIndex());
- assertFalse(rc.next());
- }
- }
-
- @Test
- public void oneTagRef() throws IOException {
- Ref exp = tag(V1_0, 1, 2);
- byte[] table = write(exp);
- assertEquals(24 + 4 + 5 + 3 + V1_0.length() + 40 + 68, table.length);
-
- ReftableReader t = read(table);
- try (RefCursor rc = t.allRefs()) {
- assertTrue(rc.next());
- Ref act = rc.getRef();
- assertNotNull(act);
- assertEquals(PACKED, act.getStorage());
- assertTrue(act.isPeeled());
- assertFalse(act.isSymbolic());
- assertEquals(exp.getName(), act.getName());
- assertEquals(exp.getObjectId(), act.getObjectId());
- assertEquals(exp.getPeeledObjectId(), act.getPeeledObjectId());
- assertEquals(0, act.getUpdateIndex());
- }
- }
-
- @Test
- public void oneSymbolicRef() throws IOException {
- Ref exp = sym(HEAD, MASTER);
- byte[] table = write(exp);
- assertEquals(
- 24 + 4 + 5 + 2 + HEAD.length() + 2 + MASTER.length() + 68,
- table.length);
-
- ReftableReader t = read(table);
- try (RefCursor rc = t.allRefs()) {
- assertTrue(rc.next());
- Ref act = rc.getRef();
- assertNotNull(act);
- assertTrue(act.isSymbolic());
- assertEquals(exp.getName(), act.getName());
- assertNotNull(act.getLeaf());
- assertEquals(MASTER, act.getTarget().getName());
- assertNull(act.getObjectId());
- assertEquals(0, act.getUpdateIndex());
- }
- }
-
- @Test
- public void resolveSymbolicRef() throws IOException {
- Reftable t = read(write(
- sym(HEAD, "refs/heads/tmp"),
- sym("refs/heads/tmp", MASTER),
- ref(MASTER, 1)));
-
- Ref head = t.exactRef(HEAD);
- assertNull(head.getObjectId());
- assertEquals("refs/heads/tmp", head.getTarget().getName());
- assertEquals(0, head.getUpdateIndex());
-
- head = t.resolve(head);
- assertNotNull(head);
- assertEquals(id(1), head.getObjectId());
- assertEquals(0, head.getUpdateIndex());
-
- Ref master = t.exactRef(MASTER);
- assertNotNull(master);
- assertSame(master, t.resolve(master));
- assertEquals(0, master.getUpdateIndex());
- }
-
- @Test
- public void failDeepChainOfSymbolicRef() throws IOException {
- Reftable t = read(write(
- sym(HEAD, "refs/heads/1"),
- sym("refs/heads/1", "refs/heads/2"),
- sym("refs/heads/2", "refs/heads/3"),
- sym("refs/heads/3", "refs/heads/4"),
- sym("refs/heads/4", "refs/heads/5"),
- sym("refs/heads/5", MASTER),
- ref(MASTER, 1)));
-
- Ref head = t.exactRef(HEAD);
- assertNull(head.getObjectId());
- assertNull(t.resolve(head));
- }
-
- @Test
- public void oneDeletedRef() throws IOException {
- String name = "refs/heads/gone";
- Ref exp = newRef(name);
- byte[] table = write(exp);
- assertEquals(24 + 4 + 5 + 3 + name.length() + 68, table.length);
-
- ReftableReader t = read(table);
- try (RefCursor rc = t.allRefs()) {
- assertFalse(rc.next());
- }
-
- t.setIncludeDeletes(true);
- try (RefCursor rc = t.allRefs()) {
- assertTrue(rc.next());
- Ref act = rc.getRef();
- assertNotNull(act);
- assertFalse(act.isSymbolic());
- assertEquals(name, act.getName());
- assertEquals(NEW, act.getStorage());
- assertNull(act.getObjectId());
- assertTrue(rc.wasDeleted());
- }
- }
-
- @Test
- public void seekNotFound() throws IOException {
- Ref exp = ref(MASTER, 1);
- ReftableReader t = read(write(exp));
- try (RefCursor rc = t.seekRef("refs/heads/a")) {
- assertFalse(rc.next());
- }
- try (RefCursor rc = t.seekRef("refs/heads/n")) {
- assertFalse(rc.next());
- }
- }
-
- @Test
- public void namespaceNotFound() throws IOException {
- Ref exp = ref(MASTER, 1);
- ReftableReader t = read(write(exp));
- try (RefCursor rc = t.seekRefsWithPrefix("refs/changes/")) {
- assertFalse(rc.next());
- }
- try (RefCursor rc = t.seekRefsWithPrefix("refs/tags/")) {
- assertFalse(rc.next());
- }
- }
-
- @Test
- public void namespaceHeads() throws IOException {
- Ref master = ref(MASTER, 1);
- Ref next = ref(NEXT, 2);
- Ref v1 = tag(V1_0, 3, 4);
-
- ReftableReader t = read(write(master, next, v1));
- try (RefCursor rc = t.seekRefsWithPrefix("refs/tags/")) {
- assertTrue(rc.next());
- assertEquals(V1_0, rc.getRef().getName());
- assertEquals(0, rc.getRef().getUpdateIndex());
- assertFalse(rc.next());
- }
- try (RefCursor rc = t.seekRefsWithPrefix("refs/heads/")) {
- assertTrue(rc.next());
- assertEquals(MASTER, rc.getRef().getName());
- assertEquals(0, rc.getRef().getUpdateIndex());
-
- assertTrue(rc.next());
- assertEquals(NEXT, rc.getRef().getName());
- assertEquals(0, rc.getRef().getUpdateIndex());
-
- assertFalse(rc.next());
- }
- }
-
- @SuppressWarnings("boxing")
- @Test
- public void indexScan() throws IOException {
- List<Ref> refs = new ArrayList<>();
- for (int i = 1; i <= 5670; i++) {
- refs.add(ref(String.format("refs/heads/%04d", i), i));
- }
-
- byte[] table = write(refs);
- assertTrue(stats.refIndexLevels() > 0);
- assertTrue(stats.refIndexSize() > 0);
- assertScan(refs, read(table));
- }
-
- @SuppressWarnings("boxing")
- @Test
- public void indexSeek() throws IOException {
- List<Ref> refs = new ArrayList<>();
- for (int i = 1; i <= 5670; i++) {
- refs.add(ref(String.format("refs/heads/%04d", i), i));
- }
-
- byte[] table = write(refs);
- assertTrue(stats.refIndexLevels() > 0);
- assertTrue(stats.refIndexSize() > 0);
- assertSeek(refs, read(table));
- }
-
- @SuppressWarnings("boxing")
- @Test
- public void noIndexScan() throws IOException {
- List<Ref> refs = new ArrayList<>();
- for (int i = 1; i <= 567; i++) {
- refs.add(ref(String.format("refs/heads/%03d", i), i));
- }
-
- byte[] table = write(refs);
- assertEquals(0, stats.refIndexLevels());
- assertEquals(0, stats.refIndexSize());
- assertEquals(table.length, stats.totalBytes());
- assertScan(refs, read(table));
- }
-
- @SuppressWarnings("boxing")
- @Test
- public void noIndexSeek() throws IOException {
- List<Ref> refs = new ArrayList<>();
- for (int i = 1; i <= 567; i++) {
- refs.add(ref(String.format("refs/heads/%03d", i), i));
- }
-
- byte[] table = write(refs);
- assertEquals(0, stats.refIndexLevels());
- assertSeek(refs, read(table));
- }
-
- @Test
- public void invalidRefWriteOrderSortAndWrite() {
- Ref master = ref(MASTER, 1);
- ReftableWriter writer = new ReftableWriter(new ByteArrayOutputStream())
- .setMinUpdateIndex(1)
- .setMaxUpdateIndex(1)
- .begin();
-
- List<Ref> refs = new ArrayList<>();
- refs.add(master);
- refs.add(master);
-
- IllegalArgumentException e = assertThrows(
- IllegalArgumentException.class,
- () -> writer.sortAndWriteRefs(refs));
- assertThat(e.getMessage(), containsString("records must be increasing"));
- }
-
- @Test
- public void invalidReflogWriteOrderUpdateIndex() throws IOException {
- ReftableWriter writer = new ReftableWriter(new ByteArrayOutputStream())
- .setMinUpdateIndex(1)
- .setMaxUpdateIndex(2)
- .begin();
- PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60);
- String msg = "test";
-
- writer.writeLog(MASTER, 1, who, ObjectId.zeroId(), id(1), msg);
- IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
- () -> writer.writeLog(
- MASTER, 2, who, ObjectId.zeroId(), id(2), msg));
- assertThat(e.getMessage(), containsString("records must be increasing"));
- }
-
- @Test
- public void invalidReflogWriteOrderName() throws IOException {
- ReftableWriter writer = new ReftableWriter(new ByteArrayOutputStream())
- .setMinUpdateIndex(1)
- .setMaxUpdateIndex(1)
- .begin();
- PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60);
- String msg = "test";
-
- writer.writeLog(NEXT, 1, who, ObjectId.zeroId(), id(1), msg);
- IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
- () -> writer.writeLog(
- MASTER, 1, who, ObjectId.zeroId(), id(2), msg));
- assertThat(e.getMessage(), containsString("records must be increasing"));
- }
-
- @Test
- public void withReflog() throws IOException {
- Ref master = ref(MASTER, 1);
- Ref next = ref(NEXT, 2);
- PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60);
- String msg = "test";
-
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- ReftableWriter writer = new ReftableWriter(buffer)
- .setMinUpdateIndex(1)
- .setMaxUpdateIndex(1)
- .begin();
-
- writer.writeRef(master);
- writer.writeRef(next);
-
- writer.writeLog(MASTER, 1, who, ObjectId.zeroId(), id(1), msg);
- writer.writeLog(NEXT, 1, who, ObjectId.zeroId(), id(2), msg);
-
- writer.finish();
- byte[] table = buffer.toByteArray();
- assertEquals(247, table.length);
-
- ReftableReader t = read(table);
- try (RefCursor rc = t.allRefs()) {
- assertTrue(rc.next());
- assertEquals(MASTER, rc.getRef().getName());
- assertEquals(id(1), rc.getRef().getObjectId());
- assertEquals(1, rc.getRef().getUpdateIndex());
-
- assertTrue(rc.next());
- assertEquals(NEXT, rc.getRef().getName());
- assertEquals(id(2), rc.getRef().getObjectId());
- assertEquals(1, rc.getRef().getUpdateIndex());
- assertFalse(rc.next());
- }
- try (LogCursor lc = t.allLogs()) {
- assertTrue(lc.next());
- assertEquals(MASTER, lc.getRefName());
- assertEquals(1, lc.getUpdateIndex());
- assertEquals(ObjectId.zeroId(), lc.getReflogEntry().getOldId());
- assertEquals(id(1), lc.getReflogEntry().getNewId());
- assertEquals(who, lc.getReflogEntry().getWho());
- assertEquals(msg, lc.getReflogEntry().getComment());
-
- assertTrue(lc.next());
- assertEquals(NEXT, lc.getRefName());
- assertEquals(1, lc.getUpdateIndex());
- assertEquals(ObjectId.zeroId(), lc.getReflogEntry().getOldId());
- assertEquals(id(2), lc.getReflogEntry().getNewId());
- assertEquals(who, lc.getReflogEntry().getWho());
- assertEquals(msg, lc.getReflogEntry().getComment());
-
- assertFalse(lc.next());
- }
- }
-
- @Test
- public void reflogReader() throws IOException {
- Ref master = ref(MASTER, 1);
- Ref next = ref(NEXT, 2);
-
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- ReftableWriter writer = new ReftableWriter(buffer).setMinUpdateIndex(1)
- .setMaxUpdateIndex(1).begin();
-
- writer.writeRef(master);
- writer.writeRef(next);
-
- PersonIdent who1 = new PersonIdent("Log", "Ger", 1500079709, -8 * 60);
- writer.writeLog(MASTER, 3, who1, ObjectId.zeroId(), id(1), "1");
- PersonIdent who2 = new PersonIdent("Log", "Ger", 1500079710, -8 * 60);
- writer.writeLog(MASTER, 2, who2, id(1), id(2), "2");
- PersonIdent who3 = new PersonIdent("Log", "Ger", 1500079711, -8 * 60);
- writer.writeLog(MASTER, 1, who3, id(2), id(3), "3");
-
- writer.finish();
- byte[] table = buffer.toByteArray();
-
- ReentrantLock lock = new ReentrantLock();
- ReftableReader t = read(table);
- ReftableReflogReader rlr = new ReftableReflogReader(lock, t, MASTER);
-
- assertEquals(rlr.getLastEntry().getWho(), who1);
- List<PersonIdent> all = rlr.getReverseEntries().stream()
- .map(x -> x.getWho()).collect(Collectors.toList());
- Matchers.contains(all, who3, who2, who1);
-
- assertEquals(rlr.getReverseEntry(1).getWho(), who2);
-
- List<ReflogEntry> reverse2 = rlr.getReverseEntries(2);
- Matchers.contains(reverse2, who3, who2);
-
- List<PersonIdent> more = rlr.getReverseEntries(4).stream()
- .map(x -> x.getWho()).collect(Collectors.toList());
- assertEquals(all, more);
- }
-
- @Test
- public void allRefs() throws IOException {
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- ReftableConfig cfg = new ReftableConfig();
- cfg.setRefBlockSize(1024);
- cfg.setLogBlockSize(1024);
- cfg.setAlignBlocks(true);
- ReftableWriter writer = new ReftableWriter(buffer)
- .setMinUpdateIndex(1)
- .setMaxUpdateIndex(1)
- .setConfig(cfg)
- .begin();
- PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60);
-
- // Fill out the 1st ref block.
- List<String> names = new ArrayList<>();
- for (int i = 0; i < 4; i++) {
- String name = new String(new char[220]).replace("\0", String.format("%c", i + 'a'));
- names.add(name);
- writer.writeRef(ref(name, i));
- }
-
- // Add some log data.
- writer.writeLog(MASTER, 1, who, ObjectId.zeroId(), id(1), "msg");
- writer.finish();
- byte[] table = buffer.toByteArray();
-
- ReftableReader t = read(table);
- RefCursor c = t.allRefs();
-
- int j = 0;
- while (c.next()) {
- assertEquals(names.get(j), c.getRef().getName());
- j++;
- }
- }
-
-
- @Test
- public void reflogSeek() throws IOException {
- PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60);
- String msg = "test";
- String msgNext = "test next";
-
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- ReftableWriter writer = new ReftableWriter(buffer)
- .setMinUpdateIndex(1)
- .setMaxUpdateIndex(1)
- .begin();
-
- writer.writeLog(MASTER, 1, who, ObjectId.zeroId(), id(1), msg);
- writer.writeLog(NEXT, 1, who, ObjectId.zeroId(), id(2), msgNext);
-
- writer.finish();
- byte[] table = buffer.toByteArray();
-
- ReftableReader t = read(table);
- try (LogCursor c = t.seekLog(MASTER, Long.MAX_VALUE)) {
- assertTrue(c.next());
- assertEquals(c.getReflogEntry().getComment(), msg);
- }
- try (LogCursor c = t.seekLog(MASTER, 0)) {
- assertFalse(c.next());
- }
- try (LogCursor c = t.seekLog(MASTER, 1)) {
- assertTrue(c.next());
- assertEquals(c.getUpdateIndex(), 1);
- assertEquals(c.getReflogEntry().getComment(), msg);
- }
- try (LogCursor c = t.seekLog(NEXT, Long.MAX_VALUE)) {
- assertTrue(c.next());
- assertEquals(c.getReflogEntry().getComment(), msgNext);
- }
- try (LogCursor c = t.seekLog(NEXT, 0)) {
- assertFalse(c.next());
- }
- try (LogCursor c = t.seekLog(NEXT, 1)) {
- assertTrue(c.next());
- assertEquals(c.getUpdateIndex(), 1);
- assertEquals(c.getReflogEntry().getComment(), msgNext);
- }
- }
-
- @Test
- public void reflogSeekPrefix() throws IOException {
- PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60);
-
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- ReftableWriter writer = new ReftableWriter(buffer)
- .setMinUpdateIndex(1)
- .setMaxUpdateIndex(1)
- .begin();
-
- writer.writeLog("branchname", 1, who, ObjectId.zeroId(), id(1), "branchname");
-
- writer.finish();
- byte[] table = buffer.toByteArray();
-
- ReftableReader t = read(table);
- try (LogCursor c = t.seekLog("branch", Long.MAX_VALUE)) {
- // We find a reflog block, but the iteration won't confuse branchname
- // and branch.
- assertFalse(c.next());
- }
- }
-
- @Test
- public void onlyReflog() throws IOException {
- PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60);
- String msg = "test";
-
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- ReftableWriter writer = new ReftableWriter(buffer)
- .setMinUpdateIndex(1)
- .setMaxUpdateIndex(1)
- .begin();
- writer.writeLog(MASTER, 1, who, ObjectId.zeroId(), id(1), msg);
- writer.writeLog(NEXT, 1, who, ObjectId.zeroId(), id(2), msg);
- writer.finish();
- byte[] table = buffer.toByteArray();
- stats = writer.getStats();
- assertEquals(170, table.length);
- assertEquals(0, stats.refCount());
- assertEquals(0, stats.refBytes());
- assertEquals(0, stats.refIndexLevels());
-
- ReftableReader t = read(table);
- try (RefCursor rc = t.allRefs()) {
- assertFalse(rc.next());
- }
- try (RefCursor rc = t.seekRefsWithPrefix("refs/heads/")) {
- assertFalse(rc.next());
- }
- try (LogCursor lc = t.allLogs()) {
- assertTrue(lc.next());
- assertEquals(MASTER, lc.getRefName());
- assertEquals(1, lc.getUpdateIndex());
- assertEquals(ObjectId.zeroId(), lc.getReflogEntry().getOldId());
- assertEquals(id(1), lc.getReflogEntry().getNewId());
- assertEquals(who, lc.getReflogEntry().getWho());
- // compare string too, to catch tz differences.
- assertEquals(who.toExternalString(), lc.getReflogEntry().getWho().toExternalString());
- assertEquals(msg, lc.getReflogEntry().getComment());
-
- assertTrue(lc.next());
- assertEquals(NEXT, lc.getRefName());
- assertEquals(1, lc.getUpdateIndex());
- assertEquals(ObjectId.zeroId(), lc.getReflogEntry().getOldId());
- assertEquals(id(2), lc.getReflogEntry().getNewId());
- assertEquals(who, lc.getReflogEntry().getWho());
- assertEquals(msg, lc.getReflogEntry().getComment());
-
- assertFalse(lc.next());
- }
- }
-
- @SuppressWarnings("boxing")
- @Test
- public void logScan() throws IOException {
- ReftableConfig cfg = new ReftableConfig();
- cfg.setRefBlockSize(256);
- cfg.setLogBlockSize(2048);
-
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- ReftableWriter writer = new ReftableWriter(cfg, buffer);
- writer.setMinUpdateIndex(1).setMaxUpdateIndex(1).begin();
-
- List<Ref> refs = new ArrayList<>();
- for (int i = 1; i <= 5670; i++) {
- Ref ref = ref(String.format("refs/heads/%04d", i), i);
- refs.add(ref);
- writer.writeRef(ref);
- }
-
- PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60);
- for (Ref ref : refs) {
- writer.writeLog(ref.getName(), 1, who,
- ObjectId.zeroId(), ref.getObjectId(),
- "create " + ref.getName());
- }
- writer.finish();
- stats = writer.getStats();
- assertTrue(stats.logBytes() > 4096);
- byte[] table = buffer.toByteArray();
-
- ReftableReader t = read(table);
- try (LogCursor lc = t.allLogs()) {
- for (Ref exp : refs) {
- assertTrue("has " + exp.getName(), lc.next());
- assertEquals(exp.getName(), lc.getRefName());
- ReflogEntry entry = lc.getReflogEntry();
- assertNotNull(entry);
- assertEquals(who, entry.getWho());
- assertEquals(ObjectId.zeroId(), entry.getOldId());
- assertEquals(exp.getObjectId(), entry.getNewId());
- assertEquals("create " + exp.getName(), entry.getComment());
- }
- assertFalse(lc.next());
- }
- }
-
- @SuppressWarnings("boxing")
- @Test
- public void byObjectIdOneRefNoIndex() throws IOException {
- List<Ref> refs = new ArrayList<>();
- for (int i = 1; i <= 200; i++) {
- refs.add(ref(String.format("refs/heads/%02d", i), i));
- }
- refs.add(ref("refs/heads/master", 100));
-
- ReftableReader t = read(write(refs));
- assertEquals(0, stats.objIndexSize());
-
- try (RefCursor rc = t.byObjectId(id(42))) {
- assertTrue("has 42", rc.next());
- assertEquals("refs/heads/42", rc.getRef().getName());
- assertEquals(id(42), rc.getRef().getObjectId());
- assertEquals(0, rc.getRef().getUpdateIndex());
- assertFalse(rc.next());
- }
- try (RefCursor rc = t.byObjectId(id(100))) {
- assertTrue("has 100", rc.next());
- assertEquals("refs/heads/100", rc.getRef().getName());
- assertEquals(id(100), rc.getRef().getObjectId());
-
- assertTrue("has master", rc.next());
- assertEquals("refs/heads/master", rc.getRef().getName());
- assertEquals(id(100), rc.getRef().getObjectId());
- assertEquals(0, rc.getRef().getUpdateIndex());
-
- assertFalse(rc.next());
- }
- }
-
- @SuppressWarnings("boxing")
- @Test
- public void byObjectIdOneRefWithIndex() throws IOException {
- List<Ref> refs = new ArrayList<>();
- for (int i = 1; i <= 5200; i++) {
- refs.add(ref(String.format("refs/heads/%02d", i), i));
- }
- refs.add(ref("refs/heads/master", 100));
-
- ReftableReader t = read(write(refs));
- assertTrue(stats.objIndexSize() > 0);
-
- try (RefCursor rc = t.byObjectId(id(42))) {
- assertTrue("has 42", rc.next());
- assertEquals("refs/heads/42", rc.getRef().getName());
- assertEquals(id(42), rc.getRef().getObjectId());
- assertEquals(0, rc.getRef().getUpdateIndex());
- assertFalse(rc.next());
- }
- try (RefCursor rc = t.byObjectId(id(100))) {
- assertTrue("has 100", rc.next());
- assertEquals("refs/heads/100", rc.getRef().getName());
- assertEquals(id(100), rc.getRef().getObjectId());
-
- assertTrue("has master", rc.next());
- assertEquals("refs/heads/master", rc.getRef().getName());
- assertEquals(id(100), rc.getRef().getObjectId());
- assertEquals(0, rc.getRef().getUpdateIndex());
-
- assertFalse(rc.next());
- }
- }
-
- @Test
- public void unpeeledDoesNotWrite() {
- try {
- write(new ObjectIdRef.Unpeeled(PACKED, MASTER, id(1)));
- fail("expected IOException");
- } catch (IOException e) {
- assertEquals(JGitText.get().peeledRefIsRequired, e.getMessage());
- }
- }
-
- @Test
- public void nameTooLongDoesNotWrite() throws IOException {
- try {
- ReftableConfig cfg = new ReftableConfig();
- cfg.setRefBlockSize(64);
-
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- ReftableWriter writer = new ReftableWriter(cfg, buffer).begin();
- writer.writeRef(ref("refs/heads/i-am-not-a-teapot", 1));
- writer.finish();
- fail("expected BlockSizeTooSmallException");
- } catch (BlockSizeTooSmallException e) {
- assertEquals(85, e.getMinimumBlockSize());
- }
- }
-
- @Test
- public void badCrc32() throws IOException {
- byte[] table = write();
- table[table.length - 1] = 0x42;
-
- try {
- read(table).seekRef(HEAD);
- fail("expected IOException");
- } catch (IOException e) {
- assertEquals(JGitText.get().invalidReftableCRC, e.getMessage());
- }
- }
-
- private static void assertScan(List<Ref> refs, Reftable t)
- throws IOException {
- try (RefCursor rc = t.allRefs()) {
- for (Ref exp : refs) {
- assertTrue("has " + exp.getName(), rc.next());
- Ref act = rc.getRef();
- assertEquals(exp.getName(), act.getName());
- assertEquals(exp.getObjectId(), act.getObjectId());
- assertEquals(0, rc.getRef().getUpdateIndex());
- }
- assertFalse(rc.next());
- }
- }
-
- private static void assertSeek(List<Ref> refs, Reftable t)
- throws IOException {
- for (Ref exp : refs) {
- try (RefCursor rc = t.seekRef(exp.getName())) {
- assertTrue("has " + exp.getName(), rc.next());
- Ref act = rc.getRef();
- assertEquals(exp.getName(), act.getName());
- assertEquals(exp.getObjectId(), act.getObjectId());
- assertEquals(0, rc.getRef().getUpdateIndex());
- assertFalse(rc.next());
- }
- }
- }
-
- private static Ref ref(String name, int id) {
- return new ObjectIdRef.PeeledNonTag(PACKED, name, id(id));
- }
-
- private static Ref tag(String name, int id1, int id2) {
- return new ObjectIdRef.PeeledTag(PACKED, name, id(id1), id(id2));
- }
-
- private static Ref sym(String name, String target) {
- return new SymbolicRef(name, newRef(target));
- }
-
- private static Ref newRef(String name) {
- return new ObjectIdRef.Unpeeled(NEW, name, null);
- }
-
- private static ObjectId id(int i) {
- byte[] buf = new byte[OBJECT_ID_LENGTH];
- buf[0] = (byte) (i & 0xff);
- buf[1] = (byte) ((i >>> 8) & 0xff);
- buf[2] = (byte) ((i >>> 16) & 0xff);
- buf[3] = (byte) (i >>> 24);
- return ObjectId.fromRaw(buf);
- }
-
- private static ReftableReader read(byte[] table) {
- return new ReftableReader(BlockSource.from(table));
- }
-
- private byte[] write(Ref... refs) throws IOException {
- return write(Arrays.asList(refs));
- }
-
- private byte[] write(Collection<Ref> refs) throws IOException {
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- stats = new ReftableWriter(buffer)
- .begin()
- .sortAndWriteRefs(refs)
- .finish()
- .getStats();
- return buffer.toByteArray();
- }
- }
|