3 * Copyright (C)2007-2008 Versabanq Innovations Inc. and contributors.
4 * See the included file named LICENSE for license information.
9 using System
.Data
.SqlClient
;
10 using System
.Collections
.Generic
;
18 // Several mono bugs worked around in this test fixture are filed as mono bug
21 public class VersaplexTester
: IDisposable
23 // A file full of "lorem ipsum dolor" text
24 private const string lipsum_file
= "lipsum.txt";
26 private const string unicode_file
= "UTF-8-demo.txt";
27 // A random file of binary goop
28 private const string goop_file
= "random.bin";
30 private const string image_file
= "thtbacs.tiff";
35 public VersaplexTester()
37 // Places to look for the config file.
38 string [] searchfiles
=
41 Path
.Combine("..", "versaplexd.ini")
44 string cfgfile
= null;
45 foreach (string searchfile
in searchfiles
)
46 if (File
.Exists(searchfile
))
50 throw new Exception("Cannot locate versaplexd.ini.");
52 WvIni cfg
= new WvIni(cfgfile
);
54 string uname
= Mono
.Unix
.UnixUserInfo
.GetRealUser().UserName
;
55 string dbname
= cfg
.get("User Map", uname
);
57 dbname
= cfg
.get("User Map", "*");
59 throw new Exception(String
.Format(
60 "User '{0}' (and '*') missing from config.", uname
));
62 string cfgval
= cfg
.get("Connections", dbname
);
64 throw new Exception(String
.Format(
65 "WvDbus string for '{0}' missing from config.", dbname
));
67 dbi
= WvDbi
.create(cfgval
);
68 bus
= WvDbus
.session_bus
;
77 public static string GetTempDir()
79 WvLog log
= new WvLog("GetTempDir");
80 string t
= Path
.Combine(Path
.GetTempPath(), Path
.GetRandomFileName());
81 log
.print("Using temporary directory " + t
+ "\n");
86 internal bool Exec(string query
)
88 Console
.WriteLine(" + Exec SQL Query: {0}", query
);
93 internal bool Scalar(string query
, out object result
)
95 Console
.WriteLine(" + Scalar SQL Query: {0}", query
);
96 result
= dbi
.select_one(query
).inner
;
100 internal WvAutoCast
Scalar(string query
)
102 Console
.WriteLine(" + Scalar SQL Query: {0}", query
);
103 return dbi
.select_one(query
);
106 internal WvSqlRows
Reader(string query
)
108 Console
.WriteLine(" + Reader SQL Query: {0}", query
);
109 return dbi
.select(query
);
112 protected WvDbusMsg
methodcall(string method
, string signature
)
114 return new WvDbusCall("vx.versaplexd", "/db",
115 "vx.db", method
, signature
);
118 internal bool VxExec(string query
)
120 Console
.WriteLine(" + VxExec SQL Query: {0}", query
);
122 WvDbusMsg call
= methodcall("ExecRecordset", "s");
124 WvDbusWriter mw
= new WvDbusWriter();
127 call
.Body
= mw
.ToArray();
129 WvDbusMsg reply
= bus
.send_and_wait(call
);
130 reply
.check("a(issnny)vaay");
134 internal bool VxExecSilent(string query
)
138 return VxExec(query
);
142 Console
.WriteLine(" Exception: {0}", e
.Message
);
147 internal bool VxScalar(string query
, out object result
)
149 Console
.WriteLine(" + VxScalar SQL Query: {0}", query
);
151 WvDbusMsg call
= methodcall("ExecScalar", "s");
153 WvDbusWriter mw
= new WvDbusWriter();
156 call
.Body
= mw
.ToArray();
158 WvDbusMsg reply
= bus
.send_and_wait(call
);
160 result
= reply
.iter().pop().inner
;
164 // Read the standard issnny signature for column information. We can't
165 // just read a VxColumnInfo[] straight from the reader any more, as the
166 // format of VxColumnInfo differs from the format on the wire.
167 internal VxColumnInfo
[] ReadColInfo(IEnumerable
<WvAutoCast
> rows
)
169 var colinfolist
= new List
<VxColumnInfo
>();
171 foreach (var _r
in rows
)
173 var r
= _r
.GetEnumerator();
175 string colname
= r
.pop();
176 string coltype_str
= r
.pop();
177 short precision
= r
.pop();
178 short scale
= r
.pop();
179 byte nullable
= r
.pop();
181 VxColumnType coltype
= (VxColumnType
)Enum
.Parse(
182 typeof(VxColumnType
), coltype_str
, true);
184 Console
.WriteLine("Read colname={0}, coltype={1}, nullable={2}, " +
185 "size={3}, precision={4}, scale={5}",
186 colname
, coltype
.ToString(), nullable
, size
, precision
, scale
);
188 colinfolist
.Add(new VxColumnInfo(colname
, coltype
, nullable
> 0,
189 size
, precision
, scale
));
192 return colinfolist
.ToArray();
195 internal bool VxChunkRecordset(string query
, out VxColumnInfo
[] colinfo
,
196 out object[][]data
, out bool[][] nullity
)
198 Console
.WriteLine(" + VxChunkRecordset SQL Query: {0}", query
);
200 WvDbusMsg call
= methodcall("ExecChunkRecordset", "s");
202 WvDbusWriter mw
= new WvDbusWriter();
205 call
.Body
= mw
.ToArray();
210 List
<object[]> rowlist
= new List
<object[]>();
211 List
<bool[]> rownulllist
= new List
<bool[]>();
216 WvDbusMsg tmp
= bus
.readmessage(-1);
217 if (tmp
.type
== Wv
.Dbus
.MType
.Signal
)
219 tmp
.check("a(issnny)vaayu");
220 RecordsetWorker(tmp
, out colinfo
, out tdata
, out tnullity
);
221 rowlist
.AddRange(tdata
);
222 rownulllist
.AddRange(tnullity
);
227 tmp
.check("a(issnny)vaay");
228 RecordsetWorker(tmp
, out colinfo
, out tdata
, out tnullity
);
229 rowlist
.AddRange(tdata
);
230 rownulllist
.AddRange(tnullity
);
231 //otherwise, we presume it's our method return response
232 data
= rowlist
.ToArray();
233 nullity
= rownulllist
.ToArray();
241 internal bool RecordsetWorker(WvDbusMsg reply
, out VxColumnInfo
[] _colinfo
,
242 out object[][] data
, out bool[][] nullity
)
244 if (reply
.signature
.e())
245 throw new Exception("D-Bus reply had no signature");
247 if (!reply
.signature
.StartsWith("a(issnny)vaay"))
248 throw new Exception("D-Bus reply had invalid signature");
250 var it
= reply
.iter();
252 // Read the column information
253 VxColumnInfo
[] colinfo
= _colinfo
= ReadColInfo(it
.pop());
255 // TODO: Check that variant sig matches colinfo
256 // Sig should be of the form a(...)
258 var results
= new List
<object[]>();
259 foreach (var _r
in it
.pop())
261 var r
= _r
.GetEnumerator();
262 object[] row
= new object[colinfo
.Length
];
264 for (int i
=0; i
< row
.Length
; i
++)
266 switch (colinfo
[i
].VxColumnType
)
268 case VxColumnType
.Uuid
:
269 string cell
= r
.pop();
273 row
[i
] = new Guid(cell
);
275 case VxColumnType
.DateTime
:
276 var xit
= r
.pop().GetEnumerator();
277 long seconds
= xit
.pop();
278 int microseconds
= xit
.pop();
280 VxDbusDateTime dt
= new VxDbusDateTime();
281 dt
.seconds
= seconds
;
282 dt
.microseconds
= microseconds
;
286 case VxColumnType
.Decimal
:
287 string dcell
= r
.pop();
289 row
[i
] = new Decimal();
291 row
[i
] = Decimal
.Parse(dcell
);
294 row
[i
] = r
.pop().inner
;
301 data
= results
.ToArray();
304 select (from c
in (IEnumerable
<WvAutoCast
>)rr
305 select (bool)(c
!=0)).ToArray()).ToArray();
309 internal bool VxRecordset(string query
, out VxColumnInfo
[] colinfo
,
310 out object[][] data
, out bool[][] nullity
)
312 Console
.WriteLine(" + VxReader SQL Query: {0}", query
);
314 WvDbusMsg call
= methodcall("ExecRecordset", "s");
316 WvDbusWriter mw
= new WvDbusWriter();
319 call
.Body
= mw
.ToArray();
321 WvDbusMsg reply
= bus
.send_and_wait(call
);
322 reply
.check("a(issnny)vaay");
323 return RecordsetWorker(reply
, out colinfo
, out data
, out nullity
);
326 internal bool Insert(string table
, params object [] param
)
328 Console
.WriteLine(" + Insert to {0} ({1})", table
, String
.Join(", ",
329 wv
.stringify(param
)));
331 var query
= new StringBuilder();
332 query
.AppendFormat("INSERT INTO [{0}] VALUES (",
333 table
.Replace("]","]]"));
335 for (int i
=0; i
< param
.Length
; i
++)
340 if (param
[i
] is DBNull
)
341 query
.Append("NULL");
343 query
.AppendFormat("@col{0}", i
);
348 Console
.WriteLine(" ++ ({0})", query
.ToString());
350 dbi
.exec(query
.ToString(), param
);
354 internal string read_lipsum()
356 WVASSERT(File
.Exists(lipsum_file
));
358 using (StreamReader sr
= new StreamReader(lipsum_file
)) {
359 return sr
.ReadToEnd();
363 internal string read_unicode()
365 WVASSERT(File
.Exists(unicode_file
));
367 using (StreamReader sr
= new StreamReader(unicode_file
)) {
368 return sr
.ReadToEnd();
372 internal Byte
[] read_goop()
374 WVASSERT(File
.Exists(goop_file
));
376 using (FileStream f
= new FileStream(goop_file
, FileMode
.Open
,
378 using (BinaryReader sr
= new BinaryReader(f
)) {
379 return sr
.ReadBytes((int)Math
.Min(f
.Length
, Int32
.MaxValue
));
383 internal Byte
[] read_image()
385 WVASSERT(File
.Exists(image_file
));
387 using (FileStream f
= new FileStream(image_file
, FileMode
.Open
,
389 using (BinaryReader sr
= new BinaryReader(f
)) {
390 return sr
.ReadBytes((int)Math
.Min(f
.Length
, Int32
.MaxValue
));
394 internal long GetInt64(SqlDataReader reader
, int colnum
) {
395 // For some reason, it won't just up-convert int32 to int64
396 if (reader
.GetFieldType(colnum
) == typeof(System
.Int32
)) {
397 return reader
.GetInt32(colnum
);
398 } else if (reader
.GetFieldType(colnum
) == typeof(System
.Int64
)) {
399 return reader
.GetInt64(colnum
);
400 } else if (reader
.GetFieldType(colnum
) == typeof(System
.Decimal
)) {
401 return (long)reader
.GetDecimal(colnum
);
404 bool unknown_type_in_result
= true;
405 WVFAIL(unknown_type_in_result
);