@@ -772,7 +772,14 @@ public void pathMappedActionIsDeduplicated() throws Exception {
772
772
// Simulate a very slow upload to the remote cache to ensure that the second spawn is
773
773
// deduplicated rather than a cache hit. This is a slight hack, but also avoid introducing
774
774
// concurrency to this test.
775
- Mockito .doNothing ().when (remoteExecutionService ).uploadOutputs (any (), any (), any ());
775
+ AtomicReference <Runnable > onUploadComplete = new AtomicReference <>();
776
+ Mockito .doAnswer (
777
+ invocationOnMock -> {
778
+ onUploadComplete .set (invocationOnMock .getArgument (2 ));
779
+ return null ;
780
+ })
781
+ .when (remoteExecutionService )
782
+ .uploadOutputs (any (), any (), any ());
776
783
777
784
// act
778
785
try (CacheHandle firstCacheHandle = cache .lookup (firstSpawn , firstPolicy )) {
@@ -795,6 +802,8 @@ public void pathMappedActionIsDeduplicated() throws Exception {
795
802
fs .getPath ("/exec/root/bazel-bin/k8-opt/bin/output" ), UTF_8 ))
796
803
.isEqualTo ("hello" );
797
804
assertThat (secondCacheHandle .willStore ()).isFalse ();
805
+ onUploadComplete .get ().run ();
806
+ assertThat (cache .getInFlightExecutionsSize ()).isEqualTo (0 );
798
807
}
799
808
800
809
@ Test
@@ -840,10 +849,12 @@ public boolean mayModifySpawnOutputsAfterExecution() {
840
849
// Simulate a very slow upload to the remote cache to ensure that the second spawn is
841
850
// deduplicated rather than a cache hit. This is a slight hack, but also avoids introducing
842
851
// more concurrency to this test.
852
+ AtomicReference <Runnable > onUploadComplete = new AtomicReference <>();
843
853
Mockito .doAnswer (
844
854
(Answer <Void >)
845
855
invocation -> {
846
856
enteredUploadOutputs .countDown ();
857
+ onUploadComplete .set (invocation .getArgument (2 ));
847
858
return null ;
848
859
})
849
860
.when (remoteExecutionService )
@@ -910,6 +921,8 @@ public boolean mayModifySpawnOutputsAfterExecution() {
910
921
fs .getPath ("/exec/root/bazel-bin/k8-opt/bin/output" ), UTF_8 ))
911
922
.isEqualTo ("hello" );
912
923
assertThat (secondCacheHandle .willStore ()).isFalse ();
924
+ onUploadComplete .get ().run ();
925
+ assertThat (cache .getInFlightExecutionsSize ()).isEqualTo (0 );
913
926
}
914
927
915
928
@ Test
@@ -934,7 +947,14 @@ public void pathMappedActionWithInMemoryOutputIsDeduplicated() throws Exception
934
947
// Simulate a very slow upload to the remote cache to ensure that the second spawn is
935
948
// deduplicated rather than a cache hit. This is a slight hack, but also avoid introducing
936
949
// concurrency to this test.
937
- Mockito .doNothing ().when (remoteExecutionService ).uploadOutputs (any (), any (), any ());
950
+ AtomicReference <Runnable > onUploadComplete = new AtomicReference <>();
951
+ Mockito .doAnswer (
952
+ invocationOnMock -> {
953
+ onUploadComplete .set (invocationOnMock .getArgument (2 ));
954
+ return null ;
955
+ })
956
+ .when (remoteExecutionService )
957
+ .uploadOutputs (any (), any (), any ());
938
958
939
959
// act
940
960
try (CacheHandle firstCacheHandle = cache .lookup (firstSpawn , firstPolicy )) {
@@ -957,6 +977,8 @@ public void pathMappedActionWithInMemoryOutputIsDeduplicated() throws Exception
957
977
.isEqualTo ("in-memory" );
958
978
assertThat (execRoot .getRelative (inMemoryOutput .getExecPath ()).exists ()).isFalse ();
959
979
assertThat (secondCacheHandle .willStore ()).isFalse ();
980
+ onUploadComplete .get ().run ();
981
+ assertThat (cache .getInFlightExecutionsSize ()).isEqualTo (0 );
960
982
}
961
983
962
984
@ Test
@@ -978,10 +1000,6 @@ public void deduplicatedActionWithNonZeroExitCodeIsACacheMiss() throws Exception
978
1000
979
1001
RemoteExecutionService remoteExecutionService = cache .getRemoteExecutionService ();
980
1002
Mockito .doCallRealMethod ().when (remoteExecutionService ).waitForAndReuseOutputs (any (), any ());
981
- // Simulate a very slow upload to the remote cache to ensure that the second spawn is
982
- // deduplicated rather than a cache hit. This is a slight hack, but also avoid introducing
983
- // concurrency to this test.
984
- Mockito .doNothing ().when (remoteExecutionService ).uploadOutputs (any (), any (), any ());
985
1003
986
1004
// act
987
1005
try (CacheHandle firstCacheHandle = cache .lookup (firstSpawn , firstPolicy )) {
@@ -1001,11 +1019,14 @@ public void deduplicatedActionWithNonZeroExitCodeIsACacheMiss() throws Exception
1001
1019
.setRunnerName ("test" )
1002
1020
.build ());
1003
1021
}
1022
+ Mockito .verify (remoteExecutionService , never ()).uploadOutputs (any (), any (), any ());
1004
1023
CacheHandle secondCacheHandle = cache .lookup (secondSpawn , secondPolicy );
1005
1024
1006
1025
// assert
1007
1026
assertThat (secondCacheHandle .hasResult ()).isFalse ();
1008
1027
assertThat (secondCacheHandle .willStore ()).isTrue ();
1028
+ secondCacheHandle .close ();
1029
+ assertThat (cache .getInFlightExecutionsSize ()).isEqualTo (0 );
1009
1030
}
1010
1031
1011
1032
@ Test
@@ -1030,7 +1051,14 @@ public void deduplicatedActionWithMissingOutputIsACacheMiss() throws Exception {
1030
1051
// Simulate a very slow upload to the remote cache to ensure that the second spawn is
1031
1052
// deduplicated rather than a cache hit. This is a slight hack, but also avoid introducing
1032
1053
// concurrency to this test.
1033
- Mockito .doNothing ().when (remoteExecutionService ).uploadOutputs (any (), any (), any ());
1054
+ AtomicReference <Runnable > onUploadComplete = new AtomicReference <>();
1055
+ Mockito .doAnswer (
1056
+ invocationOnMock -> {
1057
+ onUploadComplete .set (invocationOnMock .getArgument (2 ));
1058
+ return null ;
1059
+ })
1060
+ .when (remoteExecutionService )
1061
+ .uploadOutputs (any (), any (), any ());
1034
1062
1035
1063
// act
1036
1064
try (CacheHandle firstCacheHandle = cache .lookup (firstSpawn , firstPolicy )) {
@@ -1047,5 +1075,100 @@ public void deduplicatedActionWithMissingOutputIsACacheMiss() throws Exception {
1047
1075
// assert
1048
1076
assertThat (secondCacheHandle .hasResult ()).isFalse ();
1049
1077
assertThat (secondCacheHandle .willStore ()).isTrue ();
1078
+ onUploadComplete .get ().run ();
1079
+ assertThat (cache .getInFlightExecutionsSize ()).isEqualTo (0 );
1080
+ }
1081
+
1082
+ @ Test
1083
+ public void pathMappedActionWithCacheHitRemovesInFlightExecution () throws Exception {
1084
+ // arrange
1085
+ RemoteSpawnCache cache = createRemoteSpawnCache ();
1086
+
1087
+ SimpleSpawn spawn = simplePathMappedSpawn ("k8-fastbuild" );
1088
+ FakeActionInputFileCache fakeFileCache = new FakeActionInputFileCache (execRoot );
1089
+ fakeFileCache .createScratchInput (spawn .getInputFiles ().getSingleton (), "xyz" );
1090
+ SpawnExecutionContext policy =
1091
+ createSpawnExecutionContext (spawn , execRoot , fakeFileCache , outErr );
1092
+
1093
+ RemoteExecutionService remoteExecutionService = cache .getRemoteExecutionService ();
1094
+ Mockito .doReturn (
1095
+ RemoteActionResult .createFromCache (
1096
+ CachedActionResult .remote (ActionResult .getDefaultInstance ())))
1097
+ .when (remoteExecutionService )
1098
+ .lookupCache (any ());
1099
+ Mockito .doReturn (null ).when (remoteExecutionService ).downloadOutputs (any (), any ());
1100
+
1101
+ // act
1102
+ try (CacheHandle cacheHandle = cache .lookup (spawn , policy )) {
1103
+ checkState (cacheHandle .hasResult ());
1104
+ }
1105
+
1106
+ // assert
1107
+ assertThat (cache .getInFlightExecutionsSize ()).isEqualTo (0 );
1108
+ }
1109
+
1110
+ @ Test
1111
+ public void pathMappedActionNotUploadedRemovesInFlightExecution () throws Exception {
1112
+ // arrange
1113
+ RemoteSpawnCache cache = createRemoteSpawnCache ();
1114
+
1115
+ SimpleSpawn spawn = simplePathMappedSpawn ("k8-fastbuild" );
1116
+ FakeActionInputFileCache fakeFileCache = new FakeActionInputFileCache (execRoot );
1117
+ fakeFileCache .createScratchInput (spawn .getInputFiles ().getSingleton (), "xyz" );
1118
+ SpawnExecutionContext policy =
1119
+ createSpawnExecutionContext (spawn , execRoot , fakeFileCache , outErr );
1120
+
1121
+ RemoteExecutionService remoteExecutionService = cache .getRemoteExecutionService ();
1122
+ Mockito .doCallRealMethod ()
1123
+ .when (remoteExecutionService )
1124
+ .commitResultAndDecideWhetherToUpload (any (), any ());
1125
+
1126
+ // act
1127
+ try (CacheHandle cacheHandle = cache .lookup (spawn , policy )) {
1128
+ cacheHandle .store (
1129
+ new SpawnResult .Builder ()
1130
+ .setExitCode (1 )
1131
+ .setStatus (Status .NON_ZERO_EXIT )
1132
+ .setFailureDetail (
1133
+ FailureDetail .newBuilder ()
1134
+ .setMessage ("test spawn failed" )
1135
+ .setSpawn (
1136
+ FailureDetails .Spawn .newBuilder ()
1137
+ .setCode (FailureDetails .Spawn .Code .NON_ZERO_EXIT ))
1138
+ .build ())
1139
+ .setRunnerName ("test" )
1140
+ .build ());
1141
+ }
1142
+
1143
+ // assert
1144
+ assertThat (cache .getInFlightExecutionsSize ()).isEqualTo (0 );
1145
+ }
1146
+
1147
+ @ Test
1148
+ public void pathMappedActionWithCacheIoExceptionRemovesInFlightExecution () throws Exception {
1149
+ // arrange
1150
+ RemoteSpawnCache cache = createRemoteSpawnCache ();
1151
+
1152
+ SimpleSpawn spawn = simplePathMappedSpawn ("k8-fastbuild" );
1153
+ FakeActionInputFileCache fakeFileCache = new FakeActionInputFileCache (execRoot );
1154
+ fakeFileCache .createScratchInput (spawn .getInputFiles ().getSingleton (), "xyz" );
1155
+ SpawnExecutionContext policy =
1156
+ createSpawnExecutionContext (spawn , execRoot , fakeFileCache , outErr );
1157
+
1158
+ RemoteExecutionService remoteExecutionService = cache .getRemoteExecutionService ();
1159
+ Mockito .doReturn (
1160
+ RemoteActionResult .createFromCache (
1161
+ CachedActionResult .remote (ActionResult .getDefaultInstance ())))
1162
+ .when (remoteExecutionService )
1163
+ .lookupCache (any ());
1164
+ Mockito .doThrow (new IOException ()).when (remoteExecutionService ).downloadOutputs (any (), any ());
1165
+
1166
+ // act
1167
+ try (CacheHandle cacheHandle = cache .lookup (spawn , policy )) {
1168
+ checkState (!cacheHandle .hasResult ());
1169
+ }
1170
+
1171
+ // assert
1172
+ assertThat (cache .getInFlightExecutionsSize ()).isEqualTo (0 );
1050
1173
}
1051
1174
}
0 commit comments