Transaction now has limited support for PromotableSinglePhaseEnlistment
[mono.git] / mcs / class / System.Transactions / Test / IntResourceManager.cs
1 //
2 // ResourceManager representing an integer, used by other test cases
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.Collections.Generic;
12 using System.Text;
13 using System.Transactions;
14 using NUnit.Framework;
15
16 namespace MonoTests.System.Transactions
17 {
18     public class IntResourceManager
19     {
20         public IntResourceManager (int value) 
21         { 
22             actual = value;
23             guid = Guid.NewGuid ();
24         }
25
26         private int actual;
27         private int tmpValue;
28         private Transaction transaction = null;
29
30         public int NumPrepare = 0;
31         public int NumRollback = 0;
32         public int NumCommit = 0;
33         public int NumInDoubt = 0;
34         public int NumSingle = 0;
35         
36         public int NumInitialize = 0;
37         public int NumPromote = 0;
38         public int NumEnlistFailed = 0;
39
40         public ResourceManagerType Type = ResourceManagerType.Volatile;        
41         public bool FailPrepare = false;
42         public bool FailWithException = false;
43         public bool IgnorePrepare = false;
44         public bool IgnoreSPC = false;
45         public bool FailSPC = false;
46         public bool FailCommit = false;
47         public bool UseSingle = false;
48
49         Guid guid;
50
51         public int Actual {
52             get { return actual; }
53         }
54
55         public int Value {
56             get { return transaction == null ? actual : tmpValue; }
57             set
58             {
59                 if (Transaction.Current == null) {
60                     /* Not in a transaction */
61                     actual = value;
62                     return;
63                 }
64                 /* FIXME: Do what in this case? */
65                 if (transaction != null)
66                     Console.WriteLine ("WARNING: Setting value more than once");
67
68                 if (transaction != Transaction.Current) {
69                     transaction = Transaction.Current;
70
71                     if ( Type == ResourceManagerType.Promotable ) {
72                         transaction.EnlistPromotableSinglePhase(new PromotableSinglePhaseNotification ( this ));
73                     } else if (UseSingle) {
74                         SinglePhaseNotification enlistment = new SinglePhaseNotification ( this );
75                         if ( Type == ResourceManagerType.Volatile )
76                             transaction.EnlistVolatile ( enlistment, EnlistmentOptions.None );
77                         else
78                             transaction.EnlistDurable ( guid, enlistment, EnlistmentOptions.None );
79                     } else {
80                         EnlistmentNotification enlistment = new EnlistmentNotification ( this );
81                         if ( Type == ResourceManagerType.Volatile )
82                             transaction.EnlistVolatile ( enlistment, EnlistmentOptions.None );
83                         else
84                             transaction.EnlistDurable ( guid, enlistment, EnlistmentOptions.None );
85                     }
86                 }
87                 tmpValue = value;
88             }
89         }
90
91         public void Commit ()
92         {
93             actual = tmpValue;
94             transaction = null;
95         }
96
97         public void Rollback ()
98         {
99             transaction = null;
100         }
101
102         public  void CheckSPC ( string msg )
103         {
104             Check ( 1, 0, 0, 0, 0, 0, 0, msg );
105         }
106
107         public void Check2PC ( string msg)
108         {
109             Check ( 0, 1, 1, 0, 0, 0, 0, msg );
110         }
111
112         public void Check ( int s, int p, int c, int r, int d, int i, int pr, string msg )
113         {
114             Assert.AreEqual ( s, NumSingle, msg + ": NumSingle" );
115             Assert.AreEqual ( p, NumPrepare, msg + ": NumPrepare" );
116             Assert.AreEqual ( c, NumCommit, msg + ": NumCommit" );
117             Assert.AreEqual ( r, NumRollback, msg + ": NumRollback" );
118             Assert.AreEqual ( d, NumInDoubt, msg + ": NumInDoubt" );
119             Assert.AreEqual ( i, NumInitialize, msg + ": NumRollback" );
120             Assert.AreEqual ( pr, NumPromote, msg + ": NumInDoubt" );
121         }
122        
123         /* Used for volatile RMs */
124         public void Check ( int p, int c, int r, int d, string msg )
125         {
126             Check ( 0, p, c, r, d, 0, 0, msg );
127         }
128     }
129
130     public class EnlistmentNotification : IEnlistmentNotification {
131         protected IntResourceManager resource;
132
133         public EnlistmentNotification ( IntResourceManager resource )
134         {
135             this.resource = resource;
136         }
137
138         public void Prepare ( PreparingEnlistment preparingEnlistment )
139         {
140             resource.NumPrepare++;
141             if ( resource.IgnorePrepare )
142                 return;
143
144             if ( resource.FailPrepare ) {
145                 if (resource.FailWithException)
146                     preparingEnlistment.ForceRollback ( new NotSupportedException () );
147                 else
148                     preparingEnlistment.ForceRollback ();
149             } else {
150                 preparingEnlistment.Prepared ();
151             }
152         }
153
154         public void Commit ( Enlistment enlistment )
155         {
156             resource.NumCommit++;
157             if ( resource.FailCommit )
158                 return;
159
160             resource.Commit ();
161             enlistment.Done ();
162         }
163
164         public void Rollback ( Enlistment enlistment )
165         {
166             resource.NumRollback++;
167             resource.Rollback ();
168         }
169
170         public void InDoubt ( Enlistment enlistment )
171         {
172             resource.NumInDoubt++;
173             throw new Exception ( "IntResourceManager.InDoubt is not implemented." );
174         }
175     }
176
177     public class SinglePhaseNotification : EnlistmentNotification, ISinglePhaseNotification 
178     {
179         public SinglePhaseNotification ( IntResourceManager resource )
180             : base ( resource )
181         {
182         }
183
184         public void SinglePhaseCommit ( SinglePhaseEnlistment enlistment )
185         {
186             resource.NumSingle++;
187             if ( resource.IgnoreSPC )
188                 return;
189
190             if ( resource.FailSPC ) {
191                 if ( resource.FailWithException )
192                     enlistment.Aborted ( new NotSupportedException () );
193                 else
194                     enlistment.Aborted ();
195             }
196             else {
197                 resource.Commit ();
198                 enlistment.Committed ();
199             }
200         }
201     }
202
203     public class PromotableSinglePhaseNotification : SinglePhaseNotification, IPromotableSinglePhaseNotification
204     {
205         public PromotableSinglePhaseNotification ( IntResourceManager resource )
206             : base( resource )
207         {
208         }
209
210         public void Initialize ()
211         {
212             resource.NumInitialize++;
213         }
214
215         public void Rollback ( SinglePhaseEnlistment enlistment )
216         {
217             resource.NumRollback++;
218             resource.Rollback ();
219         }
220
221         public byte [] Promote ()
222         {
223             resource.NumPromote++;
224             return new byte[0];
225         }
226     }
227
228     public enum ResourceManagerType { Volatile, Durable, Promotable };
229 }
230