28
28
import static org .junit .jupiter .api .Assertions .assertTrue ;
29
29
import static org .junit .jupiter .api .Assertions .fail ;
30
30
import static org .junit .jupiter .api .Assumptions .assumeTrue ;
31
+ import static org .mockito .Mockito .doReturn ;
31
32
import static org .mockito .Mockito .mock ;
33
+ import static org .mockito .Mockito .spy ;
32
34
import static org .mockito .Mockito .when ;
33
35
import static org .mockito .ArgumentMatchers .anyString ;
34
36
import static org .mockito .ArgumentMatchers .any ;
@@ -122,6 +124,8 @@ public class TestAuxServices {
122
124
.getSimpleName ());
123
125
private File manifest = new File (rootDir , "manifest.txt" );
124
126
private ObjectMapper mapper = new ObjectMapper ();
127
+ private static final FsPermission WRITABLE_BY_OWNER = FsPermission .createImmutable ((short ) 0755 );
128
+ private static final FsPermission WRITABLE_BY_GROUP = FsPermission .createImmutable ((short ) 0775 );
125
129
126
130
public static Collection <Boolean > getParams () {
127
131
return Arrays .asList (false , true );
@@ -266,6 +270,24 @@ private void writeManifestFile(AuxServiceRecords services, Configuration
266
270
mapper .writeValue (manifest , services );
267
271
}
268
272
273
+ /**
274
+ * Creates a spy object of AuxServices for test cases which assume that we have proper
275
+ * file system permissions by default.
276
+ *
277
+ * Permission checking iterates through the parents of the manifest file until it
278
+ * reaches the system root, so without mocking this the success of the initialization
279
+ * would heavily depend on the environment where the test is running.
280
+ *
281
+ * @return a spy object of AuxServices
282
+ */
283
+ private AuxServices getSpyAuxServices (AuxiliaryLocalPathHandler auxiliaryLocalPathHandler ,
284
+ Context nmContext , DeletionService deletionService ) throws IOException {
285
+ AuxServices auxServices = spy (new AuxServices (auxiliaryLocalPathHandler ,
286
+ nmContext , deletionService ));
287
+ doReturn (true ).when (auxServices ).checkManifestPermissions (any (FileStatus .class ));
288
+ return auxServices ;
289
+ }
290
+
269
291
@ SuppressWarnings ("resource" )
270
292
@ ParameterizedTest
271
293
@ MethodSource ("getParams" )
@@ -317,7 +339,7 @@ public void testRemoteAuxServiceClassPath(boolean pUseManifest) throws Exception
317
339
YarnConfiguration .NM_AUX_SERVICE_REMOTE_CLASSPATH , "ServiceC" ),
318
340
testJar .getAbsolutePath ());
319
341
}
320
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
342
+ aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
321
343
mockContext2 , mockDelService2 );
322
344
aux .init (conf );
323
345
fail ("The permission of the jar is wrong."
@@ -339,7 +361,7 @@ public void testRemoteAuxServiceClassPath(boolean pUseManifest) throws Exception
339
361
YarnConfiguration .NM_AUX_SERVICE_REMOTE_CLASSPATH , "ServiceC" ),
340
362
testJar .getAbsolutePath ());
341
363
}
342
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
364
+ aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
343
365
mockContext2 , mockDelService2 );
344
366
aux .init (conf );
345
367
aux .start ();
@@ -356,7 +378,7 @@ public void testRemoteAuxServiceClassPath(boolean pUseManifest) throws Exception
356
378
357
379
// initialize the same auxservice again, and make sure that we did not
358
380
// re-download the jar from remote directory.
359
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
381
+ aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
360
382
mockContext2 , mockDelService2 );
361
383
aux .init (conf );
362
384
aux .start ();
@@ -377,7 +399,7 @@ public void testRemoteAuxServiceClassPath(boolean pUseManifest) throws Exception
377
399
FileTime fileTime = FileTime .fromMillis (time );
378
400
Files .setLastModifiedTime (Paths .get (testJar .getAbsolutePath ()),
379
401
fileTime );
380
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
402
+ aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
381
403
mockContext2 , mockDelService2 );
382
404
aux .init (conf );
383
405
aux .start ();
@@ -419,7 +441,7 @@ public void testCustomizedAuxServiceClassPath(boolean pUseManifest) throws Excep
419
441
"ServiceC" ), ServiceC .class , Service .class );
420
442
}
421
443
@ SuppressWarnings ("resource" )
422
- AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
444
+ AuxServices aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
423
445
MOCK_CONTEXT , MOCK_DEL_SERVICE );
424
446
aux .init (conf );
425
447
aux .start ();
@@ -472,7 +494,7 @@ public void testCustomizedAuxServiceClassPath(boolean pUseManifest) throws Excep
472
494
when (mockDirsHandler .getLocalPathForWrite (anyString ())).thenReturn (
473
495
rootAuxServiceDirPath );
474
496
when (mockContext2 .getLocalDirsHandler ()).thenReturn (mockDirsHandler );
475
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
497
+ aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
476
498
mockContext2 , MOCK_DEL_SERVICE );
477
499
aux .init (conf );
478
500
aux .start ();
@@ -654,7 +676,7 @@ private Configuration getABConf(String aName, String bName,
654
676
public void testAuxServices (boolean pUseManifest ) throws IOException {
655
677
initTestAuxServices (pUseManifest );
656
678
Configuration conf = getABConf ();
657
- final AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
679
+ final AuxServices aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
658
680
MOCK_CONTEXT , MOCK_DEL_SERVICE );
659
681
aux .init (conf );
660
682
@@ -684,7 +706,7 @@ public void testAuxServices(boolean pUseManifest) throws IOException {
684
706
public void testAuxServicesMeta (boolean pUseManifest ) throws IOException {
685
707
initTestAuxServices (pUseManifest );
686
708
Configuration conf = getABConf ();
687
- final AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
709
+ final AuxServices aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
688
710
MOCK_CONTEXT , MOCK_DEL_SERVICE );
689
711
aux .init (conf );
690
712
@@ -718,7 +740,7 @@ public void testAuxUnexpectedStop(boolean pUseManifest) throws IOException {
718
740
initTestAuxServices (pUseManifest );
719
741
// AuxServices no longer expected to stop when services stop
720
742
Configuration conf = getABConf ();
721
- final AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
743
+ final AuxServices aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
722
744
MOCK_CONTEXT , MOCK_DEL_SERVICE );
723
745
aux .init (conf );
724
746
aux .start ();
@@ -736,7 +758,7 @@ public void testValidAuxServiceName(boolean pUseManifest) throws IOException {
736
758
initTestAuxServices (pUseManifest );
737
759
Configuration conf = getABConf ("Asrv1" , "Bsrv_2" , ServiceA .class ,
738
760
ServiceB .class );
739
- final AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
761
+ final AuxServices aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
740
762
MOCK_CONTEXT , MOCK_DEL_SERVICE );
741
763
try {
742
764
aux .init (conf );
@@ -745,7 +767,7 @@ public void testValidAuxServiceName(boolean pUseManifest) throws IOException {
745
767
}
746
768
747
769
//Test bad auxService Name
748
- final AuxServices aux1 = new AuxServices (MOCK_AUX_PATH_HANDLER ,
770
+ final AuxServices aux1 = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
749
771
MOCK_CONTEXT , MOCK_DEL_SERVICE );
750
772
if (useManifest ) {
751
773
AuxServiceRecord serviceA =
@@ -776,7 +798,7 @@ public void testAuxServiceRecoverySetup(boolean pUseManifest) throws IOException
776
798
conf .setBoolean (YarnConfiguration .NM_RECOVERY_ENABLED , true );
777
799
conf .set (YarnConfiguration .NM_RECOVERY_DIR , TEST_DIR .toString ());
778
800
try {
779
- final AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
801
+ final AuxServices aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
780
802
MOCK_CONTEXT , MOCK_DEL_SERVICE );
781
803
aux .init (conf );
782
804
assertEquals (2 , aux .getServices ().size ());
@@ -906,62 +928,130 @@ public void testAuxServicesConfChange(boolean pUseManifest) throws IOException {
906
928
907
929
@ ParameterizedTest
908
930
@ MethodSource ("getParams" )
909
- public void testAuxServicesManifestPermissions (boolean pUseManifest ) throws IOException {
931
+ public void testAuxServicesInitWithManifestOwnerAndPermissionCheck (boolean pUseManifest )
932
+ throws IOException {
910
933
initTestAuxServices (pUseManifest );
911
934
assumeTrue (useManifest );
912
935
Configuration conf = getABConf ();
913
- FileSystem fs = FileSystem .get (conf );
914
- fs .setPermission (new Path (manifest .getAbsolutePath ()), FsPermission
915
- .createImmutable ((short ) 0777 ));
916
- AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
917
- MOCK_CONTEXT , MOCK_DEL_SERVICE );
936
+ AuxServices aux = spy (new AuxServices (MOCK_AUX_PATH_HANDLER ,
937
+ MOCK_CONTEXT , MOCK_DEL_SERVICE ));
938
+ doReturn (false ).when (aux ).checkManifestPermissions (any (FileStatus .class ));
918
939
aux .init (conf );
919
940
assertEquals (0 , aux .getServices ().size ());
920
941
921
- fs .setPermission (new Path (manifest .getAbsolutePath ()), FsPermission
922
- .createImmutable ((short ) 0775 ));
923
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
924
- MOCK_CONTEXT , MOCK_DEL_SERVICE );
925
- aux .init (conf );
926
- assertEquals (0 , aux .getServices ().size ());
927
-
928
- fs .setPermission (new Path (manifest .getAbsolutePath ()), FsPermission
929
- .createImmutable ((short ) 0755 ));
930
- fs .setPermission (new Path (rootDir .getAbsolutePath ()), FsPermission
931
- .createImmutable ((short ) 0775 ));
932
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
933
- MOCK_CONTEXT , MOCK_DEL_SERVICE );
934
- aux .init (conf );
935
- assertEquals (0 , aux .getServices ().size ());
936
-
937
- fs .setPermission (new Path (rootDir .getAbsolutePath ()), FsPermission
938
- .createImmutable ((short ) 0755 ));
939
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
942
+ aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
940
943
MOCK_CONTEXT , MOCK_DEL_SERVICE );
941
944
aux .init (conf );
942
945
assertEquals (2 , aux .getServices ().size ());
943
946
944
947
conf .set (YarnConfiguration .YARN_ADMIN_ACL , "" );
945
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
948
+ aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
946
949
MOCK_CONTEXT , MOCK_DEL_SERVICE );
947
950
aux .init (conf );
948
951
assertEquals (0 , aux .getServices ().size ());
949
952
950
953
conf .set (YarnConfiguration .YARN_ADMIN_ACL , UserGroupInformation
951
954
.getCurrentUser ().getShortUserName ());
952
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
955
+ aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
953
956
MOCK_CONTEXT , MOCK_DEL_SERVICE );
954
957
aux .init (conf );
955
958
assertEquals (2 , aux .getServices ().size ());
956
959
}
957
960
961
+ @ ParameterizedTest
962
+ @ MethodSource ("getParams" )
963
+ public void testCheckManifestPermissionsWhenFileIsOnlyWritableByOwner (boolean pUseManifest )
964
+ throws IOException {
965
+ initTestAuxServices (pUseManifest );
966
+ assumeTrue (useManifest );
967
+ final AuxServices aux = spy (new AuxServices (MOCK_AUX_PATH_HANDLER ,
968
+ MOCK_CONTEXT , MOCK_DEL_SERVICE ));
969
+ FileStatus manifestFileStatus = mock (FileStatus .class );
970
+ Path manifestPath = mock (Path .class );
971
+
972
+ when (manifestFileStatus .getPermission ()).thenReturn (WRITABLE_BY_OWNER );
973
+ when (manifestFileStatus .getPath ()).thenReturn (manifestPath );
974
+
975
+ assertTrue (aux .checkManifestPermissions (manifestFileStatus ));
976
+ }
977
+
978
+ @ ParameterizedTest
979
+ @ MethodSource ("getParams" )
980
+ public void testCheckManifestPermissionsWhenFileIsWritableByGroup (boolean pUseManifest )
981
+ throws IOException {
982
+ initTestAuxServices (pUseManifest );
983
+ assumeTrue (useManifest );
984
+ final AuxServices aux = spy (new AuxServices (MOCK_AUX_PATH_HANDLER ,
985
+ MOCK_CONTEXT , MOCK_DEL_SERVICE ));
986
+ FileStatus manifestFileStatus = mock (FileStatus .class );
987
+ Path manifestPath = mock (Path .class );
988
+
989
+ when (manifestFileStatus .getPermission ()).thenReturn (WRITABLE_BY_GROUP );
990
+ when (manifestFileStatus .getPath ()).thenReturn (manifestPath );
991
+
992
+ assertFalse (aux .checkManifestPermissions (manifestFileStatus ));
993
+ }
994
+
995
+ @ ParameterizedTest
996
+ @ MethodSource ("getParams" )
997
+ public void testCheckManifestPermissionsWhenParentIsWritableByGroup (boolean pUseManifest )
998
+ throws IOException {
999
+ initTestAuxServices (pUseManifest );
1000
+ assumeTrue (useManifest );
1001
+ final AuxServices aux = spy (new AuxServices (MOCK_AUX_PATH_HANDLER ,
1002
+ MOCK_CONTEXT , MOCK_DEL_SERVICE ));
1003
+
1004
+ FileStatus manifestFileStatus = mock (FileStatus .class );
1005
+ FileStatus parentFolderStatus = mock (FileStatus .class );
1006
+ when (manifestFileStatus .getPermission ()).thenReturn (WRITABLE_BY_OWNER );
1007
+ when (parentFolderStatus .getPermission ()).thenReturn (WRITABLE_BY_GROUP );
1008
+
1009
+ Path manifestPath = mock (Path .class );
1010
+ Path parentPath = mock (Path .class );
1011
+ when (manifestFileStatus .getPath ()).thenReturn (manifestPath );
1012
+ when (manifestPath .getParent ()).thenReturn (parentPath );
1013
+
1014
+ FileSystem manifestFs = mock (FileSystem .class );
1015
+ when (manifestFs .getFileStatus (parentPath )).thenReturn (parentFolderStatus );
1016
+ doReturn (manifestFs ).when (aux ).getManifestFS ();
1017
+
1018
+ assertFalse (aux .checkManifestPermissions (manifestFileStatus ));
1019
+ }
1020
+
1021
+ @ ParameterizedTest
1022
+ @ MethodSource ("getParams" )
1023
+ public void testCheckManifestPermissionsWhenParentAndFileIsWritableByOwner (boolean pUseManifest )
1024
+ throws IOException {
1025
+ initTestAuxServices (pUseManifest );
1026
+ assumeTrue (useManifest );
1027
+ final AuxServices aux = spy (new AuxServices (MOCK_AUX_PATH_HANDLER ,
1028
+ MOCK_CONTEXT , MOCK_DEL_SERVICE ));
1029
+
1030
+ FileStatus manifestFileStatus = mock (FileStatus .class );
1031
+ FileStatus parentFolderStatus = mock (FileStatus .class );
1032
+ when (manifestFileStatus .getPermission ()).thenReturn (WRITABLE_BY_OWNER );
1033
+ when (parentFolderStatus .getPermission ()).thenReturn (WRITABLE_BY_OWNER );
1034
+
1035
+ Path manifestPath = mock (Path .class );
1036
+ Path parentPath = mock (Path .class );
1037
+ when (manifestFileStatus .getPath ()).thenReturn (manifestPath );
1038
+ when (parentFolderStatus .getPath ()).thenReturn (parentPath );
1039
+ when (manifestPath .getParent ()).thenReturn (parentPath );
1040
+
1041
+ FileSystem manifestFs = mock (FileSystem .class );
1042
+ when (manifestFs .getFileStatus (parentPath )).thenReturn (parentFolderStatus );
1043
+ doReturn (manifestFs ).when (aux ).getManifestFS ();
1044
+
1045
+ assertTrue (aux .checkManifestPermissions (manifestFileStatus ));
1046
+ }
1047
+
958
1048
@ ParameterizedTest
959
1049
@ MethodSource ("getParams" )
960
1050
public void testRemoveManifest (boolean pUseManifest ) throws IOException {
961
1051
initTestAuxServices (pUseManifest );
962
1052
assumeTrue (useManifest );
963
1053
Configuration conf = getABConf ();
964
- final AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
1054
+ final AuxServices aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
965
1055
MOCK_CONTEXT , MOCK_DEL_SERVICE );
966
1056
aux .init (conf );
967
1057
assertEquals (2 , aux .getServices ().size ());
@@ -976,7 +1066,7 @@ public void testManualReload(boolean pUseManifest) throws IOException {
976
1066
initTestAuxServices (pUseManifest );
977
1067
assumeTrue (useManifest );
978
1068
Configuration conf = getABConf ();
979
- final AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
1069
+ final AuxServices aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
980
1070
MOCK_CONTEXT , MOCK_DEL_SERVICE );
981
1071
aux .init (conf );
982
1072
try {
0 commit comments