Add copyright notices to all source files and put a license in LICENSE.
[versaplex.git] / versaplexd / t / versaplextester.cs
blob4e20537160af3b4841215dfebd3f2070a3e18cfa
1 /*
2 * Versaplex:
3 * Copyright (C)2007-2008 Versabanq Innovations Inc. and contributors.
4 * See the included file named LICENSE for license information.
5 */
6 #include "wvtest.cs.h"
8 using System;
9 using System.Data.SqlClient;
10 using System.Collections.Generic;
11 using System.IO;
12 using System.Linq;
13 using System.Text;
14 using Wv;
15 using Wv.Test;
16 using Wv.Extensions;
18 // Several mono bugs worked around in this test fixture are filed as mono bug
19 // #81940
21 public class VersaplexTester: IDisposable
23 // A file full of "lorem ipsum dolor" text
24 private const string lipsum_file = "lipsum.txt";
25 // A UTF-8 test file
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";
29 // THTBACS image
30 private const string image_file = "thtbacs.tiff";
32 public WvDbi dbi;
33 protected WvDbus bus;
35 public VersaplexTester()
37 // Places to look for the config file.
38 string [] searchfiles =
40 "versaplexd.ini",
41 Path.Combine("..", "versaplexd.ini")
44 string cfgfile = null;
45 foreach (string searchfile in searchfiles)
46 if (File.Exists(searchfile))
47 cfgfile = searchfile;
49 if (cfgfile == null)
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);
56 if (dbname == null)
57 dbname = cfg.get("User Map", "*");
58 if (dbname == null)
59 throw new Exception(String.Format(
60 "User '{0}' (and '*') missing from config.", uname));
62 string cfgval = cfg.get("Connections", dbname);
63 if (cfgval == null)
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;
71 public void Dispose()
73 bus = null;
74 dbi.Dispose();
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");
83 return t;
86 internal bool Exec(string query)
88 Console.WriteLine(" + Exec SQL Query: {0}", query);
89 dbi.exec(query);
90 return true;
93 internal bool Scalar(string query, out object result)
95 Console.WriteLine(" + Scalar SQL Query: {0}", query);
96 result = dbi.select_one(query).inner;
97 return true;
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();
125 mw.Write(query);
127 call.Body = mw.ToArray();
129 WvDbusMsg reply = bus.send_and_wait(call);
130 reply.check("a(issnny)vaay");
131 return true;
134 internal bool VxExecSilent(string query)
138 return VxExec(query);
140 catch (Exception e)
142 Console.WriteLine(" Exception: {0}", e.Message);
143 return true;
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();
154 mw.Write(query);
156 call.Body = mw.ToArray();
158 WvDbusMsg reply = bus.send_and_wait(call);
159 reply.check("v");
160 result = reply.iter().pop().inner;
161 return true;
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();
174 int size = r.pop();
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();
203 mw.Write(query);
205 call.Body = mw.ToArray();
207 bus.send(call);
209 colinfo = null;
210 List<object[]> rowlist = new List<object[]>();
211 List<bool[]> rownulllist = new List<bool[]>();
212 while (true)
214 object[][] tdata;
215 bool[][] tnullity;
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);
224 else
226 //Method return
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();
234 break;
238 return true;
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();
270 if (cell == "")
271 row[i] = new Guid();
272 else
273 row[i] = new Guid(cell);
274 break;
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;
284 row[i] = dt;
285 break;
286 case VxColumnType.Decimal:
287 string dcell = r.pop();
288 if (dcell == "")
289 row[i] = new Decimal();
290 else
291 row[i] = Decimal.Parse(dcell);
292 break;
293 default:
294 row[i] = r.pop().inner;
295 break;
298 results.Add(row);
301 data = results.ToArray();
302 nullity =
303 (from rr in it.pop()
304 select (from c in (IEnumerable<WvAutoCast>)rr
305 select (bool)(c!=0)).ToArray()).ToArray();
306 return true;
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();
317 mw.Write(query);
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++)
337 if (i > 0)
338 query.Append(", ");
340 if (param[i] is DBNull)
341 query.Append("NULL");
342 else
343 query.AppendFormat("@col{0}", i);
346 query.Append(")");
348 Console.WriteLine(" ++ ({0})", query.ToString());
350 dbi.exec(query.ToString(), param);
351 return true;
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,
377 FileAccess.Read))
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,
388 FileAccess.Read))
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);
402 } else {
403 // Unknown type
404 bool unknown_type_in_result = true;
405 WVFAIL(unknown_type_in_result);
407 return -1;