/ToMigrate/Raven.Tests/Replication/TransformerReplication.cs

https://github.com/fitzchak/ravendb · C# · 696 lines · 564 code · 110 blank · 22 comment · 32 complexity · eef6af7c0e4614ba46859162f04bb10f MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using Raven.Abstractions.Connection;
  7. using Raven.Abstractions.Data;
  8. using Raven.Abstractions.Indexing;
  9. using Raven.Abstractions.Replication;
  10. using Raven.Abstractions.Util;
  11. using Raven.Bundles.Replication.Tasks;
  12. using Raven.Client;
  13. using Raven.Client.Document;
  14. using Raven.Client.Indexes;
  15. using Raven.Database.Bundles.Replication;
  16. using Raven.Json.Linq;
  17. using Raven.Tests.Helpers;
  18. using Xunit;
  19. namespace Raven.Tests.Replication
  20. {
  21. public class TransformerReplication : RavenTestBase
  22. {
  23. public class UserWithExtraInfo
  24. {
  25. public string Id { get; set; }
  26. public string Name { get; set; }
  27. public string Address { get; set; }
  28. }
  29. public class User
  30. {
  31. public string Id { get; set; }
  32. public string Name { get; set; }
  33. }
  34. public class UserWithoutExtraInfoTransformer : AbstractTransformerCreationTask<UserWithExtraInfo>
  35. {
  36. public override string TransformerName { get { return "UserWithoutExtraInfoTransformer"; } }
  37. public UserWithoutExtraInfoTransformer()
  38. {
  39. TransformResults = usersWithExtraInfo => from u in usersWithExtraInfo
  40. select new
  41. {
  42. u.Id,
  43. u.Name
  44. };
  45. }
  46. }
  47. public class UserWithoutExtraInfoTransformer_Extended : AbstractTransformerCreationTask<UserWithExtraInfo>
  48. {
  49. public override string TransformerName { get { return "UserWithoutExtraInfoTransformer"; } }
  50. public UserWithoutExtraInfoTransformer_Extended()
  51. {
  52. TransformResults = usersWithExtraInfo => from u in usersWithExtraInfo
  53. select new
  54. {
  55. u.Id,
  56. u.Name,
  57. u.Address
  58. };
  59. }
  60. }
  61. public class AnotherTransformer : AbstractTransformerCreationTask<UserWithExtraInfo>
  62. {
  63. public AnotherTransformer()
  64. {
  65. TransformResults = usersWithExtraInfo => from u in usersWithExtraInfo
  66. select new
  67. {
  68. u.Id,
  69. u.Name
  70. };
  71. }
  72. }
  73. public class YetAnotherTransformer : AbstractTransformerCreationTask<UserWithExtraInfo>
  74. {
  75. public YetAnotherTransformer()
  76. {
  77. TransformResults = usersWithExtraInfo => from u in usersWithExtraInfo
  78. select new
  79. {
  80. u.Id,
  81. u.Name
  82. };
  83. }
  84. }
  85. [Fact]
  86. public void Should_replicate_transformers_by_default()
  87. {
  88. using (var sourceServer = GetNewServer(8077))
  89. using (var source = NewRemoteDocumentStore(ravenDbServer: sourceServer))
  90. using (var destinationServer1 = GetNewServer(8078))
  91. using (var destination1 = NewRemoteDocumentStore(ravenDbServer: destinationServer1))
  92. using (var destinationServer2 = GetNewServer())
  93. using (var destination2 = NewRemoteDocumentStore(ravenDbServer: destinationServer2))
  94. using (var destinationServer3 = GetNewServer(8081))
  95. using (var destination3 = NewRemoteDocumentStore(ravenDbServer: destinationServer3))
  96. {
  97. CreateDatabaseWithReplication(source, "testDB");
  98. CreateDatabaseWithReplication(destination1, "testDB");
  99. CreateDatabaseWithReplication(destination2, "testDB");
  100. CreateDatabaseWithReplication(destination3, "testDB");
  101. // ReSharper disable once AccessToDisposedClosure
  102. SetupReplication(source, "testDB", store => false, destination1, destination2, destination3);
  103. var transformer = new UserWithoutExtraInfoTransformer();
  104. transformer.Execute(source.DatabaseCommands.ForDatabase("testDB"), source.Conventions);
  105. var transformersOnDestination1 = destination1.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024);
  106. Assert.Equal(1, transformersOnDestination1.Count(x => x.Name == transformer.TransformerName));
  107. var transformersOnDestination2 = destination2.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024);
  108. Assert.Equal(1, transformersOnDestination2.Count(x => x.Name == transformer.TransformerName));
  109. var transformersOnDestination3 = destination3.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024);
  110. Assert.Equal(1, transformersOnDestination3.Count(x => x.Name == transformer.TransformerName));
  111. }
  112. }
  113. [Fact]
  114. public async Task Should_replicate_transformer_deletion()
  115. {
  116. using (var sourceServer = GetNewServer(8077))
  117. using (var source = NewRemoteDocumentStore(ravenDbServer: sourceServer))
  118. using (var destinationServer1 = GetNewServer(8078))
  119. using (var destination1 = NewRemoteDocumentStore(ravenDbServer: destinationServer1))
  120. using (var destinationServer2 = GetNewServer())
  121. using (var destination2 = NewRemoteDocumentStore(ravenDbServer: destinationServer2))
  122. using (var destinationServer3 = GetNewServer(8081))
  123. using (var destination3 = NewRemoteDocumentStore(ravenDbServer: destinationServer3))
  124. {
  125. source.Conventions.IndexAndTransformerReplicationMode = IndexAndTransformerReplicationMode.None;
  126. CreateDatabaseWithReplication(source, "testDB");
  127. CreateDatabaseWithReplication(destination1, "testDB");
  128. CreateDatabaseWithReplication(destination2, "testDB");
  129. CreateDatabaseWithReplication(destination3, "testDB");
  130. // ReSharper disable once AccessToDisposedClosure
  131. SetupReplication(source, "testDB", store => false, destination1, destination2, destination3);
  132. var transformer = new UserWithoutExtraInfoTransformer();
  133. transformer.Execute(source.DatabaseCommands.ForDatabase("testDB"), source.Conventions);
  134. var sourceDB = await sourceServer.Server.GetDatabaseInternal("testDB");
  135. var replicationTask = sourceDB.StartupTasks.OfType<ReplicationTask>().First();
  136. replicationTask.TransformerReplication.TimeToWaitBeforeSendingDeletesOfTransformersToSiblings = TimeSpan.Zero;
  137. SpinWait.SpinUntil(() => replicationTask.TransformerReplication.Execute());
  138. var transformersOnDestination1 = destination1.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024);
  139. Assert.Equal(1, transformersOnDestination1.Count(x => x.Name == transformer.TransformerName));
  140. var transformersOnDestination2 = destination2.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024);
  141. Assert.Equal(1, transformersOnDestination2.Count(x => x.Name == transformer.TransformerName));
  142. var transformersOnDestination3 = destination3.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024);
  143. Assert.Equal(1, transformersOnDestination3.Count(x => x.Name == transformer.TransformerName));
  144. //now delete the transformer at the source and verify that the deletion is replicated
  145. source.DatabaseCommands.ForDatabase("testDB").DeleteTransformer(transformer.TransformerName);
  146. SpinWait.SpinUntil(() => replicationTask.TransformerReplication.Execute());
  147. transformersOnDestination1 = destination1.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024);
  148. Assert.Equal(0, transformersOnDestination1.Count(x => x.Name == transformer.TransformerName));
  149. transformersOnDestination2 = destination2.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024);
  150. Assert.Equal(0, transformersOnDestination2.Count(x => x.Name == transformer.TransformerName));
  151. transformersOnDestination3 = destination3.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024);
  152. Assert.Equal(0, transformersOnDestination3.Count(x => x.Name == transformer.TransformerName));
  153. }
  154. }
  155. [Fact]
  156. public void Should_skip_transformer_replication_if_flag_is_set()
  157. {
  158. using (var sourceServer = GetNewServer(8077))
  159. using (var source = NewRemoteDocumentStore(ravenDbServer: sourceServer))
  160. using (var destinationServer1 = GetNewServer(8078))
  161. using (var destination1 = NewRemoteDocumentStore(ravenDbServer: destinationServer1))
  162. using (var destinationServer2 = GetNewServer())
  163. using (var destination2 = NewRemoteDocumentStore(ravenDbServer: destinationServer2))
  164. using (var destinationServer3 = GetNewServer(8081))
  165. using (var destination3 = NewRemoteDocumentStore(ravenDbServer: destinationServer3))
  166. {
  167. CreateDatabaseWithReplication(source, "testDB");
  168. CreateDatabaseWithReplication(destination1, "testDB");
  169. CreateDatabaseWithReplication(destination2, "testDB");
  170. CreateDatabaseWithReplication(destination3, "testDB");
  171. // ReSharper disable once AccessToDisposedClosure
  172. SetupReplication(source, "testDB", store => destination2 == store, destination1, destination2, destination3);
  173. var conflictDocumentsTransformer = new RavenConflictDocumentsTransformer(); // #RavenDB-3981
  174. var transformer = new UserWithoutExtraInfoTransformer();
  175. transformer.Execute(source.DatabaseCommands.ForDatabase("testDB"), source.Conventions);
  176. var transformersOnDestination1 = destination1.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024);
  177. Assert.Equal(1, transformersOnDestination1.Count(x => x.Name == transformer.TransformerName));
  178. var transformersOnDestination2 = destination2.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024)
  179. .Where(x => x.Name != conflictDocumentsTransformer
  180. .TransformerName)
  181. .ToList();
  182. Assert.Equal(0, transformersOnDestination2.Count);
  183. var transformersOnDestination3 = destination3.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024);
  184. Assert.Equal(1, transformersOnDestination3.Count(x => x.Name == transformer.TransformerName));
  185. }
  186. }
  187. [Fact]
  188. public void Transformer_replication_should_respect_skip_replication_flag()
  189. {
  190. using (var sourceServer = GetNewServer(8077))
  191. using (var source = NewRemoteDocumentStore(ravenDbServer: sourceServer))
  192. using (var destinationServer1 = GetNewServer(8078))
  193. using (var destination1 = NewRemoteDocumentStore(ravenDbServer: destinationServer1))
  194. using (var destinationServer2 = GetNewServer())
  195. using (var destination2 = NewRemoteDocumentStore(ravenDbServer: destinationServer2))
  196. using (var destinationServer3 = GetNewServer(8081))
  197. using (var destination3 = NewRemoteDocumentStore(ravenDbServer: destinationServer3))
  198. {
  199. CreateDatabaseWithReplication(source, "testDB");
  200. CreateDatabaseWithReplication(destination1, "testDB");
  201. CreateDatabaseWithReplication(destination2, "testDB");
  202. CreateDatabaseWithReplication(destination3, "testDB");
  203. // ReSharper disable once AccessToDisposedClosure
  204. SetupReplication(source, "testDB", store => store == destination2, destination1, destination2, destination3);
  205. var conflictDocumentsTransformer = new RavenConflictDocumentsTransformer(); // #RavenDB-3981
  206. var transformer = new UserWithoutExtraInfoTransformer();
  207. transformer.Execute(source.DatabaseCommands.ForDatabase("testDB"), source.Conventions);
  208. var transformersOnDestination1 = destination1.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024);
  209. Assert.Equal(1, transformersOnDestination1.Count(x => x.Name == transformer.TransformerName));
  210. var transformersOnDestination2 = destination2.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024)
  211. .Where(x => x.Name != conflictDocumentsTransformer
  212. .TransformerName)
  213. .ToList();
  214. Assert.Equal(0, transformersOnDestination2.Count);
  215. var transformersOnDestination3 = destination3.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024);
  216. Assert.Equal(1, transformersOnDestination3.Count(x => x.Name == transformer.TransformerName));
  217. }
  218. }
  219. [Fact]
  220. public async Task Should_replicate_all_transformers_periodically()
  221. {
  222. using (var sourceServer = GetNewServer(8077))
  223. using (var source = NewRemoteDocumentStore(ravenDbServer: sourceServer))
  224. using (var destinationServer1 = GetNewServer(8078))
  225. using (var destination1 = NewRemoteDocumentStore(ravenDbServer: destinationServer1))
  226. using (var destinationServer2 = GetNewServer())
  227. using (var destination2 = NewRemoteDocumentStore(ravenDbServer: destinationServer2))
  228. using (var destinationServer3 = GetNewServer(8081))
  229. using (var destination3 = NewRemoteDocumentStore(ravenDbServer: destinationServer3))
  230. {
  231. CreateDatabaseWithReplication(source, "testDB");
  232. CreateDatabaseWithReplication(destination1, "testDB");
  233. CreateDatabaseWithReplication(destination2, "testDB");
  234. CreateDatabaseWithReplication(destination3, "testDB");
  235. //turn-off automatic index replication - precaution
  236. source.Conventions.IndexAndTransformerReplicationMode = IndexAndTransformerReplicationMode.None;
  237. // ReSharper disable once AccessToDisposedClosure
  238. SetupReplication(source, "testDB", store => false, destination1, destination2, destination3);
  239. var userTransformer = new UserWithoutExtraInfoTransformer();
  240. var anotherTransformer = new AnotherTransformer();
  241. var yetAnotherTransformer = new YetAnotherTransformer();
  242. var conflictDocumentsTransformer = new RavenConflictDocumentsTransformer(); // #RavenDB-3981
  243. source.DatabaseCommands.ForDatabase("testDB").PutTransformer(userTransformer.TransformerName, userTransformer.CreateTransformerDefinition());
  244. source.DatabaseCommands.ForDatabase("testDB").PutTransformer(anotherTransformer.TransformerName, anotherTransformer.CreateTransformerDefinition());
  245. source.DatabaseCommands.ForDatabase("testDB").PutTransformer(yetAnotherTransformer.TransformerName, yetAnotherTransformer.CreateTransformerDefinition());
  246. var sourceDB = await sourceServer.Server.GetDatabaseInternal("testDB");
  247. var replicationTask = sourceDB.StartupTasks.OfType<ReplicationTask>().First();
  248. SpinWait.SpinUntil(() => replicationTask.TransformerReplication.Execute());
  249. var expectedTransformerNames = new HashSet<string>
  250. {
  251. userTransformer.TransformerName,
  252. anotherTransformer.TransformerName,
  253. yetAnotherTransformer.TransformerName
  254. };
  255. var transformerNamesAtDestination1 = destination1.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024)
  256. .Where(x => x.Name != conflictDocumentsTransformer.TransformerName)
  257. .Select(x => x.Name)
  258. .ToList();
  259. var transformerNamesAtDestination2 = destination2.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024)
  260. .Where(x => x.Name != conflictDocumentsTransformer.TransformerName)
  261. .Select(x => x.Name)
  262. .ToList();
  263. var transformerNamesAtDestination3 = destination3.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024)
  264. .Where(x => x.Name != conflictDocumentsTransformer.TransformerName)
  265. .Select(x => x.Name)
  266. .ToList();
  267. Assert.True(expectedTransformerNames.SetEquals(transformerNamesAtDestination1));
  268. Assert.True(expectedTransformerNames.SetEquals(transformerNamesAtDestination2));
  269. Assert.True(expectedTransformerNames.SetEquals(transformerNamesAtDestination3));
  270. }
  271. }
  272. [Fact]
  273. public void Should_replicate_all_transformers_only_to_specific_destination_if_relevant_endpoint_is_hit()
  274. {
  275. var requestFactory = new HttpRavenRequestFactory();
  276. using (var sourceServer = GetNewServer(8077))
  277. using (var source = NewRemoteDocumentStore(ravenDbServer: sourceServer, fiddler: true))
  278. using (var destinationServer1 = GetNewServer(8078))
  279. using (var destination1 = NewRemoteDocumentStore(ravenDbServer: destinationServer1, fiddler: true))
  280. using (var destinationServer2 = GetNewServer())
  281. using (var destination2 = NewRemoteDocumentStore(ravenDbServer: destinationServer2, fiddler: true))
  282. using (var destinationServer3 = GetNewServer(8081))
  283. using (var destination3 = NewRemoteDocumentStore(ravenDbServer: destinationServer3, fiddler: true))
  284. {
  285. CreateDatabaseWithReplication(source, "testDB");
  286. CreateDatabaseWithReplication(destination1, "testDB");
  287. CreateDatabaseWithReplication(destination2, "testDB");
  288. CreateDatabaseWithReplication(destination3, "testDB");
  289. //make sure replication is off for indexes/transformers
  290. source.Conventions.IndexAndTransformerReplicationMode = IndexAndTransformerReplicationMode.None;
  291. // ReSharper disable once AccessToDisposedClosure
  292. var destinationDocuments = SetupReplication(source, "testDB", store => false, destination1, destination2, destination3);
  293. // index and transformer replication is forced if we are replicating for the first time, so replicating one document to bypass this
  294. ReplicateOneDummyDocument(source, destination1, destination2, destination3);
  295. var userTransformer = new UserWithoutExtraInfoTransformer();
  296. var anotherTransformer = new AnotherTransformer();
  297. var yetAnotherTransformer = new YetAnotherTransformer();
  298. var conflictDocumentsTransformer = new RavenConflictDocumentsTransformer(); // #RavenDB-3981
  299. source.DatabaseCommands.ForDatabase("testDB").PutTransformer(userTransformer.TransformerName, userTransformer.CreateTransformerDefinition());
  300. source.DatabaseCommands.ForDatabase("testDB").PutTransformer(anotherTransformer.TransformerName, anotherTransformer.CreateTransformerDefinition());
  301. source.DatabaseCommands.ForDatabase("testDB").PutTransformer(yetAnotherTransformer.TransformerName, yetAnotherTransformer.CreateTransformerDefinition());
  302. var expectedTransformerNames = new HashSet<string>
  303. {
  304. userTransformer.TransformerName,
  305. anotherTransformer.TransformerName,
  306. yetAnotherTransformer.TransformerName
  307. };
  308. var replicationRequestUrl = string.Format("{0}/databases/testDB/replication/replicate-transformers?op=replicate-all-to-destination", source.Url);
  309. var replicationRequest = requestFactory.Create(replicationRequestUrl, HttpMethods.Post, new RavenConnectionStringOptions
  310. {
  311. Url = source.Url
  312. });
  313. replicationRequest.Write(RavenJObject.FromObject(destinationDocuments[1]));
  314. replicationRequest.ExecuteRequest();
  315. var transformerNamesAtDestination1 = destination1.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024)
  316. .Where(x => x.Name != conflictDocumentsTransformer.TransformerName)
  317. .Select(x => x.Name)
  318. .ToList();
  319. var transformerNamesAtDestination2 = destination2.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024)
  320. .Where(x => x.Name != conflictDocumentsTransformer.TransformerName)
  321. .Select(x => x.Name)
  322. .ToList();
  323. var transformerNamesAtDestination3 = destination3.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024)
  324. .Where(x => x.Name != conflictDocumentsTransformer.TransformerName)
  325. .Select(x => x.Name)
  326. .ToList();
  327. Assert.Equal(0, transformerNamesAtDestination1.Count);
  328. Assert.True(expectedTransformerNames.SetEquals(transformerNamesAtDestination2));
  329. Assert.Equal(0, transformerNamesAtDestination3.Count);
  330. }
  331. }
  332. [Fact]
  333. public void Should_replicate_all_transformers_if_relevant_endpoint_is_hit()
  334. {
  335. var requestFactory = new HttpRavenRequestFactory();
  336. using (var sourceServer = GetNewServer(8077))
  337. using (var source = NewRemoteDocumentStore(ravenDbServer: sourceServer, fiddler: true))
  338. using (var destinationServer1 = GetNewServer(8078))
  339. using (var destination1 = NewRemoteDocumentStore(ravenDbServer: destinationServer1, fiddler: true))
  340. using (var destinationServer2 = GetNewServer())
  341. using (var destination2 = NewRemoteDocumentStore(ravenDbServer: destinationServer2, fiddler: true))
  342. using (var destinationServer3 = GetNewServer(8081))
  343. using (var destination3 = NewRemoteDocumentStore(ravenDbServer: destinationServer3, fiddler: true))
  344. {
  345. CreateDatabaseWithReplication(source, "testDB");
  346. CreateDatabaseWithReplication(destination1, "testDB");
  347. CreateDatabaseWithReplication(destination2, "testDB");
  348. CreateDatabaseWithReplication(destination3, "testDB");
  349. //make sure replication is off for indexes/transformers
  350. source.Conventions.IndexAndTransformerReplicationMode = IndexAndTransformerReplicationMode.None;
  351. var userTransformer = new UserWithoutExtraInfoTransformer();
  352. var anotherTransformer = new AnotherTransformer();
  353. var yetAnotherTransformer = new YetAnotherTransformer();
  354. var conflictDocumentsTransformer = new RavenConflictDocumentsTransformer(); // #RavenDB-3981
  355. source.DatabaseCommands.ForDatabase("testDB").PutTransformer(userTransformer.TransformerName, userTransformer.CreateTransformerDefinition());
  356. source.DatabaseCommands.ForDatabase("testDB").PutTransformer(anotherTransformer.TransformerName, anotherTransformer.CreateTransformerDefinition());
  357. source.DatabaseCommands.ForDatabase("testDB").PutTransformer(yetAnotherTransformer.TransformerName, yetAnotherTransformer.CreateTransformerDefinition());
  358. var expectedTransformerNames = new List<string>()
  359. {
  360. userTransformer.TransformerName,
  361. anotherTransformer.TransformerName,
  362. yetAnotherTransformer.TransformerName
  363. };
  364. expectedTransformerNames.Sort();
  365. // ReSharper disable once AccessToDisposedClosure
  366. SetupReplication(source, "testDB", store => false, destination1, destination2, destination3);
  367. var replicationRequestUrl = string.Format("{0}/databases/testDB/replication/replicate-transformers?op=replicate-all", source.Url);
  368. var replicationRequest = requestFactory.Create(replicationRequestUrl, HttpMethods.Post, new RavenConnectionStringOptions
  369. {
  370. Url = source.Url
  371. });
  372. replicationRequest.ExecuteRequest();
  373. var transformerNamesAtDestination1 = destination1.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024)
  374. .Where(x => x.Name != conflictDocumentsTransformer.TransformerName)
  375. .Select(x => x.Name)
  376. .ToList();
  377. var transformerNamesAtDestination2 = destination2.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024)
  378. .Where(x => x.Name != conflictDocumentsTransformer.TransformerName)
  379. .Select(x => x.Name)
  380. .ToList();
  381. var transformerNamesAtDestination3 = destination3.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024)
  382. .Where(x => x.Name != conflictDocumentsTransformer.TransformerName)
  383. .Select(x => x.Name)
  384. .ToList();
  385. transformerNamesAtDestination1.Sort();
  386. transformerNamesAtDestination2.Sort();
  387. transformerNamesAtDestination3.Sort();
  388. Assert.Equal(expectedTransformerNames, transformerNamesAtDestination1);
  389. Assert.Equal(expectedTransformerNames, transformerNamesAtDestination2);
  390. Assert.Equal(expectedTransformerNames, transformerNamesAtDestination3);
  391. }
  392. }
  393. [Fact]
  394. public void Replicate_all_transformers_should_respect_disable_replication_flag()
  395. {
  396. var requestFactory = new HttpRavenRequestFactory();
  397. using (var sourceServer = GetNewServer(8077))
  398. using (var source = NewRemoteDocumentStore(ravenDbServer: sourceServer, fiddler: true))
  399. using (var destinationServer1 = GetNewServer(8078))
  400. using (var destination1 = NewRemoteDocumentStore(ravenDbServer: destinationServer1, fiddler: true))
  401. using (var destinationServer2 = GetNewServer())
  402. using (var destination2 = NewRemoteDocumentStore(ravenDbServer: destinationServer2, fiddler: true))
  403. using (var destinationServer3 = GetNewServer(8081))
  404. using (var destination3 = NewRemoteDocumentStore(ravenDbServer: destinationServer3, fiddler: true))
  405. {
  406. CreateDatabaseWithReplication(source, "testDB");
  407. CreateDatabaseWithReplication(destination1, "testDB");
  408. CreateDatabaseWithReplication(destination2, "testDB");
  409. CreateDatabaseWithReplication(destination3, "testDB");
  410. //make sure replication is off for indexes/transformers
  411. source.Conventions.IndexAndTransformerReplicationMode = IndexAndTransformerReplicationMode.None;
  412. var userTransformer = new UserWithoutExtraInfoTransformer();
  413. var anotherTransformer = new AnotherTransformer();
  414. var yetAnotherTransformer = new YetAnotherTransformer();
  415. var conflictDocumentsTransformer = new RavenConflictDocumentsTransformer(); // #RavenDB-3981
  416. source.DatabaseCommands.ForDatabase("testDB").PutTransformer(userTransformer.TransformerName, userTransformer.CreateTransformerDefinition());
  417. source.DatabaseCommands.ForDatabase("testDB").PutTransformer(anotherTransformer.TransformerName, anotherTransformer.CreateTransformerDefinition());
  418. source.DatabaseCommands.ForDatabase("testDB").PutTransformer(yetAnotherTransformer.TransformerName, yetAnotherTransformer.CreateTransformerDefinition());
  419. var expectedTransformerNames = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase)
  420. {
  421. userTransformer.TransformerName,
  422. anotherTransformer.TransformerName,
  423. yetAnotherTransformer.TransformerName,
  424. };
  425. // ReSharper disable once AccessToDisposedClosure
  426. SetupReplication(source, "testDB", store => store == destination2, destination1, destination2, destination3);
  427. var replicationRequestUrl = string.Format("{0}/databases/testDB/replication/replicate-transformers?op=replicate-all", source.Url);
  428. var replicationRequest = requestFactory.Create(replicationRequestUrl, HttpMethods.Post, new RavenConnectionStringOptions
  429. {
  430. Url = source.Url
  431. });
  432. replicationRequest.ExecuteRequest();
  433. var transformerNamesAtDestination1 = destination1.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024).Where(x => x.Name != conflictDocumentsTransformer.TransformerName);
  434. var transformerNamesAtDestination2 = destination2.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024).Where(x => x.Name != conflictDocumentsTransformer.TransformerName);
  435. var transformerNamesAtDestination3 = destination3.DatabaseCommands.ForDatabase("testDB").GetTransformers(0, 1024).Where(x => x.Name != conflictDocumentsTransformer.TransformerName);
  436. Assert.True(expectedTransformerNames.SetEquals(transformerNamesAtDestination1.Select(x => x.Name).ToArray()));
  437. Assert.Equal(0, transformerNamesAtDestination2.Count());
  438. Assert.True(expectedTransformerNames.SetEquals(transformerNamesAtDestination3.Select(x => x.Name).ToArray()));
  439. }
  440. }
  441. [Fact]
  442. public void should_replicate_only_updated_transformer()
  443. {
  444. var requestFactory = new HttpRavenRequestFactory();
  445. using (var sourceServer = GetNewServer(8077))
  446. using (var source = NewRemoteDocumentStore(ravenDbServer: sourceServer, fiddler: true))
  447. using (var destinationServer = GetNewServer(8078))
  448. using (var destination = NewRemoteDocumentStore(ravenDbServer: destinationServer, fiddler: true))
  449. {
  450. CreateDatabaseWithReplication(source, "testDB");
  451. CreateDatabaseWithReplication(destination, "testDB");
  452. source.Conventions.IndexAndTransformerReplicationMode = IndexAndTransformerReplicationMode.None;
  453. destination.Conventions.IndexAndTransformerReplicationMode = IndexAndTransformerReplicationMode.None;
  454. SetupReplication(source, "testDB", store => false, destination);
  455. SetupReplication(destination, "testDB", store => false, source);
  456. for (var i = 0; i < 30; i++)
  457. {
  458. //just for starting the initial index and transformer replication
  459. source.DatabaseCommands.ForDatabase("testDB").Put("test" + i, Etag.Empty, new RavenJObject(), new RavenJObject());
  460. destination.DatabaseCommands.ForDatabase("testDB").Put("test" + (i + 50), Etag.Empty, new RavenJObject(), new RavenJObject());
  461. }
  462. WaitForDocument(destination.DatabaseCommands.ForDatabase("testDB"), "test29");
  463. WaitForDocument(source.DatabaseCommands.ForDatabase("testDB"), "test79");
  464. var userTransformer = new UserWithoutExtraInfoTransformer();
  465. source.DatabaseCommands.ForDatabase("testDB").PutTransformer(userTransformer.TransformerName, userTransformer.CreateTransformerDefinition());
  466. //replicating transformer from the source
  467. var replicationRequestUrl = string.Format("{0}/databases/testDB/replication/replicate-transformers?op=replicate-all", source.Url);
  468. var replicationRequest = requestFactory.Create(replicationRequestUrl, HttpMethods.Post, new RavenConnectionStringOptions
  469. {
  470. Url = source.Url
  471. });
  472. replicationRequest.ExecuteRequest();
  473. var updatedUserTransformer = new UserWithoutExtraInfoTransformer_Extended();
  474. source.DatabaseCommands.ForDatabase("testDB").PutTransformer(userTransformer.TransformerName, updatedUserTransformer.CreateTransformerDefinition());
  475. var transformer = source.DatabaseCommands.ForDatabase("testDB").GetTransformer(userTransformer.TransformerName);
  476. Assert.True(updatedUserTransformer.CreateTransformerDefinition().TransformResults.Equals(transformer.TransformResults));
  477. //replicating transformer from the destination
  478. replicationRequestUrl = string.Format("{0}/databases/testDB/replication/replicate-transformers?op=replicate-all", destination.Url);
  479. replicationRequest = requestFactory.Create(replicationRequestUrl, HttpMethods.Post, new RavenConnectionStringOptions
  480. {
  481. Url = destination.Url
  482. });
  483. replicationRequest.ExecuteRequest();
  484. //the new transformer shouldn't be overwritten
  485. transformer = source.DatabaseCommands.ForDatabase("testDB").GetTransformer(userTransformer.TransformerName);
  486. Assert.True(updatedUserTransformer.CreateTransformerDefinition().TransformResults.Equals(transformer.TransformResults));
  487. }
  488. }
  489. [Fact]
  490. public void can_update_transformer_lock_mode()
  491. {
  492. var requestFactory = new HttpRavenRequestFactory();
  493. using (var sourceServer = GetNewServer(8077))
  494. using (var source = NewRemoteDocumentStore(ravenDbServer: sourceServer, fiddler: true))
  495. using (var destinationServer = GetNewServer(8078))
  496. using (var destination = NewRemoteDocumentStore(ravenDbServer: destinationServer, fiddler: true))
  497. {
  498. CreateDatabaseWithReplication(source, "testDB");
  499. CreateDatabaseWithReplication(destination, "testDB");
  500. source.Conventions.IndexAndTransformerReplicationMode = IndexAndTransformerReplicationMode.None;
  501. destination.Conventions.IndexAndTransformerReplicationMode = IndexAndTransformerReplicationMode.None;
  502. SetupReplication(source, "testDB", store => false, destination);
  503. SetupReplication(destination, "testDB", store => false, source);
  504. for (var i = 0; i < 30; i++)
  505. {
  506. //just for starting the initial index and transformer replication
  507. source.DatabaseCommands.ForDatabase("testDB").Put("test" + i, Etag.Empty, new RavenJObject(), new RavenJObject());
  508. destination.DatabaseCommands.ForDatabase("testDB").Put("test" + (i + 50), Etag.Empty, new RavenJObject(), new RavenJObject());
  509. }
  510. WaitForDocument(destination.DatabaseCommands.ForDatabase("testDB"), "test29");
  511. WaitForDocument(source.DatabaseCommands.ForDatabase("testDB"), "test79");
  512. var userTransformer = new UserWithoutExtraInfoTransformer();
  513. source.DatabaseCommands.ForDatabase("testDB").PutTransformer(userTransformer.TransformerName, userTransformer.CreateTransformerDefinition());
  514. source.DatabaseCommands.ForDatabase("testDB").SetTransformerLock(userTransformer.TransformerName, TransformerLockMode.LockedIgnore);
  515. //replicating transformer from the source
  516. var replicationRequestUrl = string.Format("{0}/databases/testDB/replication/replicate-transformers?op=replicate-all", source.Url);
  517. var replicationRequest = requestFactory.Create(replicationRequestUrl, HttpMethods.Post, new RavenConnectionStringOptions
  518. {
  519. Url = source.Url
  520. });
  521. replicationRequest.ExecuteRequest();
  522. var updatedUserTransformer = new UserWithoutExtraInfoTransformer_Extended();
  523. source.DatabaseCommands.ForDatabase("testDB").SetTransformerLock(updatedUserTransformer.TransformerName, TransformerLockMode.Unlock);
  524. source.DatabaseCommands.ForDatabase("testDB").PutTransformer(userTransformer.TransformerName, updatedUserTransformer.CreateTransformerDefinition());
  525. var transformer = source.DatabaseCommands.ForDatabase("testDB").GetTransformer(userTransformer.TransformerName);
  526. Assert.True(updatedUserTransformer.CreateTransformerDefinition().TransformResults.Equals(transformer.TransformResults));
  527. //replicating transformer from the source
  528. replicationRequestUrl = string.Format("{0}/databases/testDB/replication/replicate-transformers?op=replicate-all", source.Url);
  529. replicationRequest = requestFactory.Create(replicationRequestUrl, HttpMethods.Post, new RavenConnectionStringOptions
  530. {
  531. Url = source.Url
  532. });
  533. replicationRequest.ExecuteRequest();
  534. //the transformer lock mode should change
  535. transformer = destination.DatabaseCommands.ForDatabase("testDB").GetTransformer(userTransformer.TransformerName);
  536. Assert.Equal(transformer.LockMode, TransformerLockMode.Unlock);
  537. Assert.True(updatedUserTransformer.CreateTransformerDefinition().TransformResults.Equals(transformer.TransformResults));
  538. }
  539. }
  540. private static void CreateDatabaseWithReplication(DocumentStore store, string databaseName)
  541. {
  542. store.DatabaseCommands.GlobalAdmin.CreateDatabase(new DatabaseDocument
  543. {
  544. Id = databaseName,
  545. Settings =
  546. {
  547. {"Raven/DataDir", "~/Tenants/" + databaseName},
  548. {"Raven/ActiveBundles", "Replication"}
  549. }
  550. });
  551. }
  552. private static List<ReplicationDestination> SetupReplication(IDocumentStore source, string databaseName, Func<IDocumentStore, bool> shouldSkipIndexReplication, params IDocumentStore[] destinations)
  553. {
  554. var replicationDocument = new ReplicationDocument
  555. {
  556. Destinations = new List<ReplicationDestination>(destinations.Select(destination =>
  557. new ReplicationDestination
  558. {
  559. Database = databaseName,
  560. Url = destination.Url,
  561. SkipIndexReplication = shouldSkipIndexReplication(destination)
  562. }))
  563. };
  564. using (var session = source.OpenSession(databaseName))
  565. {
  566. session.Store(replicationDocument, Constants.RavenReplicationDestinations);
  567. session.SaveChanges();
  568. }
  569. return replicationDocument.Destinations;
  570. }
  571. private void ReplicateOneDummyDocument(IDocumentStore source, IDocumentStore destination1, IDocumentStore destination2, IDocumentStore destination3)
  572. {
  573. string id;
  574. using (var session = source.OpenSession("testDB"))
  575. {
  576. var dummy = new { Id = "" };
  577. session.Store(dummy);
  578. session.SaveChanges();
  579. id = dummy.Id;
  580. }
  581. WaitForDocument(destination1.DatabaseCommands.ForDatabase("testDB"), id);
  582. WaitForDocument(destination2.DatabaseCommands.ForDatabase("testDB"), id);
  583. WaitForDocument(destination3.DatabaseCommands.ForDatabase("testDB"), id);
  584. }
  585. }
  586. }