@ -43,22 +43,35 @@
package org.eclipse.jgit.internal.storage.file ;
import static org.eclipse.jgit.internal.storage.file.BatchRefUpdateTest.Result.LOCK_FAILURE ;
import static org.eclipse.jgit.internal.storage.file.BatchRefUpdateTest.Result.OK ;
import static org.eclipse.jgit.internal.storage.file.BatchRefUpdateTest.Result.REJECTED_MISSING_OBJECT ;
import static org.eclipse.jgit.internal.storage.file.BatchRefUpdateTest.Result.REJECTED_NONFASTFORWARD ;
import static org.eclipse.jgit.internal.storage.file.BatchRefUpdateTest.Result.TRANSACTION_ABORTED ;
import static org.eclipse.jgit.lib.ObjectId.zeroId ;
import static org.eclipse.jgit.transport.ReceiveCommand.Type.CREATE ;
import static org.eclipse.jgit.transport.ReceiveCommand.Type.DELETE ;
import static org.eclipse.jgit.transport.ReceiveCommand.Type.UPDATE ;
import static org.eclipse.jgit.transport.ReceiveCommand.Type.UPDATE_NONFASTFORWARD ;
import static org.junit.Assert.assertEquals ;
import static org.junit.Assert.assertNotNull ;
import static org.junit.Assert.assertTrue ;
import java.io.File ;
import java.io.IOException ;
import java.util.Arrays ;
import java.util.Collection ;
import java.util.LinkedHashMap ;
import java.util.List ;
import java.util.Map ;
import java.util.function.Predicate ;
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase ;
import org.eclipse.jgit.junit.StrictWorkMonitor ;
import org.eclipse.jgit.junit.TestRepository ;
import org.eclipse.jgit.lib.AnyObjectId ;
import org.eclipse.jgit.lib.BatchRefUpdate ;
import org.eclipse.jgit.lib.Constants ;
import org.eclipse.jgit.lib.NullProgressMonitor ;
import org.eclipse.jgit.lib.ObjectId ;
import org.eclipse.jgit.lib.Ref ;
@ -103,43 +116,26 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase {
B = repo . commit ( repo . getRevWalk ( ) . parseCommit ( A ) ) ;
}
private BatchRefUpdate newBatchUpdate ( ) {
BatchRefUpdate u = refdir . newBatchUpdate ( ) ;
if ( atomic ) {
assertTrue ( u . isAtomic ( ) ) ;
} else {
u . setAtomic ( false ) ;
}
return u ;
}
@Test
public void simpleNoForce ( ) throws IOException {
writeLooseRef ( "refs/heads/master" , A ) ;
writeLooseRef ( "refs/heads/masters" , B ) ;
List < ReceiveCommand > commands = Arrays . asList (
new ReceiveCommand ( A , B , "refs/heads/master" ,
ReceiveCommand . Type . UPDATE ) ,
new ReceiveCommand ( B , A , "refs/heads/masters" ,
ReceiveCommand . Type . UPDATE_NONFASTFORWARD ) ) ;
BatchRefUpdate batchUpdate = newBatchUpdate ( ) ;
batchUpdate . addCommand ( commands ) ;
batchUpdate . execute ( new RevWalk ( diskRepo ) , new StrictWorkMonitor ( ) ) ;
Map < String , Ref > refs = refdir . getRefs ( RefDatabase . ALL ) ;
assertEquals ( ReceiveCommand . Result . REJECTED_NONFASTFORWARD , commands
. get ( 1 ) . getResult ( ) ) ;
List < ReceiveCommand > cmds = Arrays . asList (
new ReceiveCommand ( A , B , "refs/heads/master" , UPDATE ) ,
new ReceiveCommand ( B , A , "refs/heads/masters" , UPDATE_NONFASTFORWARD ) ) ;
execute ( newBatchUpdate ( cmds ) ) ;
if ( atomic ) {
assertTrue ( ReceiveCommand . isTransactionAborted ( commands . get ( 0 ) ) ) ;
assertEquals ( "[HEAD, refs/heads/master, refs/heads/masters]" , refs
. keySet ( ) . toString ( ) ) ;
assertEquals ( A . getId ( ) , refs . get ( "refs/heads/master" ) . getObjectId ( ) ) ;
assertEquals ( B . getId ( ) , refs . get ( "refs/heads/masters" ) . getObjectId ( ) ) ;
assertResults ( cmds , TRANSACTION_ABORTED , REJECTED_NONFASTFORWARD ) ;
assertRefs (
"refs/heads/master" , A ,
"refs/heads/masters" , B ) ;
} else {
assertEquals ( ReceiveCommand . Result . OK , commands . get ( 0 ) . getResult ( ) ) ;
assertEquals ( "[HEAD, refs/heads/master, refs/heads/masters]" , refs
. keySet ( ) . toString ( ) ) ;
assertEquals ( B . getId ( ) , refs . get ( "refs/heads/master" ) . getObjectId ( ) ) ;
assertEquals ( B . getId ( ) , refs . get ( "refs/heads/masters" ) . getObjectId ( ) ) ;
assertResults ( cmds , OK , REJECTED_NONFASTFORWARD ) ;
assertRefs (
"refs/heads/master" , B ,
"refs/heads/masters" , B ) ;
}
}
@ -147,85 +143,65 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase {
public void simpleForce ( ) throws IOException {
writeLooseRef ( "refs/heads/master" , A ) ;
writeLooseRef ( "refs/heads/masters" , B ) ;
List < ReceiveCommand > commands = Arrays . asList (
new ReceiveCommand ( A , B , "refs/heads/master" ,
ReceiveCommand . Type . UPDATE ) ,
new ReceiveCommand ( B , A , "refs/heads/masters" ,
ReceiveCommand . Type . UPDATE_NONFASTFORWARD ) ) ;
BatchRefUpdate batchUpdate = newBatchUpdate ( ) ;
batchUpdate . setAllowNonFastForwards ( true ) ;
batchUpdate . addCommand ( commands ) ;
batchUpdate . execute ( new RevWalk ( diskRepo ) , new StrictWorkMonitor ( ) ) ;
Map < String , Ref > refs = refdir . getRefs ( RefDatabase . ALL ) ;
assertEquals ( ReceiveCommand . Result . OK , commands . get ( 0 ) . getResult ( ) ) ;
assertEquals ( ReceiveCommand . Result . OK , commands . get ( 1 ) . getResult ( ) ) ;
assertEquals ( "[HEAD, refs/heads/master, refs/heads/masters]" , refs
. keySet ( ) . toString ( ) ) ;
assertEquals ( B . getId ( ) , refs . get ( "refs/heads/master" ) . getObjectId ( ) ) ;
assertEquals ( A . getId ( ) , refs . get ( "refs/heads/masters" ) . getObjectId ( ) ) ;
List < ReceiveCommand > cmds = Arrays . asList (
new ReceiveCommand ( A , B , "refs/heads/master" , UPDATE ) ,
new ReceiveCommand ( B , A , "refs/heads/masters" , UPDATE_NONFASTFORWARD ) ) ;
execute ( newBatchUpdate ( cmds ) . setAllowNonFastForwards ( true ) ) ;
assertResults ( cmds , OK , OK ) ;
assertRefs (
"refs/heads/master" , B ,
"refs/heads/masters" , A ) ;
}
@Test
public void nonFastForwardDoesNotDoExpensiveMergeCheck ( ) throws IOException {
writeLooseRef ( "refs/heads/master" , B ) ;
List < ReceiveCommand > commands = Arrays . asList (
new ReceiveCommand ( B , A , "refs/heads/master" ,
ReceiveCommand . Type . UPDATE_NONFASTFORWARD ) ) ;
BatchRefUpdate batchUpdate = newBatchUpdate ( ) ;
batchUpdate . setAllowNonFastForwards ( true ) ;
batchUpdate . addCommand ( commands ) ;
batchUpdate . execute ( new RevWalk ( diskRepo ) {
@Override
public boolean isMergedInto ( RevCommit base , RevCommit tip ) {
throw new AssertionError ( "isMergedInto() should not be called" ) ;
}
} , new StrictWorkMonitor ( ) ) ;
Map < String , Ref > refs = refdir . getRefs ( RefDatabase . ALL ) ;
assertEquals ( ReceiveCommand . Result . OK , commands . get ( 0 ) . getResult ( ) ) ;
assertEquals ( A . getId ( ) , refs . get ( "refs/heads/master" ) . getObjectId ( ) ) ;
List < ReceiveCommand > cmds = Arrays . asList (
new ReceiveCommand ( B , A , "refs/heads/master" , UPDATE_NONFASTFORWARD ) ) ;
try ( RevWalk rw = new RevWalk ( diskRepo ) {
@Override
public boolean isMergedInto ( RevCommit base , RevCommit tip ) {
throw new AssertionError ( "isMergedInto() should not be called" ) ;
}
} ) {
newBatchUpdate ( cmds )
. setAllowNonFastForwards ( true )
. execute ( rw , new StrictWorkMonitor ( ) ) ;
}
assertResults ( cmds , OK ) ;
assertRefs ( "refs/heads/master" , A ) ;
}
@Test
public void fileDirectoryConflict ( ) throws IOException {
writeLooseRef ( "refs/heads/master" , A ) ;
writeLooseRef ( "refs/heads/masters" , B ) ;
List < ReceiveCommand > commands = Arrays . asList (
new ReceiveCommand ( A , B , "refs/heads/master" ,
ReceiveCommand . Type . UPDATE ) ,
new ReceiveCommand ( zeroId ( ) , A , "refs/heads/master/x" ,
ReceiveCommand . Type . CREATE ) ,
new ReceiveCommand ( zeroId ( ) , A , "refs/heads" ,
ReceiveCommand . Type . CREATE ) ) ;
BatchRefUpdate batchUpdate = newBatchUpdate ( ) ;
batchUpdate . setAllowNonFastForwards ( true ) ;
batchUpdate . addCommand ( commands ) ;
batchUpdate
. execute ( new RevWalk ( diskRepo ) , NullProgressMonitor . INSTANCE ) ;
Map < String , Ref > refs = refdir . getRefs ( RefDatabase . ALL ) ;
List < ReceiveCommand > cmds = Arrays . asList (
new ReceiveCommand ( A , B , "refs/heads/master" , UPDATE ) ,
new ReceiveCommand ( zeroId ( ) , A , "refs/heads/master/x" , CREATE ) ,
new ReceiveCommand ( zeroId ( ) , A , "refs/heads" , CREATE ) ) ;
execute ( newBatchUpdate ( cmds ) . setAllowNonFastForwards ( true ) , false ) ;
if ( atomic ) {
// Atomic update sees that master and master/x are conflicting, then marks
// the first one in the list as LOCK_FAILURE and aborts the rest.
assertEquals ( ReceiveCommand . Result . LOCK_FAILURE ,
commands . get ( 0 ) . getResult ( ) ) ;
assertTrue ( ReceiveCommand . isTransactionAborted ( commands . get ( 1 ) ) ) ;
assertTrue ( ReceiveCommand . isTransactionAborted ( commands . get ( 2 ) ) ) ;
assertEquals ( "[HEAD, refs/heads/master, refs/heads/masters]" , refs
. keySet ( ) . toString ( ) ) ;
assertEquals ( A . getId ( ) , refs . get ( "refs/heads/master" ) . getObjectId ( ) ) ;
assertEquals ( B . getId ( ) , refs . get ( "refs/heads/masters" ) . getObjectId ( ) ) ;
assertResults ( cmds ,
LOCK_FAILURE , TRANSACTION_ABORTED , TRANSACTION_ABORTED ) ;
assertRefs (
"refs/heads/master" , A ,
"refs/heads/masters" , B ) ;
} else {
// Non-atomic updates are applied in order: master succeeds, then master/x
// fails due to conflict.
assertEquals ( ReceiveCommand . Result . OK , commands . get ( 0 ) . getResult ( ) ) ;
assertEquals ( ReceiveCommand . Result . LOCK_FAILURE , commands . get ( 1 )
. getResult ( ) ) ;
assertEquals ( ReceiveCommand . Result . LOCK_FAILURE , commands . get ( 2 )
. getResult ( ) ) ;
assertEquals ( "[HEAD, refs/heads/master, refs/heads/masters]" , refs
. keySet ( ) . toString ( ) ) ;
assertEquals ( B . getId ( ) , refs . get ( "refs/heads/master" ) . getObjectId ( ) ) ;
assertEquals ( B . getId ( ) , refs . get ( "refs/heads/masters" ) . getObjectId ( ) ) ;
assertResults ( cmds , OK , LOCK_FAILURE , LOCK_FAILURE ) ;
assertRefs (
"refs/heads/master" , B ,
"refs/heads/masters" , B ) ;
}
}
@ -233,170 +209,205 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase {
public void conflictThanksToDelete ( ) throws IOException {
writeLooseRef ( "refs/heads/master" , A ) ;
writeLooseRef ( "refs/heads/masters" , B ) ;
List < ReceiveCommand > commands = Arrays . asList (
new ReceiveCommand ( A , B , "refs/heads/master" ,
ReceiveCommand . Type . UPDATE ) ,
new ReceiveCommand ( zeroId ( ) , A , "refs/heads/masters/x" ,
ReceiveCommand . Type . CREATE ) ,
new ReceiveCommand ( B , zeroId ( ) , "refs/heads/masters" ,
ReceiveCommand . Type . DELETE ) ) ;
BatchRefUpdate batchUpdate = newBatchUpdate ( ) ;
batchUpdate . setAllowNonFastForwards ( true ) ;
batchUpdate . addCommand ( commands ) ;
batchUpdate . execute ( new RevWalk ( diskRepo ) , new StrictWorkMonitor ( ) ) ;
Map < String , Ref > refs = refdir . getRefs ( RefDatabase . ALL ) ;
assertEquals ( ReceiveCommand . Result . OK , commands . get ( 0 ) . getResult ( ) ) ;
assertEquals ( ReceiveCommand . Result . OK , commands . get ( 1 ) . getResult ( ) ) ;
assertEquals ( ReceiveCommand . Result . OK , commands . get ( 2 ) . getResult ( ) ) ;
assertEquals ( "[HEAD, refs/heads/master, refs/heads/masters/x]" , refs
. keySet ( ) . toString ( ) ) ;
assertEquals ( A . getId ( ) , refs . get ( "refs/heads/masters/x" ) . getObjectId ( ) ) ;
List < ReceiveCommand > cmds = Arrays . asList (
new ReceiveCommand ( A , B , "refs/heads/master" , UPDATE ) ,
new ReceiveCommand ( zeroId ( ) , A , "refs/heads/masters/x" , CREATE ) ,
new ReceiveCommand ( B , zeroId ( ) , "refs/heads/masters" , DELETE ) ) ;
execute ( newBatchUpdate ( cmds ) . setAllowNonFastForwards ( true ) ) ;
assertResults ( cmds , OK , OK , OK ) ;
assertRefs (
"refs/heads/master" , B ,
"refs/heads/masters/x" , A ) ;
}
@Test
public void updateToMissingObject ( ) throws IOException {
writeLooseRef ( "refs/heads/master" , A ) ;
ObjectId bad =
ObjectId . fromString ( "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef" ) ;
List < ReceiveCommand > commands = Arrays . asList (
new ReceiveCommand ( A , bad , "refs/heads/master" ,
ReceiveCommand . Type . UPDATE ) ,
new ReceiveCommand ( zeroId ( ) , B , "refs/heads/foo2" ,
ReceiveCommand . Type . CREATE ) ) ;
BatchRefUpdate batchUpdate = newBatchUpdate ( ) ;
batchUpdate . setAllowNonFastForwards ( true ) ;
batchUpdate . addCommand ( commands ) ;
batchUpdate . execute ( new RevWalk ( diskRepo ) , NullProgressMonitor . INSTANCE ) ;
Map < String , Ref > refs = refdir . getRefs ( RefDatabase . ALL ) ;
assertEquals ( ReceiveCommand . Result . REJECTED_MISSING_OBJECT ,
commands . get ( 0 ) . getResult ( ) ) ;
List < ReceiveCommand > cmds = Arrays . asList (
new ReceiveCommand ( A , bad , "refs/heads/master" , UPDATE ) ,
new ReceiveCommand ( zeroId ( ) , B , "refs/heads/foo2" , CREATE ) ) ;
execute ( newBatchUpdate ( cmds ) . setAllowNonFastForwards ( true ) , false ) ;
if ( atomic ) {
assertTrue ( ReceiveCommand . isTransactionAborted ( commands . get ( 1 ) ) ) ;
assertEquals ( "[HEAD, refs/heads/master]" , refs . keySet ( )
. toString ( ) ) ;
assertEquals ( A . getId ( ) , refs . get ( "refs/heads/master" ) . getObjectId ( ) ) ;
assertResults ( cmds , REJECTED_MISSING_OBJECT , TRANSACTION_ABORTED ) ;
assertRefs ( "refs/heads/master" , A ) ;
} else {
assertEquals ( ReceiveCommand . Result . OK , commands . get ( 1 ) . getResult ( ) ) ;
assertEquals ( "[HEAD, refs/heads/foo2, refs/heads/master]" , refs . keySet ( )
. toString ( ) ) ;
assertEquals ( A . getId ( ) , refs . get ( "refs/heads/master" ) . getObjectId ( ) ) ;
assertEquals ( B . getId ( ) , refs . get ( "refs/heads/foo2" ) . getObjectId ( ) ) ;
assertResults ( cmds , REJECTED_MISSING_OBJECT , OK ) ;
assertRefs (
"refs/heads/master" , A ,
"refs/heads/foo2" , B ) ;
}
}
@Test
public void addMissingObject ( ) throws IOException {
writeLooseRef ( "refs/heads/master" , A ) ;
ObjectId bad =
ObjectId . fromString ( "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef" ) ;
List < ReceiveCommand > commands = Arrays . asList (
new ReceiveCommand ( A , B , "refs/heads/master" ,
ReceiveCommand . Type . UPDATE ) ,
new ReceiveCommand ( zeroId ( ) , bad , "refs/heads/foo2" ,
ReceiveCommand . Type . CREATE ) ) ;
BatchRefUpdate batchUpdate = newBatchUpdate ( ) ;
batchUpdate . setAllowNonFastForwards ( true ) ;
batchUpdate . addCommand ( commands ) ;
batchUpdate . execute ( new RevWalk ( diskRepo ) , NullProgressMonitor . INSTANCE ) ;
Map < String , Ref > refs = refdir . getRefs ( RefDatabase . ALL ) ;
assertEquals ( ReceiveCommand . Result . REJECTED_MISSING_OBJECT ,
commands . get ( 1 ) . getResult ( ) ) ;
List < ReceiveCommand > cmds = Arrays . asList (
new ReceiveCommand ( A , B , "refs/heads/master" , UPDATE ) ,
new ReceiveCommand ( zeroId ( ) , bad , "refs/heads/foo2" , CREATE ) ) ;
execute ( newBatchUpdate ( cmds ) . setAllowNonFastForwards ( true ) , false ) ;
if ( atomic ) {
assertTrue ( ReceiveCommand . isTransactionAborted ( commands . get ( 0 ) ) ) ;
assertEquals ( "[HEAD, refs/heads/master]" , refs . keySet ( ) . toString ( ) ) ;
assertEquals ( A . getId ( ) , refs . get ( "refs/heads/master" ) . getObjectId ( ) ) ;
assertResults ( cmds , TRANSACTION_ABORTED , REJECTED_MISSING_OBJECT ) ;
assertRefs ( "refs/heads/master" , A ) ;
} else {
assertEquals ( ReceiveCommand . Result . OK , commands . get ( 0 ) . getResult ( ) ) ;
assertEquals ( "[HEAD, refs/heads/master]" , refs . keySet ( )
. toString ( ) ) ;
assertEquals ( B . getId ( ) , refs . get ( "refs/heads/master" ) . getObjectId ( ) ) ;
assertResults ( cmds , OK , REJECTED_MISSING_OBJECT ) ;
assertRefs ( "refs/heads/master" , B ) ;
}
}
@Test
public void oneNonExistentRef ( ) throws IOException {
List < ReceiveCommand > commands = Arrays . asList (
new ReceiveCommand ( A , B , "refs/heads/foo1" ,
ReceiveCommand . Type . UPDATE ) ,
new ReceiveCommand ( zeroId ( ) , B , "refs/heads/foo2" ,
ReceiveCommand . Type . CREATE ) ) ;
BatchRefUpdate batchUpdate = newBatchUpdate ( ) ;
batchUpdate . setAllowNonFastForwards ( true ) ;
batchUpdate . addCommand ( commands ) ;
batchUpdate . execute ( new RevWalk ( diskRepo ) , new StrictWorkMonitor ( ) ) ;
Map < String , Ref > refs = refdir . getRefs ( RefDatabase . ALL ) ;
assertEquals ( ReceiveCommand . Result . LOCK_FAILURE ,
commands . get ( 0 ) . getResult ( ) ) ;
List < ReceiveCommand > cmds = Arrays . asList (
new ReceiveCommand ( A , B , "refs/heads/foo1" , UPDATE ) ,
new ReceiveCommand ( zeroId ( ) , B , "refs/heads/foo2" , CREATE ) ) ;
execute ( newBatchUpdate ( cmds ) . setAllowNonFastForwards ( true ) ) ;
if ( atomic ) {
assertTrue ( ReceiveCommand . isTransactionAborted ( commands . get ( 1 ) ) ) ;
assertEquals ( "[]" , refs . keySet ( ) . toString ( ) ) ;
assertResults ( cmds , LOCK_FAILURE , TRANSACTION_ABORTED ) ;
assertRefs ( ) ;
} else {
assertEquals ( ReceiveCommand . Result . OK , commands . get ( 1 ) . getResult ( ) ) ;
assertEquals ( "[refs/heads/foo2]" , refs . keySet ( ) . toString ( ) ) ;
assertEquals ( B . getId ( ) , refs . get ( "refs/heads/foo2" ) . getObjectId ( ) ) ;
assertResults ( cmds , LOCK_FAILURE , OK ) ;
assertRefs ( "refs/heads/foo2" , B ) ;
}
}
@Test
public void oneRefWrongOldValue ( ) throws IOException {
writeLooseRef ( "refs/heads/master" , A ) ;
List < ReceiveCommand > commands = Arrays . asList (
new ReceiveCommand ( B , B , "refs/heads/master" ,
ReceiveCommand . Type . UPDATE ) ,
new ReceiveCommand ( zeroId ( ) , B , "refs/heads/foo2" ,
ReceiveCommand . Type . CREATE ) ) ;
BatchRefUpdate batchUpdate = newBatchUpdate ( ) ;
batchUpdate . setAllowNonFastForwards ( true ) ;
batchUpdate . addCommand ( commands ) ;
batchUpdate . execute ( new RevWalk ( diskRepo ) , new StrictWorkMonitor ( ) ) ;
Map < String , Ref > refs = refdir . getRefs ( RefDatabase . ALL ) ;
assertEquals ( ReceiveCommand . Result . LOCK_FAILURE ,
commands . get ( 0 ) . getResult ( ) ) ;
List < ReceiveCommand > cmds = Arrays . asList (
new ReceiveCommand ( B , B , "refs/heads/master" , UPDATE ) ,
new ReceiveCommand ( zeroId ( ) , B , "refs/heads/foo2" , CREATE ) ) ;
execute ( newBatchUpdate ( cmds ) . setAllowNonFastForwards ( true ) ) ;
if ( atomic ) {
assertTrue ( ReceiveCommand . isTransactionAborted ( commands . get ( 1 ) ) ) ;
assertEquals ( "[HEAD, refs/heads/master]" , refs . keySet ( ) . toString ( ) ) ;
assertEquals ( A . getId ( ) , refs . get ( "refs/heads/master" ) . getObjectId ( ) ) ;
assertResults ( cmds , LOCK_FAILURE , TRANSACTION_ABORTED ) ;
assertRefs ( "refs/heads/master" , A ) ;
} else {
assertEquals ( ReceiveCommand . Result . OK , commands . get ( 1 ) . getResult ( ) ) ;
assertEquals ( "[HEAD, refs/heads/foo2, refs/heads/master]" , refs
. keySet ( ) . toString ( ) ) ;
assertEquals ( A . getId ( ) , refs . get ( "refs/heads/master" ) . getObjectId ( ) ) ;
assertEquals ( B . getId ( ) , refs . get ( "refs/heads/foo2" ) . getObjectId ( ) ) ;
assertResults ( cmds , LOCK_FAILURE , OK ) ;
assertRefs (
"refs/heads/master" , A ,
"refs/heads/foo2" , B ) ;
}
}
@Test
public void nonExistentRef ( ) throws IOException {
writeLooseRef ( "refs/heads/master" , A ) ;
List < ReceiveCommand > commands = Arrays . asList (
new ReceiveCommand ( A , B , "refs/heads/master" ,
ReceiveCommand . Type . UPDATE ) ,
new ReceiveCommand ( A , zeroId ( ) , "refs/heads/foo2" ,
ReceiveCommand . Type . DELETE ) ) ;
BatchRefUpdate batchUpdate = newBatchUpdate ( ) ;
batchUpdate . setAllowNonFastForwards ( true ) ;
batchUpdate . addCommand ( commands ) ;
batchUpdate . execute ( new RevWalk ( diskRepo ) , new StrictWorkMonitor ( ) ) ;
Map < String , Ref > refs = refdir . getRefs ( RefDatabase . ALL ) ;
assertEquals ( ReceiveCommand . Result . LOCK_FAILURE ,
commands . get ( 1 ) . getResult ( ) ) ;
List < ReceiveCommand > cmds = Arrays . asList (
new ReceiveCommand ( A , B , "refs/heads/master" , UPDATE ) ,
new ReceiveCommand ( A , zeroId ( ) , "refs/heads/foo2" , DELETE ) ) ;
execute ( newBatchUpdate ( cmds ) . setAllowNonFastForwards ( true ) ) ;
if ( atomic ) {
assertTrue ( ReceiveCommand . isTransactionAborted ( commands . get ( 0 ) ) ) ;
assertEquals ( "[HEAD, refs/heads/master]" , refs . keySet ( ) . toString ( ) ) ;
assertEquals ( A . getId ( ) , refs . get ( "refs/heads/master" ) . getObjectId ( ) ) ;
assertResults ( cmds , TRANSACTION_ABORTED , LOCK_FAILURE ) ;
assertRefs ( "refs/heads/master" , A ) ;
} else {
assertEquals ( ReceiveCommand . Result . OK , commands . get ( 0 ) . getResult ( ) ) ;
assertEquals ( "[HEAD, refs/heads/master]" , refs . keySet ( ) . toString ( ) ) ;
assertEquals ( B . getId ( ) , refs . get ( "refs/heads/master" ) . getObjectId ( ) ) ;
assertResults ( cmds , OK , LOCK_FAILURE ) ;
assertRefs ( "refs/heads/master" , B ) ;
}
}
private void writeLooseRef ( String name , AnyObjectId id ) throws IOException {
write ( new File ( diskRepo . getDirectory ( ) , name ) , id . name ( ) + "\n" ) ;
}
private BatchRefUpdate newBatchUpdate ( List < ReceiveCommand > cmds ) {
BatchRefUpdate u = refdir . newBatchUpdate ( ) ;
if ( atomic ) {
assertTrue ( u . isAtomic ( ) ) ;
} else {
u . setAtomic ( false ) ;
}
u . addCommand ( cmds ) ;
return u ;
}
private void execute ( BatchRefUpdate u ) throws IOException {
execute ( u , false ) ;
}
private void execute ( BatchRefUpdate u , boolean strictWork ) throws IOException {
try ( RevWalk rw = new RevWalk ( diskRepo ) ) {
u . execute ( rw ,
strictWork ? new StrictWorkMonitor ( ) : NullProgressMonitor . INSTANCE ) ;
}
}
private void assertRefs ( Object . . . args ) throws IOException {
if ( args . length % 2 ! = 0 ) {
throw new IllegalArgumentException (
"expected even number of args: " + Arrays . toString ( args ) ) ;
}
Map < String , AnyObjectId > expected = new LinkedHashMap < > ( ) ;
for ( int i = 0 ; i < args . length ; i + = 2 ) {
expected . put ( ( String ) args [ i ] , ( AnyObjectId ) args [ i + 1 ] ) ;
}
Map < String , Ref > refs = refdir . getRefs ( RefDatabase . ALL ) ;
Ref actualHead = refs . remove ( Constants . HEAD ) ;
if ( actualHead ! = null ) {
String actualLeafName = actualHead . getLeaf ( ) . getName ( ) ;
assertEquals (
"expected HEAD to point to refs/heads/master, got: " + actualLeafName ,
"refs/heads/master" , actualLeafName ) ;
AnyObjectId expectedMaster = expected . get ( "refs/heads/master" ) ;
assertNotNull ( "expected master ref since HEAD exists" , expectedMaster ) ;
assertEquals ( expectedMaster , actualHead . getObjectId ( ) ) ;
}
Map < String , AnyObjectId > actual = new LinkedHashMap < > ( ) ;
refs . forEach ( ( n , r ) - > actual . put ( n , r . getObjectId ( ) ) ) ;
assertEquals ( expected . keySet ( ) , actual . keySet ( ) ) ;
actual . forEach ( ( n , a ) - > assertEquals ( n , expected . get ( n ) , a ) ) ;
}
enum Result {
OK ( ReceiveCommand . Result . OK ) ,
LOCK_FAILURE ( ReceiveCommand . Result . LOCK_FAILURE ) ,
REJECTED_NONFASTFORWARD ( ReceiveCommand . Result . REJECTED_NONFASTFORWARD ) ,
REJECTED_MISSING_OBJECT ( ReceiveCommand . Result . REJECTED_MISSING_OBJECT ) ,
TRANSACTION_ABORTED ( ReceiveCommand : : isTransactionAborted ) ;
final Predicate < ? super ReceiveCommand > p ;
private Result ( Predicate < ? super ReceiveCommand > p ) {
this . p = p ;
}
private Result ( ReceiveCommand . Result result ) {
this ( c - > c . getResult ( ) = = result ) ;
}
}
private void assertResults (
List < ReceiveCommand > cmds , Result . . . expected ) {
if ( expected . length ! = cmds . size ( ) ) {
throw new IllegalArgumentException (
"expected " + cmds . size ( ) + " result args" ) ;
}
for ( int i = 0 ; i < cmds . size ( ) ; i + + ) {
ReceiveCommand c = cmds . get ( i ) ;
Result r = expected [ i ] ;
assertTrue (
String . format (
"result of command (%d) should be %s: %s %s%s" ,
Integer . valueOf ( i ) , r , c ,
c . getResult ( ) ,
c . getMessage ( ) ! = null ? " (" + c . getMessage ( ) + ")" : "" ) ,
r . p . test ( c ) ) ;
}
}
}