b06d0b896f2cdf873dddad07501095e47139670d
[mono.git] / mcs / class / System.Transactions / Test / EnlistTest.cs
1 //
2 // Tests for combination of volatile & durable resource manangers
3 //
4 // Author:
5 //      Ankit Jain      <JAnkit@novell.com>
6 //
7 // Copyright (C) 2006 Novell, Inc (http://www.novell.com)
8 //
9
10 using System;
11 using System.Transactions;
12 using NUnit.Framework;
13
14 namespace MonoTests.System.Transactions {
15
16         [TestFixture]
17         public class EnlistTest {
18
19                 #region Vol1_Dur0
20
21                 /* Single volatile resource, SPC happens */
22                 [Test]
23                 public void Vol1_Dur0 ()
24                 {
25                         IntResourceManager irm = new IntResourceManager (1);
26                         irm.UseSingle = true;
27                         using (TransactionScope scope = new TransactionScope ()) {
28                                 irm.Value = 2;
29
30                                 scope.Complete ();
31                         }
32                         irm.CheckSPC ("irm");
33                 }
34
35                 [Test]
36                 public void Vol1_Dur0_2PC ()
37                 {
38                         IntResourceManager irm = new IntResourceManager (1);
39
40                         using (TransactionScope scope = new TransactionScope ()) {
41                                 irm.Value = 2;
42
43                                 scope.Complete ();
44                         }
45                         irm.Check2PC ("irm");
46                 }
47
48                 /* Single volatile resource, SPC happens */
49                 [Test]
50                 public void Vol1_Dur0_Fail1 ()
51                 {
52                         IntResourceManager irm = new IntResourceManager (1);
53                         irm.UseSingle = true;
54                         using (TransactionScope scope = new TransactionScope ()) {
55                                 irm.Value = 2;
56
57                                 /* Not completing this..
58                                 scope.Complete ();*/
59                         }
60
61                         irm.Check ( 0, 0, 0, 1, 0, "irm" );
62                 }
63
64                 [Test]
65                 [ExpectedException ( typeof ( TransactionAbortedException ) )]
66                 public void Vol1_Dur0_Fail2 ()
67                 {
68                         IntResourceManager irm = new IntResourceManager (1);
69
70                         irm.FailPrepare = true;
71
72                         using (TransactionScope scope = new TransactionScope ()) {
73                                 irm.Value = 2;
74
75                                 scope.Complete ();
76                         }
77                 }
78
79                 [Test]
80                 [ExpectedException ( typeof ( TransactionAbortedException ) )]
81                 public void Vol1_Dur0_Fail3 ()
82                 {
83                         IntResourceManager irm = new IntResourceManager (1);
84                         irm.UseSingle = true;
85                         irm.FailSPC = true;
86
87                         using (TransactionScope scope = new TransactionScope ()) {
88                                 irm.Value = 2;
89
90                                 scope.Complete ();
91                         }
92                 }
93
94                 #endregion
95
96                 #region Vol2_Dur0
97
98                 /* >1 volatile, 2PC */
99                 [Test]
100                 public void Vol2_Dur0_SPC ()
101                 {
102                         IntResourceManager irm = new IntResourceManager (1);
103                         IntResourceManager irm2 = new IntResourceManager (3);
104
105                         irm.UseSingle = true;
106                         irm2.UseSingle = true;
107                         using (TransactionScope scope = new TransactionScope ()) {
108                                 irm.Value = 2;
109                                 irm2.Value = 6;
110
111                                 scope.Complete ();
112                         }
113                         irm.Check2PC ( "irm" );
114                         irm2.Check2PC ( "irm2" );
115                 }
116
117                 #endregion
118
119                 #region Vol0_Dur1
120                 /* 1 durable */
121                 [Test]
122                 public void Vol0_Dur1 ()
123                 {
124                         IntResourceManager irm = new IntResourceManager (1);
125                         irm.Volatile = false;
126                         irm.UseSingle = true;
127
128                         using (TransactionScope scope = new TransactionScope ()) {
129                                 irm.Value = 2;
130
131                                 scope.Complete ();
132                         }
133
134                         irm.CheckSPC ( "irm" );
135                 }
136
137                 /* We support only 1 durable with 2PC
138                  * On .net, this becomes a distributed transaction
139                  */ 
140                 [Test]
141                 [Category ("NotWorking")]
142                 public void Vol0_Dur1_2PC ()
143                 {
144                         IntResourceManager irm = new IntResourceManager (1);
145
146                         /* Durable resource enlisted with a IEnlistedNotification
147                          * object
148                          */
149                         irm.Volatile = false;
150
151                         using (TransactionScope scope = new TransactionScope ()) {
152                                 irm.Value = 2;
153
154                                 scope.Complete ();
155                         }
156                 }
157
158                 [Test]
159                 public void Vol0_Dur1_Fail ()
160                 {
161                         IntResourceManager irm = new IntResourceManager ( 1 );
162
163                         /* Durable resource enlisted with a IEnlistedNotification
164                          * object
165                          */
166                         irm.Volatile = false;
167                         irm.FailSPC = true;
168                         irm.UseSingle = true;
169                         try {
170                                 using (TransactionScope scope = new TransactionScope ()) {
171                                         irm.Value = 2;
172
173                                         scope.Complete ();
174                                 }
175                         }
176                         catch (TransactionAbortedException) {
177                                 irm.Check ( 1, 0, 0, 0, 0, "irm" );
178                                 return;
179                         }
180
181                         Assert.Fail ();
182                 }
183                 #endregion
184
185                 #region Vol2_Dur1
186                 /* >1vol + 1 durable */
187                 [Test]
188                 public void Vol2_Dur1 ()
189                 {
190                         IntResourceManager [] irm = new IntResourceManager [4];
191                         irm [0] = new IntResourceManager ( 1 );
192                         irm [1] = new IntResourceManager ( 3 );
193                         irm [2] = new IntResourceManager ( 5 );
194                         irm [3] = new IntResourceManager ( 7 );
195
196                         irm [0].Volatile = false;
197                         for ( int i = 0; i < 4; i++ )
198                                 irm [i].UseSingle = true;
199
200                         using (TransactionScope scope = new TransactionScope ()) {
201                                 irm [0].Value = 2;
202                                 irm [1].Value = 6;
203                                 irm [2].Value = 10;
204                                 irm [3].Value = 14;
205
206                                 scope.Complete ();
207                         }
208
209                         irm [0].CheckSPC ( "irm [0]" );
210
211                         /* Volatile RMs get 2PC */
212                         for (int i = 1; i < 4; i++)
213                                 irm [i].Check2PC ( "irm [" + i + "]" );
214                 }
215
216                 /* >1vol + 1 durable
217                  * Durable fails SPC
218                  */
219                 [Test]
220                 public void Vol2_Dur1_Fail1 ()
221                 {
222                         IntResourceManager [] irm = new IntResourceManager [4];
223                         irm [0] = new IntResourceManager (1);
224                         irm [1] = new IntResourceManager (3);
225                         irm [2] = new IntResourceManager (5);
226                         irm [3] = new IntResourceManager (7);
227
228                         irm [0].Volatile = false;
229                         irm [0].FailSPC = true;
230
231                         for ( int i = 0; i < 4; i++ )
232                                 irm [i].UseSingle = true;
233
234                         /* Durable RM irm[0] does Abort on SPC, so
235                          * all volatile RMs get Rollback */
236                         try {
237                                 using (TransactionScope scope = new TransactionScope ()) {
238                                         irm [0].Value = 2;
239                                         irm [1].Value = 6;
240                                         irm [2].Value = 10;
241                                         irm [3].Value = 14;
242
243                                         scope.Complete ();
244                                 }
245                         }
246                         catch (TransactionAbortedException) {
247                                 irm [0].CheckSPC ( "irm [0]" );
248                                 /* Volatile RMs get 2PC Prepare, and then get rolled back */
249                                 for (int i = 1; i < 4; i++)
250                                         irm [i].Check ( 0, 1, 0, 1, 0, "irm [" + i + "]" );
251                         }
252                 }
253
254                 /* >1vol + 1 durable 
255                  * durable doesn't complete SPC
256                  */
257                 [Test]
258                 [Ignore ( "Correct this test, it should throw TimeOutException or something" )]
259                 public void Vol2_Dur1_Fail2 ()
260                 {
261                         TransactionAbortedException exception = null;
262                         IntResourceManager [] irm = new IntResourceManager [4];
263                         irm [0] = new IntResourceManager (1);
264                         irm [1] = new IntResourceManager (3);
265                         irm [2] = new IntResourceManager (5);
266                         irm [3] = new IntResourceManager (7);
267
268                         irm [0].Volatile = false;
269                         irm [0].IgnoreSPC = true;
270
271                         for ( int i = 0; i < 4; i++ )
272                                 irm [i].UseSingle = true;
273
274                         /* Durable RM irm[2] does on SPC, so
275                          * all volatile RMs get Rollback */
276                         try {
277                                 using (TransactionScope scope = new TransactionScope ( TransactionScopeOption.Required, new TimeSpan ( 0, 0, 5 ) )) {
278                                         irm [0].Value = 2;
279                                         irm [1].Value = 6;
280                                         irm [2].Value = 10;
281                                         irm [3].Value = 14;
282
283                                         scope.Complete ();
284                                 }
285                         }
286                         catch (TransactionAbortedException ex) {
287                                 irm [0].CheckSPC ( "irm [0]" );
288
289                                 /* Volatile RMs get 2PC Prepare, and then get rolled back */
290                                 for (int i = 1; i < 4; i++)
291                                         irm [i].Check ( 0, 1, 0, 1, 0, "irm [" + i + "]" );
292
293                                 exception = ex;
294                         }
295
296                         Assert.IsNotNull(exception, "Expected TransactionAbortedException not thrown!");
297                         Assert.IsNotNull(exception.InnerException, "TransactionAbortedException has no inner exception!");
298                         Assert.AreEqual(typeof(TimeoutException), exception.InnerException.GetType());
299                 }
300
301                 /* Same as Vol2_Dur1_Fail2, but with a volatile manager timming out */
302                 [Test]
303                 [Ignore ( "Correct this test, it should throw TimeOutException or something" )]
304                 public void Vol2_Dur1_Fail2b()
305                 {
306                         TransactionAbortedException exception = null;
307                         IntResourceManager[] irm = new IntResourceManager[4];
308                         irm[0] = new IntResourceManager(1);
309                         irm[1] = new IntResourceManager(3);
310                         irm[2] = new IntResourceManager(5);
311                         irm[3] = new IntResourceManager(7);
312
313                         irm[0].IgnoreSPC = true;
314                         irm[1].Volatile = false;
315
316                         for (int i = 0; i < 4; i++)
317                                 irm[i].UseSingle = true;
318
319                         /* Durable RM irm[2] does on SPC, so
320                          * all volatile RMs get Rollback */
321                         try
322                         {
323                                 using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0, 0, 5)))
324                                 {
325                                         irm[0].Value = 2;
326                                         irm[1].Value = 6;
327                                         irm[2].Value = 10;
328                                         irm[3].Value = 14;
329
330                                         scope.Complete();
331                                 }
332                         }
333                         catch (TransactionAbortedException ex)
334                         {
335                                 irm[0].CheckSPC("irm [0]");
336
337                                 /* Volatile RMs get 2PC Prepare, and then get rolled back */
338                                 for (int i = 1; i < 4; i++)
339                                         irm[i].Check(0, 1, 0, 1, 0, "irm [" + i + "]");
340
341                                 exception = ex;
342                         }
343
344                         Assert.IsNotNull(exception, "Expected TransactionAbortedException not thrown!");
345                         Assert.IsNotNull(exception.InnerException, "TransactionAbortedException has no inner exception!");
346                         Assert.AreEqual(typeof(TimeoutException), exception.InnerException.GetType());
347                 }
348
349                 /* >1vol + 1 durable
350                  * Volatile fails Prepare
351                  */
352                 [Test]
353                 public void Vol2_Dur1_Fail3 ()
354                 {
355                         IntResourceManager [] irm = new IntResourceManager [4];
356                         irm [0] = new IntResourceManager ( 1 );
357                         irm [1] = new IntResourceManager ( 3 );
358                         irm [2] = new IntResourceManager ( 5 );
359                         irm [3] = new IntResourceManager ( 7 );
360
361                         irm [0].Volatile = false;
362                         irm [2].FailPrepare = true;
363
364                         for ( int i = 0; i < 4; i++ )
365                                 irm [i].UseSingle = true;
366
367                         /* Durable RM irm[2] does on SPC, so
368                          * all volatile RMs get Rollback */
369                         try {
370                                 using (TransactionScope scope = new TransactionScope ()) {
371                                         irm [0].Value = 2;
372                                         irm [1].Value = 6;
373                                         irm [2].Value = 10;
374                                         irm [3].Value = 14;
375
376                                         scope.Complete ();
377                                 }
378                         }
379                         catch (TransactionAbortedException) {
380                                 irm [0].Check ( 0, 0, 0, 1, 0, "irm [0]");
381
382                                 /* irm [1] & [2] get prepare,
383                                  * [2] -> ForceRollback,
384                                  * [1] & [3] get rollback,
385                                  * [0](durable) gets rollback */
386                                 irm [1].Check ( 0, 1, 0, 1, 0, "irm [1]" );
387                                 irm [2].Check ( 0, 1, 0, 0, 0, "irm [2]" );
388                                 irm [3].Check ( 0, 0, 0, 1, 0, "irm [3]" );
389
390                                 return;
391                         }
392
393                         Assert.Fail ( "Expected TransactionAbortedException" );
394                 }
395
396                 [Test]
397                 public void Vol2_Dur1_Fail4 ()
398                 {
399                         IntResourceManager [] irm = new IntResourceManager [2];
400                         irm [0] = new IntResourceManager ( 1 );
401                         irm [1] = new IntResourceManager ( 3 );
402
403                         irm [0].Volatile = false;
404                         irm [0].FailSPC = true;
405                         irm [0].FailWithException = true;
406
407                         for ( int i = 0; i < 2; i++ )
408                                 irm [i].UseSingle = true;
409
410                         /* Durable RM irm[2] does on SPC, so
411                          * all volatile RMs get Rollback */
412                         try {
413                                 using ( TransactionScope scope = new TransactionScope () ) {
414                                         irm [0].Value = 2;
415                                         irm [1].Value = 6;
416
417                                         scope.Complete ();
418                                 }
419                         }
420                         catch ( TransactionAbortedException e) {
421                                 Assert.IsNotNull ( e.InnerException, "Expected e.InnerException == NotSupportedException, but got None");
422                                 Assert.AreEqual ( typeof ( NotSupportedException ), e.InnerException.GetType (), "Expected e.InnerException == NotSupportedException, but got " + e.GetType () );
423
424                                 irm [0].Check ( 1, 0, 0, 0, 0, "irm [0]" );
425                                 irm [1].Check ( 0, 1, 0, 1, 0, "irm [1]" );
426                                 return;
427                         }
428
429                         Assert.Fail ( "Expected TransactionAbortedException" );
430                 }
431
432                 [Test]
433                 public void Vol2_Dur1_Fail5 ()
434                 {
435                         CommittableTransaction ct = new CommittableTransaction ();
436                         IntResourceManager [] irm = new IntResourceManager [2];
437                         irm [0] = new IntResourceManager ( 1 );
438                         irm [1] = new IntResourceManager ( 3 );
439
440                         Transaction.Current = ct;
441                         irm [0].Volatile = false;
442                         irm [0].FailSPC = true;
443                         irm [0].FailWithException = true;
444
445                         for ( int i = 0; i < 2; i++ )
446                                 irm [i].UseSingle = true;
447
448                         /* Durable RM irm[2] does on SPC, so
449                          * all volatile RMs get Rollback */
450                         
451                         using ( TransactionScope scope = new TransactionScope () ) {
452                                 irm [0].Value = 2;
453                                 irm [1].Value = 6;
454
455                                 scope.Complete ();
456                         }
457
458                         try {
459                                 ct.Commit ();
460                         }
461                         catch ( TransactionAbortedException e ) {
462                                 Assert.IsNotNull ( e.InnerException, "Expected e.InnerException == NotSupportedException, but got None" );
463                                 Assert.AreEqual ( typeof ( NotSupportedException ), e.InnerException.GetType (), "Expected e.InnerException == NotSupportedException, but got " + e.GetType () );
464
465                                 irm [0].Check ( 1, 0, 0, 0, 0, "irm [0]" );
466                                 irm [1].Check ( 0, 1, 0, 1, 0, "irm [1]" );
467                                 try {
468                                         ct.Commit ();
469                                 }
470                                 catch (InvalidOperationException x ) {
471                                         Assert.IsNull ( x.InnerException);
472                                         Transaction.Current = null;
473                                         return;
474                                 }
475                                 Assert.Fail ( "Should not be reached" );
476                         }
477
478                         Assert.Fail ( "Expected TransactionAbortedException" );
479                 }
480
481                 #endregion
482
483                 #region Others
484                 /* >1vol  
485                  * > 1 durable, On .net this becomes a distributed transaction
486                  * We don't support this in mono yet. 
487                  */
488                 [Test]
489                 [Category ("NotWorking")]
490                 public void Vol0_Dur2 ()
491                 {
492                         IntResourceManager [] irm = new IntResourceManager [2];
493                         irm [0] = new IntResourceManager ( 1 );
494                         irm [1] = new IntResourceManager ( 3 );
495
496                         irm [0].Volatile = false;
497                         irm [1].Volatile = false;
498
499                         for ( int i = 0; i < 2; i++ )
500                                 irm [i].UseSingle = true;
501
502                         using (TransactionScope scope = new TransactionScope ()) {
503                                 irm [0].Value = 2;
504                                 irm [1].Value = 6;
505
506                                 scope.Complete ();
507                         }
508                 }
509
510                 [Test]
511                 public void TransactionDispose ()
512                 {
513                         CommittableTransaction ct = new CommittableTransaction ();
514                         IntResourceManager irm = new IntResourceManager (1);
515                         irm.Volatile = false;
516
517                         ct.Dispose ();
518                         irm.Check  (0, 0, 0, 0, "Dispose transaction");
519                 }
520
521                 [Test]
522                 public void TransactionDispose2 ()
523                 {
524                         CommittableTransaction ct = new CommittableTransaction ();
525                         IntResourceManager irm = new IntResourceManager (1);
526
527                         Transaction.Current = ct;
528                         irm.Value = 5;
529
530                         try {
531                                 ct.Dispose ();
532                         } finally {
533                                 Transaction.Current = null;
534                         }
535
536                         irm.Check (0, 0, 1, 0, "Dispose transaction");
537                         Assert.AreEqual (1, irm.Value);
538                 }
539
540                 [Test]
541                 public void TransactionDispose3 ()
542                 {
543                         CommittableTransaction ct = new CommittableTransaction ();
544                         IntResourceManager irm = new IntResourceManager (1);
545
546                         try {
547                                 Transaction.Current = ct;
548                                 irm.Value = 5;
549                                 ct.Commit ();
550                                 ct.Dispose ();
551                         } finally {
552                                 Transaction.Current = null;
553                         }
554
555                         irm.Check (1, 1, 0, 0, "Dispose transaction");
556                         Assert.AreEqual (5, irm.Value);
557                 }
558
559                 [Test]
560                 public void TransactionCompleted_Committed ()
561                 {
562                         bool called = false;
563                         using (var ts = new TransactionScope ())
564                         {
565                                 var tr = Transaction.Current;
566                                 tr.TransactionCompleted += (s, e) => called = true;
567                                 ts.Complete ();
568                         }
569
570                         Assert.IsTrue (called, "TransactionCompleted event handler not called!");
571                 }
572
573                 [Test]
574                 public void TransactionCompleted_Rollback ()
575                 {
576                         bool called = false;
577                         using (var ts = new TransactionScope ())
578                         {
579                                 var tr = Transaction.Current;
580                                 tr.TransactionCompleted += (s, e) => called = true;
581                                 // Not calling ts.Complete() on purpose..
582                         }
583
584                         Assert.IsTrue (called, "TransactionCompleted event handler not called!");
585                 }
586                 #endregion
587
588         }
589 }
590