Kinetica   C#   API  Version 7.2.3.1
AsyncKifsFileHandlerTests.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Text;
5 using System.Threading.Tasks;
6 using Xunit;
8 using kinetica;
9 using kinetica.FileSystem;
10 
11 namespace Kinetica.AsyncTests
12 {
17  [Trait("Category", "Integration")]
18  [Trait("Category", "Async")]
19  public class AsyncKifsFileHandlerTests : IAsyncLifetime
20  {
21  private KineticaFileHandler? _fileHandler;
22  private string? _tempDir;
23  private const string TestDirName = "async_kifs_test_dir";
24  private TestContext? _ctx;
25 
26  public async Task InitializeAsync()
27  {
28  _ctx = new TestContext("async_kifs_tests");
29  _fileHandler = new KineticaFileHandler(_ctx.Kinetica);
30  _tempDir = Path.Combine(Path.GetTempPath(), $"async_kifs_test_{Guid.NewGuid():N}");
31  Directory.CreateDirectory(_tempDir);
32 
33  // Clean up any existing test directory
34  try { _fileHandler.DeleteDirectory(TestDirName, true, true); } catch { }
35 
36  await Task.CompletedTask;
37  }
38 
39  public async Task DisposeAsync()
40  {
41  // Clean up test directory
42  if (_fileHandler != null)
43  {
44  try { _fileHandler.DeleteDirectory(TestDirName, true, true); } catch { }
45  }
46 
47  // Clean up temp directory
48  if (_tempDir != null && Directory.Exists(_tempDir))
49  {
50  try { Directory.Delete(_tempDir, true); } catch { }
51  }
52 
53  _ctx?.Dispose();
54 
55  await Task.CompletedTask;
56  }
57 
58  #region Directory Tests
59 
60  [Fact]
62  {
63  _fileHandler!.CreateDirectory(TestDirName);
64  Assert.True(_fileHandler.KifsDirectoryExists(TestDirName));
65  }
66 
67  [Fact]
69  {
70  _fileHandler!.CreateDirectory(TestDirName);
71  Assert.True(_fileHandler.KifsDirectoryExists(TestDirName));
72 
73  _fileHandler.DeleteDirectory(TestDirName);
74  Assert.False(_fileHandler.KifsDirectoryExists(TestDirName));
75  }
76 
77  [Fact]
79  {
80  _fileHandler!.CreateDirectory(TestDirName);
81 
82  var directories = _fileHandler.ShowAllDirectories();
83 
84  Assert.NotNull(directories);
85  Assert.Contains(directories, d => d.KifsPath == TestDirName);
86  }
87 
88  [Fact]
90  {
91  _fileHandler!.CreateDirectory(TestDirName);
92  Assert.True(_fileHandler.KifsDirectoryExists(TestDirName));
93  }
94 
95  [Fact]
97  {
98  Assert.False(_fileHandler!.KifsDirectoryExists("non_existing_dir_" + Guid.NewGuid().ToString("N")));
99  }
100 
101  [Fact]
103  {
104  _fileHandler!.CreateDirectory(TestDirName);
105 
106  // Should not throw when noErrorIfExists is true
107  _fileHandler.CreateDirectory(TestDirName, noErrorIfExists: true);
108  Assert.True(_fileHandler.KifsDirectoryExists(TestDirName));
109  }
110 
111  [Fact]
113  {
114  _fileHandler!.CreateDirectory(TestDirName);
115 
116  var directories = _fileHandler.ShowDirectory(TestDirName);
117 
118  Assert.NotNull(directories);
119  Assert.Single(directories);
120  Assert.Equal(TestDirName, directories[0].KifsPath);
121  Assert.NotEmpty(directories[0].CreatedBy);
122  }
123 
124  #endregion
125 
126  #region Upload Tests (Async)
127 
128  [Fact]
130  {
131  _fileHandler!.CreateDirectory(TestDirName);
132 
133  // Create test file
134  var testFile = Path.Combine(_tempDir!, "test_upload.txt");
135  await File.WriteAllTextAsync(testFile, "Test content for upload");
136 
137  // Upload using async method
138  await _fileHandler.UploadAsync(new List<string> { testFile }, TestDirName);
139 
140  // Verify
141  var files = _fileHandler.ShowFiles(new List<string> { TestDirName });
142  Assert.Single(files);
143  Assert.Contains(files, f => f.FileName.EndsWith("test_upload.txt"));
144  }
145 
146  [Fact]
148  {
149  _fileHandler!.CreateDirectory(TestDirName);
150 
151  // Create multiple test files
152  var file1 = Path.Combine(_tempDir!, "file1.txt");
153  var file2 = Path.Combine(_tempDir!, "file2.txt");
154  var file3 = Path.Combine(_tempDir!, "file3.txt");
155 
156  await File.WriteAllTextAsync(file1, "Content 1");
157  await File.WriteAllTextAsync(file2, "Content 2");
158  await File.WriteAllTextAsync(file3, "Content 3");
159 
160  // Upload all files using async method
161  await _fileHandler.UploadAsync(new List<string> { file1, file2, file3 }, TestDirName);
162 
163  // Verify
164  var files = _fileHandler.ShowFiles(new List<string> { TestDirName });
165  Assert.Equal(3, files.Count);
166  }
167 
168  [Fact]
170  {
171  _fileHandler!.CreateDirectory(TestDirName);
172 
173  // Create a 5MB test file
174  var largeFile = Path.Combine(_tempDir!, "large_file.bin");
175  var content = new byte[5 * 1024 * 1024]; // 5MB
176  new Random().NextBytes(content);
177  await File.WriteAllBytesAsync(largeFile, content);
178 
179  // Upload using async method
180  await _fileHandler.UploadAsync(new List<string> { largeFile }, TestDirName);
181 
182  // Verify
183  var files = _fileHandler.ShowFiles(new List<string> { TestDirName });
184  Assert.Single(files);
185  Assert.True(files[0].FileSize > 0);
186  }
187 
188  [Fact]
190  {
191  _fileHandler!.CreateDirectory(TestDirName);
192 
193  var testFile = Path.Combine(_tempDir!, "test_with_options.txt");
194  await File.WriteAllTextAsync(testFile, "Test content with options");
195 
196  var options = new UploadOptions
197  {
198  DeleteIfExists = false
199  };
200 
201  await _fileHandler.UploadAsync(new List<string> { testFile }, TestDirName, options);
202 
203  var files = _fileHandler.ShowFiles(new List<string> { TestDirName });
204  Assert.Single(files);
205  }
206 
207  [Fact]
209  {
210  _fileHandler!.CreateDirectory(TestDirName);
211 
212  var testFile = Path.Combine(_tempDir!, "test_callback.txt");
213  await File.WriteAllTextAsync(testFile, "Hello, Callback!");
214 
215  var callback = new TestUploadListener();
216 
217  await _fileHandler.UploadAsync(new List<string> { testFile }, TestDirName, UploadOptions.Default, callback);
218 
219  Assert.True(callback.FullFileUploadCalled);
220  }
221 
222  [Fact]
224  {
225  _fileHandler!.CreateDirectory(TestDirName);
226 
227  await Assert.ThrowsAsync<KineticaException>(async () =>
228  await _fileHandler.UploadAsync(new List<string> { "/non/existent/file.txt" }, TestDirName));
229  }
230 
231  [Fact]
233  {
234  var testFile = Path.Combine(_tempDir!, "test.txt");
235  await File.WriteAllTextAsync(testFile, "Test");
236 
237  await Assert.ThrowsAsync<KineticaException>(async () =>
238  await _fileHandler!.UploadAsync(new List<string> { testFile }, "non_existent_dir_" + Guid.NewGuid().ToString("N")));
239  }
240 
241  #endregion
242 
243  #region Download Tests (Async)
244 
245  [Fact]
247  {
248  _fileHandler!.CreateDirectory(TestDirName);
249 
250  // Upload a file first
251  var uploadFile = Path.Combine(_tempDir!, "upload_for_download.txt");
252  var testContent = "Test content for download";
253  await File.WriteAllTextAsync(uploadFile, testContent);
254  await _fileHandler.UploadAsync(new List<string> { uploadFile }, TestDirName);
255 
256  // Download it
257  var downloadDir = Path.Combine(_tempDir!, "downloads");
258  Directory.CreateDirectory(downloadDir);
259 
260  await _fileHandler.DownloadAsync(
261  new List<string> { $"{TestDirName}/upload_for_download.txt" },
262  downloadDir);
263 
264  // Verify
265  var downloadedFile = Path.Combine(downloadDir, "upload_for_download.txt");
266  Assert.True(File.Exists(downloadedFile));
267  var downloadedContent = await File.ReadAllTextAsync(downloadedFile);
268  Assert.Equal(testContent, downloadedContent);
269  }
270 
271  [Fact]
273  {
274  _fileHandler!.CreateDirectory(TestDirName);
275 
276  // Upload multiple files
277  var file1 = Path.Combine(_tempDir!, "download1.txt");
278  var file2 = Path.Combine(_tempDir!, "download2.txt");
279  await File.WriteAllTextAsync(file1, "Content 1");
280  await File.WriteAllTextAsync(file2, "Content 2");
281  await _fileHandler.UploadAsync(new List<string> { file1, file2 }, TestDirName);
282 
283  // Download them
284  var downloadDir = Path.Combine(_tempDir!, "downloads_multi");
285  Directory.CreateDirectory(downloadDir);
286 
287  await _fileHandler.DownloadAsync(
288  new List<string> {
289  $"{TestDirName}/download1.txt",
290  $"{TestDirName}/download2.txt"
291  },
292  downloadDir);
293 
294  // Verify
295  Assert.True(File.Exists(Path.Combine(downloadDir, "download1.txt")));
296  Assert.True(File.Exists(Path.Combine(downloadDir, "download2.txt")));
297  }
298 
299  [Fact]
301  {
302  _fileHandler!.CreateDirectory(TestDirName);
303 
304  // Upload files with pattern
305  var csvFile1 = Path.Combine(_tempDir!, "data1.csv");
306  var csvFile2 = Path.Combine(_tempDir!, "data2.csv");
307  var txtFile = Path.Combine(_tempDir!, "readme.txt");
308 
309  await File.WriteAllTextAsync(csvFile1, "csv1");
310  await File.WriteAllTextAsync(csvFile2, "csv2");
311  await File.WriteAllTextAsync(txtFile, "txt");
312 
313  await _fileHandler.UploadAsync(new List<string> { csvFile1, csvFile2, txtFile }, TestDirName);
314 
315  // Download only CSV files using glob pattern
316  var downloadDir = Path.Combine(_tempDir!, "downloads_glob");
317  Directory.CreateDirectory(downloadDir);
318 
319  await _fileHandler.DownloadAsync(
320  new List<string> { $"{TestDirName}/*.csv" },
321  downloadDir);
322 
323  // Verify only CSV files were downloaded
324  Assert.True(File.Exists(Path.Combine(downloadDir, "data1.csv")));
325  Assert.True(File.Exists(Path.Combine(downloadDir, "data2.csv")));
326  Assert.False(File.Exists(Path.Combine(downloadDir, "readme.txt")));
327  }
328 
329  [Fact]
331  {
332  _fileHandler!.CreateDirectory(TestDirName);
333 
334  var testFileName = "test_overwrite.txt";
335  var uploadPath = Path.Combine(_tempDir!, testFileName);
336  await File.WriteAllTextAsync(uploadPath, "Original content");
337  await _fileHandler.UploadAsync(new List<string> { uploadPath }, TestDirName);
338 
339  var downloadDir = Path.Combine(_tempDir!, "downloads_overwrite");
340  Directory.CreateDirectory(downloadDir);
341  var existingFile = Path.Combine(downloadDir, testFileName);
342  await File.WriteAllTextAsync(existingFile, "Existing content");
343 
344  var remoteFilePath = $"{TestDirName}/{testFileName}";
345  var options = new DownloadOptions(overwriteExisting: false);
346 
347  await Assert.ThrowsAsync<KineticaException>(async () =>
348  await _fileHandler.DownloadAsync(new List<string> { remoteFilePath }, downloadDir, options, null));
349  }
350 
351  #endregion
352 
353  #region File Management Tests
354 
355  [Fact]
357  {
358  _fileHandler!.CreateDirectory(TestDirName);
359 
360  var testFile = Path.Combine(_tempDir!, "show_file_test.txt");
361  await File.WriteAllTextAsync(testFile, "Test content");
362  await _fileHandler.UploadAsync(new List<string> { testFile }, TestDirName);
363 
364  var files = _fileHandler.ShowFiles(new List<string> { TestDirName });
365 
366  Assert.Single(files);
367  Assert.EndsWith("show_file_test.txt", files[0].FileName);
368  Assert.True(files[0].FileSize > 0);
369  }
370 
371  [Fact]
372  public async Task DeleteFiles_RemovesFiles()
373  {
374  _fileHandler!.CreateDirectory(TestDirName);
375 
376  var testFile = Path.Combine(_tempDir!, "delete_test.txt");
377  await File.WriteAllTextAsync(testFile, "Delete me");
378  await _fileHandler.UploadAsync(new List<string> { testFile }, TestDirName);
379 
380  // Verify file exists
381  var filesBefore = _fileHandler.ShowFiles(new List<string> { TestDirName });
382  Assert.Single(filesBefore);
383 
384  // Delete file
385  _fileHandler.DeleteFiles(new List<string> { $"{TestDirName}/delete_test.txt" });
386 
387  // Verify file is gone
388  var filesAfter = _fileHandler.ShowFiles(new List<string> { TestDirName });
389  Assert.Empty(filesAfter);
390  }
391 
392  [Fact]
394  {
395  _fileHandler!.CreateDirectory(TestDirName);
396 
397  var testFile = Path.Combine(_tempDir!, "exists_test.txt");
398  await File.WriteAllTextAsync(testFile, "I exist");
399  await _fileHandler.UploadAsync(new List<string> { testFile }, TestDirName);
400 
401  Assert.True(_fileHandler.KifsFileExists($"{TestDirName}/exists_test.txt"));
402  }
403 
404  [Fact]
406  {
407  Assert.False(_fileHandler!.KifsFileExists($"{TestDirName}/nonexistent.txt"));
408  }
409 
410  [Fact]
412  {
413  _fileHandler!.CreateDirectory(TestDirName);
414 
415  for (int i = 1; i <= 3; i++)
416  {
417  var fileName = $"test_delete_all_{i}.txt";
418  var filePath = Path.Combine(_tempDir!, fileName);
419  await File.WriteAllTextAsync(filePath, $"Content {i}");
420  await _fileHandler.UploadAsync(new List<string> { filePath }, TestDirName);
421  }
422 
423  var files = _fileHandler.ShowFiles(new List<string> { TestDirName });
424  Assert.Equal(3, files.Count);
425 
426  _fileHandler.DeleteFilesInDirectory(TestDirName);
427 
428  files = _fileHandler.ShowFiles(new List<string> { TestDirName });
429  Assert.Empty(files);
430  }
431 
432  #endregion
433 
434  #region Helper Classes
435 
436  private class TestUploadListener : IFileUploadListener
437  {
438  public bool MultiPartUploadCompleteCalled { get; private set; }
439  public bool PartUploadCalled { get; private set; }
440  public bool FullFileUploadCalled { get; private set; }
441  public List<FileOperationResult> Results { get; } = new List<FileOperationResult>();
442 
443  public void OnMultiPartUploadComplete(IList<FileOperationResult> results)
444  {
445  MultiPartUploadCompleteCalled = true;
446  Results.AddRange(results);
447  }
448 
449  public void OnPartUpload(FileOperationResult result)
450  {
451  PartUploadCalled = true;
452  Results.Add(result);
453  }
454 
455  public void OnFullFileUpload(FileOperationResult result)
456  {
457  FullFileUploadCalled = true;
458  Results.Add(result);
459  }
460  }
461 
462  #endregion
463  }
464 }
Async integration tests for KiFS (Kinetica File System) operations.
bool KifsFileExists(string fileName)
Checks whether a KiFS file exists.
Interface for receiving callbacks during file upload operations.
Main class for handling file operations with Kinetica's KiFS (Kinetica File System).
void DeleteFilesInDirectory(string remoteDirName)
Deletes all files in a KiFS directory.
Test context that manages schema and cleanup for integration tests.
Definition: TestContext.cs:11
Options for uploading files to KiFS.
Definition: UploadOptions.cs:6
void DeleteFiles(IList< string > fileNames)
Deletes files from KiFS, suppressing error if files don't exist.
IList< KifsDirectoryInfo > ShowAllDirectories()
Returns statistics about all KiFS directories.
async Task UploadAsync(IList< string > fileNames, string remoteDirName, UploadOptions? uploadOptions=null, IFileUploadListener? callback=null)
Uploads files asynchronously to a KiFS directory.
bool KifsDirectoryExists(string dirName)
Checks whether a KiFS directory exists.
Options for downloading files from KiFS.
static UploadOptions Default
Returns the default upload options.
void DeleteDirectory(string remoteDirName)
Deletes a KiFS directory and all files under it, suppressing error if it doesn't exist.
void CreateDirectory(string remoteDirName)
Creates a KiFS directory, suppressing error if it already exists.
async Task DownloadAsync(IList< string > fileNames, string localDirName, DownloadOptions? downloadOptions=null, IFileDownloadListener? callback=null)
Downloads files asynchronously from KiFS to a local directory.
Failover to clusters in a random order (default)
IList< KifsFileInfo > ShowFiles(IList< string > remotePaths)
Returns statistics about the given KiFS files.
Contains the result of a file upload or download operation.
IList< KifsDirectoryInfo > ShowDirectory(string remoteDirName)
Returns statistics about a single KiFS directory.