/ToMigrate/Raven.Tests.FileSystem/Bundles/Versioning/VersioningTests.cs

https://github.com/fitzchak/ravendb · C# · 637 lines · 493 code · 137 blank · 7 comment · 8 complexity · d92d9c68d78b3edc2bac31437ec2b5c1 MD5 · raw file

  1. // -----------------------------------------------------------------------
  2. // <copyright file="VersioningTests.cs" company="Hibernating Rhinos LTD">
  3. // Copyright (c) Hibernating Rhinos LTD. All rights reserved.
  4. // </copyright>
  5. // -----------------------------------------------------------------------
  6. using System.IO;
  7. using System.Linq;
  8. using System.Threading.Tasks;
  9. using Raven.Abstractions.Connection;
  10. using Raven.Abstractions.Data;
  11. using Raven.Abstractions.Exceptions;
  12. using Raven.Abstractions.FileSystem;
  13. using Raven.Client.FileSystem.Bundles.Versioning;
  14. using Raven.Database.Bundles.Versioning.Data;
  15. using Raven.Database.FileSystem.Bundles.Versioning;
  16. using Raven.Json.Linq;
  17. using Raven.Tests.Common;
  18. using Xunit;
  19. using Xunit.Extensions;
  20. namespace Raven.Tests.FileSystem.Bundles.Versioning
  21. {
  22. public class VersioningTests : RavenFilesTestWithLogs
  23. {
  24. private const string Content1 = "aaa";
  25. private const string Content2 = "bbb";
  26. private const string Content3 = "ccc";
  27. private const string Content4 = "ddd";
  28. [Theory]
  29. [PropertyData("Storages")]
  30. public async Task FirstUploadWillCreateRevision(string requestedStorage)
  31. {
  32. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning"))
  33. {
  34. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName, MaxRevisions = 10 });
  35. using (var session = store.OpenAsyncSession())
  36. {
  37. session.RegisterUpload("test.txt", StringToStream("abc"));
  38. await session.SaveChangesAsync();
  39. var revisions = await session.GetRevisionNamesForAsync("test.txt", 0, 128);
  40. Assert.Equal(1, revisions.Length);
  41. }
  42. }
  43. }
  44. [Theory]
  45. [PropertyData("Storages")]
  46. public async Task Simple(string requestedStorage)
  47. {
  48. const string FileName = "file1.txt";
  49. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning"))
  50. {
  51. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName, MaxRevisions = 10 });
  52. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content1));
  53. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content2));
  54. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content3));
  55. var stream = await store.AsyncFilesCommands.DownloadAsync(FileName);
  56. Assert.NotNull(stream);
  57. Assert.Equal(Content3, StreamToString(stream));
  58. stream = await store.AsyncFilesCommands.DownloadAsync(FileName + "/revisions/1");
  59. Assert.NotNull(stream);
  60. Assert.Equal(Content1, StreamToString(stream));
  61. stream = await store.AsyncFilesCommands.DownloadAsync(FileName + "/revisions/2");
  62. Assert.NotNull(stream);
  63. Assert.Equal(Content2, StreamToString(stream));
  64. }
  65. }
  66. [Theory]
  67. [PropertyData("Storages")]
  68. public async Task MaxRevisions(string requestedStorage)
  69. {
  70. const string FileName = "file1.txt";
  71. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning"))
  72. {
  73. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName, MaxRevisions = 3 });
  74. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content1));
  75. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content2));
  76. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content3));
  77. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content4));
  78. var stream = await store.AsyncFilesCommands.DownloadAsync(FileName);
  79. Assert.NotNull(stream);
  80. Assert.Equal(Content4, StreamToString(stream));
  81. await AssertAsync.Throws<FileNotFoundException>(async () => await store.AsyncFilesCommands.DownloadAsync(FileName + "/revisions/1"));
  82. stream = await store.AsyncFilesCommands.DownloadAsync(FileName + "/revisions/2");
  83. Assert.NotNull(stream);
  84. Assert.Equal(Content2, StreamToString(stream));
  85. stream = await store.AsyncFilesCommands.DownloadAsync(FileName + "/revisions/3");
  86. Assert.NotNull(stream);
  87. Assert.Equal(Content3, StreamToString(stream));
  88. }
  89. }
  90. [Theory]
  91. [PropertyData("Storages")]
  92. public async Task WhenPurgeOnDeleteIsSetToFalseRevisionFilesShouldNotBeDeleted(string requestedStorage)
  93. {
  94. const string FileName = "file1.txt";
  95. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning"))
  96. {
  97. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName, PurgeOnDelete = false });
  98. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content1));
  99. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content2));
  100. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content3));
  101. var stream = await store.AsyncFilesCommands.DownloadAsync(FileName);
  102. Assert.NotNull(stream);
  103. Assert.Equal(Content3, StreamToString(stream));
  104. stream = await store.AsyncFilesCommands.DownloadAsync(FileName + "/revisions/1");
  105. Assert.NotNull(stream);
  106. Assert.Equal(Content1, StreamToString(stream));
  107. stream = await store.AsyncFilesCommands.DownloadAsync(FileName + "/revisions/2");
  108. Assert.NotNull(stream);
  109. Assert.Equal(Content2, StreamToString(stream));
  110. await store.AsyncFilesCommands.DeleteAsync(FileName);
  111. await AssertAsync.Throws<FileNotFoundException>(async () => await store.AsyncFilesCommands.DownloadAsync(FileName));
  112. stream = await store.AsyncFilesCommands.DownloadAsync(FileName + "/revisions/1");
  113. Assert.NotNull(stream);
  114. Assert.Equal(Content1, StreamToString(stream));
  115. stream = await store.AsyncFilesCommands.DownloadAsync(FileName + "/revisions/2");
  116. Assert.NotNull(stream);
  117. Assert.Equal(Content2, StreamToString(stream));
  118. }
  119. }
  120. [Theory]
  121. [PropertyData("Storages")]
  122. public async Task WhenPurgeOnDeleteIsSetToTrueRevisionFilesShouldBeDeleted(string requestedStorage)
  123. {
  124. const string FileName = "file1.txt";
  125. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning"))
  126. {
  127. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName, PurgeOnDelete = true });
  128. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content1));
  129. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content2));
  130. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content3));
  131. var stream = await store.AsyncFilesCommands.DownloadAsync(FileName);
  132. Assert.NotNull(stream);
  133. Assert.Equal(Content3, StreamToString(stream));
  134. stream = await store.AsyncFilesCommands.DownloadAsync(FileName + "/revisions/1");
  135. Assert.NotNull(stream);
  136. Assert.Equal(Content1, StreamToString(stream));
  137. stream = await store.AsyncFilesCommands.DownloadAsync(FileName + "/revisions/2");
  138. Assert.NotNull(stream);
  139. Assert.Equal(Content2, StreamToString(stream));
  140. await store.AsyncFilesCommands.DeleteAsync(FileName);
  141. await AssertAsync.Throws<FileNotFoundException>(async () => await store.AsyncFilesCommands.DownloadAsync(FileName));
  142. await AssertAsync.Throws<FileNotFoundException>(async () => await store.AsyncFilesCommands.DownloadAsync(FileName + "/revisions/1"));
  143. await AssertAsync.Throws<FileNotFoundException>(async () => await store.AsyncFilesCommands.DownloadAsync(FileName + "/revisions/2"));
  144. }
  145. }
  146. [Theory]
  147. [PropertyData("Storages")]
  148. public async Task RevisionsCannotBeDeletedWithoutProperSetting(string requestedStorage)
  149. {
  150. const string FileName = "file1.txt";
  151. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning"))
  152. {
  153. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName });
  154. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content1));
  155. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content2));
  156. var stream = await store.AsyncFilesCommands.DownloadAsync(FileName);
  157. Assert.NotNull(stream);
  158. Assert.Equal(Content2, StreamToString(stream));
  159. stream = await store.AsyncFilesCommands.DownloadAsync(FileName + "/revisions/1");
  160. Assert.NotNull(stream);
  161. Assert.Equal(Content1, StreamToString(stream));
  162. var e = await AssertAsync.Throws<ErrorResponseException>(async () => await store.AsyncFilesCommands.DeleteAsync(FileName + "/revisions/1"));
  163. Assert.True(e.Message.Contains("Deleting a historical revision is not allowed"));
  164. stream = await store.AsyncFilesCommands.DownloadAsync(FileName + "/revisions/1");
  165. Assert.NotNull(stream);
  166. Assert.Equal(Content1, StreamToString(stream));
  167. }
  168. }
  169. [Theory]
  170. [PropertyData("Storages")]
  171. public async Task RevisionsCanBeDeletedWithProperSetting(string requestedStorage)
  172. {
  173. const string FileName = "file1.txt";
  174. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning", customConfig: configuration => configuration.Settings[Constants.FileSystem.Versioning.ChangesToRevisionsAllowed] = "true"))
  175. {
  176. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName });
  177. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content1));
  178. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content2));
  179. var stream = await store.AsyncFilesCommands.DownloadAsync(FileName);
  180. Assert.NotNull(stream);
  181. Assert.Equal(Content2, StreamToString(stream));
  182. stream = await store.AsyncFilesCommands.DownloadAsync(FileName + "/revisions/1");
  183. Assert.NotNull(stream);
  184. Assert.Equal(Content1, StreamToString(stream));
  185. await store.AsyncFilesCommands.DeleteAsync(FileName + "/revisions/1");
  186. await AssertAsync.Throws<FileNotFoundException>(async () => await store.AsyncFilesCommands.DownloadAsync(FileName + "/revisions/1"));
  187. }
  188. }
  189. [Theory]
  190. [PropertyData("Storages")]
  191. public async Task GetRevisionsForAsyncShouldWork(string requestedStorage)
  192. {
  193. const string FileName = "file1.txt";
  194. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning"))
  195. {
  196. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName });
  197. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content1));
  198. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content2));
  199. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content3));
  200. using (var session = store.OpenAsyncSession())
  201. {
  202. var revisions = await session.GetRevisionsForAsync(FileName, 0, 100);
  203. Assert.Equal(3, revisions.Length);
  204. }
  205. }
  206. }
  207. [Theory]
  208. [PropertyData("Storages")]
  209. public async Task GetRevisionsWithoutKnowingTheFileName(string requestedStorage)
  210. {
  211. const string FileName1 = "/file1.txt";
  212. const string FileName2 = "/file2.txt";
  213. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning"))
  214. {
  215. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName });
  216. await store.AsyncFilesCommands.UploadAsync(FileName1, StringToStream(Content1));
  217. await store.AsyncFilesCommands.UploadAsync(FileName1, StringToStream(Content2));
  218. await store.AsyncFilesCommands.UploadAsync(FileName1, StringToStream(Content3));
  219. await store.AsyncFilesCommands.UploadAsync(FileName2, StringToStream(Content1));
  220. await store.AsyncFilesCommands.UploadAsync(FileName2, StringToStream(Content2));
  221. await store.AsyncFilesCommands.UploadAsync(FileName2, StringToStream(Content3));
  222. var revisions = await store.AsyncFilesCommands.StartsWithAsync("/", "*/revisions/*", 0, 128);
  223. Assert.Equal(6, revisions.Length);
  224. revisions = await store.AsyncFilesCommands.StartsWithAsync("/", "*/revisions/*", 0, 2);
  225. Assert.Equal(2, revisions.Length);
  226. Assert.True(revisions.Any(x => x.FullPath == FileName1 + "/revisions/1"));
  227. Assert.True(revisions.Any(x => x.FullPath == FileName1 + "/revisions/2"));
  228. revisions = await store.AsyncFilesCommands.StartsWithAsync("/", "*/revisions/*", 2, 5);
  229. Assert.Equal(4, revisions.Length);
  230. Assert.True(revisions.Any(x => x.FullPath == FileName1 + "/revisions/3"));
  231. Assert.True(revisions.Any(x => x.FullPath == FileName2 + "/revisions/1"));
  232. Assert.True(revisions.Any(x => x.FullPath == FileName2 + "/revisions/2"));
  233. Assert.True(revisions.Any(x => x.FullPath == FileName2 + "/revisions/3"));
  234. revisions = await store.AsyncFilesCommands.StartsWithAsync("/", "*/revisions/*", 3, 2);
  235. Assert.Equal(2, revisions.Length);
  236. Assert.True(revisions.Any(x => x.FullPath == FileName2 + "/revisions/1"));
  237. Assert.True(revisions.Any(x => x.FullPath == FileName2 + "/revisions/2"));
  238. }
  239. }
  240. [Theory]
  241. [PropertyData("Storages")]
  242. public async Task GetRevisionNamesForAsyncShouldWork(string requestedStorage)
  243. {
  244. const string FileName = "file1.txt";
  245. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning"))
  246. {
  247. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName });
  248. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content1));
  249. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content2));
  250. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content3));
  251. using (var session = store.OpenAsyncSession())
  252. {
  253. var revisions = await session.GetRevisionNamesForAsync(FileName, 0, 100);
  254. Assert.Equal(3, revisions.Length);
  255. Assert.Contains(FileHeader.Canonize(FileName) + "/revisions/1", revisions);
  256. Assert.Contains(FileHeader.Canonize(FileName) + "/revisions/2", revisions);
  257. Assert.Contains(FileHeader.Canonize(FileName) + "/revisions/3", revisions);
  258. }
  259. }
  260. }
  261. [Theory]
  262. [PropertyData("Storages")]
  263. public async Task Exclude(string requestedStorage)
  264. {
  265. const string FileName = "file1.txt";
  266. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning"))
  267. {
  268. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName, Exclude = true });
  269. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content1));
  270. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content2));
  271. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content3));
  272. using (var session = store.OpenAsyncSession())
  273. {
  274. var revisions = await session.GetRevisionNamesForAsync(FileName, 0, 100);
  275. Assert.Equal(0, revisions.Length);
  276. }
  277. var stream = await store.AsyncFilesCommands.DownloadAsync(FileName);
  278. Assert.NotNull(stream);
  279. Assert.Equal(Content3, StreamToString(stream));
  280. }
  281. }
  282. [Theory]
  283. [PropertyData("Storages")]
  284. public async Task ExcludeExplicit1(string requestedStorage)
  285. {
  286. const string FileName = "file1.txt";
  287. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning"))
  288. {
  289. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName, ExcludeUnlessExplicit = true });
  290. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content1));
  291. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content2));
  292. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content3));
  293. using (var session = store.OpenAsyncSession())
  294. {
  295. var revisions = await session.GetRevisionNamesForAsync(FileName, 0, 100);
  296. Assert.Equal(0, revisions.Length);
  297. }
  298. var stream = await store.AsyncFilesCommands.DownloadAsync(FileName);
  299. Assert.NotNull(stream);
  300. Assert.Equal(Content3, StreamToString(stream));
  301. }
  302. }
  303. [Theory]
  304. [PropertyData("Storages")]
  305. public async Task ExcludeExplicit2(string requestedStorage)
  306. {
  307. const string FileName = "file1.txt";
  308. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning"))
  309. {
  310. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName, ExcludeUnlessExplicit = true });
  311. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content1), new RavenJObject { { Constants.RavenCreateVersion, true } });
  312. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content2), new RavenJObject { { Constants.RavenCreateVersion, true } });
  313. await store.AsyncFilesCommands.UploadAsync(FileName, StringToStream(Content3), new RavenJObject { { Constants.RavenCreateVersion, true } });
  314. using (var session = store.OpenAsyncSession())
  315. {
  316. var revisions = await session.GetRevisionNamesForAsync(FileName, 0, 100);
  317. Assert.Equal(3, revisions.Length);
  318. }
  319. var stream = await store.AsyncFilesCommands.DownloadAsync(FileName);
  320. Assert.NotNull(stream);
  321. Assert.Equal(Content3, StreamToString(stream));
  322. }
  323. }
  324. [Theory]
  325. [PropertyData("Storages")]
  326. public async Task CannotModifyHistoricalRevisionByDefault_PUT(string requestedStorage)
  327. {
  328. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning"))
  329. {
  330. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName });
  331. await store.AsyncFilesCommands.UploadAsync("file.txt", StringToStream(Content1));
  332. using (var session = store.OpenAsyncSession())
  333. {
  334. var revisions = await session.GetRevisionNamesForAsync("file.txt", 0, 100);
  335. Assert.Equal(1, revisions.Length);
  336. session.RegisterUpload(revisions[0], StringToStream(Content2));
  337. var ex = await ThrowsAsync<ErrorResponseException>(() => session.SaveChangesAsync());
  338. Assert.Contains("PUT vetoed on file /file.txt/revisions/1 by Raven.Database.FileSystem.Bundles.Versioning.Plugins.VersioningPutTrigger because: Modifying a historical revision is not allowed", ex.Message);
  339. }
  340. }
  341. }
  342. [Theory]
  343. [PropertyData("Storages")]
  344. public async Task CanModifyHistoricalRevisionIfProperConfigurationSet_PUT(string requestedStorage)
  345. {
  346. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning", customConfig: configuration => configuration.Settings[Constants.FileSystem.Versioning.ChangesToRevisionsAllowed] = "true"))
  347. {
  348. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName });
  349. await store.AsyncFilesCommands.UploadAsync("file.txt", StringToStream(Content1));
  350. using (var session = store.OpenAsyncSession())
  351. {
  352. var revisions = await session.GetRevisionNamesForAsync("file.txt", 0, 100);
  353. Assert.Equal(1, revisions.Length);
  354. session.RegisterUpload(revisions[0], StringToStream(Content2));
  355. await session.SaveChangesAsync();
  356. }
  357. }
  358. }
  359. [Theory]
  360. [PropertyData("Storages")]
  361. public async Task CannotModifyHistoricalRevisionByDefault_POST(string requestedStorage)
  362. {
  363. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning"))
  364. {
  365. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName });
  366. await store.AsyncFilesCommands.UploadAsync("file.txt", StringToStream(Content1));
  367. using (var session = store.OpenAsyncSession())
  368. {
  369. var revisions = await session.GetRevisionNamesForAsync("file.txt", 0, 100);
  370. Assert.Equal(1, revisions.Length);
  371. var revision = await session.LoadFileAsync(revisions[0]);
  372. revision.Metadata.Add("new", "item");
  373. var ex = await ThrowsAsync<ErrorResponseException>(() => session.SaveChangesAsync());
  374. Assert.Contains("POST vetoed on file /file.txt/revisions/1 by Raven.Database.FileSystem.Bundles.Versioning.Plugins.VersioningMetadataUpdateTrigger because: Modifying a historical revision is not allowed", ex.Message);
  375. }
  376. }
  377. }
  378. [Theory]
  379. [PropertyData("Storages")]
  380. public async Task CanModifyHistoricalRevisionIfProperConfigurationSet_POST(string requestedStorage)
  381. {
  382. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning", customConfig: configuration => configuration.Settings[Constants.FileSystem.Versioning.ChangesToRevisionsAllowed] = "true"))
  383. {
  384. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName });
  385. await store.AsyncFilesCommands.UploadAsync("file.txt", StringToStream(Content1));
  386. using (var session = store.OpenAsyncSession())
  387. {
  388. var revisions = await session.GetRevisionNamesForAsync("file.txt", 0, 100);
  389. Assert.Equal(1, revisions.Length);
  390. var revision = await session.LoadFileAsync(revisions[0]);
  391. revision.Metadata.Add("new", "item");
  392. await session.SaveChangesAsync();
  393. }
  394. }
  395. }
  396. [Theory]
  397. [PropertyData("Storages")]
  398. public async Task ShouldCreateRevisionAfterMetadataUpdate(string requestedStorage)
  399. {
  400. const string fileName = "file1.txt";
  401. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning"))
  402. {
  403. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName });
  404. await store.AsyncFilesCommands.UploadAsync(fileName, StringToStream(Content1));
  405. await store.AsyncFilesCommands.UploadAsync(fileName, StringToStream(Content2));
  406. using (var session = store.OpenAsyncSession())
  407. {
  408. var revisions = await session.GetRevisionNamesForAsync(fileName, 0, 100);
  409. Assert.Equal(2, revisions.Length);
  410. }
  411. await store.AsyncFilesCommands.UpdateMetadataAsync(fileName, new RavenJObject{ { "New", "Data" } });
  412. using (var session = store.OpenAsyncSession())
  413. {
  414. var revisions = await session.GetRevisionNamesForAsync(fileName, 0, 100);
  415. Assert.Equal(3, revisions.Length);
  416. var revisionFile = await session.LoadFileAsync(revisions[2]);
  417. Assert.Equal("Data", revisionFile.Metadata.Value<string>("New"));
  418. var stream = await store.AsyncFilesCommands.DownloadAsync(revisionFile.FullPath);
  419. Assert.NotNull(stream);
  420. Assert.Equal(Content2, StreamToString(stream));
  421. }
  422. }
  423. }
  424. [Theory]
  425. [PropertyData("Storages")]
  426. public async Task ShouldDeleteRevisionsAfterRenameByDefault(string requestedStorage)
  427. {
  428. const string fileName = "file1.txt";
  429. const string newFileName = "file2.txt";
  430. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning"))
  431. {
  432. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName });
  433. await store.AsyncFilesCommands.UploadAsync(fileName, StringToStream(Content1));
  434. await store.AsyncFilesCommands.UploadAsync(fileName, StringToStream(Content2));
  435. await store.AsyncFilesCommands.UploadAsync(fileName, StringToStream(Content3));
  436. using (var session = store.OpenAsyncSession())
  437. {
  438. var revisions = await session.GetRevisionNamesForAsync(fileName, 0, 100);
  439. Assert.Equal(3, revisions.Length);
  440. }
  441. await store.AsyncFilesCommands.RenameAsync(fileName, newFileName);
  442. using (var session = store.OpenAsyncSession())
  443. {
  444. var revisions = await session.GetRevisionNamesForAsync(newFileName, 0, 100);
  445. Assert.Equal(1, revisions.Length);
  446. var revisionFile = await session.LoadFileAsync(revisions[0]);
  447. var stream = await store.AsyncFilesCommands.DownloadAsync(revisionFile.FullPath);
  448. Assert.NotNull(stream);
  449. Assert.Equal(Content3, StreamToString(stream));
  450. }
  451. // make sure that versioning keep working
  452. await store.AsyncFilesCommands.UploadAsync(newFileName, StringToStream(Content4));
  453. using (var session = store.OpenAsyncSession())
  454. {
  455. var revisions = await session.GetRevisionNamesForAsync(newFileName, 0, 100);
  456. Assert.Equal(2, revisions.Length);
  457. }
  458. }
  459. }
  460. [Theory]
  461. [PropertyData("Storages")]
  462. public async Task ShouldRenameAllRevisions(string requestedStorage)
  463. {
  464. const string fileName = "file1.txt";
  465. const string newFileName = "file2.txt";
  466. using (var store = NewStore(requestedStorage: requestedStorage, activeBundles: "Versioning"))
  467. {
  468. await store.AsyncFilesCommands.Configuration.SetKeyAsync(VersioningUtil.DefaultConfigurationName, new FileVersioningConfiguration { Id = VersioningUtil.DefaultConfigurationName, ResetOnRename = false });
  469. await store.AsyncFilesCommands.UploadAsync(fileName, StringToStream(Content1));
  470. await store.AsyncFilesCommands.UploadAsync(fileName, StringToStream(Content2));
  471. await store.AsyncFilesCommands.UploadAsync(fileName, StringToStream(Content3));
  472. using (var session = store.OpenAsyncSession())
  473. {
  474. var revisions = await session.GetRevisionNamesForAsync(fileName, 0, 100);
  475. Assert.Equal(3, revisions.Length);
  476. }
  477. await store.AsyncFilesCommands.RenameAsync(fileName, newFileName);
  478. using (var session = store.OpenAsyncSession())
  479. {
  480. var revisions = await session.GetRevisionNamesForAsync(newFileName, 0, 100);
  481. Assert.Equal(3, revisions.Length);
  482. var revisionFile = await session.LoadFileAsync(revisions[2]);
  483. var stream = await store.AsyncFilesCommands.DownloadAsync(revisionFile.FullPath);
  484. Assert.NotNull(stream);
  485. Assert.Equal(Content3, StreamToString(stream));
  486. }
  487. // make sure that versioning keep working
  488. await store.AsyncFilesCommands.UploadAsync(newFileName, StringToStream(Content4));
  489. using (var session = store.OpenAsyncSession())
  490. {
  491. var revisions = await session.GetRevisionNamesForAsync(newFileName, 0, 100);
  492. Assert.Equal(4, revisions.Length);
  493. var stream = await store.AsyncFilesCommands.DownloadAsync(revisions[3]);
  494. Assert.NotNull(stream);
  495. Assert.Equal(Content4, StreamToString(stream));
  496. }
  497. }
  498. }
  499. }
  500. }