schemamatic tests: print out some error messages before reporting failure.
[versaplex.git] / versaplexd / t / schemamatic.t.cs
blobdf082c15d2f03566c704105269ae4d7bdfce5b3d
1 #include "wvtest.cs.h"
2 // Test the Schemamatic functions that live in the Versaplex daemon.
4 using System;
5 using System.IO;
6 using System.Linq;
7 using System.Text;
8 using System.Collections.Generic;
9 using System.Security.Cryptography;
10 using Wv;
11 using Wv.Extensions;
12 using Wv.Test;
13 using NDesk.DBus;
15 [TestFixture]
16 class SchemamaticTests : SchemamaticTester
18 VxDbusSchema dbus;
19 WvLog log;
21 public SchemamaticTests()
23 dbus = new VxDbusSchema(bus);
24 log = new WvLog("Schemamatic Tests");
27 // Utility function to put a single schema element.
28 // This may someday be useful to have in the VxDbusSchema class (or even
29 // in ISchemaBackend), but this implementation is a tiny bit too hacky for
30 // general consumption.
31 VxSchemaError VxPutSchema(string type, string name, string text,
32 VxPutOpts opts)
34 VxSchemaElement elem = new VxSchemaElement(type, name, text, false);
35 VxSchema schema = new VxSchema(elem);
36 VxSchemaErrors errs = VxPutSchema(schema, opts);
37 if (errs == null || errs.Count == 0)
38 return null;
40 WVPASSEQ(errs.Count, 1);
42 // Just return the first error
43 foreach (KeyValuePair<string,VxSchemaError> p in errs)
44 return p.Value;
46 WVFAIL("Shouldn't happen: couldn't find error to return");
48 return null;
51 VxSchemaErrors VxPutSchema(VxSchema schema, VxPutOpts opts)
53 log.print(" + VxPutSchema\n");
55 return dbus.Put(schema, null, opts);
58 [Test, Category("Schemamatic"), Category("GetSchemaChecksums")]
59 public void TestProcedureChecksums()
61 try { VxExec("drop procedure Func1"); } catch { }
62 try { VxExec("drop procedure EncFunc"); } catch { }
64 VxSchemaChecksums sums;
65 sums = dbus.GetChecksums();
66 if (sums.Count != 0)
68 log.print("Found entries:");
69 foreach (KeyValuePair<string,VxSchemaChecksum> p in sums)
70 log.print(p.Key);
72 //WVPASSEQ(sums.Count, 0);
74 string msg1 = "Hello, world, this is Func1!";
75 string msg2 = "Hello, world, this is Func2!";
76 object outmsg;
77 WVASSERT(VxExec("create procedure Func1 as select '" + msg1 + "'"));
78 WVASSERT(VxScalar("exec Func1", out outmsg));
79 WVPASSEQ(msg1, (string)outmsg);
81 sums = dbus.GetChecksums();
83 WVASSERT(sums.ContainsKey("Procedure/Func1"));
84 WVPASSEQ(sums["Procedure/Func1"].checksums.Count(), 1);
85 WVPASSEQ(sums["Procedure/Func1"].checksums.First(), 0x55F9D9E3);
87 WVASSERT(VxExec("create procedure EncFunc with encryption as select '" +
88 msg2 + "'"));
90 WVASSERT(VxScalar("exec EncFunc", out outmsg));
91 WVPASSEQ(msg2, (string)outmsg);
93 sums = dbus.GetChecksums();
94 //WVPASSEQ(sums.Count, 2);
96 WVASSERT(sums.ContainsKey("Procedure/Func1"));
97 WVASSERT(sums.ContainsKey("Procedure-Encrypted/EncFunc"));
98 WVPASSEQ(sums["Procedure/Func1"].checksums.Count(), 1);
99 WVPASSEQ(sums["Procedure-Encrypted/EncFunc"].checksums.Count(), 1);
100 WVPASSEQ(sums["Procedure/Func1"].checksums.First(), 0x55F9D9E3);
101 WVPASSEQ(sums["Procedure-Encrypted/EncFunc"].checksums.First(), 0xE5E9304F);
103 WVASSERT(VxExec("drop procedure EncFunc"));
105 sums = dbus.GetChecksums();
106 //WVPASSEQ(sums.Count, 1);
108 WVASSERT(sums.ContainsKey("Procedure/Func1"));
109 WVFAIL(sums.ContainsKey("Procedure/EncFunc"));
110 WVPASSEQ(sums["Procedure/Func1"].checksums.Count(), 1);
111 WVPASSEQ(sums["Procedure/Func1"].checksums.First(), 0x55F9D9E3);
113 WVASSERT(VxExec("drop procedure Func1"));
116 [Test, Category("Schemamatic"), Category("GetSchemaChecksums")]
117 public void TestTableChecksums()
119 SchemaCreator sc = new SchemaCreator(this);
120 sc.Create();
122 VxSchemaChecksums sums;
123 sums = dbus.GetChecksums();
125 // Three columns gives us three checksums
126 WVPASSEQ(sums["Table/Tab1"].checksums.Count(), 3);
127 WVPASSEQ(sums["Table/Tab1"].checksums.ElementAt(0), 0xE8634548)
128 WVPASSEQ(sums["Table/Tab1"].checksums.ElementAt(1), 0xA5F77357)
129 WVPASSEQ(sums["Table/Tab1"].checksums.ElementAt(2), 0xE50EE702)
131 WVASSERT(VxExec("drop table Tab1"));
133 sc.Cleanup();
136 [Test, Category("Schemamatic"), Category("GetSchemaChecksums")]
137 public void TestIndexChecksums()
139 try { VxExec("drop table Tab1"); } catch { }
140 string query = "CREATE TABLE [Tab1] (\n" +
141 "\t[f1] [int] NOT NULL PRIMARY KEY,\n" +
142 "\t[f2] [money] NULL,\n" +
143 "\t[f3] [varchar] (80) NULL);\n\n";
144 WVASSERT(VxExec(query));
146 query = "CREATE INDEX [Index1] ON [Tab1] (f1)";
147 WVASSERT(VxExec(query));
149 query = "CREATE INDEX [Index2] ON [Tab1] (f1, f2)";
150 WVASSERT(VxExec(query));
152 VxSchemaChecksums sums;
153 sums = dbus.GetChecksums();
155 WVPASSEQ(sums["Index/Tab1/Index1"].checksums.Count(), 1);
156 WVPASSEQ(sums["Index/Tab1/Index1"].checksums.First(), 0x62781FDD);
157 // An index on two columns will include two checksums
158 WVPASSEQ(sums["Index/Tab1/Index2"].checksums.Count(), 2);
159 WVPASSEQ(sums["Index/Tab1/Index2"].checksums.ElementAt(0), 0x603EA184);
160 WVPASSEQ(sums["Index/Tab1/Index2"].checksums.ElementAt(1), 0x8FD2C903);
162 WVASSERT(VxExec("drop table Tab1"));
165 [Test, Category("Schemamatic"), Category("GetSchemaChecksums")]
166 public void TestXmlSchemaChecksums()
168 SchemaCreator sc = new SchemaCreator(this);
169 WVASSERT(VxExec(sc.xmlq));
171 VxSchemaChecksums sums;
172 sums = dbus.GetChecksums();
174 WVPASSEQ(sums["XMLSchema/TestSchema"].checksums.Count(), 1);
175 WVPASSEQ(sums["XMLSchema/TestSchema"].checksums.First(), 4105357156);
177 WVASSERT(VxExec("drop xml schema collection TestSchema"));
179 sc.Cleanup();
182 [Test, Category("Schemamatic"), Category("GetSchema")]
183 public void TestGetProcSchema()
185 try { VxExec("drop procedure [Func1!]"); } catch { }
186 try { VxExec("drop procedure [Func2]"); } catch { }
188 string msg1 = "Hello, world, this is Func1!";
189 string msg2 = "Hello, world, this is Func2!";
190 string fmt = "create procedure [{0}] {1} as select '{2}'";
191 string query1 = String.Format(fmt, "Func1!", "", msg1);
192 string query2 = String.Format(fmt, "Func2", "with encryption", msg2);
193 object outmsg;
194 WVASSERT(VxExec(query1));
195 WVASSERT(VxScalar("exec [Func1!]", out outmsg));
196 WVPASSEQ(msg1, (string)outmsg);
198 WVASSERT(VxExec(query2));
199 WVASSERT(VxScalar("exec [Func2]", out outmsg));
200 WVPASSEQ(msg2, (string)outmsg);
202 // Check that the query limiting works. Also test that the evil
203 // character cleansing works (turning bad characters into !s)
204 VxSchema schema = dbus.Get("Procedure/Func1é");
205 WVPASSEQ(schema.Count, 1);
207 WVASSERT(schema.ContainsKey("Procedure/Func1!"));
208 WVPASSEQ(schema["Procedure/Func1!"].name, "Func1!");
209 WVPASSEQ(schema["Procedure/Func1!"].type, "Procedure");
210 WVPASSEQ(schema["Procedure/Func1!"].encrypted, false);
211 WVPASSEQ(schema["Procedure/Func1!"].text, query1);
213 schema = dbus.Get("Func1é");
214 WVPASSEQ(schema.Count, 1);
216 WVASSERT(schema.ContainsKey("Procedure/Func1!"));
217 WVPASSEQ(schema["Procedure/Func1!"].name, "Func1!");
218 WVPASSEQ(schema["Procedure/Func1!"].type, "Procedure");
219 WVPASSEQ(schema["Procedure/Func1!"].encrypted, false);
220 WVPASSEQ(schema["Procedure/Func1!"].text, query1);
222 // Also check that unlimited queries get everything
223 schema = dbus.Get();
224 WVASSERT(schema.Count >= 2);
226 WVASSERT(schema.ContainsKey("Procedure/Func1!"));
227 WVPASSEQ(schema["Procedure/Func1!"].name, "Func1!");
228 WVPASSEQ(schema["Procedure/Func1!"].type, "Procedure");
229 WVPASSEQ(schema["Procedure/Func1!"].encrypted, false);
230 WVPASSEQ(schema["Procedure/Func1!"].text, query1);
232 WVASSERT(schema.ContainsKey("Procedure-Encrypted/Func2"));
233 WVPASSEQ(schema["Procedure-Encrypted/Func2"].name, "Func2");
234 WVPASSEQ(schema["Procedure-Encrypted/Func2"].type, "Procedure");
235 WVPASSEQ(schema["Procedure-Encrypted/Func2"].encrypted, true);
236 // FIXME: Can't yet retrieve the contents of encrypted functions
237 //WVPASSEQ(schema["Procedure-Encrypted/Func2"].text, query2);
239 WVASSERT(VxExec("drop procedure [Func1!]"));
240 WVASSERT(VxExec("drop procedure [Func2]"));
243 [Test, Category("Schemamatic"), Category("GetSchema")]
244 public void TestGetIndexSchema()
246 SchemaCreator sc = new SchemaCreator(this);
247 sc.Create();
249 // Check that the query limiting works
250 VxSchema schema = dbus.Get("Index/Tab1/Idx1");
251 WVPASSEQ(schema.Count, 1);
253 WVASSERT(schema.ContainsKey("Index/Tab1/Idx1"));
254 WVPASSEQ(schema["Index/Tab1/Idx1"].name, "Tab1/Idx1");
255 WVPASSEQ(schema["Index/Tab1/Idx1"].type, "Index");
256 WVPASSEQ(schema["Index/Tab1/Idx1"].encrypted, false);
257 WVPASSEQ(schema["Index/Tab1/Idx1"].text.Length, sc.idx1q.Length);
258 WVPASSEQ(schema["Index/Tab1/Idx1"].text, sc.idx1q);
260 // Now get everything, since we don't know the primary key's name
261 schema = dbus.Get();
262 WVASSERT(schema.Count >= 2);
264 WVASSERT(schema.ContainsKey("Index/Tab1/Idx1"));
265 WVPASSEQ(schema["Index/Tab1/Idx1"].name, "Tab1/Idx1");
266 WVPASSEQ(schema["Index/Tab1/Idx1"].type, "Index");
267 WVPASSEQ(schema["Index/Tab1/Idx1"].encrypted, false);
268 WVPASSEQ(schema["Index/Tab1/Idx1"].text.Length, sc.idx1q.Length);
269 WVPASSEQ(schema["Index/Tab1/Idx1"].text, sc.idx1q);
271 CheckForPrimaryKey(schema, "Tab1");
273 sc.Cleanup();
276 [Test, Category("Schemamatic"), Category("GetSchema")]
277 public void TestGetXmlSchemas()
279 SchemaCreator sc = new SchemaCreator(this);
281 try { VxExec("drop xml schema collection TestSchema"); } catch { }
282 try { VxExec("drop xml schema collection TestSchema2"); } catch { }
284 string query1 = sc.xmlq;
285 WVASSERT(VxExec(query1));
287 // Make a long XML Schema, to test the 4000-character chunking
288 string query2 = "\nCREATE XML SCHEMA COLLECTION [dbo].[TestSchema2] AS " +
289 "'<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
290 "<xsd:element name=\"Employee\">" +
291 "<xsd:complexType>" +
292 "<xsd:complexContent>" +
293 "<xsd:restriction base=\"xsd:anyType\">" +
294 "<xsd:sequence>";
296 while (query2.Length < 8000)
297 query2 +=
298 "<xsd:element name=\"SIN\" type=\"xsd:string\"/>" +
299 "<xsd:element name=\"Name\" type=\"xsd:string\"/>" +
300 "<xsd:element name=\"DateOfBirth\" type=\"xsd:date\"/>" +
301 "<xsd:element name=\"EmployeeType\" type=\"xsd:string\"/>" +
302 "<xsd:element name=\"Salary\" type=\"xsd:long\"/>";
304 query2 += "</xsd:sequence>" +
305 "</xsd:restriction>" +
306 "</xsd:complexContent>" +
307 "</xsd:complexType>" +
308 "</xsd:element>" +
309 "</xsd:schema>'\n";
311 WVASSERT(VxExec(query2));
313 // Test that the query limiting works
314 VxSchema schema = dbus.Get("TestSchema");
315 WVPASSEQ(schema.Count, 1);
317 WVASSERT(schema.ContainsKey("XMLSchema/TestSchema"));
318 WVPASSEQ(schema["XMLSchema/TestSchema"].name, "TestSchema");
319 WVPASSEQ(schema["XMLSchema/TestSchema"].type, "XMLSchema");
320 WVPASSEQ(schema["XMLSchema/TestSchema"].encrypted, false);
321 WVPASSEQ(schema["XMLSchema/TestSchema"].text, query1);
323 schema = dbus.Get("XMLSchema/TestSchema");
324 WVPASSEQ(schema.Count, 1);
326 WVASSERT(schema.ContainsKey("XMLSchema/TestSchema"));
327 WVPASSEQ(schema["XMLSchema/TestSchema"].name, "TestSchema");
328 WVPASSEQ(schema["XMLSchema/TestSchema"].type, "XMLSchema");
329 WVPASSEQ(schema["XMLSchema/TestSchema"].encrypted, false);
330 WVPASSEQ(schema["XMLSchema/TestSchema"].text, query1);
332 // Also check that unlimited queries get everything
333 schema = dbus.Get();
334 WVASSERT(schema.Count >= 2)
336 WVASSERT(schema.ContainsKey("XMLSchema/TestSchema"));
337 WVPASSEQ(schema["XMLSchema/TestSchema"].name, "TestSchema");
338 WVPASSEQ(schema["XMLSchema/TestSchema"].type, "XMLSchema");
339 WVPASSEQ(schema["XMLSchema/TestSchema"].encrypted, false);
340 WVPASSEQ(schema["XMLSchema/TestSchema"].text, query1);
342 WVASSERT(schema.ContainsKey("XMLSchema/TestSchema2"));
343 WVPASSEQ(schema["XMLSchema/TestSchema2"].name, "TestSchema2");
344 WVPASSEQ(schema["XMLSchema/TestSchema2"].type, "XMLSchema");
345 WVPASSEQ(schema["XMLSchema/TestSchema2"].encrypted, false);
346 WVPASSEQ(schema["XMLSchema/TestSchema2"].text, query2);
348 WVASSERT(VxExec("drop xml schema collection TestSchema"));
349 WVASSERT(VxExec("drop xml schema collection TestSchema2"));
352 [Test, Category("Schemamatic"), Category("GetSchema")]
353 public void TestGetTableSchema()
355 try { VxExec("drop table Table1"); } catch { }
356 string query = "CREATE TABLE [Table1] (\n\t" +
357 "[f1] [int] NOT NULL PRIMARY KEY,\n\t" +
358 "[f2] [money] NULL,\n\t" +
359 "[f3] [varchar] (80) NOT NULL,\n\t" +
360 "[f4] [varchar] (max) DEFAULT 'Default Value' NULL,\n\t" +
361 "[f5] [decimal] (3,2),\n\t" +
362 "[f6] [bigint] NOT NULL IDENTITY(4, 5));\n\n";
363 WVASSERT(VxExec(query));
365 VxSchema schema = dbus.Get();
366 WVASSERT(schema.Count >= 2);
368 // Primary keys get returned as indexes, not in the CREATE TABLE
369 string result = query.Replace(" PRIMARY KEY", "");
370 // Check that columns default to nullable
371 result = result.Replace("[f5] [decimal] (3,2)",
372 "[f5] [decimal] (3,2) NULL");
374 WVASSERT(schema.ContainsKey("Table/Table1"));
375 WVPASSEQ(schema["Table/Table1"].name, "Table1");
376 WVPASSEQ(schema["Table/Table1"].type, "Table");
377 WVPASSEQ(schema["Table/Table1"].encrypted, false);
378 WVPASSEQ(schema["Table/Table1"].text, result);
380 CheckForPrimaryKey(schema, "Table1");
382 try { VxExec("drop table Table1"); } catch { }
385 [Test, Category("Schemamatic"), Category("DropSchema")]
386 public void TestDropSchema()
388 SchemaCreator sc = new SchemaCreator(this);
390 sc.Create();
392 VxSchemaChecksums sums = dbus.GetChecksums();
394 WVASSERT(sums.ContainsKey("Index/Tab1/Idx1"));
395 WVASSERT(sums.ContainsKey("Procedure/Func1"));
396 WVASSERT(sums.ContainsKey("ScalarFunction/Func2"));
397 WVASSERT(sums.ContainsKey("Table/Tab1"));
398 WVASSERT(sums.ContainsKey("Table/Tab2"));
399 WVASSERT(sums.ContainsKey("XMLSchema/TestSchema"));
401 dbus.DropSchema("Index/Tab1/Idx1", "Procedure/Func1",
402 "ScalarFunction/Func2", "Table/Tab2", "XMLSchema/TestSchema");
404 sums = dbus.GetChecksums();
406 WVASSERT(!sums.ContainsKey("Index/Tab1/Idx1"));
407 WVASSERT(!sums.ContainsKey("Procedure/Func1"));
408 WVASSERT(!sums.ContainsKey("ScalarFunction/Func2"));
409 WVASSERT(sums.ContainsKey("Table/Tab1"));
410 WVASSERT(!sums.ContainsKey("Table/Tab2"));
411 WVASSERT(!sums.ContainsKey("XMLSchema/TestSchema"));
413 VxSchemaErrors errs = dbus.DropSchema("Procedure/Func1");
414 WVPASSEQ(errs.Count, 1);
415 WVPASSEQ(errs["Procedure/Func1"].msg,
416 "Cannot drop the procedure 'Func1', because it does not exist " +
417 "or you do not have permission.");
419 sc.Cleanup();
422 [Test, Category("Schemamatic"), Category("PutSchema")]
423 public void TestPutSchema()
425 SchemaCreator sc = new SchemaCreator(this);
427 VxPutOpts no_opts = VxPutOpts.None;
428 WVPASSEQ(VxPutSchema("Table", "Tab1", sc.tab1q, no_opts), null);
429 WVPASSEQ(VxPutSchema("Index", "Tab1/Idx1", sc.idx1q, no_opts), null);
430 WVPASSEQ(VxPutSchema("Procedure", "Func1", sc.func1q, no_opts), null);
431 WVPASSEQ(VxPutSchema("XMLSchema", "TestSchema", sc.xmlq, no_opts), null);
433 VxSchema schema = dbus.Get();
435 WVASSERT(schema.ContainsKey("Index/Tab1/Idx1"));
436 WVPASSEQ(schema["Index/Tab1/Idx1"].name, "Tab1/Idx1");
437 WVPASSEQ(schema["Index/Tab1/Idx1"].type, "Index");
438 WVPASSEQ(schema["Index/Tab1/Idx1"].text, sc.idx1q);
439 WVASSERT(schema.ContainsKey("Procedure/Func1"));
440 WVPASSEQ(schema["Procedure/Func1"].name, "Func1");
441 WVPASSEQ(schema["Procedure/Func1"].type, "Procedure");
442 WVPASSEQ(schema["Procedure/Func1"].text, sc.func1q);
443 WVASSERT(schema.ContainsKey("Table/Tab1"));
444 WVPASSEQ(schema["Table/Tab1"].name, "Tab1");
445 WVPASSEQ(schema["Table/Tab1"].type, "Table");
446 WVPASSEQ(schema["Table/Tab1"].text, sc.tab1q_nopk);
447 WVASSERT(schema.ContainsKey("XMLSchema/TestSchema"));
448 WVPASSEQ(schema["XMLSchema/TestSchema"].name, "TestSchema");
449 WVPASSEQ(schema["XMLSchema/TestSchema"].type, "XMLSchema");
450 WVPASSEQ(schema["XMLSchema/TestSchema"].text, sc.xmlq);
452 string tab1q2 = "CREATE TABLE [Tab1] (\n\t" +
453 "[f4] [binary] (1) NOT NULL);\n\n";
455 VxSchemaError err = VxPutSchema("Table", "Tab1", tab1q2, no_opts);
456 WVPASS(err != null);
457 WVPASSEQ(err.key, "Table/Tab1");
458 WVPASSEQ(err.msg,
459 "There is already an object named 'Tab1' in the database.");
460 WVPASSEQ(err.errnum, 2714);
462 schema = dbus.Get("Table/Tab1");
463 WVPASSEQ(schema["Table/Tab1"].name, "Tab1");
464 WVPASSEQ(schema["Table/Tab1"].type, "Table");
465 WVPASSEQ(schema["Table/Tab1"].text, sc.tab1q_nopk);
467 WVPASSEQ(VxPutSchema("Table", "Tab1", tab1q2, VxPutOpts.Destructive),
468 null);
470 schema = dbus.Get("Table/Tab1");
471 WVPASSEQ(schema["Table/Tab1"].name, "Tab1");
472 WVPASSEQ(schema["Table/Tab1"].type, "Table");
473 WVPASSEQ(schema["Table/Tab1"].text, tab1q2);
475 string msg2 = "This is definitely not the Func1 you thought you knew.";
476 string func1q2 = "create procedure Func1 as select '" + msg2 + "'";
477 WVPASSEQ(VxPutSchema("Procedure", "Func1", func1q2, no_opts), null);
479 schema = dbus.Get("Procedure/Func1");
480 WVPASSEQ(schema["Procedure/Func1"].name, "Func1");
481 WVPASSEQ(schema["Procedure/Func1"].type, "Procedure");
482 WVPASSEQ(schema["Procedure/Func1"].text, func1q2);
484 sc.Cleanup();
487 [Test, Category("Schemamatic"), Category("SchemaData")]
488 public void TestSchemaData()
490 SchemaCreator sc = new SchemaCreator(this);
492 WVPASSEQ(VxPutSchema("Table", "Tab1", sc.tab1q, VxPutOpts.None), null);
494 List<string> inserts = new List<string>();
495 for (int ii = 0; ii < 22; ii++)
497 inserts.Add(String.Format("INSERT INTO Tab1 ([f1],[f2],[f3]) " +
498 "VALUES ({0},{1},'{2}');\n",
499 ii, ii + ".3400", "Hi" + ii));
502 inserts.Add("INSERT INTO Tab1 ([f1],[f2],[f3]) " +
503 "VALUES (100,NULL,'');\n");
504 inserts.Add("INSERT INTO Tab1 ([f1],[f2],[f3]) " +
505 "VALUES (101,NULL," +
506 "'This string''s good for \"testing\" escaping, isn''t it?');\n");
508 foreach (string ins in inserts)
509 WVASSERT(VxExec(ins));
511 WVPASSEQ(dbus.GetSchemaData("Tab1", 0, ""), inserts.Join(""));
513 VxExec("drop table Tab1");
515 try {
516 WVEXCEPT(dbus.GetSchemaData("Tab1", 0, ""));
517 } catch (Wv.Test.WvAssertionFailure e) {
518 throw e;
519 } catch (System.Exception e) {
520 WVPASS(e is DbusError);
521 WVPASSEQ(e.Message, "vx.db.sqlerror: Invalid object name 'Tab1'.");
522 log.print(e.ToString() + "\n");
525 WVPASSEQ(VxPutSchema("Table", "Tab1", sc.tab1q, VxPutOpts.None), null);
527 WVPASSEQ(dbus.GetSchemaData("Tab1", 0, ""), "");
529 dbus.PutSchemaData("Tab1", inserts.Join(""), 0);
530 WVPASSEQ(dbus.GetSchemaData("Tab1", 0, ""), inserts.Join(""));
532 WVPASSEQ(dbus.GetSchemaData("Tab1", 0, "f1 = 11"),
533 "INSERT INTO Tab1 ([f1],[f2],[f3]) VALUES (11,11.3400,'Hi11');\n");
535 sc.Cleanup();
538 [Test, Category("Schemamatic"), Category("VxSchemaDiff")]
539 public void TestChecksumDiff()
541 VxSchemaChecksums srcsums = new VxSchemaChecksums();
542 VxSchemaChecksums goalsums = new VxSchemaChecksums();
543 VxSchemaChecksums emptysums = new VxSchemaChecksums();
545 srcsums.AddSum("XMLSchema/secondxml", 2);
546 srcsums.AddSum("XMLSchema/firstxml", 1);
547 srcsums.AddSum("Index/Tab1/ConflictIndex", 3);
548 srcsums.AddSum("Table/HarmonyTable", 6);
550 goalsums.AddSum("Table/NewTable", 3);
551 goalsums.AddSum("Procedure/NewFunc", 4);
552 goalsums.AddSum("Index/Tab1/ConflictIndex", 5);
553 goalsums.AddSum("Table/HarmonyTable", 6);
555 VxSchemaDiff diff = new VxSchemaDiff(srcsums, goalsums);
557 string expected = "- XMLSchema/firstxml\n" +
558 "- XMLSchema/secondxml\n" +
559 "+ Table/NewTable\n" +
560 "* Index/Tab1/ConflictIndex\n" +
561 "+ Procedure/NewFunc\n";
562 WVPASSEQ(diff.ToString(), expected);
564 // Check that the internal order matches the string's order.
565 WVPASSEQ(diff.ElementAt(0).Key, "XMLSchema/firstxml");
566 WVPASSEQ(diff.ElementAt(1).Key, "XMLSchema/secondxml");
567 WVPASSEQ(diff.ElementAt(2).Key, "Table/NewTable");
568 WVPASSEQ(diff.ElementAt(3).Key, "Index/Tab1/ConflictIndex");
569 WVPASSEQ(diff.ElementAt(4).Key, "Procedure/NewFunc");
571 // Check that a comparison with an empty set of sums returns the other
572 // side, sorted.
573 diff = new VxSchemaDiff(srcsums, emptysums);
574 expected = "- XMLSchema/firstxml\n" +
575 "- XMLSchema/secondxml\n" +
576 "- Table/HarmonyTable\n" +
577 "- Index/Tab1/ConflictIndex\n";
578 WVPASSEQ(diff.ToString(), expected);
580 diff = new VxSchemaDiff(emptysums, goalsums);
581 expected = "+ Table/HarmonyTable\n" +
582 "+ Table/NewTable\n" +
583 "+ Index/Tab1/ConflictIndex\n" +
584 "+ Procedure/NewFunc\n";
585 WVPASSEQ(diff.ToString(), expected);
588 public void TestApplySchemaDiff(ISchemaBackend backend)
590 log.print("In TestApplySchemaDiff({0})\n", backend.GetType().ToString());
591 SchemaCreator sc = new SchemaCreator(this);
592 sc.Create();
594 string msg2 = "Hello, world, this used to be Func1!";
595 string func1q2 = "create procedure Func1 as select '" + msg2 + "'\n";
597 VxSchema origschema = dbus.Get();
598 VxSchemaChecksums origsums = dbus.GetChecksums();
599 VxSchema newschema = new VxSchema(origschema);
600 VxSchemaChecksums newsums = new VxSchemaChecksums(origsums);
602 // Don't bother putting the data again if we're talking to dbus:
603 // we already snuck it in the back door.
604 if (backend != dbus)
605 backend.Put(origschema, origsums, VxPutOpts.None);
607 VxSchemaChecksums diffsums = new VxSchemaChecksums(newsums);
609 newschema["Procedure/Func1"].text = func1q2;
610 newsums.AddSum("Procedure/Func1", 123);
611 newsums.Remove("XMLSchema/TestSchema");
612 origsums.Remove("Index/Tab1/Idx1");
614 VxSchemaDiff diff = new VxSchemaDiff(origsums, newsums);
615 using (IEnumerator<KeyValuePair<string,VxDiffType>> iter =
616 diff.GetEnumerator())
618 WVPASS(iter.MoveNext());
619 WVPASSEQ(iter.Current.Key, "XMLSchema/TestSchema");
620 WVPASSEQ((char)iter.Current.Value, (char)VxDiffType.Remove);
621 WVPASS(iter.MoveNext());
622 WVPASSEQ(iter.Current.Key, "Index/Tab1/Idx1");
623 WVPASSEQ((char)iter.Current.Value, (char)VxDiffType.Add);
624 WVPASS(iter.MoveNext());
625 WVPASSEQ(iter.Current.Key, "Procedure/Func1");
626 WVPASSEQ((char)iter.Current.Value, (char)VxDiffType.Change);
627 WVFAIL(iter.MoveNext());
630 VxSchema diffschema = newschema.GetDiffElements(diff);
631 WVPASSEQ(diffschema["XMLSchema/TestSchema"].type, "XMLSchema");
632 WVPASSEQ(diffschema["XMLSchema/TestSchema"].name, "TestSchema");
633 WVPASSEQ(diffschema["XMLSchema/TestSchema"].text, "");
634 WVPASSEQ(diffschema["Index/Tab1/Idx1"].type, "Index");
635 WVPASSEQ(diffschema["Index/Tab1/Idx1"].name, "Tab1/Idx1");
636 WVPASSEQ(diffschema["Index/Tab1/Idx1"].text, sc.idx1q);
637 WVPASSEQ(diffschema["Procedure/Func1"].type, "Procedure");
638 WVPASSEQ(diffschema["Procedure/Func1"].name, "Func1");
639 WVPASSEQ(diffschema["Procedure/Func1"].text, func1q2);
641 VxSchemaErrors errs = backend.Put(diffschema, diffsums, VxPutOpts.None);
642 WVPASSEQ(errs.Count, 0);
644 VxSchema updated = backend.Get(null);
645 WVASSERT(!updated.ContainsKey("XMLSchema/TestSchema"));
646 WVPASSEQ(updated["Index/Tab1/Idx1"].text,
647 newschema["Index/Tab1/Idx1"].text);
648 WVPASSEQ(updated["Procedure/Func1"].text,
649 newschema["Procedure/Func1"].text);
650 WVPASSEQ(updated["Table/Tab1"].text, newschema["Table/Tab1"].text);
652 sc.Cleanup();
655 [Test, Category("Schemamatic"), Category("PutSchema")]
656 public void TestApplySchemaDiff()
658 log.print("Testing applying diffs through DBus");
659 TestApplySchemaDiff(dbus);
661 log.print("Testing applying diffs to the disk");
663 string tmpdir = GetTempDir();
666 Directory.CreateDirectory(tmpdir);
667 VxDiskSchema disk = new VxDiskSchema(tmpdir);
669 TestApplySchemaDiff(disk);
671 finally
673 Directory.Delete(tmpdir, true);
674 WVPASS(!Directory.Exists(tmpdir));
678 [Test, Category("Schemamatic"), Category("PutSchema")]
679 public void TestPutSchemaErrors()
681 SchemaCreator sc = new SchemaCreator(this);
683 // FIXME: Test with all the SchemaCreator elements
684 WVASSERT(VxExec(sc.tab1q));
685 WVASSERT(VxExec(sc.tab2q));
687 VxSchema schema = dbus.Get();
688 VxPutOpts no_opts = VxPutOpts.None;
689 VxSchemaErrors errs = VxPutSchema(schema, no_opts);
691 log.print("Results: [\n{0}]\n", errs.Join("'\n'"));
692 WVPASSEQ(errs.Count, 2);
693 WVPASSEQ(errs["Table/Tab1"].key, "Table/Tab1");
694 WVPASSEQ(errs["Table/Tab1"].msg,
695 "There is already an object named 'Tab1' in the database.");
696 WVPASSEQ(errs["Table/Tab1"].errnum, 2714);
697 WVPASSEQ(errs["Table/Tab2"].key, "Table/Tab2");
698 WVPASSEQ(errs["Table/Tab2"].msg,
699 "There is already an object named 'Tab2' in the database.");
700 WVPASSEQ(errs["Table/Tab2"].errnum, 2714);
702 sc.Cleanup();
705 [Test, Category("Schemamatic"), Category("PutSchema")]
706 public void TestPutSchemaRetry()
708 try { VxExec("drop view View1"); } catch { }
709 try { VxExec("drop view View2"); } catch { }
710 try { VxExec("drop view View3"); } catch { }
711 try { VxExec("drop view View4"); } catch { }
713 // Create the views in the wrong order, so it'll take a few tries
714 // to get them all working. The server seems to sort them
715 // alphabetically when it runs them, though this isn't a guarantee.
716 string view1q = "create view View1 as select * from View2";
717 string view2q = "create view View2 as select * from View3";
718 string view3q = "create view View3 as select * from View4";
719 string view4q = "create view View4(viewcol1) as select 42";
721 VxSchema schema = new VxSchema();
722 schema.Add("View", "View1", view1q, false);
723 schema.Add("View", "View2", view2q, false);
724 schema.Add("View", "View3", view3q, false);
725 schema.Add("View", "View4", view4q, false);
727 VxSchemaErrors errs = VxPutSchema(schema, VxPutOpts.NoRetry);
729 WVPASSEQ(errs.Count, 3);
730 WVPASSEQ(errs["View/View1"].key, "View/View1");
731 WVPASSEQ(errs["View/View2"].key, "View/View2");
732 WVPASSEQ(errs["View/View3"].key, "View/View3");
733 WVPASSEQ(errs["View/View1"].msg, "Invalid object name 'View2'.");
734 WVPASSEQ(errs["View/View2"].msg, "Invalid object name 'View3'.");
735 WVPASSEQ(errs["View/View3"].msg, "Invalid object name 'View4'.");
736 WVPASSEQ(errs["View/View1"].errnum, 208);
737 WVPASSEQ(errs["View/View2"].errnum, 208);
738 WVPASSEQ(errs["View/View3"].errnum, 208);
740 try { VxExec("drop view View4"); } catch { }
741 errs = VxPutSchema(schema, VxPutOpts.None);
742 WVPASSEQ(errs.Count, 0);
744 object result;
745 WVASSERT(VxScalar("select viewcol1 from View1;", out result));
746 WVPASSEQ((int)result, 42);
748 try { VxExec("drop view View1"); } catch { }
749 try { VxExec("drop view View2"); } catch { }
750 try { VxExec("drop view View3"); } catch { }
751 try { VxExec("drop view View4"); } catch { }
754 // Make sure we can insert double-quoted strings, i.e. that
755 // the database has done a "set quoted_identifiers off"
756 [Test, Category("Schemamatic"), Category("PutSchema")]
757 public void TestQuotedIdentifiers()
759 try { VxExec("drop procedure Proc1"); } catch { }
761 string quote_proc = "create procedure Proc1 as " +
762 "select \"I'm a double-quoted string!\"\n";
763 VxSchema schema = new VxSchema();
764 schema.Add("Procedure", "Proc1", quote_proc, false);
766 VxSchemaErrors errs = VxPutSchema(schema, VxPutOpts.None);
768 WVPASSEQ(errs.Count, 0);
770 try { VxExec("drop procedure Proc1"); } catch { }
773 public static void Main()
775 WvTest.DoMain();