1818 */
1919package org .apache .iceberg .hadoop ;
2020
21+ import static org .apache .hadoop .fs .CommonConfigurationKeysPublic .FS_TRASH_INTERVAL_KEY ;
22+ import static org .apache .iceberg .hadoop .HadoopFileIO .USE_TRASH_IF_CONFIGURED ;
2123import static org .assertj .core .api .Assertions .assertThat ;
24+ import static org .assertj .core .api .Assertions .assertThatNoException ;
2225import static org .assertj .core .api .Assertions .assertThatThrownBy ;
2326
2427import java .io .File ;
@@ -126,6 +129,47 @@ public void testDeletePrefix() {
126129 .hasMessageContaining ("java.io.FileNotFoundException" );
127130 }
128131
132+ @ Test
133+ public void testDeletePrefixWithTrashEnabled () throws IOException {
134+ Configuration conf = new Configuration ();
135+ conf .set (FS_TRASH_INTERVAL_KEY , "60" );
136+ conf .set (USE_TRASH_IF_CONFIGURED , "true" );
137+ fs = FileSystem .getLocal (conf );
138+
139+ hadoopFileIO = new HadoopFileIO (conf );
140+ Path parent = new Path (tempDir .toURI ());
141+
142+ List <Integer > scaleSizes = Lists .newArrayList (1 , 1000 , 2500 );
143+
144+ scaleSizes .parallelStream ()
145+ .forEach (
146+ scale -> {
147+ Path scalePath = new Path (parent , Integer .toString (scale ));
148+
149+ List <Path > filesCreated = createRandomFiles (scalePath , scale );
150+ hadoopFileIO .deletePrefix (scalePath .toUri ().toString ());
151+
152+ // Hadoop filesystem will throw if the path does not exist
153+ assertThatThrownBy (
154+ () -> hadoopFileIO .listPrefix (scalePath .toUri ().toString ()).iterator ())
155+ .isInstanceOf (UncheckedIOException .class )
156+ .hasMessageContaining ("java.io.FileNotFoundException" );
157+ filesCreated .forEach (
158+ file -> {
159+ String fileSuffix = Path .getPathWithoutSchemeAndAuthority (file ).toString ();
160+ String trashPath =
161+ fs .getTrashRoot (scalePath ).toString () + "/Current" + fileSuffix ;
162+ assertThat (hadoopFileIO .newInputFile (trashPath ).exists ()).isTrue ();
163+ });
164+ });
165+
166+ hadoopFileIO .deletePrefix (parent .toUri ().toString ());
167+ // Hadoop filesystem will throw if the path does not exist
168+ assertThatThrownBy (() -> hadoopFileIO .listPrefix (parent .toUri ().toString ()).iterator ())
169+ .isInstanceOf (UncheckedIOException .class )
170+ .hasMessageContaining ("java.io.FileNotFoundException" );
171+ }
172+
129173 @ Test
130174 public void testDeleteFiles () {
131175 Path parent = new Path (tempDir .toURI ());
@@ -136,6 +180,74 @@ public void testDeleteFiles() {
136180 file -> assertThat (hadoopFileIO .newInputFile (file .toString ()).exists ()).isFalse ());
137181 }
138182
183+ @ Test
184+ public void testDeleteFilesWithTrashEnabled () throws IOException {
185+ Configuration conf = new Configuration ();
186+ conf .set (FS_TRASH_INTERVAL_KEY , "60" );
187+ conf .set (USE_TRASH_IF_CONFIGURED , "true" );
188+ fs = FileSystem .getLocal (conf );
189+
190+ hadoopFileIO = new HadoopFileIO (conf );
191+ Path parent = new Path (tempDir .toURI ());
192+ List <Path > filesCreated = createRandomFiles (parent , 10 );
193+ hadoopFileIO .deleteFiles (
194+ filesCreated .stream ().map (Path ::toString ).collect (Collectors .toList ()));
195+ filesCreated .forEach (
196+ file -> assertThat (hadoopFileIO .newInputFile (file .toString ()).exists ()).isFalse ());
197+ filesCreated .forEach (
198+ file -> {
199+ String fileSuffix = Path .getPathWithoutSchemeAndAuthority (file ).toString ();
200+ String trashPath = fs .getTrashRoot (parent ).toString () + "/Current" + fileSuffix ;
201+ assertThat (hadoopFileIO .newInputFile (trashPath ).exists ()).isTrue ();
202+ });
203+ }
204+
205+ @ Test
206+ public void testDeleteFilesWithoutIcebergTrashToggleDoesNotMoveToTrash () throws IOException {
207+ Configuration conf = new Configuration ();
208+ conf .set (FS_TRASH_INTERVAL_KEY , "60" );
209+ fs = FileSystem .getLocal (conf );
210+
211+ hadoopFileIO = new HadoopFileIO (conf );
212+ Path parent = new Path (tempDir .toURI ());
213+ List <Path > filesCreated = createRandomFiles (parent , 10 );
214+ hadoopFileIO .deleteFiles (
215+ filesCreated .stream ().map (Path ::toString ).collect (Collectors .toList ()));
216+ filesCreated .forEach (
217+ file -> assertThat (hadoopFileIO .newInputFile (file .toString ()).exists ()).isFalse ());
218+ filesCreated .forEach (
219+ file -> {
220+ String fileSuffix = Path .getPathWithoutSchemeAndAuthority (file ).toString ();
221+ String trashPath = fs .getTrashRoot (parent ).toString () + "/Current" + fileSuffix ;
222+ assertThat (hadoopFileIO .newInputFile (trashPath ).exists ()).isFalse ();
223+ });
224+ }
225+
226+ @ Test
227+ public void testDeleteDirectoryWithTrashEnabledShouldThrow () throws IOException {
228+ Configuration conf = new Configuration ();
229+ conf .set (FS_TRASH_INTERVAL_KEY , "60" );
230+ conf .set (USE_TRASH_IF_CONFIGURED , "true" );
231+ fs = FileSystem .getLocal (conf );
232+
233+ hadoopFileIO = new HadoopFileIO (conf );
234+ Path parent = new Path (tempDir .toURI ());
235+ assertThatThrownBy (() -> hadoopFileIO .deleteFile (parent .toString ()))
236+ .hasCauseInstanceOf (IOException .class );
237+ }
238+
239+ @ Test
240+ public void testDeleteDirectoryWithTrashEnabledShouldNotThrow () throws IOException {
241+ Configuration conf = new Configuration ();
242+ conf .set (FS_TRASH_INTERVAL_KEY , "60" );
243+ conf .set (USE_TRASH_IF_CONFIGURED , "true" );
244+ fs = FileSystem .getLocal (conf );
245+
246+ hadoopFileIO = new HadoopFileIO (conf );
247+ Path parent = new Path (tempDir .toURI ());
248+ assertThatNoException ().isThrownBy (() -> hadoopFileIO .deletePrefix (parent .toString ()));
249+ }
250+
139251 @ Test
140252 public void testDeleteFilesErrorHandling () {
141253 List <String > filesCreated =
0 commit comments