<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://opensimulator.org/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://opensimulator.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mikem</id>
		<title>OpenSimulator - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="http://opensimulator.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mikem"/>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Special:Contributions/Mikem"/>
		<updated>2026-06-13T17:29:40Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.19.9</generator>

	<entry>
		<id>http://opensimulator.org/wiki/Development_Team</id>
		<title>Development Team</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Development_Team"/>
				<updated>2010-06-08T09:38:00Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* Active OpenSim Core Developers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{Template:Quicklinks}}&lt;br /&gt;
&lt;br /&gt;
[[Technical Reference | Technical Reference]] -&amp;gt; [[Technical Reference/terms | Terms]] -&amp;gt; [[Development_Team | Core Development Team]]&lt;br /&gt;
&lt;br /&gt;
== Active OpenSim Core Developers ==&lt;br /&gt;
These people have commit access to our central SVN server and are [http://www.ohloh.net/projects/4753/contributors regular contributors] to the codebase.&lt;br /&gt;
** '''Only voted in developers should be listed here, please do not list yourself''' &lt;br /&gt;
(please add in as much info as you like for your name) &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot; class=&amp;quot;sortable&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Photo &amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;IRC Nick &amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;SL Avatar&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Other Grid&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Time Zone&amp;lt;br&amp;gt;(UTC)&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Org&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Areas of Interest&amp;lt;/th&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:MW |MW ]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Darren&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Wright Juran&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;0&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Everything&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:Adam Frisby|Adam Frisby]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Adam Frisby&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Adam Zaius&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;+8&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;DeepThink Pty Ltd&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Terrain, Performance&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:MingChen|MingChen]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Mike/Michael Ortman&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Ming Chen&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;-6 (-5 in Summer)&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;DeepThink Pty Ltd&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Estate/Parcel Support/Modules/Keeping things all neat and tidy.&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt; &lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:SeanDague|sdague]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Sean Dague&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Neas Bade&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;-5&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;IBM&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Database, Linux, Testing, Misc&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:Tedd|Tedd]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Tedd Hansen&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Tedd Maa&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;+1&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Tedd Hansen&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Programming/Scripting/Architecture&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;ckrinke&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Charles&amp;amp;nbsp;Krinke&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Charlesk&amp;amp;nbsp;Bing&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;-8&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Reliability/Grid servers/ll-functions&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:chi11ken|chi11ken]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Jeff Ames&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Chillken Proto&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;+9&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[http://www.genkii.com Genkii]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:adjohn|adjohn]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Adam Johnson&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Zeuz Zenovka&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;+9&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[http://www.genkii.com Genkii]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:joha1|joha1]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Johan Berntsson&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Joppi Brandenburg&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;+9&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[http://www.3di.jp/en/ 3Di Inc, Japan]&amp;lt;br/&amp;gt;http://www.3di.jp/en/&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Performance, packet handling/libSL&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:Teravus|Teravus]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Daniel Olivares&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Teravus Ousley&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;-5&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;W3z&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Physics &amp;amp; Admin tools, A working sim.&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:justincc|justincc]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Justin Clark-Casey&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Lulworth Beaumont&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Justin Clark-Casey (all other grids)&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;0&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[http://justincc.org/blog justincc's OpenSim blog]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Grid, performance &amp;amp; reliability, inventory (avatar and object), assets, scenes, OARs, etc.&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:DrScofield|drscofld]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Dirk Husemann&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Dr Scofield&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;+1&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[http://xyzzyxyzzy.net/ xyzzyxyzzy.net]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Reliability, networking protocols, inventory, assets, remote control, voice, and pretty much everything else :-)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:dahlia|dahlia]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;T. Hoff&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Dahlia Trimble&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;-8 / -7&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Independent&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Collision geometry, various math and physics issues, occasional bug fixes and random enhancements&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:Mikem|mikem]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Mike Mazur&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;+9&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Independent&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Patches, scripting improvements, LSL compiler&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:Melanie_T|Melanie_T]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Melanie&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Melanie Milland&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;+1&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Independent&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Scripting, Prims/Scene, Life, The Universe, and Everything&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:HomerHorwitz|homerh]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Homer Horwitz&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Homer Horwitz&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;+2&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Independent&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Rev. engineering, &amp;quot;now, that's funny&amp;quot; problems, but still interested in all parts of it&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:Diva|Diva]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Crista Lopes&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Diva Canto&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Crista Lopes / Diva Canto&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;-8&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;University of California, Irvine&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Everything, except databases&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:nlin|nlin]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;N Lin&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Standard Drucker&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;+9&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[http://www.3di.jp/en/ 3Di Inc, Japan]&amp;lt;br/&amp;gt;http://www.3di.jp/en/&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Physics, scripting, more to come&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:arthursv|arthursv]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Arthur Valadares&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Arthur Valadares&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;NONE&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;-3&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;IBM&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Unit testing, database plugins, bug fixes, general &amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Retired OpenSim core developers ==&lt;br /&gt;
&lt;br /&gt;
These people are core developers who have transcended our mortal plane (i.e. they are no longer active).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot; class=&amp;quot;sortable&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Photo &amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;IRC Nick &amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;SL Avatar&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Other Grid&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Time Zone&amp;lt;br&amp;gt;(UTC)&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Org&amp;lt;/th&amp;gt;&lt;br /&gt;
  &amp;lt;th&amp;gt;Areas of Interest&amp;lt;/th&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:babblefrog|babblefrog]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Brian McBee&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Dogen Coldstream&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Babblefrog Ballistic (osgrid)&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;-8&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Disorganized&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:danx0r|danx0r]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Dan Miller&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Albert Pascal&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;-8&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;squiggle.com&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;PHEEZIKS; everything&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Tleiades&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Tleiades&amp;amp;nbsp;Hax&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;+1&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Grid servers/Database&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:Darok|Darok]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Darok Kaminski&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;+1&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Physics engines (especially BulletX)&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Gareth / Gwen&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Gareth Nelson&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Gareth Ellison&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Gareth Nelson (on everywhere but SL)&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;BST (UTC+1)&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Litesim Ltd&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Grid servers, sim border crossing, avatar animations&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:dalien|dalien]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Dalien Talbot&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Dalien Talbot&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;+1&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Mostly TCP-based&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Small fixes; rev.eng./prototyping; nightlies; git-keeper &amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td /&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[Alondria]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Alondria LeFay&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Alondria LeFay (OSGrid)&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;-8&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Independent&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Implementation of LSL functions and other scripting tidbits.&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[[User:lbsa71|lbsa71]]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Stefan Andersson&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Tribal Skytower&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;OSG:Stefan Andersson&amp;lt;br/&amp;gt;TN:Stefan Andersson&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;+1&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;[http://tribalmedia.se/ Tribal Media AB]&amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;Web Integration&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Additional Developers/Testers/Contributors  ==&lt;br /&gt;
&lt;br /&gt;
These people have contributed bug reports, patches or other contributions to OpenSim. &amp;lt;br&amp;gt; '''New comers please add yourself to bottom of the list!''' &lt;br /&gt;
&lt;br /&gt;
{| cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;2&amp;quot; border=&amp;quot;1&amp;quot; class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! IRC Nick &lt;br /&gt;
! Name &lt;br /&gt;
! SL Avatar &lt;br /&gt;
! Other Grid &lt;br /&gt;
! Time Zone&amp;lt;br&amp;gt;(UTC) &lt;br /&gt;
! Org &lt;br /&gt;
! Areas of Interest&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Nebadon|Nebadon]] &lt;br /&gt;
| Michael Cerquoni &lt;br /&gt;
| Nebadon Izumi &lt;br /&gt;
| Nebadon Izumi &lt;br /&gt;
| -7 Arizona &lt;br /&gt;
| Oni Kenkon Creations &lt;br /&gt;
| Building, Scripting, Testing&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Jtclark48|jclark4]] &lt;br /&gt;
| Jay Clark &lt;br /&gt;
| Jay Clarke &lt;br /&gt;
| &lt;br /&gt;
| -5 &lt;br /&gt;
| IBM &lt;br /&gt;
| Physics, Grid Host, AI, Scripting, Testing&lt;br /&gt;
|-&lt;br /&gt;
| [[User:AdamStevenson|BigFootAg]] &lt;br /&gt;
| Adam Stevenson &lt;br /&gt;
| Adamus Petrov &lt;br /&gt;
| &lt;br /&gt;
| -6 &lt;br /&gt;
| Texas A&amp;amp;amp;M University &lt;br /&gt;
| AI, Skynet, Evolving Systems, Biology&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Jeff1564|Jeff1564]] &lt;br /&gt;
| Jeff &lt;br /&gt;
| Potter Taurog &lt;br /&gt;
| Potter Taurog &lt;br /&gt;
| -8 &lt;br /&gt;
| http://myopengrid.com&lt;br /&gt;
| Building, Scripting, Testing&lt;br /&gt;
|-&lt;br /&gt;
| Rock_Vacirca &lt;br /&gt;
| Colin Withers &lt;br /&gt;
| Rock Vacirca &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| +1 &lt;br /&gt;
| http://rock-vacirca.blogspot.com &lt;br /&gt;
| Testing, building, scripting, maintaining an opensim blog.&lt;br /&gt;
|-&lt;br /&gt;
| simsim &lt;br /&gt;
| caocao &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| +9 &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| Testing whole functions of OpenSim system,working with OpenSim-Engine,reporting on OpenSim&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Vicero Lambert|Vicero Lambert]] &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Magi|Magi]] &lt;br /&gt;
| Andy Agnew &lt;br /&gt;
| Magi Merlin &lt;br /&gt;
| &lt;br /&gt;
| +10 &lt;br /&gt;
| Spun Pty Ltd &lt;br /&gt;
| 3D Web Integration, Database stuff and playing with the odds and ends box.&lt;br /&gt;
|-&lt;br /&gt;
| [[User:ClarkZone|ClarkZone]] &lt;br /&gt;
| Troy Admin(@ClarkZone) &lt;br /&gt;
| Troy Childs &lt;br /&gt;
| Troy Admin (ClarkZone) &lt;br /&gt;
| -5 &lt;br /&gt;
| Http://clarkzone.dyndns.org &lt;br /&gt;
| Tester and Grid Host&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Aiaustin|aiaustin]] &lt;br /&gt;
| Ai Austin &lt;br /&gt;
| Ai&amp;amp;nbsp;Austin &lt;br /&gt;
| Ai&amp;amp;nbsp;AIAI&amp;amp;nbsp;(AIAI Grid) &lt;br /&gt;
| +0 &lt;br /&gt;
| AIAI,&amp;amp;nbsp;University&amp;amp;nbsp;of&amp;amp;nbsp;Edinburgh&amp;lt;br&amp;gt;http://www.aiai.ed.ac.uk/~ai/&amp;lt;br&amp;gt;http://vue.ed.ac.uk/openvue/ &lt;br /&gt;
| Windows Vista tests&amp;lt;br&amp;gt;Content testing&amp;lt;br&amp;gt;Use of multiple VWs&lt;br /&gt;
|-&lt;br /&gt;
| Marc Manders &lt;br /&gt;
| Marc Manders &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| +6 &lt;br /&gt;
| marcmanders@gmail.com &lt;br /&gt;
| Creative features&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Balthazar|balthazar]] &lt;br /&gt;
| Trevor Brooks &lt;br /&gt;
| Balthazar Sin &lt;br /&gt;
| &lt;br /&gt;
| -5 &lt;br /&gt;
| None &lt;br /&gt;
| Terrains, testing and some small coding tasks&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Jimbo2120|jimbo2120]] &lt;br /&gt;
| Michael Osias &lt;br /&gt;
| Illuminous Beltran &lt;br /&gt;
| &lt;br /&gt;
| -5 &lt;br /&gt;
| IBM &lt;br /&gt;
| Grid, AI, Skynet, coding and testing&lt;br /&gt;
|-&lt;br /&gt;
| ZeroPoint &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| Guilderoy&amp;amp;nbsp;Dench &lt;br /&gt;
| &lt;br /&gt;
| -5 &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| Programming/Database&lt;br /&gt;
|-&lt;br /&gt;
| [[User:DerekTang|DerekTang]] &lt;br /&gt;
| Derek Tang &lt;br /&gt;
| Derek Timeless &lt;br /&gt;
| Derek Tang (ChineseGrid) &lt;br /&gt;
| +8 &lt;br /&gt;
| http://ChineseGrid.net &lt;br /&gt;
| Running a public WINDOWS sim for testing, Docs, Helping Chinese users to enjoy OpenSim; building Chinese OpenSim communities. In construction...&lt;br /&gt;
|-&lt;br /&gt;
| [[User:TayB|TayB]] &lt;br /&gt;
| Earl B &lt;br /&gt;
| Taylor Boyau &lt;br /&gt;
| &lt;br /&gt;
| -10 &lt;br /&gt;
| ViziGrid &lt;br /&gt;
| Grid Host,Networking,Contributions &amp;amp;amp; Testing.&lt;br /&gt;
|-&lt;br /&gt;
| [[User:JamieDav|JamieDav]] &lt;br /&gt;
| Jamie David &lt;br /&gt;
| Jamie David &lt;br /&gt;
| &lt;br /&gt;
| +7 &lt;br /&gt;
| Forum &lt;br /&gt;
| Grid, Sim, Avitar, Functionality&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Krtaylor|Krtaylor]] &lt;br /&gt;
| Kurt Taylor &lt;br /&gt;
| Kurt Stringer &lt;br /&gt;
| &lt;br /&gt;
| -6 &lt;br /&gt;
| IBM &lt;br /&gt;
| Grid, Networking, Monitoring, Scripting, Inventory, Testing&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Nink|Nink]] &lt;br /&gt;
| Peter Finn &lt;br /&gt;
| Nink Noonan &lt;br /&gt;
| &lt;br /&gt;
| -5 &lt;br /&gt;
| IBM &lt;br /&gt;
| Disruptive Influence.&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Bruce|Bruce]] &lt;br /&gt;
| Bruce Meerson &lt;br /&gt;
| Bruce Meerson &lt;br /&gt;
| &lt;br /&gt;
| +8 &lt;br /&gt;
| HiPiHi &lt;br /&gt;
| Watching.&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Darb|DarbD]] &lt;br /&gt;
| Brian B. Quinn &lt;br /&gt;
| Darb Dabney &lt;br /&gt;
| regions&amp;lt;br&amp;gt;near Marin &lt;br /&gt;
| PST/SLT (-7 or -8) &lt;br /&gt;
| County of Marin, California&amp;lt;br&amp;gt; http://blog.simgis.com &lt;br /&gt;
| LiDAR-based sculpties, real-world terrain, &amp;lt;br&amp;gt;pursuit of civic paraverses&lt;br /&gt;
|-&lt;br /&gt;
| [[CharlieO]] &lt;br /&gt;
| Dan &lt;br /&gt;
| Charlie Omega &lt;br /&gt;
| &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| Mild coding/tweaking/simple feature adds, Stress testing/break stuff, Testing limits of existing code. Making sure [[LSL Status]] is up to date&lt;br /&gt;
|-&lt;br /&gt;
| oobscure &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| Opensource Obscure &lt;br /&gt;
| &lt;br /&gt;
| +1 &lt;br /&gt;
| http://www.opensim.it &lt;br /&gt;
| Running a public Linux sim for testing, Docs, Helping italian users, Building opensim communities, Watching&lt;br /&gt;
|-&lt;br /&gt;
| pitman &lt;br /&gt;
| Mike Pitman &lt;br /&gt;
| Rez Tone &lt;br /&gt;
| &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| IBM &lt;br /&gt;
| Scientific visualization schemes, virt world product design, persistant workspaces, virt world based big biz&lt;br /&gt;
|-&lt;br /&gt;
| Shenlei &lt;br /&gt;
| Shenlei Winkler &lt;br /&gt;
| Shenlei Flasheart, Shenlei Winkler&lt;br /&gt;
| &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| Fashion Research Institute &lt;br /&gt;
| Product Design and Development, Apparel industry, and o yes, I wrote the book ;)&lt;br /&gt;
|-&lt;br /&gt;
| cmu &lt;br /&gt;
| Christopher Mumme &lt;br /&gt;
| Snook Destiny &lt;br /&gt;
| &lt;br /&gt;
| +1 &lt;br /&gt;
| http://www.cmu-develop.de/ and research group &amp;quot;Collaboration Systems and CSCW&amp;quot; at Clausthal University of Technology &lt;br /&gt;
| Testing OpenSim, working with OpenSim-Engine, reporting on OpenSim&lt;br /&gt;
|-&lt;br /&gt;
| [[Silpol]] &lt;br /&gt;
| Andriy Tymchenko &lt;br /&gt;
| Andy Tir &lt;br /&gt;
| &lt;br /&gt;
| EET (+2/3) &lt;br /&gt;
| http://silpol.blogspot.com/ (also visible at Nokia) &lt;br /&gt;
| Highly uncoordinated mess with elements of palace games, under-table diplomacy, rebellion, coup d'état and mutiny. optionally pirate&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Grumly|Grumly]] &lt;br /&gt;
| &lt;br /&gt;
| Forest Klaar &lt;br /&gt;
| Grumly TheBear &lt;br /&gt;
| GMT+1 &lt;br /&gt;
| .NET MCAD Dev/Arch/Trainer http://www.devoteam.com &lt;br /&gt;
| Trying to get into OpenSim code for now. Particularly interrested in data persistence. blog (Hello, Avatar!): http://lslblog.free.fr&lt;br /&gt;
|-&lt;br /&gt;
| [[DaTwitch]] &lt;br /&gt;
| James G. Stallings II &lt;br /&gt;
| &amp;lt;br&amp;gt;Lazarus Longstaff &lt;br /&gt;
| Hiro Protagonist (OSGrid) &lt;br /&gt;
| -5 &lt;br /&gt;
| House Husband &lt;br /&gt;
| OSGrid Region owner, OSGrid Operator,&amp;lt;br&amp;gt;Forum Admin, sometime wiki editor&lt;br /&gt;
|-&lt;br /&gt;
| gryc &lt;br /&gt;
| Gryc Ueusp &lt;br /&gt;
| Gryc Uriza &lt;br /&gt;
| Gryc Uriza(OSGrid) &lt;br /&gt;
| -6 &lt;br /&gt;
| &lt;br /&gt;
| PHP scripting, web interfaces, interconnectivity, cross-platformedness&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Phrearch|Phrearch]] &lt;br /&gt;
| Jeroen van Veen &lt;br /&gt;
| Phrearch Miles &lt;br /&gt;
| Phrearch Miles(OSGrid) &lt;br /&gt;
| Amsterdam/Paris &lt;br /&gt;
| &lt;br /&gt;
| HWIOS, WiXTD, Wikidoc, Moo, User interfaces&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Burnman|Burnman]] &lt;br /&gt;
| Allen Wilkins &lt;br /&gt;
| Burnman Bedlam &lt;br /&gt;
| Sid Green (United Grid) &lt;br /&gt;
| Boston, USA &lt;br /&gt;
| United Grid &lt;br /&gt;
| Testing, testing, and more testing! Getting familiar with the source, interested in all aspects of the project.&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Krisbfunk|krisbfunk]] &lt;br /&gt;
| Kris Bulman &lt;br /&gt;
| Krisbfunk Vought &lt;br /&gt;
| Krisbfunk Nocturnal(OSGrid) &lt;br /&gt;
| PE, Canada (-4) &lt;br /&gt;
| Edactive Technologies&amp;lt;br&amp;gt;NocturnalEye Productions&amp;lt;br&amp;gt;UPEI &lt;br /&gt;
| Currently: Testing, bug reports, wiki updating, building on OSGrid&lt;br /&gt;
|-&lt;br /&gt;
| [[User:HashBox|HashBox]] &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| Sibariel Darkstone &lt;br /&gt;
| Sibariel Darkstone (OSGrid) &lt;br /&gt;
| New Zealand (+12) &lt;br /&gt;
| &lt;br /&gt;
| Testing, bug reports, and updating the wiki.&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Kinoc|Kinoc]] &lt;br /&gt;
| Kino Coursey &lt;br /&gt;
| Daxxon Jaxxon &lt;br /&gt;
| Daxxon Kinoc (OSgrid) &lt;br /&gt;
| -6 &lt;br /&gt;
| Daxtron Laboratories &amp;lt;br&amp;gt; http://www.daxtron.com&amp;lt;br&amp;gt; University of North Texas &lt;br /&gt;
| AI, Semantic web, Ontologies, Natural Laanguage Processing, Cyc, Bots, NPC&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Trapuh|trapuh]] &lt;br /&gt;
| Pedro Ribeiro &lt;br /&gt;
| Vaiten Forder &lt;br /&gt;
| &lt;br /&gt;
| GMT &lt;br /&gt;
| University Student, Escola Superior de Educação de Viseu, Portugal &lt;br /&gt;
| Testing, eventual bug reports and wiki. Music, web/digital arts and php+sql.&lt;br /&gt;
|-&lt;br /&gt;
| [[User:SonicViz|SonicViz]] &lt;br /&gt;
| Paul Cohen &lt;br /&gt;
| Komuso Tokugawa &lt;br /&gt;
| &lt;br /&gt;
| +9 &lt;br /&gt;
| Http://sonicviz.com &lt;br /&gt;
| Audio/Music, Interactive Music, Control Protocols, Interfaces, VisualFX, Procedural animation/Generative systems + testing and general dev&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Mokele|mokele]] &lt;br /&gt;
| Scott Norman &lt;br /&gt;
| Mokelembembe Mokeev &lt;br /&gt;
| &lt;br /&gt;
| -8 (Southern California) &lt;br /&gt;
| Web Developer (PHP and MySQL) &lt;br /&gt;
| Interested in seeing running on PowerPC Macs which it is. So, when I can, I'll compile and test on PowerPC Mac (PowerBook G4) and submit reports and then update the wiki if need on installing on Mac. Also have a Ubuntu 7.10 server that I can do testing on too.&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Devalnor|devalnor]] &lt;br /&gt;
| Devalnor &lt;br /&gt;
| M. Watkin &lt;br /&gt;
| &lt;br /&gt;
| +1 (Belgium) &lt;br /&gt;
| &lt;br /&gt;
| Small Patch code, bug reports, and updating the wiki.&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Ezekiel|Ezekiel]] &lt;br /&gt;
| Ezekiel &lt;br /&gt;
| Ezekiel Zabelin &lt;br /&gt;
| &lt;br /&gt;
| +1 &lt;br /&gt;
| http://www.yosims.com &lt;br /&gt;
| Concepts, business aspects of virtual worlds - web developer (PHP, MySQL, Javascript, LSL)&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Buggmaster|Buggmaster]] &lt;br /&gt;
| Mike D &lt;br /&gt;
| Bug Master &lt;br /&gt;
| None &lt;br /&gt;
| -8 &lt;br /&gt;
| http://www.adultmetaverse.com &lt;br /&gt;
| Grid, Data/Web PHP/PERL/MySQL&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Nixnerd|nixnerd]] &lt;br /&gt;
| &lt;br /&gt;
| Dangerously Moody &lt;br /&gt;
| None &lt;br /&gt;
| GMT &lt;br /&gt;
| http://www.integratedtechnologies.eu &lt;br /&gt;
| Cross Platform Testing, Feedback, Bug Reporting&lt;br /&gt;
|-&lt;br /&gt;
| [[User:MoHax|mohax]] &lt;br /&gt;
| Mo Hax &lt;br /&gt;
| Mo Hax &lt;br /&gt;
| &lt;br /&gt;
| -5 Eastern &lt;br /&gt;
| IBM &lt;br /&gt;
| Testing, Feedback, Content Contributions, Bug Reporting, Documenting, Development&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Webmage|webmage]] &lt;br /&gt;
| webmage &lt;br /&gt;
| Leyla Masala &lt;br /&gt;
| Web Mage &lt;br /&gt;
| +1 &lt;br /&gt;
| IBM &lt;br /&gt;
| Testing, terrain&lt;br /&gt;
|-&lt;br /&gt;
| [[User:NLStitch|NLStitch]] &lt;br /&gt;
| Marijn Oosterveld &lt;br /&gt;
| Stitch Seale &lt;br /&gt;
| NYA &lt;br /&gt;
| GMT +1 Amsterdam &lt;br /&gt;
| Twingate Systems (http://www.twingate.nl)&amp;lt;br&amp;gt;HanzeHogeschool Groningen, Netherlands &lt;br /&gt;
| Programming, Photography, AI&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Ideia Boa|Ideia Boa]] &lt;br /&gt;
| Joao Lopes &lt;br /&gt;
| Ideia Boa &lt;br /&gt;
| Ideia Boa or Boa Ideia in some grids &lt;br /&gt;
| GTM+1 Stockholm/Sweden &lt;br /&gt;
| WorldSimTERRA - Virtual World that speaks Portuguese too&amp;lt;br&amp;gt;http://www.worldsimterra.com &lt;br /&gt;
| Testing and more testing! Updating the original wiki and translating the OpenSim Wiki into Portuguese and reporting on OpenSim&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Lulurun|lulurun]] &lt;br /&gt;
| liu &lt;br /&gt;
| &amp;lt;br&amp;gt; &lt;br /&gt;
| &amp;lt;br&amp;gt; &lt;br /&gt;
| +9 &lt;br /&gt;
| 3Di Inc, Japan &amp;lt;br&amp;gt;http://www.3di.jp &lt;br /&gt;
| Patches, openid, server performance, UGAI&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Carlosroundel|Carlosrounde]] &lt;br /&gt;
| Carlosroundel &lt;br /&gt;
| Carlos Roundel &lt;br /&gt;
| &amp;lt;br&amp;gt; &lt;br /&gt;
| +1 &lt;br /&gt;
| Cyberlandia Italy&amp;lt;br&amp;gt;http://www.cyberlandia.net &lt;br /&gt;
| Grid, programmer, database, tester&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Mikebert|Mikebert]] &lt;br /&gt;
| Michael Strunck &lt;br /&gt;
| Mikebert Miles &lt;br /&gt;
| Mikebert M34 &lt;br /&gt;
| +1 &lt;br /&gt;
| OpenSIM Wiki, Germany&amp;lt;br&amp;gt;http://www.opensim.de &lt;br /&gt;
| German Wiki, Translater, Server Performance (Linux/Windows), Tester, Feedback, Bug Reporting, Server-Hosting&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Fly-man-|Fly-Man-]] &lt;br /&gt;
| Laurence &lt;br /&gt;
| &lt;br /&gt;
| Fly Man &lt;br /&gt;
| +1 &lt;br /&gt;
| &lt;br /&gt;
| Testing, OpenSimSearch, OpenSimProfile&lt;br /&gt;
|-&lt;br /&gt;
| Taoki &lt;br /&gt;
| Mircea Kitsune / Taoki Vixen &lt;br /&gt;
| Mircea Kitsune (OSGrid) / Mircea Lobo (LL grid) &lt;br /&gt;
| &amp;lt;br&amp;gt; &lt;br /&gt;
| GMT +2 &lt;br /&gt;
| &amp;lt;br&amp;gt; &lt;br /&gt;
| Usually testing and bug reporting but I also make smaller patches where I know what to do.&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Patnad|Patnad]] &lt;br /&gt;
| Patrick &lt;br /&gt;
| Patnad Babii &lt;br /&gt;
| Patnad Babii (OSGrid) &lt;br /&gt;
| GMT -5 &lt;br /&gt;
| RezzMe Technologies&amp;lt;br&amp;gt;http://www.rezzme.com &lt;br /&gt;
| Bug testing and reporting, I code C# and have submitted a few patches&lt;br /&gt;
|-&lt;br /&gt;
| [[User:^DarkMan|^DarkMan]] &lt;br /&gt;
| Brian Adair &lt;br /&gt;
| Patrick Ouachita &lt;br /&gt;
| Brian Adair &amp;amp;#124; Patrick Meta &lt;br /&gt;
| -6 CST &lt;br /&gt;
| RealMetaLife &amp;amp;#124; B&amp;amp;amp;H Networking &lt;br /&gt;
| Building, Scripting, Testing, etc.&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Tlaukkan|Tommi Laukkanen]] &lt;br /&gt;
| Tommi Laukkanen &lt;br /&gt;
| &amp;amp;nbsp; &lt;br /&gt;
| Tommi Laukkanen &lt;br /&gt;
| +2 GMT &lt;br /&gt;
| http://www.bubblecloud.org &lt;br /&gt;
| Protocols ([http://www.bubblecloud.org MXP]), NHibernate, Scrip API, Map Generation, Bug Fixes, Grid Hosting&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Mystical|Mystical]] &lt;br /&gt;
| Kevin Tweedy &lt;br /&gt;
| Mystical Demina &lt;br /&gt;
| Mystical Demina &lt;br /&gt;
| -5 &lt;br /&gt;
| Extreme Reality Grid&amp;lt;br&amp;gt;http://www.XRGrid.com &lt;br /&gt;
| Windows Communication Framework, Windows Workflow,Entity Framework, MSSQL&amp;lt;br&amp;gt;Enhancements,Commerce, Content,DotNetNuke based portal, development services&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Godfrey|Godfrey]] &lt;br /&gt;
| Jeff Lee &lt;br /&gt;
| Warin Cascabel &lt;br /&gt;
| &lt;br /&gt;
| -5 (EST5EDT) &lt;br /&gt;
| &lt;br /&gt;
| Testing, minor bugfixes. Scripting, building, animating&lt;br /&gt;
|-&lt;br /&gt;
| Jamenai &lt;br /&gt;
| Christopher Händler &lt;br /&gt;
| Jamenai Luik &lt;br /&gt;
| Jamenai Luik &lt;br /&gt;
| +1 &lt;br /&gt;
| Playneko Grid &amp;amp;#124; XIMDEX Jamenai&amp;lt;br&amp;gt;http://www.playneko.de&amp;lt;br&amp;gt;http://www.ximdex.de &lt;br /&gt;
| Performance,Bug Reporting, Hosting, Grid-Owner,(PHP, MySQL, Perl, JavaScript, LSL)&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Bikcmp|bikcmp]] &lt;br /&gt;
| Jason &lt;br /&gt;
| Jake1500 Allen &lt;br /&gt;
| Jason Helios (The Helios Grid) &lt;br /&gt;
| EST &lt;br /&gt;
| Blue Software &lt;br /&gt;
| Search, groups, land, and currency&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Mark.malewski|Slipaway]] &lt;br /&gt;
| Mark Malewski &lt;br /&gt;
| Chris Rock &lt;br /&gt;
| &lt;br /&gt;
| -6 (-5 during summer - CDT) &lt;br /&gt;
| NexTECH / Joopla &lt;br /&gt;
| Web development &amp;amp;amp; systems integration, terrain, WIKI documentation, tutorials, testing, bug reporting and feedback.&lt;br /&gt;
|-&lt;br /&gt;
| barakademi &lt;br /&gt;
| Steve Topp &lt;br /&gt;
| barakademi Barzane &lt;br /&gt;
| same avi on baragrid OSgrid Grid4us sciencesim &lt;br /&gt;
| utc+1 (CET) paris &lt;br /&gt;
| http://xbot-sl.barakademi.org http://vps.barakademi.org/oswi http://vps.barakademi.org/oswi/loginscreen.php &lt;br /&gt;
| Music LiveMusic MetaverseMusic Opensim Libomv Mono-2.4 Linux (suse,debian,ubuntu) Admin Scripting Automating Development Intergration php mysql bash nant +++&lt;br /&gt;
|-&lt;br /&gt;
| [[User:RemedyTomm|RemedyTomm]] &lt;br /&gt;
| Tom Grimshaw &lt;br /&gt;
| Tomm Remedy &lt;br /&gt;
| KGrid: Casper Warden OSGrid: Tomm Remedy &lt;br /&gt;
| UTC+0 (BST) &lt;br /&gt;
| Remedy Communications &lt;br /&gt;
| Texture pipeline, Groups, ObjectUpdates&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Robert d|robert_d]] &lt;br /&gt;
| Robert Dzikowski &lt;br /&gt;
| &lt;br /&gt;
| OSGrid: robert_d 13 &lt;br /&gt;
| UTC+1 &lt;br /&gt;
| [http://blog.rd-it.net http://blog.rd-it.net] &lt;br /&gt;
| Region Modules, Tutorials&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Snoopy2|Snoopy2]] &lt;br /&gt;
| Snoopy Pfeffer &lt;br /&gt;
| Snoopy Pfeffer &lt;br /&gt;
| Snoopy Pfeffer &lt;br /&gt;
| &lt;br /&gt;
| [http://www.3dmetaverse.com/ http://www.3dmetaverse.com/] &lt;br /&gt;
| Region Hosting, Open Metaverse, 3D Web, server and viewers, service management&lt;br /&gt;
|-&lt;br /&gt;
| john_ &lt;br /&gt;
| John&amp;amp;nbsp;Moyer &lt;br /&gt;
| VAJohn&amp;amp;nbsp;GeekSquad or&amp;amp;nbsp;Matthew&amp;amp;nbsp;Kendal &lt;br /&gt;
| &lt;br /&gt;
| -5 &lt;br /&gt;
| Best&amp;amp;nbsp;Buy/Geek&amp;amp;nbsp;Squad &lt;br /&gt;
| Tester&lt;br /&gt;
|-&lt;br /&gt;
| [[User:W!cKeD|_WicKeD]] &lt;br /&gt;
| Maik &lt;br /&gt;
| Maik Galaxy &lt;br /&gt;
| El Diablo &lt;br /&gt;
| +1 Germany &lt;br /&gt;
| Creatio Inc. / [http://www.OpenSimGerman.us/ OpenSimGerman.us] &lt;br /&gt;
| German Support, Translator, Building, Scripting, Testing, Hosting&lt;br /&gt;
|-&lt;br /&gt;
| [[User:Stevie Wakowski|Stevie Wakowksi]] &lt;br /&gt;
| Steve Roberts &lt;br /&gt;
| Stevie Wakowski &lt;br /&gt;
| &lt;br /&gt;
| +10 Australia &lt;br /&gt;
| IBM &lt;br /&gt;
| OpenSim builds, Linux, Modrex, bug reporting, evangalist for OpenSim in business applications.&lt;br /&gt;
|-&lt;br /&gt;
[[User:Revolution]] &lt;br /&gt;
| Revolution&lt;br /&gt;
| Matthew&lt;br /&gt;
| Revolution Smythe &lt;br /&gt;
| Revolution Smythe &lt;br /&gt;
| -6 Central USA &lt;br /&gt;
| None&lt;br /&gt;
| Script engine, physics engine, general odd bugs, interesting and odd things&lt;br /&gt;
|-&amp;lt;br&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Main]] [[Category:Development]] [[Category:Tech_Reference]] [[Category:Help]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Talk:Automated_Testing</id>
		<title>Talk:Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Talk:Automated_Testing"/>
				<updated>2009-03-12T08:55:16Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I crossed out a paragraph about naming tests a certain way in order to make sure they're run in a certain order because they depend on each other. This is bad practice. All tests should be able to run independently of one another. For any environment setup, use the SetUp and TearDown NUnit attributes.&lt;br /&gt;
&lt;br /&gt;
[[User:Mikem|Mikem]] 01:01, 9 October 2008 (PDT)&lt;br /&gt;
&lt;br /&gt;
I changed this back, because it's the way the unit tests work today.  The &amp;quot;theory&amp;quot; that no test method should depend on any other one tends to force unit tests into very shallow coverage because you would need massive code duplication to test anything deep.  My experience has shown that imposing the &amp;quot;no test should really on another test&amp;quot; generates much worse test cases.&lt;br /&gt;
&lt;br /&gt;
If you want to go through the unit tests and adjust them to all have Setup and Teardown methods, be my guest. :)  However it really just makes things much more difficult than they need to be, for lots of effort, and no real benefit.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
While my experience hasn't yet shown that test which depend on other tests are the ultimate evil, I'm confident that one should strive to avoid such a situation. The argument against chained tests stating that massive code duplication is necessary to test anything deep isn't convincing because good use of test fixture SetUp/TearDown eliminates most of the duplication.&lt;br /&gt;
&lt;br /&gt;
Chained tests probably do have their place in extremely complicated systems, however I'm not convinced the components of OpenSim that are being tested have ''not'' reached such a level of complexity.&lt;br /&gt;
&lt;br /&gt;
[[User:Mikem|Mikem]] 08:54, 12 March 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Talk:Automated_Testing</id>
		<title>Talk:Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Talk:Automated_Testing"/>
				<updated>2009-03-12T08:54:31Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* = */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I crossed out a paragraph about naming tests a certain way in order to make sure they're run in a certain order because they depend on each other. This is bad practice. All tests should be able to run independently of one another. For any environment setup, use the SetUp and TearDown NUnit attributes.&lt;br /&gt;
&lt;br /&gt;
[[User:Mikem|Mikem]] 01:01, 9 October 2008 (PDT)&lt;br /&gt;
&lt;br /&gt;
I changed this back, because it's the way the unit tests work today.  The &amp;quot;theory&amp;quot; that no test method should depend on any other one tends to force unit tests into very shallow coverage because you would need massive code duplication to test anything deep.  My experience has shown that imposing the &amp;quot;no test should really on another test&amp;quot; generates much worse test cases.&lt;br /&gt;
&lt;br /&gt;
If you want to go through the unit tests and adjust them to all have Setup and Teardown methods, be my guest. :)  However it really just makes things much more difficult than they need to be, for lots of effort, and no real benefit.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
While my experience hasn't yet shown that test which depend on other tests are the ultimate evil, I'm confident that one should strive to avoid such a situation. The argument against chained tests stating that massive code duplication is necessary to test anything deep isn't convincing because good use of test fixture SetUp/TearDown eliminates most of the duplication.&lt;br /&gt;
&lt;br /&gt;
Chained tests probably do have their place in extremely complicated systems, however I'm not convinced the components of OpenSim that are being tested have reached such a level of complexity.&lt;br /&gt;
&lt;br /&gt;
[[User:Mikem|Mikem]] 08:54, 12 March 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Talk:Automated_Testing</id>
		<title>Talk:Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Talk:Automated_Testing"/>
				<updated>2009-03-12T08:54:17Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I crossed out a paragraph about naming tests a certain way in order to make sure they're run in a certain order because they depend on each other. This is bad practice. All tests should be able to run independently of one another. For any environment setup, use the SetUp and TearDown NUnit attributes.&lt;br /&gt;
&lt;br /&gt;
[[User:Mikem|Mikem]] 01:01, 9 October 2008 (PDT)&lt;br /&gt;
&lt;br /&gt;
I changed this back, because it's the way the unit tests work today.  The &amp;quot;theory&amp;quot; that no test method should depend on any other one tends to force unit tests into very shallow coverage because you would need massive code duplication to test anything deep.  My experience has shown that imposing the &amp;quot;no test should really on another test&amp;quot; generates much worse test cases.&lt;br /&gt;
&lt;br /&gt;
If you want to go through the unit tests and adjust them to all have Setup and Teardown methods, be my guest. :)  However it really just makes things much more difficult than they need to be, for lots of effort, and no real benefit.&lt;br /&gt;
&lt;br /&gt;
===&lt;br /&gt;
&lt;br /&gt;
While my experience hasn't yet shown that test which depend on other tests are the ultimate evil, I'm confident that one should strive to avoid such a situation. The argument against chained tests stating that massive code duplication is necessary to test anything deep isn't convincing because good use of test fixture SetUp/TearDown eliminates most of the duplication.&lt;br /&gt;
&lt;br /&gt;
Chained tests probably do have their place in extremely complicated systems, however I'm not convinced the components of OpenSim that are being tested have reached such a level of complexity.&lt;br /&gt;
&lt;br /&gt;
[[User:Mikem|Mikem]] 08:54, 12 March 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Talk:Automated_Testing</id>
		<title>Talk:Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Talk:Automated_Testing"/>
				<updated>2009-03-12T08:53:06Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* Chained tests are not necessary */ new section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I crossed out a paragraph about naming tests a certain way in order to make sure they're run in a certain order because they depend on each other. This is bad practice. All tests should be able to run independently of one another. For any environment setup, use the SetUp and TearDown NUnit attributes.&lt;br /&gt;
&lt;br /&gt;
[[User:Mikem|Mikem]] 01:01, 9 October 2008 (PDT)&lt;br /&gt;
&lt;br /&gt;
I changed this back, because it's the way the unit tests work today.  The &amp;quot;theory&amp;quot; that no test method should depend on any other one tends to force unit tests into very shallow coverage because you would need massive code duplication to test anything deep.  My experience has shown that imposing the &amp;quot;no test should really on another test&amp;quot; generates much worse test cases.&lt;br /&gt;
&lt;br /&gt;
If you want to go through the unit tests and adjust them to all have Setup and Teardown methods, be my guest. :)  However it really just makes things much more difficult than they need to be, for lots of effort, and no real benefit.&lt;br /&gt;
&lt;br /&gt;
== Chained tests are not necessary ==&lt;br /&gt;
&lt;br /&gt;
While my experience hasn't yet shown that test which depend on other tests are the ultimate evil, I'm confident that one should strive to avoid such a situation. The argument against chained tests stating that massive code duplication is necessary to test anything deep isn't convincing because good use of test fixture SetUp/TearDown eliminates most of the duplication.&lt;br /&gt;
&lt;br /&gt;
Chained tests probably do have their place in extremely complicated systems, however I'm not convinced the components of OpenSim that are being tested have reached such a level of complexity.&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Automated_Testing</id>
		<title>Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Automated_Testing"/>
				<updated>2009-03-12T08:47:32Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As OpenSim matures, we are extremely interested in adding more automated verification into the OpenSim source tree.  Test exist not only to prevent bugs from creeping in, but also to provide fair warning that the behavior of the system has changed, and tests may need updating.&lt;br /&gt;
&lt;br /&gt;
In OpenSim today we use NUnit tests.  Our conventions are:&lt;br /&gt;
# Tests should '''not''' exist inside runtime assemblies, as this makes nunit a production requirement&lt;br /&gt;
# Tests should be in .Tests.dll assemblies.  For instance, the tests for OpenSim.Data.SQLite.dll should be in the OpenSim.Data.SQLite.Tests.dll assembly.  This allows for easy removal of test assemblies in products.&lt;br /&gt;
# Tests should be as close to the code as possible, but not intermingled.  So the tests for OpenSim/Data/SQLite should be in OpenSim/Data/SQLite/Tests/.  Through the use of the '''Exclude''' keyword in prebuild.xml you can ensure that directory is part of OpenSim.Data.SQLite.Tests.dll and not OpenSim.Data.SQLite.dll. See exclude clarification in writing unit tests section.&lt;br /&gt;
# Tests testing a class should be grouped into a test class file called xxxTest.cs, where xxx is the name of the class that is being tested.&lt;br /&gt;
# Tests should be able to run safely in a production environment.  That means that care must be taken not to damage data on the machine that it is being run.&lt;br /&gt;
# Tests should be deterministic in other words repeatable. Avoid randomness in tests. See good and bad testing practices below.&lt;br /&gt;
&lt;br /&gt;
== Core Functionality Missing Unit Tests ==&lt;br /&gt;
&lt;br /&gt;
This is a list of functionality which is not covered by unit tests and is identified as highly desireable test target:&lt;br /&gt;
&lt;br /&gt;
# Database Modules (These are mysql tables)&lt;br /&gt;
## region ban&lt;br /&gt;
## land&lt;br /&gt;
## landaccesslist&lt;br /&gt;
&lt;br /&gt;
== Good / Bad Test practices ==&lt;br /&gt;
Creating good tests is an art, not a science.  Tests are useful by how many bugs they find or how many bugs they avoid.  Things you should think about in creating good tests is:&lt;br /&gt;
* Throwing edge cases, like 0, &amp;quot;&amp;quot;, or Null at parameters.  This ensures that people functions are hardened against incomplete data.  Many of our crashes come from the lack of this hardening showing up at just the wrong time.&lt;br /&gt;
* Use stateful testing to build up complex scenarios.  This is more useful than just cursory get / set calls.&lt;br /&gt;
* Random tests are not a good idea. We need test results to be deterministic. In other words tests need to be repeatable. If you want to test for a range it is good idea to make separate tests for min and max values. Random values in fields can fail randomly. When something goes wrong for example in database schema the developer will not necessarily notice if the stored values are random. On the other hand its hard to troubleshoot randomly failing tests as you dont know which specific value caused the failure.&lt;br /&gt;
* Tests should be independent and should not rely on another test being run, passing or failing. An excerpt from [http://xunitpatterns.com/Principles%20of%20Test%20Automation.html#Independent%20Test xUnit Patterns]:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;If tests are interdependent and (even worse) order dependent, we will be depriving ourselves of the useful feedback test failures provide. Interacting Tests [...] tend to fail in a group. The failure of a test that moved the [subject under test] into the state required by the dependent test will lead to the failure of the dependent test too. With both tests failing, how can we tell if it is because of a problem in code that both rely on in some way or is it a problem in code that only the first relies on. With both tests failing we can't tell. We are only talking about two tests here. Imagine how much worse this is with tens or hundreds of tests.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Only one function of the subject under test should be tested in one test. When testing a database access object, for example, write separate tests for creating DB entries, updating them and removing them.&lt;br /&gt;
* Do not use the subject under test to set up the state for the test or to verify the result. Use a different method. When testing a database access object, for example, use raw SQL to insert the initial data into the DB, then run the method being tested. To verify if the operation was successful, use raw SQL again to verify the DB changed as expected.&lt;br /&gt;
&lt;br /&gt;
== Writing Tests ==&lt;br /&gt;
&lt;br /&gt;
See [http://www.nunit.org/index.php?p=quickStart&amp;amp;r=2.4 NUnit Quick Start] for an introduction to unit testing with NUnit.&lt;br /&gt;
&lt;br /&gt;
Writing a new unit test is pretty easy, and very helpful in increasing the stability of opensim by nailing down bugs.  I'm going to present an example here of SQLite Asset testing to show how simple such a test case is to write.  The actual in tree SQLite Asset tests are a little different because the code was factored out so that it was easily applied to any database driver, so don't be concerned with the fact that what you see here isn't in the tree.&lt;br /&gt;
&lt;br /&gt;
Exclude clarification: Make sure your master project (not the test project) has an entry for files like the following so that the test code is not included in the master project dll:&lt;br /&gt;
      &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;lt;Files&amp;gt;&lt;br /&gt;
        &amp;lt;Match pattern=&amp;quot;*.cs&amp;quot; recurse=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;Exclude name=&amp;quot;Tests&amp;quot; pattern=&amp;quot;Tests&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/Match&amp;gt;&lt;br /&gt;
      &amp;lt;/Files&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NUnit Conventions ===&lt;br /&gt;
An NUnit test suite:&lt;br /&gt;
* is a class with a default constructor (takes no arguments)&lt;br /&gt;
* has public methods that are tests&lt;br /&gt;
* uses annotations to determine what are tests&lt;br /&gt;
* runs it's tests in '''alphabetical order by method name'''&lt;br /&gt;
&lt;br /&gt;
An NUnit test method:&lt;br /&gt;
* must be public&lt;br /&gt;
* must return void&lt;br /&gt;
* must take no arguments&lt;br /&gt;
* is successful if no exception or assert is thrown while running it&lt;br /&gt;
&lt;br /&gt;
The run order is important if you want to have early tests that setup some complicated state (like creating objects), and have later tests remove or update that state.  For that reason I find it very helpful to name all test methods '''Txxx_somename''' where '''xxx''' is a number between 000 and 999.  That guaruntees no surprises in run order.&lt;br /&gt;
&lt;br /&gt;
=== Fixture Setup / Teardown ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[TestFixtureSetUp]&lt;br /&gt;
public void Init()&lt;br /&gt;
{&lt;br /&gt;
    uuid1 = UUID.Random();&lt;br /&gt;
    uuid2 = UUID.Random();&lt;br /&gt;
    uuid3 = UUID.Random();&lt;br /&gt;
    name1 = &amp;quot;asset one&amp;quot;;&lt;br /&gt;
    name2 = &amp;quot;asset two&amp;quot;;&lt;br /&gt;
    name3 = &amp;quot;asset three&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    asset1 = new byte[100];&lt;br /&gt;
    asset1.Initialize();&lt;br /&gt;
    file = Path.GetTempFileName() + &amp;quot;.db&amp;quot;;&lt;br /&gt;
    connect = &amp;quot;URI=file:&amp;quot; + file + &amp;quot;,version=3&amp;quot;;&lt;br /&gt;
    db = new SQLiteAssetData();&lt;br /&gt;
    db.Initialise(connect);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[TestFixtureTearDown]&lt;br /&gt;
public void Cleanup()&lt;br /&gt;
{&lt;br /&gt;
    db.Dispose();&lt;br /&gt;
    System.IO.File.Delete(file);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the case of testing something like the database layer, we have to actually attempt to store / retrieve things from a database.  Following from rule #4 of good tests, we want to make sure not to touch the production databases to run our tests, so during startup we generate a temporary file name which is guaranteed not to be an existing file on the system, and use that as our database file name.  By running db.Initialize() the OpenSim migration code will correctly populate that database with the latest schema.&lt;br /&gt;
&lt;br /&gt;
Once we are done with the tests we want to make sure we aren't leaving garbage temp files on the user's system.  So we remove that file we created.&lt;br /&gt;
&lt;br /&gt;
During setup we also create a set of state variables, such as 3 uuids, 3 strings, and a data block.  You could have always just stuck these inline, but variables are there for a reason, so use them.&lt;br /&gt;
&lt;br /&gt;
=== Test Setup / Teardown ===&lt;br /&gt;
&lt;br /&gt;
What's missing in [[Example Test SQLite Assets]] are individual test Setup and Teardown methods. These methods allow each test to be completely self sufficient without the code duplication needed to set up the test environment at the start of each test.&lt;br /&gt;
&lt;br /&gt;
Let's assume the &amp;lt;code&amp;gt;SQLiteAssetData&amp;lt;/code&amp;gt; class provided a &amp;lt;code&amp;gt;FetchAsset()&amp;lt;/code&amp;gt; method and a &amp;lt;code&amp;gt;UpdateAsset()&amp;lt;/code&amp;gt; method. Since every test should be independent of any other test, and &amp;lt;code&amp;gt;FetchAsset()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;UpdateAsset()&amp;lt;/code&amp;gt; should be tested in separate tests, that means each test would need to create its own entries in the asset table in order to succeed. You may have something like this (see [[Example Test SQLite Assets#This Test is Flawed|Example Test SQLite Assets]] for an explanation of &amp;lt;code&amp;gt;sqldb.executeSQL()&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;[Test]&lt;br /&gt;
public void T101_TestFetchAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(...);&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;INSERT INTO assets VALUES({0}, ...)&amp;quot;, a1.uuid, ...);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1_actual = db.FetchAsset(a1.uuid);&lt;br /&gt;
&lt;br /&gt;
    Assert.Equal(a1_actual.uuid, a1.uuid);&lt;br /&gt;
    Assert.Equal(a1_actual.Name, a1.Name);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T103_TestUpdateAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(...);&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;INSERT INTO assets VALUES({0}, ...)&amp;quot;, a1.uuid, ...);&lt;br /&gt;
&lt;br /&gt;
    a1.Name = &amp;quot;new name&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    db.UpdateAsset(a1.uuid, a1);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1_actual = sqldb.executeSQL(&amp;quot;SELECT * FROM assets WHERE uuid = {0}&amp;quot;, a1.uuid);&lt;br /&gt;
&lt;br /&gt;
    Assert.Equal(a1_actual.uuid, a1.uuid);&lt;br /&gt;
    Assert.Equal(a1_actual.Name, a1.Name);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will note that both tests have the same code at the top in which they create an entry in the assets table. This duplicate code can be factored out into a Setup method, which is called before every test is executed (assume &amp;lt;code&amp;gt;a1&amp;lt;/code&amp;gt; is a class attribute):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[SetUp]&lt;br /&gt;
public void SetUp()&lt;br /&gt;
{&lt;br /&gt;
    a1 = new AssetBase(...);&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;INSERT INTO assets VALUES({0}, ...)&amp;quot;, a1.uuid, ...);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[TearDown]&lt;br /&gt;
public void TearDown()&lt;br /&gt;
{&lt;br /&gt;
    // clean up after ourselves so the next test has a clean DB to start with&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;DELETE FROM assets&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T101_TestFetchAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1_actual = db.FetchAsset(a1.uuid);&lt;br /&gt;
&lt;br /&gt;
    Assert.Equal(a1_actual.uuid, a1.uuid);&lt;br /&gt;
    Assert.Equal(a1_actual.Name, a1.Name);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T103_TestUpdateAsset()&lt;br /&gt;
{&lt;br /&gt;
    a1.Name = &amp;quot;new name&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    db.UpdateAsset(a1.uuid, a1);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1_actual = sqldb.executeSQL(&amp;quot;SELECT * FROM assets WHERE uuid = {0}&amp;quot;, a1.uuid);&lt;br /&gt;
&lt;br /&gt;
    Assert.Equal(a1_actual.uuid, a1.uuid);&lt;br /&gt;
    Assert.Equal(a1_actual.Name, a1.Name);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also note the &amp;lt;code&amp;gt;TearDown()&amp;lt;/code&amp;gt; method; it is called after each test has run, regardless whether the test passed or failed. It deletes all the entries in the &amp;lt;code&amp;gt;assets&amp;lt;/code&amp;gt; table so that there is no leftover data in the database to interfere with the next test.&lt;br /&gt;
&lt;br /&gt;
==== Multiple Setup Methods ====&lt;br /&gt;
&lt;br /&gt;
Not all setup and teardown must happen in methods declared [SetUp] and [TearDown]. It may be useful to provide methods which perform part of the setup and to call them from whichever test may need it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
private AssetBase InsertAssetWithRandomData(UUID assetUuid)&lt;br /&gt;
{&lt;br /&gt;
    AssetBase asset = new AssetBase(assetUuid);&lt;br /&gt;
    asset.Name = somethingRandom();&lt;br /&gt;
    asset.Data = somethingRandom();&lt;br /&gt;
&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;INSERT INTO assets VALUES({0}, ...)&amp;quot;, asset.uuid, ...);&lt;br /&gt;
&lt;br /&gt;
    return asset;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T201_TestNeedsTwoAssets()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = InsertAssetWithRandomData(uuid1);&lt;br /&gt;
    AssetBase a2 = InsertAssetWithRandomData(uuid2);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T203_TestNeedsFiveAssets()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = InsertAssetWithRandomData(uuid1);&lt;br /&gt;
    AssetBase a2 = InsertAssetWithRandomData(uuid2);&lt;br /&gt;
    AssetBase a3 = InsertAssetWithRandomData(uuid3);&lt;br /&gt;
    AssetBase a4 = InsertAssetWithRandomData(uuid4);&lt;br /&gt;
    AssetBase a5 = InsertAssetWithRandomData(uuid5);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that &amp;lt;code&amp;gt;InsertAssetWithRandomData&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;private&amp;lt;/code&amp;gt; as it's only called from within the class.&lt;br /&gt;
&lt;br /&gt;
=== Asserts ===&lt;br /&gt;
You will see scattered through the code '''Assert.That(...)'''.  These will throw an exception if the condition is not valid.  This format of assertions is called the [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 Constraint Model] in NUnit, and provides a large number of tests with the flavor of:&lt;br /&gt;
* Assert.That(foo, Is.Null)&lt;br /&gt;
* Assert.That(foo, Is.Not.Null)&lt;br /&gt;
* Assert.That(foo, Is.True)&lt;br /&gt;
* Assert.That(foo, Is.EqualTo(bar))&lt;br /&gt;
* Assert.That(foo, Text.Matches( &amp;quot;*bar*&amp;quot; ))&lt;br /&gt;
&lt;br /&gt;
Of note, Is.EqualTo uses the Equals function of foo, so this can only be used on objects that are IComparable.  Most of the OpenSim base objects are not, so you'll have to compare fields manually in tests.&lt;br /&gt;
&lt;br /&gt;
For the complete set of conditions you can use see [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 the Constraint Model NUnit documentation].  While there is another syntax for tests, the Constraint Model is preferred as it is far more human readable.&lt;br /&gt;
&lt;br /&gt;
=== Simple Negative Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;[Test]&lt;br /&gt;
public void T001_LoadEmpty()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Test T001 is an example of a simple negative test.  We assume a new database will not have any of those assets in them.  While the value of this test may look low, it does provide a baseline in ensuring that the database connection is there, that these return false correctly, and that no other exception is thrown.  Negative tests are a good way to force bounds conditions and ensure that not only does it  ''return what you expect'' it also ''doesn't return what you don't expect''.  Thought of another way, it ensures your code is somewhat defensive in nature, not coughing on bad or unexpected data.&lt;br /&gt;
&lt;br /&gt;
=== Simple Positive Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T010_StoreSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
    AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
    AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
    a1.Data = asset1;&lt;br /&gt;
    a2.Data = asset1;&lt;br /&gt;
    a3.Data = asset1;&lt;br /&gt;
    &lt;br /&gt;
    db.CreateAsset(a1);&lt;br /&gt;
    db.CreateAsset(a2);&lt;br /&gt;
    db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
    Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
    Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
    Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
    Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
    Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
    Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
T010 is an example of a simple positive test.  In it we create and store 3 assets (ensuring no exceptions), then load those 3 assets back from the database and ensure the fields are correct.  Because AssetBase is not IComparible we just check the ID and Name fields with equals tests.  If any of the Asserts fail, the whole test fails.&lt;br /&gt;
&lt;br /&gt;
=== Stateful Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T011_ExistsSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.True);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
T011 is an example of a stateful test, because it requires the state created by T010 (i.e. the creation of those 3 objects).  In order to test any kind of complicated scenario you will find that you need to use stateful tests to build up various amounts of state (testing along the way), then manipulating and possibly tearing it down.  Without doing this you can't do truly deep testing of function in any complex environment.  This example isn't very stateful (I tried to pick an easy example), but it should give you some ideas.&lt;br /&gt;
&lt;br /&gt;
=== Speculative Tests ===&lt;br /&gt;
Speculative tests are tests that might or might not apply in a given situation.  MySQL testing in the OpenSim tree is done by speculative testing, the tests will only run if there is a properly configured database, otherwise they will not be run.  If you execute '''Assert.Ignore()''' in a '''Test''' the test will end and be ignored.  If you run '''Assert.Ignore()''' in the '''TestFixtureSetup''' all tests in the test fixture will be skipped and ignored.&lt;br /&gt;
&lt;br /&gt;
Speculative testing lets you create tests that require certain preconditions to be met which you can't guarantee on all platforms/configuration, and are an important part of deep testing.&lt;br /&gt;
&lt;br /&gt;
== Adding Tests to the Tree ==&lt;br /&gt;
As we said previously all tests for assembly OpenSim.Foo (in directory OpenSim/Foo) should:&lt;br /&gt;
* be in assembly OpenSim.Foo.Tests.dll&lt;br /&gt;
* not be in the OpenSim.Foo.dll assembly&lt;br /&gt;
* be in OpenSim/Foo/Tests directory&lt;br /&gt;
&lt;br /&gt;
Also, if you have created a new test assembly you must add references to it in both ''.nant/local.include'' and ''.nant/bamboo.build'' to ensure that the assembly is added to the automated bamboo runs as well as the nant test target.&lt;br /&gt;
&lt;br /&gt;
== Executing Tests ==&lt;br /&gt;
&lt;br /&gt;
=== Bamboo ===&lt;br /&gt;
On every commit to opensim all the tests are run on a [http://opensimulator.org:8085 Bamboo build server on opensimulator.org].  The process takes about 5 minutes to build, test, and report the results back out on #opensim-dev via the osmantis bot.&lt;br /&gt;
&lt;br /&gt;
=== Nant ===&lt;br /&gt;
You can manually run all the tests for OpenSim on your system by running '''nant test''' as a nant target.  This will run all the tests that are in the tree, though some speculative tests might be ignored if your platform does not have the right features or configuration to run these tests.&lt;br /&gt;
&lt;br /&gt;
=== NUnit Console ===&lt;br /&gt;
If you only want to run tests for one assembly you can do that using the NUnit Console.  On Linux just run '''nunit-console2 OpenSim.Foo.Tests.dll''' and it will run only the tests for OpenSim.Foo.Tests.dll.  If you are only making changes to 1 dll and just want a quick sanity check, this is the fastest way to do that.&lt;br /&gt;
&lt;br /&gt;
=== Debugging Tests ===&lt;br /&gt;
There is a special page dedicated to this. See [[Debugging Unit Tests]].&lt;br /&gt;
&lt;br /&gt;
== Learning More ==&lt;br /&gt;
You should definitely read the documentation at the [http://www.nunit.org/index.php?p=documentation NUnit homepage] if you want to know more about testing.  It's a very good reference for all the APIs in NUnit that you can use for creating tests.&lt;br /&gt;
&lt;br /&gt;
== Code Coverage ==&lt;br /&gt;
&lt;br /&gt;
A prototype has been included using monocov, which has a profile built-in in mono. Instructions for using monocov can be found on the Mono homepage, in [http://www.mono-project.com/Code_Coverage Code Coverage] section. Unfortunately nunit2 and nant do not support code coverage with monocov (only some other proprietary code coverages), so there is no &amp;lt;monocov&amp;gt; tag. The solution was to implement it using many nunit-console and on &amp;lt;exec&amp;gt; tags. &lt;br /&gt;
&lt;br /&gt;
ATTENTION: Code coverage only works with mono 1.2.x , any other version will most likely not work. Code coverage development is being put on hold for now until it supports newer mono versions.&lt;br /&gt;
&lt;br /&gt;
=== Running ===&lt;br /&gt;
&lt;br /&gt;
Download [http://primates.ximian.com/~lupus/monocov-0.2.tar.gz monocov] and [http://prdownloads.sourceforge.net/nunit/NUnit-2.4.8-net-2.0.zip?download nunit-console] if your nunit-console does not work. To test if it works (my Ubuntu's Hardy version did not), just run one of the tests with nunit-console.&lt;br /&gt;
&lt;br /&gt;
Install monocov (./configure, ./make install, there could be some minor conflicts, I had to add to the compiling line -I/usr/include/mono-1.0/) and make sure the working nunit-console.exe is in /usr/lib/nunit/nunit-console.exe. Now just run nant test-cov and it will generate .cov files and HTML directories in the cov directory. The .cov files can be seen by running monocov on them, and have the same information as the HTML directories.&lt;br /&gt;
&lt;br /&gt;
== Testing Todo ==&lt;br /&gt;
&lt;br /&gt;
=== Coverage ===&lt;br /&gt;
&lt;br /&gt;
A prototype has been done and documented. Now we must keep a look if monocov will evolve to support newer mono versions.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
[[Category:Testing]]&lt;br /&gt;
&lt;br /&gt;
== Links to More Information on Unit Testing ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.nunit.org/index.php?p=quickStart&amp;amp;r=2.4 NUnit Quick Start]&lt;br /&gt;
* [http://xunitpatterns.com/ xUnit Patterns book homepage], with lots of information on good practices, patterns, code smells, etc.&lt;br /&gt;
* There is a lot of information on unit testing at the [http://c2.com/cgi/wiki?search=unittest Cunningham &amp;amp; Cunningham, Inc wiki at c2.com]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Automated_Testing</id>
		<title>Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Automated_Testing"/>
				<updated>2009-03-12T08:42:54Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* Writing Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As OpenSim matures, we are extremely interested in adding more automated verification into the OpenSim source tree.  Test exist not only to prevent bugs from creeping in, but also to provide fair warning that the behavior of the system has changed, and tests may need updating.&lt;br /&gt;
&lt;br /&gt;
In OpenSim today we use NUnit tests.  Our conventions are:&lt;br /&gt;
# Tests should '''not''' exist inside runtime assemblies, as this makes nunit a production requirement&lt;br /&gt;
# Tests should be in .Tests.dll assemblies.  For instance, the tests for OpenSim.Data.SQLite.dll should be in the OpenSim.Data.SQLite.Tests.dll assembly.  This allows for easy removal of test assemblies in products.&lt;br /&gt;
# Tests should be as close to the code as possible, but not intermingled.  So the tests for OpenSim/Data/SQLite should be in OpenSim/Data/SQLite/Tests/.  Through the use of the '''Exclude''' keyword in prebuild.xml you can ensure that directory is part of OpenSim.Data.SQLite.Tests.dll and not OpenSim.Data.SQLite.dll. See exclude clarification in writing unit tests section.&lt;br /&gt;
# Tests testing a class should be grouped into a test class file called xxxTest.cs, where xxx is the name of the class that is being tested.&lt;br /&gt;
# Tests should be able to run safely in a production environment.  That means that care must be taken not to damage data on the machine that it is being run.&lt;br /&gt;
# Tests should be deterministic in other words repeatable. Avoid randomness in tests. See good and bad testing practices below.&lt;br /&gt;
&lt;br /&gt;
== Core Functionality Missing Unit Tests ==&lt;br /&gt;
&lt;br /&gt;
This is a list of functionality which is not covered by unit tests and is identified as highly desireable test target:&lt;br /&gt;
&lt;br /&gt;
# Database Modules (These are mysql tables)&lt;br /&gt;
## region ban&lt;br /&gt;
## land&lt;br /&gt;
## landaccesslist&lt;br /&gt;
&lt;br /&gt;
== Good / Bad Test practices ==&lt;br /&gt;
Creating good tests is an art, not a science.  Tests are useful by how many bugs they find or how many bugs they avoid.  Things you should think about in creating good tests is:&lt;br /&gt;
* Throwing edge cases, like 0, &amp;quot;&amp;quot;, or Null at parameters.  This ensures that people functions are hardened against incomplete data.  Many of our crashes come from the lack of this hardening showing up at just the wrong time.&lt;br /&gt;
* Use stateful testing to build up complex scenarios.  This is more useful than just cursory get / set calls.&lt;br /&gt;
* Random tests are not a good idea. We need test results to be deterministic. In other words tests need to be repeatable. If you want to test for a range it is good idea to make separate tests for min and max values. Random values in fields can fail randomly. When something goes wrong for example in database schema the developer will not necessarily notice if the stored values are random. On the other hand its hard to troubleshoot randomly failing tests as you dont know which specific value caused the failure.&lt;br /&gt;
* Tests should be independent and should not rely on another test being run, passing or failing. An excerpt from [http://xunitpatterns.com/Principles%20of%20Test%20Automation.html#Independent%20Test xUnit Patterns]:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;If tests are interdependent and (even worse) order dependent, we will be depriving ourselves of the useful feedback test failures provide. Interacting Tests [...] tend to fail in a group. The failure of a test that moved the [subject under test] into the state required by the dependent test will lead to the failure of the dependent test too. With both tests failing, how can we tell if it is because of a problem in code that both rely on in some way or is it a problem in code that only the first relies on. With both tests failing we can't tell. We are only talking about two tests here. Imagine how much worse this is with tens or hundreds of tests.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Only one function of the subject under test should be tested in one test. When testing a database access object, for example, write separate tests for creating DB entries, updating them and removing them.&lt;br /&gt;
* Do not use the subject under test to set up the state for the test or to verify the result. Use a different method. When testing a database access object, for example, use raw SQL to insert the initial data into the DB, then run the method being tested. To verify if the operation was successful, use raw SQL again to verify the DB changed as expected.&lt;br /&gt;
&lt;br /&gt;
== Writing Tests ==&lt;br /&gt;
&lt;br /&gt;
See [http://www.nunit.org/index.php?p=quickStart&amp;amp;r=2.4 NUnit Quick Start] for an introduction to unit testing with NUnit.&lt;br /&gt;
&lt;br /&gt;
Writing a new unit test is pretty easy, and very helpful in increasing the stability of opensim by nailing down bugs.  I'm going to present an example here of SQLite Asset testing to show how simple such a test case is to write.  The actual in tree SQLite Asset tests are a little different because the code was factored out so that it was easily applied to any database driver, so don't be concerned with the fact that what you see here isn't in the tree.&lt;br /&gt;
&lt;br /&gt;
Exclude clarification: Make sure your master project (not the test project) has an entry for files like the following so that the test code is not included in the master project dll:&lt;br /&gt;
      &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;lt;Files&amp;gt;&lt;br /&gt;
        &amp;lt;Match pattern=&amp;quot;*.cs&amp;quot; recurse=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;Exclude name=&amp;quot;Tests&amp;quot; pattern=&amp;quot;Tests&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/Match&amp;gt;&lt;br /&gt;
      &amp;lt;/Files&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NUnit Conventions ===&lt;br /&gt;
An NUnit test suite:&lt;br /&gt;
* is a class with a default constructor (takes no arguments)&lt;br /&gt;
* has public methods that are tests&lt;br /&gt;
* uses annotations to determine what are tests&lt;br /&gt;
* runs it's tests in '''alphabetical order by method name'''&lt;br /&gt;
&lt;br /&gt;
An NUnit test method:&lt;br /&gt;
* must be public&lt;br /&gt;
* must return void&lt;br /&gt;
* must take no arguments&lt;br /&gt;
* is successful if no exception or assert is thrown while running it&lt;br /&gt;
&lt;br /&gt;
The run order is important if you want to have early tests that setup some complicated state (like creating objects), and have later tests remove or update that state.  For that reason I find it very helpful to name all test methods '''Txxx_somename''' where '''xxx''' is a number between 000 and 999.  That guaruntees no surprises in run order.&lt;br /&gt;
&lt;br /&gt;
=== Fixture Setup / Teardown ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[TestFixtureSetUp]&lt;br /&gt;
public void Init()&lt;br /&gt;
{&lt;br /&gt;
    uuid1 = UUID.Random();&lt;br /&gt;
    uuid2 = UUID.Random();&lt;br /&gt;
    uuid3 = UUID.Random();&lt;br /&gt;
    name1 = &amp;quot;asset one&amp;quot;;&lt;br /&gt;
    name2 = &amp;quot;asset two&amp;quot;;&lt;br /&gt;
    name3 = &amp;quot;asset three&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    asset1 = new byte[100];&lt;br /&gt;
    asset1.Initialize();&lt;br /&gt;
    file = Path.GetTempFileName() + &amp;quot;.db&amp;quot;;&lt;br /&gt;
    connect = &amp;quot;URI=file:&amp;quot; + file + &amp;quot;,version=3&amp;quot;;&lt;br /&gt;
    db = new SQLiteAssetData();&lt;br /&gt;
    db.Initialise(connect);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[TestFixtureTearDown]&lt;br /&gt;
public void Cleanup()&lt;br /&gt;
{&lt;br /&gt;
    db.Dispose();&lt;br /&gt;
    System.IO.File.Delete(file);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the case of testing something like the database layer, we have to actually attempt to store / retrieve things from a database.  Following from rule #4 of good tests, we want to make sure not to touch the production databases to run our tests, so during startup we generate a temporary file name which is guaranteed not to be an existing file on the system, and use that as our database file name.  By running db.Initialize() the OpenSim migration code will correctly populate that database with the latest schema.&lt;br /&gt;
&lt;br /&gt;
Once we are done with the tests we want to make sure we aren't leaving garbage temp files on the user's system.  So we remove that file we created.&lt;br /&gt;
&lt;br /&gt;
During setup we also create a set of state variables, such as 3 uuids, 3 strings, and a data block.  You could have always just stuck these inline, but variables are there for a reason, so use them.&lt;br /&gt;
&lt;br /&gt;
=== Test Setup / Teardown ===&lt;br /&gt;
&lt;br /&gt;
What's missing in [[Example Test SQLite Assets]] are individual test Setup and Teardown methods. These methods allow each test to be completely self sufficient without the code duplication needed to set up the test environment at the start of each test.&lt;br /&gt;
&lt;br /&gt;
Let's assume the &amp;lt;code&amp;gt;SQLiteAssetData&amp;lt;/code&amp;gt; class provided a &amp;lt;code&amp;gt;FetchAsset()&amp;lt;/code&amp;gt; method and a &amp;lt;code&amp;gt;UpdateAsset()&amp;lt;/code&amp;gt; method. Since every test should be independent of any other test, and &amp;lt;code&amp;gt;FetchAsset()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;UpdateAsset()&amp;lt;/code&amp;gt; should be tested in separate tests, that means each test would need to create its own entries in the asset table in order to succeed. You may have something like this (see [[Example Test SQLite Assets#This Test is Flawed|Example Test SQLite Assets]] for an explanation of &amp;lt;code&amp;gt;sqldb.executeSQL()&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;[Test]&lt;br /&gt;
public void T101_TestFetchAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(...);&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;INSERT INTO assets VALUES({0}, ...)&amp;quot;, a1.uuid, ...);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1_actual = db.FetchAsset(a1.uuid);&lt;br /&gt;
&lt;br /&gt;
    Assert.Equal(a1_actual.uuid, a1.uuid);&lt;br /&gt;
    Assert.Equal(a1_actual.Name, a1.Name);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T103_TestUpdateAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(...);&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;INSERT INTO assets VALUES({0}, ...)&amp;quot;, a1.uuid, ...);&lt;br /&gt;
&lt;br /&gt;
    a1.Name = &amp;quot;new name&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    db.UpdateAsset(a1.uuid, a1);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1_actual = sqldb.executeSQL(&amp;quot;SELECT * FROM assets WHERE uuid = {0}&amp;quot;, a1.uuid);&lt;br /&gt;
&lt;br /&gt;
    Assert.Equal(a1_actual.uuid, a1.uuid);&lt;br /&gt;
    Assert.Equal(a1_actual.Name, a1.Name);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will note that both tests have the same code at the top in which they create an entry in the assets table. This duplicate code can be factored out into a Setup method, which is called before every test is executed (assume &amp;lt;code&amp;gt;a1&amp;lt;/code&amp;gt; is a class attribute):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[SetUp]&lt;br /&gt;
public void SetUp()&lt;br /&gt;
{&lt;br /&gt;
    a1 = new AssetBase(...);&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;INSERT INTO assets VALUES({0}, ...)&amp;quot;, a1.uuid, ...);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[TearDown]&lt;br /&gt;
public void TearDown()&lt;br /&gt;
{&lt;br /&gt;
    // clean up after ourselves so the next test has a clean DB to start with&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;DELETE FROM assets&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T101_TestFetchAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1_actual = db.FetchAsset(a1.uuid);&lt;br /&gt;
&lt;br /&gt;
    Assert.Equal(a1_actual.uuid, a1.uuid);&lt;br /&gt;
    Assert.Equal(a1_actual.Name, a1.Name);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T103_TestUpdateAsset()&lt;br /&gt;
{&lt;br /&gt;
    a1.Name = &amp;quot;new name&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    db.UpdateAsset(a1.uuid, a1);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1_actual = sqldb.executeSQL(&amp;quot;SELECT * FROM assets WHERE uuid = {0}&amp;quot;, a1.uuid);&lt;br /&gt;
&lt;br /&gt;
    Assert.Equal(a1_actual.uuid, a1.uuid);&lt;br /&gt;
    Assert.Equal(a1_actual.Name, a1.Name);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also note the &amp;lt;code&amp;gt;TearDown()&amp;lt;/code&amp;gt; method; it is called after each test has run, regardless whether the test passed or failed. It deletes all the entries in the &amp;lt;code&amp;gt;assets&amp;lt;/code&amp;gt; table so that there is no leftover data in the database to interfere with the next test.&lt;br /&gt;
&lt;br /&gt;
==== Multiple Setup Methods ====&lt;br /&gt;
&lt;br /&gt;
Not all setup and teardown must happen in methods declared [SetUp] and [TearDown]. It may be useful to provide methods which perform part of the setup and to call them from whichever test may need it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
private AssetBase InsertAssetWithRandomData(UUID assetUuid)&lt;br /&gt;
{&lt;br /&gt;
    AssetBase asset = new AssetBase(assetUuid);&lt;br /&gt;
    asset.Name = somethingRandom();&lt;br /&gt;
    asset.Data = somethingRandom();&lt;br /&gt;
&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;INSERT INTO assets VALUES({0}, ...)&amp;quot;, asset.uuid, ...);&lt;br /&gt;
&lt;br /&gt;
    return asset;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T201_TestNeedsTwoAssets()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = InsertAssetWithRandomData(uuid1);&lt;br /&gt;
    AssetBase a2 = InsertAssetWithRandomData(uuid2);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T203_TestNeedsFiveAssets()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = InsertAssetWithRandomData(uuid1);&lt;br /&gt;
    AssetBase a2 = InsertAssetWithRandomData(uuid2);&lt;br /&gt;
    AssetBase a3 = InsertAssetWithRandomData(uuid3);&lt;br /&gt;
    AssetBase a4 = InsertAssetWithRandomData(uuid4);&lt;br /&gt;
    AssetBase a5 = InsertAssetWithRandomData(uuid5);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that &amp;lt;code&amp;gt;InsertAssetWithRandomData&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;private&amp;lt;/code&amp;gt; as it's only called from within the class.&lt;br /&gt;
&lt;br /&gt;
=== Asserts ===&lt;br /&gt;
You will see scattered through the code '''Assert.That(...)'''.  These will throw an exception if the condition is not valid.  This format of assertions is called the [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 Constraint Model] in NUnit, and provides a large number of tests with the flavor of:&lt;br /&gt;
* Assert.That(foo, Is.Null)&lt;br /&gt;
* Assert.That(foo, Is.Not.Null)&lt;br /&gt;
* Assert.That(foo, Is.True)&lt;br /&gt;
* Assert.That(foo, Is.EqualTo(bar))&lt;br /&gt;
* Assert.That(foo, Text.Matches( &amp;quot;*bar*&amp;quot; ))&lt;br /&gt;
&lt;br /&gt;
Of note, Is.EqualTo uses the Equals function of foo, so this can only be used on objects that are IComparable.  Most of the OpenSim base objects are not, so you'll have to compare fields manually in tests.&lt;br /&gt;
&lt;br /&gt;
For the complete set of conditions you can use see [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 the Constraint Model NUnit documentation].  While there is another syntax for tests, the Constraint Model is preferred as it is far more human readable.&lt;br /&gt;
&lt;br /&gt;
=== Simple Negative Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;[Test]&lt;br /&gt;
public void T001_LoadEmpty()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Test T001 is an example of a simple negative test.  We assume a new database will not have any of those assets in them.  While the value of this test may look low, it does provide a baseline in ensuring that the database connection is there, that these return false correctly, and that no other exception is thrown.  Negative tests are a good way to force bounds conditions and ensure that not only does it  ''return what you expect'' it also ''doesn't return what you don't expect''.  Thought of another way, it ensures your code is somewhat defensive in nature, not coughing on bad or unexpected data.&lt;br /&gt;
&lt;br /&gt;
=== Simple Positive Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T010_StoreSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
    AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
    AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
    a1.Data = asset1;&lt;br /&gt;
    a2.Data = asset1;&lt;br /&gt;
    a3.Data = asset1;&lt;br /&gt;
    &lt;br /&gt;
    db.CreateAsset(a1);&lt;br /&gt;
    db.CreateAsset(a2);&lt;br /&gt;
    db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
    Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
    Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
    Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
    Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
    Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
    Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
T010 is an example of a simple positive test.  In it we create and store 3 assets (ensuring no exceptions), then load those 3 assets back from the database and ensure the fields are correct.  Because AssetBase is not IComparible we just check the ID and Name fields with equals tests.  If any of the Asserts fail, the whole test fails.&lt;br /&gt;
&lt;br /&gt;
=== Stateful Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T011_ExistsSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.True);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
T011 is an example of a stateful test, because it requires the state created by T010 (i.e. the creation of those 3 objects).  In order to test any kind of complicated scenario you will find that you need to use stateful tests to build up various amounts of state (testing along the way), then manipulating and possibly tearing it down.  Without doing this you can't do truly deep testing of function in any complex environment.  This example isn't very stateful (I tried to pick an easy example), but it should give you some ideas.&lt;br /&gt;
&lt;br /&gt;
=== Speculative Tests ===&lt;br /&gt;
Speculative tests are tests that might or might not apply in a given situation.  MySQL testing in the OpenSim tree is done by speculative testing, the tests will only run if there is a properly configured database, otherwise they will not be run.  If you execute '''Assert.Ignore()''' in a '''Test''' the test will end and be ignored.  If you run '''Assert.Ignore()''' in the '''TestFixtureSetup''' all tests in the test fixture will be skipped and ignored.&lt;br /&gt;
&lt;br /&gt;
Speculative testing lets you create tests that require certain preconditions to be met which you can't guarantee on all platforms/configuration, and are an important part of deep testing.&lt;br /&gt;
&lt;br /&gt;
== Adding Tests to the Tree ==&lt;br /&gt;
As we said previously all tests for assembly OpenSim.Foo (in directory OpenSim/Foo) should:&lt;br /&gt;
* be in assembly OpenSim.Foo.Tests.dll&lt;br /&gt;
* not be in the OpenSim.Foo.dll assembly&lt;br /&gt;
* be in OpenSim/Foo/Tests directory&lt;br /&gt;
&lt;br /&gt;
Also, if you have created a new test assembly you must add references to it in both ''.nant/local.include'' and ''.nant/bamboo.build'' to ensure that the assembly is added to the automated bamboo runs as well as the nant test target.&lt;br /&gt;
&lt;br /&gt;
== Executing Tests ==&lt;br /&gt;
&lt;br /&gt;
=== Bamboo ===&lt;br /&gt;
On every commit to opensim all the tests are run on a [http://opensimulator.org:8085 Bamboo build server on opensimulator.org].  The process takes about 5 minutes to build, test, and report the results back out on #opensim-dev via the osmantis bot.&lt;br /&gt;
&lt;br /&gt;
=== Nant ===&lt;br /&gt;
You can manually run all the tests for OpenSim on your system by running '''nant test''' as a nant target.  This will run all the tests that are in the tree, though some speculative tests might be ignored if your platform does not have the right features or configuration to run these tests.&lt;br /&gt;
&lt;br /&gt;
=== NUnit Console ===&lt;br /&gt;
If you only want to run tests for one assembly you can do that using the NUnit Console.  On Linux just run '''nunit-console2 OpenSim.Foo.Tests.dll''' and it will run only the tests for OpenSim.Foo.Tests.dll.  If you are only making changes to 1 dll and just want a quick sanity check, this is the fastest way to do that.&lt;br /&gt;
&lt;br /&gt;
=== Debugging Tests ===&lt;br /&gt;
There is a special page dedicated to this. See [[Debugging Unit Tests]].&lt;br /&gt;
&lt;br /&gt;
== Learning More ==&lt;br /&gt;
You should definitely read the documentation at the [http://www.nunit.org/index.php?p=documentation NUnit homepage] if you want to know more about testing.  It's a very good reference for all the APIs in NUnit that you can use for creating tests.&lt;br /&gt;
&lt;br /&gt;
== Code Coverage ==&lt;br /&gt;
&lt;br /&gt;
A prototype has been included using monocov, which has a profile built-in in mono. Instructions for using monocov can be found on the Mono homepage, in [http://www.mono-project.com/Code_Coverage Code Coverage] section. Unfortunately nunit2 and nant do not support code coverage with monocov (only some other proprietary code coverages), so there is no &amp;lt;monocov&amp;gt; tag. The solution was to implement it using many nunit-console and on &amp;lt;exec&amp;gt; tags. &lt;br /&gt;
&lt;br /&gt;
ATTENTION: Code coverage only works with mono 1.2.x , any other version will most likely not work. Code coverage development is being put on hold for now until it supports newer mono versions.&lt;br /&gt;
&lt;br /&gt;
=== Running ===&lt;br /&gt;
&lt;br /&gt;
Download [http://primates.ximian.com/~lupus/monocov-0.2.tar.gz monocov] and [http://prdownloads.sourceforge.net/nunit/NUnit-2.4.8-net-2.0.zip?download nunit-console] if your nunit-console does not work. To test if it works (my Ubuntu's Hardy version did not), just run one of the tests with nunit-console.&lt;br /&gt;
&lt;br /&gt;
Install monocov (./configure, ./make install, there could be some minor conflicts, I had to add to the compiling line -I/usr/include/mono-1.0/) and make sure the working nunit-console.exe is in /usr/lib/nunit/nunit-console.exe. Now just run nant test-cov and it will generate .cov files and HTML directories in the cov directory. The .cov files can be seen by running monocov on them, and have the same information as the HTML directories.&lt;br /&gt;
&lt;br /&gt;
== Testing Todo ==&lt;br /&gt;
&lt;br /&gt;
=== Coverage ===&lt;br /&gt;
&lt;br /&gt;
A prototype has been done and documented. Now we must keep a look if monocov will evolve to support newer mono versions.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
[[Category:Testing]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Automated_Testing</id>
		<title>Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Automated_Testing"/>
				<updated>2009-03-12T08:32:29Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* Test Setup / Teardown */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As OpenSim matures, we are extremely interested in adding more automated verification into the OpenSim source tree.  Test exist not only to prevent bugs from creeping in, but also to provide fair warning that the behavior of the system has changed, and tests may need updating.&lt;br /&gt;
&lt;br /&gt;
In OpenSim today we use NUnit tests.  Our conventions are:&lt;br /&gt;
# Tests should '''not''' exist inside runtime assemblies, as this makes nunit a production requirement&lt;br /&gt;
# Tests should be in .Tests.dll assemblies.  For instance, the tests for OpenSim.Data.SQLite.dll should be in the OpenSim.Data.SQLite.Tests.dll assembly.  This allows for easy removal of test assemblies in products.&lt;br /&gt;
# Tests should be as close to the code as possible, but not intermingled.  So the tests for OpenSim/Data/SQLite should be in OpenSim/Data/SQLite/Tests/.  Through the use of the '''Exclude''' keyword in prebuild.xml you can ensure that directory is part of OpenSim.Data.SQLite.Tests.dll and not OpenSim.Data.SQLite.dll. See exclude clarification in writing unit tests section.&lt;br /&gt;
# Tests testing a class should be grouped into a test class file called xxxTest.cs, where xxx is the name of the class that is being tested.&lt;br /&gt;
# Tests should be able to run safely in a production environment.  That means that care must be taken not to damage data on the machine that it is being run.&lt;br /&gt;
# Tests should be deterministic in other words repeatable. Avoid randomness in tests. See good and bad testing practices below.&lt;br /&gt;
&lt;br /&gt;
== Core Functionality Missing Unit Tests ==&lt;br /&gt;
&lt;br /&gt;
This is a list of functionality which is not covered by unit tests and is identified as highly desireable test target:&lt;br /&gt;
&lt;br /&gt;
# Database Modules (These are mysql tables)&lt;br /&gt;
## region ban&lt;br /&gt;
## land&lt;br /&gt;
## landaccesslist&lt;br /&gt;
&lt;br /&gt;
== Good / Bad Test practices ==&lt;br /&gt;
Creating good tests is an art, not a science.  Tests are useful by how many bugs they find or how many bugs they avoid.  Things you should think about in creating good tests is:&lt;br /&gt;
* Throwing edge cases, like 0, &amp;quot;&amp;quot;, or Null at parameters.  This ensures that people functions are hardened against incomplete data.  Many of our crashes come from the lack of this hardening showing up at just the wrong time.&lt;br /&gt;
* Use stateful testing to build up complex scenarios.  This is more useful than just cursory get / set calls.&lt;br /&gt;
* Random tests are not a good idea. We need test results to be deterministic. In other words tests need to be repeatable. If you want to test for a range it is good idea to make separate tests for min and max values. Random values in fields can fail randomly. When something goes wrong for example in database schema the developer will not necessarily notice if the stored values are random. On the other hand its hard to troubleshoot randomly failing tests as you dont know which specific value caused the failure.&lt;br /&gt;
* Tests should be independent and should not rely on another test being run, passing or failing. An excerpt from [http://xunitpatterns.com/Principles%20of%20Test%20Automation.html#Independent%20Test xUnit Patterns]:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;If tests are interdependent and (even worse) order dependent, we will be depriving ourselves of the useful feedback test failures provide. Interacting Tests [...] tend to fail in a group. The failure of a test that moved the [subject under test] into the state required by the dependent test will lead to the failure of the dependent test too. With both tests failing, how can we tell if it is because of a problem in code that both rely on in some way or is it a problem in code that only the first relies on. With both tests failing we can't tell. We are only talking about two tests here. Imagine how much worse this is with tens or hundreds of tests.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Only one function of the subject under test should be tested in one test. When testing a database access object, for example, write separate tests for creating DB entries, updating them and removing them.&lt;br /&gt;
* Do not use the subject under test to set up the state for the test or to verify the result. Use a different method. When testing a database access object, for example, use raw SQL to insert the initial data into the DB, then run the method being tested. To verify if the operation was successful, use raw SQL again to verify the DB changed as expected.&lt;br /&gt;
&lt;br /&gt;
== Writing Tests ==&lt;br /&gt;
Writing a new unit test is pretty easy, and very helpful in increasing the stability of opensim by nailing down bugs.  I'm going to present an example here of SQLite Asset testing to show how simple such a test case is to write.  The actual in tree SQLite Asset tests are a little different because the code was factored out so that it was easily applied to any database driver, so don't be concerned with the fact that what you see here isn't in the tree.&lt;br /&gt;
&lt;br /&gt;
Exclude clarification: Make sure your master project (not the test project) has an entry for files like the following so that the test code is not included in the master project dll:&lt;br /&gt;
      &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;lt;Files&amp;gt;&lt;br /&gt;
        &amp;lt;Match pattern=&amp;quot;*.cs&amp;quot; recurse=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;Exclude name=&amp;quot;Tests&amp;quot; pattern=&amp;quot;Tests&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/Match&amp;gt;&lt;br /&gt;
      &amp;lt;/Files&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NUnit Conventions ===&lt;br /&gt;
An NUnit test suite:&lt;br /&gt;
* is a class with a default constructor (takes no arguments)&lt;br /&gt;
* has public methods that are tests&lt;br /&gt;
* uses annotations to determine what are tests&lt;br /&gt;
* runs it's tests in '''alphabetical order by method name'''&lt;br /&gt;
&lt;br /&gt;
An NUnit test method:&lt;br /&gt;
* must be public&lt;br /&gt;
* must return void&lt;br /&gt;
* must take no arguments&lt;br /&gt;
* is successful if no exception or assert is thrown while running it&lt;br /&gt;
&lt;br /&gt;
The run order is important if you want to have early tests that setup some complicated state (like creating objects), and have later tests remove or update that state.  For that reason I find it very helpful to name all test methods '''Txxx_somename''' where '''xxx''' is a number between 000 and 999.  That guaruntees no surprises in run order.&lt;br /&gt;
&lt;br /&gt;
==== Fixture Setup / Teardown ====&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[TestFixtureSetUp]&lt;br /&gt;
public void Init()&lt;br /&gt;
{&lt;br /&gt;
    uuid1 = UUID.Random();&lt;br /&gt;
    uuid2 = UUID.Random();&lt;br /&gt;
    uuid3 = UUID.Random();&lt;br /&gt;
    name1 = &amp;quot;asset one&amp;quot;;&lt;br /&gt;
    name2 = &amp;quot;asset two&amp;quot;;&lt;br /&gt;
    name3 = &amp;quot;asset three&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    asset1 = new byte[100];&lt;br /&gt;
    asset1.Initialize();&lt;br /&gt;
    file = Path.GetTempFileName() + &amp;quot;.db&amp;quot;;&lt;br /&gt;
    connect = &amp;quot;URI=file:&amp;quot; + file + &amp;quot;,version=3&amp;quot;;&lt;br /&gt;
    db = new SQLiteAssetData();&lt;br /&gt;
    db.Initialise(connect);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[TestFixtureTearDown]&lt;br /&gt;
public void Cleanup()&lt;br /&gt;
{&lt;br /&gt;
    db.Dispose();&lt;br /&gt;
    System.IO.File.Delete(file);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the case of testing something like the database layer, we have to actually attempt to store / retrieve things from a database.  Following from rule #4 of good tests, we want to make sure not to touch the production databases to run our tests, so during startup we generate a temporary file name which is guaranteed not to be an existing file on the system, and use that as our database file name.  By running db.Initialize() the OpenSim migration code will correctly populate that database with the latest schema.&lt;br /&gt;
&lt;br /&gt;
Once we are done with the tests we want to make sure we aren't leaving garbage temp files on the user's system.  So we remove that file we created.&lt;br /&gt;
&lt;br /&gt;
During setup we also create a set of state variables, such as 3 uuids, 3 strings, and a data block.  You could have always just stuck these inline, but variables are there for a reason, so use them.&lt;br /&gt;
&lt;br /&gt;
==== Test Setup / Teardown ====&lt;br /&gt;
&lt;br /&gt;
What's missing in [[Example Test SQLite Assets]] are individual test Setup and Teardown methods. These methods allow each test to be completely self sufficient without the code duplication needed to set up the test environment at the start of each test.&lt;br /&gt;
&lt;br /&gt;
Let's assume the &amp;lt;code&amp;gt;SQLiteAssetData&amp;lt;/code&amp;gt; class provided a &amp;lt;code&amp;gt;FetchAsset()&amp;lt;/code&amp;gt; method and a &amp;lt;code&amp;gt;UpdateAsset()&amp;lt;/code&amp;gt; method. Since every test should be independent of any other test, and &amp;lt;code&amp;gt;FetchAsset()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;UpdateAsset()&amp;lt;/code&amp;gt; should be tested in separate tests, that means each test would need to create its own entries in the asset table in order to succeed. You may have something like this (see [[Example Test SQLite Assets#This Test is Flawed|Example Test SQLite Assets]] for an explanation of &amp;lt;code&amp;gt;sqldb.executeSQL()&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;[Test]&lt;br /&gt;
public void T101_TestFetchAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(...);&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;INSERT INTO assets VALUES({0}, ...)&amp;quot;, a1.uuid, ...);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1_actual = db.FetchAsset(a1.uuid);&lt;br /&gt;
&lt;br /&gt;
    Assert.Equal(a1_actual.uuid, a1.uuid);&lt;br /&gt;
    Assert.Equal(a1_actual.Name, a1.Name);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T103_TestUpdateAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(...);&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;INSERT INTO assets VALUES({0}, ...)&amp;quot;, a1.uuid, ...);&lt;br /&gt;
&lt;br /&gt;
    a1.Name = &amp;quot;new name&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    db.UpdateAsset(a1.uuid, a1);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1_actual = sqldb.executeSQL(&amp;quot;SELECT * FROM assets WHERE uuid = {0}&amp;quot;, a1.uuid);&lt;br /&gt;
&lt;br /&gt;
    Assert.Equal(a1_actual.uuid, a1.uuid);&lt;br /&gt;
    Assert.Equal(a1_actual.Name, a1.Name);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will note that both tests have the same code at the top in which they create an entry in the assets table. This duplicate code can be factored out into a Setup method, which is called before every test is executed (assume &amp;lt;code&amp;gt;a1&amp;lt;/code&amp;gt; is a class attribute):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[SetUp]&lt;br /&gt;
public void SetUp()&lt;br /&gt;
{&lt;br /&gt;
    a1 = new AssetBase(...);&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;INSERT INTO assets VALUES({0}, ...)&amp;quot;, a1.uuid, ...);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[TearDown]&lt;br /&gt;
public void TearDown()&lt;br /&gt;
{&lt;br /&gt;
    // clean up after ourselves so the next test has a clean DB to start with&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;DELETE FROM assets&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T101_TestFetchAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1_actual = db.FetchAsset(a1.uuid);&lt;br /&gt;
&lt;br /&gt;
    Assert.Equal(a1_actual.uuid, a1.uuid);&lt;br /&gt;
    Assert.Equal(a1_actual.Name, a1.Name);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T103_TestUpdateAsset()&lt;br /&gt;
{&lt;br /&gt;
    a1.Name = &amp;quot;new name&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    db.UpdateAsset(a1.uuid, a1);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1_actual = sqldb.executeSQL(&amp;quot;SELECT * FROM assets WHERE uuid = {0}&amp;quot;, a1.uuid);&lt;br /&gt;
&lt;br /&gt;
    Assert.Equal(a1_actual.uuid, a1.uuid);&lt;br /&gt;
    Assert.Equal(a1_actual.Name, a1.Name);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also note the &amp;lt;code&amp;gt;TearDown()&amp;lt;/code&amp;gt; method; it is called after each test has run, regardless whether the test passed or failed. It deletes all the entries in the &amp;lt;code&amp;gt;assets&amp;lt;/code&amp;gt; table so that there is no leftover data in the database to interfere with the next test.&lt;br /&gt;
&lt;br /&gt;
Not all setup and teardown must happen in methods declared [SetUp] and [TearDown]. It may be useful to provide methods which perform part of the setup and to call them from whichever test may need it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
private AssetBase InsertAssetWithRandomData(UUID assetUuid)&lt;br /&gt;
{&lt;br /&gt;
    AssetBase asset = new AssetBase(assetUuid);&lt;br /&gt;
    asset.Name = somethingRandom();&lt;br /&gt;
    asset.Data = somethingRandom();&lt;br /&gt;
&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;INSERT INTO assets VALUES({0}, ...)&amp;quot;, asset.uuid, ...);&lt;br /&gt;
&lt;br /&gt;
    return asset;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T201_TestNeedsTwoAssets()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = InsertAssetWithRandomData(uuid1);&lt;br /&gt;
    AssetBase a2 = InsertAssetWithRandomData(uuid2);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T203_TestNeedsFiveAssets()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = InsertAssetWithRandomData(uuid1);&lt;br /&gt;
    AssetBase a2 = InsertAssetWithRandomData(uuid2);&lt;br /&gt;
    AssetBase a3 = InsertAssetWithRandomData(uuid3);&lt;br /&gt;
    AssetBase a4 = InsertAssetWithRandomData(uuid4);&lt;br /&gt;
    AssetBase a5 = InsertAssetWithRandomData(uuid5);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that &amp;lt;code&amp;gt;InsertAssetWithRandomData&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;private&amp;lt;/code&amp;gt; as it's only called from within the class.&lt;br /&gt;
&lt;br /&gt;
==== Asserts ====&lt;br /&gt;
You will see scattered through the code '''Assert.That(...)'''.  These will throw an exception if the condition is not valid.  This format of assertions is called the [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 Constraint Model] in NUnit, and provides a large number of tests with the flavor of:&lt;br /&gt;
* Assert.That(foo, Is.Null)&lt;br /&gt;
* Assert.That(foo, Is.Not.Null)&lt;br /&gt;
* Assert.That(foo, Is.True)&lt;br /&gt;
* Assert.That(foo, Is.EqualTo(bar))&lt;br /&gt;
* Assert.That(foo, Text.Matches( &amp;quot;*bar*&amp;quot; ))&lt;br /&gt;
&lt;br /&gt;
Of note, Is.EqualTo uses the Equals function of foo, so this can only be used on objects that are IComparable.  Most of the OpenSim base objects are not, so you'll have to compare fields manually in tests.&lt;br /&gt;
&lt;br /&gt;
For the complete set of conditions you can use see [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 the Constraint Model NUnit documentation].  While there is another syntax for tests, the Constraint Model is preferred as it is far more human readable.&lt;br /&gt;
&lt;br /&gt;
=== Simple Negative Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;[Test]&lt;br /&gt;
public void T001_LoadEmpty()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Test T001 is an example of a simple negative test.  We assume a new database will not have any of those assets in them.  While the value of this test may look low, it does provide a baseline in ensuring that the database connection is there, that these return false correctly, and that no other exception is thrown.  Negative tests are a good way to force bounds conditions and ensure that not only does it  ''return what you expect'' it also ''doesn't return what you don't expect''.  Thought of another way, it ensures your code is somewhat defensive in nature, not coughing on bad or unexpected data.&lt;br /&gt;
&lt;br /&gt;
=== Simple Positive Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T010_StoreSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
    AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
    AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
    a1.Data = asset1;&lt;br /&gt;
    a2.Data = asset1;&lt;br /&gt;
    a3.Data = asset1;&lt;br /&gt;
    &lt;br /&gt;
    db.CreateAsset(a1);&lt;br /&gt;
    db.CreateAsset(a2);&lt;br /&gt;
    db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
    Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
    Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
    Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
    Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
    Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
    Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
T010 is an example of a simple positive test.  In it we create and store 3 assets (ensuring no exceptions), then load those 3 assets back from the database and ensure the fields are correct.  Because AssetBase is not IComparible we just check the ID and Name fields with equals tests.  If any of the Asserts fail, the whole test fails.&lt;br /&gt;
&lt;br /&gt;
=== Stateful Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T011_ExistsSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.True);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
T011 is an example of a stateful test, because it requires the state created by T010 (i.e. the creation of those 3 objects).  In order to test any kind of complicated scenario you will find that you need to use stateful tests to build up various amounts of state (testing along the way), then manipulating and possibly tearing it down.  Without doing this you can't do truly deep testing of function in any complex environment.  This example isn't very stateful (I tried to pick an easy example), but it should give you some ideas.&lt;br /&gt;
&lt;br /&gt;
=== Speculative Tests ===&lt;br /&gt;
Speculative tests are tests that might or might not apply in a given situation.  MySQL testing in the OpenSim tree is done by speculative testing, the tests will only run if there is a properly configured database, otherwise they will not be run.  If you execute '''Assert.Ignore()''' in a '''Test''' the test will end and be ignored.  If you run '''Assert.Ignore()''' in the '''TestFixtureSetup''' all tests in the test fixture will be skipped and ignored.&lt;br /&gt;
&lt;br /&gt;
Speculative testing lets you create tests that require certain preconditions to be met which you can't guarantee on all platforms/configuration, and are an important part of deep testing.&lt;br /&gt;
&lt;br /&gt;
== Adding Tests to the Tree ==&lt;br /&gt;
As we said previously all tests for assembly OpenSim.Foo (in directory OpenSim/Foo) should:&lt;br /&gt;
* be in assembly OpenSim.Foo.Tests.dll&lt;br /&gt;
* not be in the OpenSim.Foo.dll assembly&lt;br /&gt;
* be in OpenSim/Foo/Tests directory&lt;br /&gt;
&lt;br /&gt;
Also, if you have created a new test assembly you must add references to it in both ''.nant/local.include'' and ''.nant/bamboo.build'' to ensure that the assembly is added to the automated bamboo runs as well as the nant test target.&lt;br /&gt;
&lt;br /&gt;
== Executing Tests ==&lt;br /&gt;
&lt;br /&gt;
=== Bamboo ===&lt;br /&gt;
On every commit to opensim all the tests are run on a [http://opensimulator.org:8085 Bamboo build server on opensimulator.org].  The process takes about 5 minutes to build, test, and report the results back out on #opensim-dev via the osmantis bot.&lt;br /&gt;
&lt;br /&gt;
=== Nant ===&lt;br /&gt;
You can manually run all the tests for OpenSim on your system by running '''nant test''' as a nant target.  This will run all the tests that are in the tree, though some speculative tests might be ignored if your platform does not have the right features or configuration to run these tests.&lt;br /&gt;
&lt;br /&gt;
=== NUnit Console ===&lt;br /&gt;
If you only want to run tests for one assembly you can do that using the NUnit Console.  On Linux just run '''nunit-console2 OpenSim.Foo.Tests.dll''' and it will run only the tests for OpenSim.Foo.Tests.dll.  If you are only making changes to 1 dll and just want a quick sanity check, this is the fastest way to do that.&lt;br /&gt;
&lt;br /&gt;
=== Debugging Tests ===&lt;br /&gt;
There is a special page dedicated to this. See [[Debugging Unit Tests]].&lt;br /&gt;
&lt;br /&gt;
== Learning More ==&lt;br /&gt;
You should definitely read the documentation at the [http://www.nunit.org/index.php?p=documentation NUnit homepage] if you want to know more about testing.  It's a very good reference for all the APIs in NUnit that you can use for creating tests.&lt;br /&gt;
&lt;br /&gt;
== Code Coverage ==&lt;br /&gt;
&lt;br /&gt;
A prototype has been included using monocov, which has a profile built-in in mono. Instructions for using monocov can be found on the Mono homepage, in [http://www.mono-project.com/Code_Coverage Code Coverage] section. Unfortunately nunit2 and nant do not support code coverage with monocov (only some other proprietary code coverages), so there is no &amp;lt;monocov&amp;gt; tag. The solution was to implement it using many nunit-console and on &amp;lt;exec&amp;gt; tags. &lt;br /&gt;
&lt;br /&gt;
ATTENTION: Code coverage only works with mono 1.2.x , any other version will most likely not work. Code coverage development is being put on hold for now until it supports newer mono versions.&lt;br /&gt;
&lt;br /&gt;
=== Running ===&lt;br /&gt;
&lt;br /&gt;
Download [http://primates.ximian.com/~lupus/monocov-0.2.tar.gz monocov] and [http://prdownloads.sourceforge.net/nunit/NUnit-2.4.8-net-2.0.zip?download nunit-console] if your nunit-console does not work. To test if it works (my Ubuntu's Hardy version did not), just run one of the tests with nunit-console.&lt;br /&gt;
&lt;br /&gt;
Install monocov (./configure, ./make install, there could be some minor conflicts, I had to add to the compiling line -I/usr/include/mono-1.0/) and make sure the working nunit-console.exe is in /usr/lib/nunit/nunit-console.exe. Now just run nant test-cov and it will generate .cov files and HTML directories in the cov directory. The .cov files can be seen by running monocov on them, and have the same information as the HTML directories.&lt;br /&gt;
&lt;br /&gt;
== Testing Todo ==&lt;br /&gt;
&lt;br /&gt;
=== Coverage ===&lt;br /&gt;
&lt;br /&gt;
A prototype has been done and documented. Now we must keep a look if monocov will evolve to support newer mono versions.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
[[Category:Testing]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Automated_Testing</id>
		<title>Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Automated_Testing"/>
				<updated>2009-03-12T08:23:18Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As OpenSim matures, we are extremely interested in adding more automated verification into the OpenSim source tree.  Test exist not only to prevent bugs from creeping in, but also to provide fair warning that the behavior of the system has changed, and tests may need updating.&lt;br /&gt;
&lt;br /&gt;
In OpenSim today we use NUnit tests.  Our conventions are:&lt;br /&gt;
# Tests should '''not''' exist inside runtime assemblies, as this makes nunit a production requirement&lt;br /&gt;
# Tests should be in .Tests.dll assemblies.  For instance, the tests for OpenSim.Data.SQLite.dll should be in the OpenSim.Data.SQLite.Tests.dll assembly.  This allows for easy removal of test assemblies in products.&lt;br /&gt;
# Tests should be as close to the code as possible, but not intermingled.  So the tests for OpenSim/Data/SQLite should be in OpenSim/Data/SQLite/Tests/.  Through the use of the '''Exclude''' keyword in prebuild.xml you can ensure that directory is part of OpenSim.Data.SQLite.Tests.dll and not OpenSim.Data.SQLite.dll. See exclude clarification in writing unit tests section.&lt;br /&gt;
# Tests testing a class should be grouped into a test class file called xxxTest.cs, where xxx is the name of the class that is being tested.&lt;br /&gt;
# Tests should be able to run safely in a production environment.  That means that care must be taken not to damage data on the machine that it is being run.&lt;br /&gt;
# Tests should be deterministic in other words repeatable. Avoid randomness in tests. See good and bad testing practices below.&lt;br /&gt;
&lt;br /&gt;
== Core Functionality Missing Unit Tests ==&lt;br /&gt;
&lt;br /&gt;
This is a list of functionality which is not covered by unit tests and is identified as highly desireable test target:&lt;br /&gt;
&lt;br /&gt;
# Database Modules (These are mysql tables)&lt;br /&gt;
## region ban&lt;br /&gt;
## land&lt;br /&gt;
## landaccesslist&lt;br /&gt;
&lt;br /&gt;
== Good / Bad Test practices ==&lt;br /&gt;
Creating good tests is an art, not a science.  Tests are useful by how many bugs they find or how many bugs they avoid.  Things you should think about in creating good tests is:&lt;br /&gt;
* Throwing edge cases, like 0, &amp;quot;&amp;quot;, or Null at parameters.  This ensures that people functions are hardened against incomplete data.  Many of our crashes come from the lack of this hardening showing up at just the wrong time.&lt;br /&gt;
* Use stateful testing to build up complex scenarios.  This is more useful than just cursory get / set calls.&lt;br /&gt;
* Random tests are not a good idea. We need test results to be deterministic. In other words tests need to be repeatable. If you want to test for a range it is good idea to make separate tests for min and max values. Random values in fields can fail randomly. When something goes wrong for example in database schema the developer will not necessarily notice if the stored values are random. On the other hand its hard to troubleshoot randomly failing tests as you dont know which specific value caused the failure.&lt;br /&gt;
* Tests should be independent and should not rely on another test being run, passing or failing. An excerpt from [http://xunitpatterns.com/Principles%20of%20Test%20Automation.html#Independent%20Test xUnit Patterns]:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;If tests are interdependent and (even worse) order dependent, we will be depriving ourselves of the useful feedback test failures provide. Interacting Tests [...] tend to fail in a group. The failure of a test that moved the [subject under test] into the state required by the dependent test will lead to the failure of the dependent test too. With both tests failing, how can we tell if it is because of a problem in code that both rely on in some way or is it a problem in code that only the first relies on. With both tests failing we can't tell. We are only talking about two tests here. Imagine how much worse this is with tens or hundreds of tests.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Only one function of the subject under test should be tested in one test. When testing a database access object, for example, write separate tests for creating DB entries, updating them and removing them.&lt;br /&gt;
* Do not use the subject under test to set up the state for the test or to verify the result. Use a different method. When testing a database access object, for example, use raw SQL to insert the initial data into the DB, then run the method being tested. To verify if the operation was successful, use raw SQL again to verify the DB changed as expected.&lt;br /&gt;
&lt;br /&gt;
== Writing Tests ==&lt;br /&gt;
Writing a new unit test is pretty easy, and very helpful in increasing the stability of opensim by nailing down bugs.  I'm going to present an example here of SQLite Asset testing to show how simple such a test case is to write.  The actual in tree SQLite Asset tests are a little different because the code was factored out so that it was easily applied to any database driver, so don't be concerned with the fact that what you see here isn't in the tree.&lt;br /&gt;
&lt;br /&gt;
Exclude clarification: Make sure your master project (not the test project) has an entry for files like the following so that the test code is not included in the master project dll:&lt;br /&gt;
      &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;lt;Files&amp;gt;&lt;br /&gt;
        &amp;lt;Match pattern=&amp;quot;*.cs&amp;quot; recurse=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;Exclude name=&amp;quot;Tests&amp;quot; pattern=&amp;quot;Tests&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/Match&amp;gt;&lt;br /&gt;
      &amp;lt;/Files&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NUnit Conventions ===&lt;br /&gt;
An NUnit test suite:&lt;br /&gt;
* is a class with a default constructor (takes no arguments)&lt;br /&gt;
* has public methods that are tests&lt;br /&gt;
* uses annotations to determine what are tests&lt;br /&gt;
* runs it's tests in '''alphabetical order by method name'''&lt;br /&gt;
&lt;br /&gt;
An NUnit test method:&lt;br /&gt;
* must be public&lt;br /&gt;
* must return void&lt;br /&gt;
* must take no arguments&lt;br /&gt;
* is successful if no exception or assert is thrown while running it&lt;br /&gt;
&lt;br /&gt;
The run order is important if you want to have early tests that setup some complicated state (like creating objects), and have later tests remove or update that state.  For that reason I find it very helpful to name all test methods '''Txxx_somename''' where '''xxx''' is a number between 000 and 999.  That guaruntees no surprises in run order.&lt;br /&gt;
&lt;br /&gt;
==== Fixture Setup / Teardown ====&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[TestFixtureSetUp]&lt;br /&gt;
public void Init()&lt;br /&gt;
{&lt;br /&gt;
    uuid1 = UUID.Random();&lt;br /&gt;
    uuid2 = UUID.Random();&lt;br /&gt;
    uuid3 = UUID.Random();&lt;br /&gt;
    name1 = &amp;quot;asset one&amp;quot;;&lt;br /&gt;
    name2 = &amp;quot;asset two&amp;quot;;&lt;br /&gt;
    name3 = &amp;quot;asset three&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    asset1 = new byte[100];&lt;br /&gt;
    asset1.Initialize();&lt;br /&gt;
    file = Path.GetTempFileName() + &amp;quot;.db&amp;quot;;&lt;br /&gt;
    connect = &amp;quot;URI=file:&amp;quot; + file + &amp;quot;,version=3&amp;quot;;&lt;br /&gt;
    db = new SQLiteAssetData();&lt;br /&gt;
    db.Initialise(connect);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[TestFixtureTearDown]&lt;br /&gt;
public void Cleanup()&lt;br /&gt;
{&lt;br /&gt;
    db.Dispose();&lt;br /&gt;
    System.IO.File.Delete(file);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the case of testing something like the database layer, we have to actually attempt to store / retrieve things from a database.  Following from rule #4 of good tests, we want to make sure not to touch the production databases to run our tests, so during startup we generate a temporary file name which is guaranteed not to be an existing file on the system, and use that as our database file name.  By running db.Initialize() the OpenSim migration code will correctly populate that database with the latest schema.&lt;br /&gt;
&lt;br /&gt;
Once we are done with the tests we want to make sure we aren't leaving garbage temp files on the user's system.  So we remove that file we created.&lt;br /&gt;
&lt;br /&gt;
During setup we also create a set of state variables, such as 3 uuids, 3 strings, and a data block.  You could have always just stuck these inline, but variables are there for a reason, so use them.&lt;br /&gt;
&lt;br /&gt;
==== Test Setup / Teardown ====&lt;br /&gt;
&lt;br /&gt;
What's missing in [[Example Test SQLite Assets]] are individual test Setup and Teardown methods. Let's assume the &amp;lt;code&amp;gt;SQLiteAssetData&amp;lt;/code&amp;gt; class provided a &amp;lt;code&amp;gt;FetchAsset()&amp;lt;/code&amp;gt; method and a &amp;lt;code&amp;gt;UpdateAsset()&amp;lt;/code&amp;gt; method. Since every test should be independent of any other test, and &amp;lt;code&amp;gt;FetchAsset()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;UpdateAsset()&amp;lt;/code&amp;gt; should be tested in separate tests, that means each test would need to create its own entries in the asset table in order to succeed. You may have something like this (see [[Example Test SQLite Assets#This Test is Flawed|Example Test SQLite Assets]] for an explanation of &amp;lt;code&amp;gt;sqldb.executeSQL()&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;[Test]&lt;br /&gt;
public void T101_TestFetchAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(...);&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;INSERT INTO assets VALUES({0}, ...)&amp;quot;, a1.uuid, ...);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1_actual = db.FetchAsset(a1.uuid);&lt;br /&gt;
&lt;br /&gt;
    Assert.Equal(a1_actual.uuid, a1.uuid);&lt;br /&gt;
    Assert.Equal(a1_actual.Name, a1.Name);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T103_TestUpdateAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(...);&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;INSERT INTO assets VALUES({0}, ...)&amp;quot;, a1.uuid, ...);&lt;br /&gt;
&lt;br /&gt;
    a1.Name = &amp;quot;new name&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    db.UpdateAsset(a1.uuid, a1);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1_actual = sqldb.executeSQL(&amp;quot;SELECT * FROM assets WHERE uuid = {0}&amp;quot;, a1.uuid);&lt;br /&gt;
&lt;br /&gt;
    Assert.Equal(a1_actual.uuid, a1.uuid);&lt;br /&gt;
    Assert.Equal(a1_actual.Name, a1.Name);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will note that both tests have the same code at the top in which they create an entry in the assets table. This duplicate code can be factored out into a Setup method, which is called before every test is executed (assume &amp;lt;code&amp;gt;a1&amp;lt;/code&amp;gt; is a class attribute):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[SetUp]&lt;br /&gt;
public void SetUp()&lt;br /&gt;
{&lt;br /&gt;
    a1 = new AssetBase(...);&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;INSERT INTO assets VALUES({0}, ...)&amp;quot;, a1.uuid, ...);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[TearDown]&lt;br /&gt;
public void TearDown()&lt;br /&gt;
{&lt;br /&gt;
    // clean up after ourselves so the next test has a clean DB to start with&lt;br /&gt;
    sqldb.executeSQL(&amp;quot;DELETE FROM assets&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T101_TestFetchAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1_actual = db.FetchAsset(a1.uuid);&lt;br /&gt;
&lt;br /&gt;
    Assert.Equal(a1_actual.uuid, a1.uuid);&lt;br /&gt;
    Assert.Equal(a1_actual.Name, a1.Name);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[Test]&lt;br /&gt;
public void T103_TestUpdateAsset()&lt;br /&gt;
{&lt;br /&gt;
    a1.Name = &amp;quot;new name&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    db.UpdateAsset(a1.uuid, a1);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1_actual = sqldb.executeSQL(&amp;quot;SELECT * FROM assets WHERE uuid = {0}&amp;quot;, a1.uuid);&lt;br /&gt;
&lt;br /&gt;
    Assert.Equal(a1_actual.uuid, a1.uuid);&lt;br /&gt;
    Assert.Equal(a1_actual.Name, a1.Name);&lt;br /&gt;
    // etc&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also note the &amp;lt;code&amp;gt;TearDown()&amp;lt;/code&amp;gt; method; it is called after each test has run, regardless whether the test passed or failed. It deletes all the entries in the &amp;lt;code&amp;gt;assets&amp;lt;/code&amp;gt; table so that there is no leftover data in the database to interfere with the next test.&lt;br /&gt;
&lt;br /&gt;
==== Asserts ====&lt;br /&gt;
You will see scattered through the code '''Assert.That(...)'''.  These will throw an exception if the condition is not valid.  This format of assertions is called the [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 Constraint Model] in NUnit, and provides a large number of tests with the flavor of:&lt;br /&gt;
* Assert.That(foo, Is.Null)&lt;br /&gt;
* Assert.That(foo, Is.Not.Null)&lt;br /&gt;
* Assert.That(foo, Is.True)&lt;br /&gt;
* Assert.That(foo, Is.EqualTo(bar))&lt;br /&gt;
* Assert.That(foo, Text.Matches( &amp;quot;*bar*&amp;quot; ))&lt;br /&gt;
&lt;br /&gt;
Of note, Is.EqualTo uses the Equals function of foo, so this can only be used on objects that are IComparable.  Most of the OpenSim base objects are not, so you'll have to compare fields manually in tests.&lt;br /&gt;
&lt;br /&gt;
For the complete set of conditions you can use see [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 the Constraint Model NUnit documentation].  While there is another syntax for tests, the Constraint Model is preferred as it is far more human readable.&lt;br /&gt;
&lt;br /&gt;
=== Simple Negative Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;[Test]&lt;br /&gt;
public void T001_LoadEmpty()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Test T001 is an example of a simple negative test.  We assume a new database will not have any of those assets in them.  While the value of this test may look low, it does provide a baseline in ensuring that the database connection is there, that these return false correctly, and that no other exception is thrown.  Negative tests are a good way to force bounds conditions and ensure that not only does it  ''return what you expect'' it also ''doesn't return what you don't expect''.  Thought of another way, it ensures your code is somewhat defensive in nature, not coughing on bad or unexpected data.&lt;br /&gt;
&lt;br /&gt;
=== Simple Positive Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T010_StoreSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
    AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
    AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
    a1.Data = asset1;&lt;br /&gt;
    a2.Data = asset1;&lt;br /&gt;
    a3.Data = asset1;&lt;br /&gt;
    &lt;br /&gt;
    db.CreateAsset(a1);&lt;br /&gt;
    db.CreateAsset(a2);&lt;br /&gt;
    db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
    Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
    Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
    Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
    Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
    Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
    Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
T010 is an example of a simple positive test.  In it we create and store 3 assets (ensuring no exceptions), then load those 3 assets back from the database and ensure the fields are correct.  Because AssetBase is not IComparible we just check the ID and Name fields with equals tests.  If any of the Asserts fail, the whole test fails.&lt;br /&gt;
&lt;br /&gt;
=== Stateful Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T011_ExistsSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.True);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
T011 is an example of a stateful test, because it requires the state created by T010 (i.e. the creation of those 3 objects).  In order to test any kind of complicated scenario you will find that you need to use stateful tests to build up various amounts of state (testing along the way), then manipulating and possibly tearing it down.  Without doing this you can't do truly deep testing of function in any complex environment.  This example isn't very stateful (I tried to pick an easy example), but it should give you some ideas.&lt;br /&gt;
&lt;br /&gt;
=== Speculative Tests ===&lt;br /&gt;
Speculative tests are tests that might or might not apply in a given situation.  MySQL testing in the OpenSim tree is done by speculative testing, the tests will only run if there is a properly configured database, otherwise they will not be run.  If you execute '''Assert.Ignore()''' in a '''Test''' the test will end and be ignored.  If you run '''Assert.Ignore()''' in the '''TestFixtureSetup''' all tests in the test fixture will be skipped and ignored.&lt;br /&gt;
&lt;br /&gt;
Speculative testing lets you create tests that require certain preconditions to be met which you can't guarantee on all platforms/configuration, and are an important part of deep testing.&lt;br /&gt;
&lt;br /&gt;
== Adding Tests to the Tree ==&lt;br /&gt;
As we said previously all tests for assembly OpenSim.Foo (in directory OpenSim/Foo) should:&lt;br /&gt;
* be in assembly OpenSim.Foo.Tests.dll&lt;br /&gt;
* not be in the OpenSim.Foo.dll assembly&lt;br /&gt;
* be in OpenSim/Foo/Tests directory&lt;br /&gt;
&lt;br /&gt;
Also, if you have created a new test assembly you must add references to it in both ''.nant/local.include'' and ''.nant/bamboo.build'' to ensure that the assembly is added to the automated bamboo runs as well as the nant test target.&lt;br /&gt;
&lt;br /&gt;
== Executing Tests ==&lt;br /&gt;
&lt;br /&gt;
=== Bamboo ===&lt;br /&gt;
On every commit to opensim all the tests are run on a [http://opensimulator.org:8085 Bamboo build server on opensimulator.org].  The process takes about 5 minutes to build, test, and report the results back out on #opensim-dev via the osmantis bot.&lt;br /&gt;
&lt;br /&gt;
=== Nant ===&lt;br /&gt;
You can manually run all the tests for OpenSim on your system by running '''nant test''' as a nant target.  This will run all the tests that are in the tree, though some speculative tests might be ignored if your platform does not have the right features or configuration to run these tests.&lt;br /&gt;
&lt;br /&gt;
=== NUnit Console ===&lt;br /&gt;
If you only want to run tests for one assembly you can do that using the NUnit Console.  On Linux just run '''nunit-console2 OpenSim.Foo.Tests.dll''' and it will run only the tests for OpenSim.Foo.Tests.dll.  If you are only making changes to 1 dll and just want a quick sanity check, this is the fastest way to do that.&lt;br /&gt;
&lt;br /&gt;
=== Debugging Tests ===&lt;br /&gt;
There is a special page dedicated to this. See [[Debugging Unit Tests]].&lt;br /&gt;
&lt;br /&gt;
== Learning More ==&lt;br /&gt;
You should definitely read the documentation at the [http://www.nunit.org/index.php?p=documentation NUnit homepage] if you want to know more about testing.  It's a very good reference for all the APIs in NUnit that you can use for creating tests.&lt;br /&gt;
&lt;br /&gt;
== Code Coverage ==&lt;br /&gt;
&lt;br /&gt;
A prototype has been included using monocov, which has a profile built-in in mono. Instructions for using monocov can be found on the Mono homepage, in [http://www.mono-project.com/Code_Coverage Code Coverage] section. Unfortunately nunit2 and nant do not support code coverage with monocov (only some other proprietary code coverages), so there is no &amp;lt;monocov&amp;gt; tag. The solution was to implement it using many nunit-console and on &amp;lt;exec&amp;gt; tags. &lt;br /&gt;
&lt;br /&gt;
ATTENTION: Code coverage only works with mono 1.2.x , any other version will most likely not work. Code coverage development is being put on hold for now until it supports newer mono versions.&lt;br /&gt;
&lt;br /&gt;
=== Running ===&lt;br /&gt;
&lt;br /&gt;
Download [http://primates.ximian.com/~lupus/monocov-0.2.tar.gz monocov] and [http://prdownloads.sourceforge.net/nunit/NUnit-2.4.8-net-2.0.zip?download nunit-console] if your nunit-console does not work. To test if it works (my Ubuntu's Hardy version did not), just run one of the tests with nunit-console.&lt;br /&gt;
&lt;br /&gt;
Install monocov (./configure, ./make install, there could be some minor conflicts, I had to add to the compiling line -I/usr/include/mono-1.0/) and make sure the working nunit-console.exe is in /usr/lib/nunit/nunit-console.exe. Now just run nant test-cov and it will generate .cov files and HTML directories in the cov directory. The .cov files can be seen by running monocov on them, and have the same information as the HTML directories.&lt;br /&gt;
&lt;br /&gt;
== Testing Todo ==&lt;br /&gt;
&lt;br /&gt;
=== Coverage ===&lt;br /&gt;
&lt;br /&gt;
A prototype has been done and documented. Now we must keep a look if monocov will evolve to support newer mono versions.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
[[Category:Testing]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Automated_Testing</id>
		<title>Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Automated_Testing"/>
				<updated>2009-03-12T08:00:38Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* Setup / Teardown */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As OpenSim matures, we are extremely interested in adding more automated verification into the OpenSim source tree.  Test exist not only to prevent bugs from creeping in, but also to provide fair warning that the behavior of the system has changed, and tests may need updating.&lt;br /&gt;
&lt;br /&gt;
In OpenSim today we use NUnit tests.  Our conventions are:&lt;br /&gt;
# Tests should '''not''' exist inside runtime assemblies, as this makes nunit a production requirement&lt;br /&gt;
# Tests should be in .Tests.dll assemblies.  For instance, the tests for OpenSim.Data.SQLite.dll should be in the OpenSim.Data.SQLite.Tests.dll assembly.  This allows for easy removal of test assemblies in products.&lt;br /&gt;
# Tests should be as close to the code as possible, but not intermingled.  So the tests for OpenSim/Data/SQLite should be in OpenSim/Data/SQLite/Tests/.  Through the use of the '''Exclude''' keyword in prebuild.xml you can ensure that directory is part of OpenSim.Data.SQLite.Tests.dll and not OpenSim.Data.SQLite.dll. See exclude clarification in writing unit tests section.&lt;br /&gt;
# Tests testing a class should be grouped into a test class file called xxxTest.cs, where xxx is the name of the class that is being tested.&lt;br /&gt;
# Tests should be able to run safely in a production environment.  That means that care must be taken not to damage data on the machine that it is being run.&lt;br /&gt;
# Tests should be deterministic in other words repeatable. Avoid randomness in tests. See good and bad testing practices below.&lt;br /&gt;
&lt;br /&gt;
== Core Functionality Missing Unit Tests ==&lt;br /&gt;
&lt;br /&gt;
This is a list of functionality which is not covered by unit tests and is identified as highly desireable test target:&lt;br /&gt;
&lt;br /&gt;
# Database Modules (These are mysql tables)&lt;br /&gt;
## region ban&lt;br /&gt;
## land&lt;br /&gt;
## landaccesslist&lt;br /&gt;
&lt;br /&gt;
== Good / Bad Test practices ==&lt;br /&gt;
Creating good tests is an art, not a science.  Tests are useful by how many bugs they find or how many bugs they avoid.  Things you should think about in creating good tests is:&lt;br /&gt;
* Throwing edge cases, like 0, &amp;quot;&amp;quot;, or Null at parameters.  This ensures that people functions are hardened against incomplete data.  Many of our crashes come from the lack of this hardening showing up at just the wrong time.&lt;br /&gt;
* Use stateful testing to build up complex scenarios.  This is more useful than just cursory get / set calls.&lt;br /&gt;
* Random tests are not a good idea. We need test results to be deterministic. In other words tests need to be repeatable. If you want to test for a range it is good idea to make separate tests for min and max values. Random values in fields can fail randomly. When something goes wrong for example in database schema the developer will not necessarily notice if the stored values are random. On the other hand its hard to troubleshoot randomly failing tests as you dont know which specific value caused the failure.&lt;br /&gt;
* Tests should be independent and should not rely on another test being run, passing or failing. An excerpt from [http://xunitpatterns.com/Principles%20of%20Test%20Automation.html#Independent%20Test xUnit Patterns]:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;If tests are interdependent and (even worse) order dependent, we will be depriving ourselves of the useful feedback test failures provide. Interacting Tests [...] tend to fail in a group. The failure of a test that moved the [subject under test] into the state required by the dependent test will lead to the failure of the dependent test too. With both tests failing, how can we tell if it is because of a problem in code that both rely on in some way or is it a problem in code that only the first relies on. With both tests failing we can't tell. We are only talking about two tests here. Imagine how much worse this is with tens or hundreds of tests.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Only one function of the subject under test should be tested in one test. When testing a database access object, for example, write separate tests for creating DB entries, updating them and removing them.&lt;br /&gt;
* Do not use the subject under test to set up the state for the test or to verify the result. Use a different method. When testing a database access object, for example, use raw SQL to insert the initial data into the DB, then run the method being tested. To verify if the operation was successful, use raw SQL again to verify the DB changed as expected.&lt;br /&gt;
&lt;br /&gt;
== Writing Tests ==&lt;br /&gt;
Writing a new unit test is pretty easy, and very helpful in increasing the stability of opensim by nailing down bugs.  I'm going to present an example here of SQLite Asset testing to show how simple such a test case is to write.  The actual in tree SQLite Asset tests are a little different because the code was factored out so that it was easily applied to any database driver, so don't be concerned with the fact that what you see here isn't in the tree.&lt;br /&gt;
&lt;br /&gt;
Exclude clarification: Make sure your master project (not the test project) has an entry for files like the following so that the test code is not included in the master project dll:&lt;br /&gt;
      &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;lt;Files&amp;gt;&lt;br /&gt;
        &amp;lt;Match pattern=&amp;quot;*.cs&amp;quot; recurse=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;Exclude name=&amp;quot;Tests&amp;quot; pattern=&amp;quot;Tests&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/Match&amp;gt;&lt;br /&gt;
      &amp;lt;/Files&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NUnit Conventions ===&lt;br /&gt;
An NUnit test suite:&lt;br /&gt;
* is a class with a default constructor (takes no arguments)&lt;br /&gt;
* has public methods that are tests&lt;br /&gt;
* uses annotations to determine what are tests&lt;br /&gt;
* runs it's tests in '''alphabetical order by method name'''&lt;br /&gt;
&lt;br /&gt;
An NUnit test method:&lt;br /&gt;
* must be public&lt;br /&gt;
* must return void&lt;br /&gt;
* must take no arguments&lt;br /&gt;
* is successful if no exception or assert is thrown while running it&lt;br /&gt;
&lt;br /&gt;
The run order is important if you want to have early tests that setup some complicated state (like creating objects), and have later tests remove or update that state.  For that reason I find it very helpful to name all test methods '''Txxx_somename''' where '''xxx''' is a number between 000 and 999.  That guaruntees no surprises in run order.&lt;br /&gt;
&lt;br /&gt;
==== Fixture Setup / Teardown ====&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[TestFixtureSetUp]&lt;br /&gt;
public void Init()&lt;br /&gt;
{&lt;br /&gt;
    uuid1 = UUID.Random();&lt;br /&gt;
    uuid2 = UUID.Random();&lt;br /&gt;
    uuid3 = UUID.Random();&lt;br /&gt;
    name1 = &amp;quot;asset one&amp;quot;;&lt;br /&gt;
    name2 = &amp;quot;asset two&amp;quot;;&lt;br /&gt;
    name3 = &amp;quot;asset three&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    asset1 = new byte[100];&lt;br /&gt;
    asset1.Initialize();&lt;br /&gt;
    file = Path.GetTempFileName() + &amp;quot;.db&amp;quot;;&lt;br /&gt;
    connect = &amp;quot;URI=file:&amp;quot; + file + &amp;quot;,version=3&amp;quot;;&lt;br /&gt;
    db = new SQLiteAssetData();&lt;br /&gt;
    db.Initialise(connect);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[TestFixtureTearDown]&lt;br /&gt;
public void Cleanup()&lt;br /&gt;
{&lt;br /&gt;
    db.Dispose();&lt;br /&gt;
    System.IO.File.Delete(file);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the case of testing something like the database layer, we have to actually attempt to store / retrieve things from a database.  Following from rule #4 of good tests, we want to make sure not to touch the production databases to run our tests, so during startup we generate a temporary file name which is guaranteed not to be an existing file on the system, and use that as our database file name.  By running db.Initialize() the OpenSim migration code will correctly populate that database with the latest schema.&lt;br /&gt;
&lt;br /&gt;
Once we are done with the tests we want to make sure we aren't leaving garbage temp files on the user's system.  So we remove that file we created.&lt;br /&gt;
&lt;br /&gt;
During setup we also create a set of state variables, such as 3 uuids, 3 strings, and a data block.  You could have always just stuck these inline, but variables are there for a reason, so use them.&lt;br /&gt;
&lt;br /&gt;
==== Asserts ====&lt;br /&gt;
You will see scattered through the code '''Assert.That(...)'''.  These will throw an exception if the condition is not valid.  This format of assertions is called the [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 Constraint Model] in NUnit, and provides a large number of tests with the flavor of:&lt;br /&gt;
* Assert.That(foo, Is.Null)&lt;br /&gt;
* Assert.That(foo, Is.Not.Null)&lt;br /&gt;
* Assert.That(foo, Is.True)&lt;br /&gt;
* Assert.That(foo, Is.EqualTo(bar))&lt;br /&gt;
* Assert.That(foo, Text.Matches( &amp;quot;*bar*&amp;quot; ))&lt;br /&gt;
&lt;br /&gt;
Of note, Is.EqualTo uses the Equals function of foo, so this can only be used on objects that are IComparable.  Most of the OpenSim base objects are not, so you'll have to compare fields manually in tests.&lt;br /&gt;
&lt;br /&gt;
For the complete set of conditions you can use see [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 the Constraint Model NUnit documentation].  While there is another syntax for tests, the Constraint Model is preferred as it is far more human readable.&lt;br /&gt;
&lt;br /&gt;
=== Simple Negative Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;[Test]&lt;br /&gt;
public void T001_LoadEmpty()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Test T001 is an example of a simple negative test.  We assume a new database will not have any of those assets in them.  While the value of this test may look low, it does provide a baseline in ensuring that the database connection is there, that these return false correctly, and that no other exception is thrown.  Negative tests are a good way to force bounds conditions and ensure that not only does it  ''return what you expect'' it also ''doesn't return what you don't expect''.  Thought of another way, it ensures your code is somewhat defensive in nature, not coughing on bad or unexpected data.&lt;br /&gt;
&lt;br /&gt;
=== Simple Positive Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T010_StoreSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
    AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
    AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
    a1.Data = asset1;&lt;br /&gt;
    a2.Data = asset1;&lt;br /&gt;
    a3.Data = asset1;&lt;br /&gt;
    &lt;br /&gt;
    db.CreateAsset(a1);&lt;br /&gt;
    db.CreateAsset(a2);&lt;br /&gt;
    db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
    Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
    Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
    Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
    Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
    Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
    Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
T010 is an example of a simple positive test.  In it we create and store 3 assets (ensuring no exceptions), then load those 3 assets back from the database and ensure the fields are correct.  Because AssetBase is not IComparible we just check the ID and Name fields with equals tests.  If any of the Asserts fail, the whole test fails.&lt;br /&gt;
&lt;br /&gt;
=== Stateful Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T011_ExistsSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.True);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
T011 is an example of a stateful test, because it requires the state created by T010 (i.e. the creation of those 3 objects).  In order to test any kind of complicated scenario you will find that you need to use stateful tests to build up various amounts of state (testing along the way), then manipulating and possibly tearing it down.  Without doing this you can't do truly deep testing of function in any complex environment.  This example isn't very stateful (I tried to pick an easy example), but it should give you some ideas.&lt;br /&gt;
&lt;br /&gt;
=== Speculative Tests ===&lt;br /&gt;
Speculative tests are tests that might or might not apply in a given situation.  MySQL testing in the OpenSim tree is done by speculative testing, the tests will only run if there is a properly configured database, otherwise they will not be run.  If you execute '''Assert.Ignore()''' in a '''Test''' the test will end and be ignored.  If you run '''Assert.Ignore()''' in the '''TestFixtureSetup''' all tests in the test fixture will be skipped and ignored.&lt;br /&gt;
&lt;br /&gt;
Speculative testing lets you create tests that require certain preconditions to be met which you can't guarantee on all platforms/configuration, and are an important part of deep testing.&lt;br /&gt;
&lt;br /&gt;
== Adding Tests to the Tree ==&lt;br /&gt;
As we said previously all tests for assembly OpenSim.Foo (in directory OpenSim/Foo) should:&lt;br /&gt;
* be in assembly OpenSim.Foo.Tests.dll&lt;br /&gt;
* not be in the OpenSim.Foo.dll assembly&lt;br /&gt;
* be in OpenSim/Foo/Tests directory&lt;br /&gt;
&lt;br /&gt;
Also, if you have created a new test assembly you must add references to it in both ''.nant/local.include'' and ''.nant/bamboo.build'' to ensure that the assembly is added to the automated bamboo runs as well as the nant test target.&lt;br /&gt;
&lt;br /&gt;
== Executing Tests ==&lt;br /&gt;
&lt;br /&gt;
=== Bamboo ===&lt;br /&gt;
On every commit to opensim all the tests are run on a [http://opensimulator.org:8085 Bamboo build server on opensimulator.org].  The process takes about 5 minutes to build, test, and report the results back out on #opensim-dev via the osmantis bot.&lt;br /&gt;
&lt;br /&gt;
=== Nant ===&lt;br /&gt;
You can manually run all the tests for OpenSim on your system by running '''nant test''' as a nant target.  This will run all the tests that are in the tree, though some speculative tests might be ignored if your platform does not have the right features or configuration to run these tests.&lt;br /&gt;
&lt;br /&gt;
=== NUnit Console ===&lt;br /&gt;
If you only want to run tests for one assembly you can do that using the NUnit Console.  On Linux just run '''nunit-console2 OpenSim.Foo.Tests.dll''' and it will run only the tests for OpenSim.Foo.Tests.dll.  If you are only making changes to 1 dll and just want a quick sanity check, this is the fastest way to do that.&lt;br /&gt;
&lt;br /&gt;
=== Debugging Tests ===&lt;br /&gt;
There is a special page dedicated to this. See [[Debugging Unit Tests]].&lt;br /&gt;
&lt;br /&gt;
== Learning More ==&lt;br /&gt;
You should definitely read the documentation at the [http://www.nunit.org/index.php?p=documentation NUnit homepage] if you want to know more about testing.  It's a very good reference for all the APIs in NUnit that you can use for creating tests.&lt;br /&gt;
&lt;br /&gt;
== Code Coverage ==&lt;br /&gt;
&lt;br /&gt;
A prototype has been included using monocov, which has a profile built-in in mono. Instructions for using monocov can be found on the Mono homepage, in [http://www.mono-project.com/Code_Coverage Code Coverage] section. Unfortunately nunit2 and nant do not support code coverage with monocov (only some other proprietary code coverages), so there is no &amp;lt;monocov&amp;gt; tag. The solution was to implement it using many nunit-console and on &amp;lt;exec&amp;gt; tags. &lt;br /&gt;
&lt;br /&gt;
ATTENTION: Code coverage only works with mono 1.2.x , any other version will most likely not work. Code coverage development is being put on hold for now until it supports newer mono versions.&lt;br /&gt;
&lt;br /&gt;
=== Running ===&lt;br /&gt;
&lt;br /&gt;
Download [http://primates.ximian.com/~lupus/monocov-0.2.tar.gz monocov] and [http://prdownloads.sourceforge.net/nunit/NUnit-2.4.8-net-2.0.zip?download nunit-console] if your nunit-console does not work. To test if it works (my Ubuntu's Hardy version did not), just run one of the tests with nunit-console.&lt;br /&gt;
&lt;br /&gt;
Install monocov (./configure, ./make install, there could be some minor conflicts, I had to add to the compiling line -I/usr/include/mono-1.0/) and make sure the working nunit-console.exe is in /usr/lib/nunit/nunit-console.exe. Now just run nant test-cov and it will generate .cov files and HTML directories in the cov directory. The .cov files can be seen by running monocov on them, and have the same information as the HTML directories.&lt;br /&gt;
&lt;br /&gt;
== Testing Todo ==&lt;br /&gt;
&lt;br /&gt;
=== Coverage ===&lt;br /&gt;
&lt;br /&gt;
A prototype has been done and documented. Now we must keep a look if monocov will evolve to support newer mono versions.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
[[Category:Testing]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Example_Test_SQLite_Assets</id>
		<title>Example Test SQLite Assets</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Example_Test_SQLite_Assets"/>
				<updated>2009-03-12T08:00:02Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* An Example Test - SQLite Assets */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== An Example Test - SQLite Assets ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
using System;&lt;br /&gt;
using System.IO;&lt;br /&gt;
using System.Collections.Generic;&lt;br /&gt;
using NUnit.Framework;&lt;br /&gt;
using NUnit.Framework.SyntaxHelpers;&lt;br /&gt;
using OpenSim.Framework;&lt;br /&gt;
using OpenSim.Data.Tests;&lt;br /&gt;
using OpenSim.Data.SQLite;&lt;br /&gt;
using OpenSim.Region.Environment.Scenes;&lt;br /&gt;
using OpenMetaverse;&lt;br /&gt;
&lt;br /&gt;
namespace OpenSim.Data.SQLite.Tests&lt;br /&gt;
{&lt;br /&gt;
    [TestFixture]&lt;br /&gt;
    public class SQLiteAssetTest&lt;br /&gt;
    {&lt;br /&gt;
        public string file;&lt;br /&gt;
        public string connect;&lt;br /&gt;
        public AssetDataBase db;&lt;br /&gt;
        public UUID uuid1;&lt;br /&gt;
        public UUID uuid2;&lt;br /&gt;
        public UUID uuid3;&lt;br /&gt;
        public string name1;&lt;br /&gt;
        public string name2;&lt;br /&gt;
        public string name3;&lt;br /&gt;
        public byte[] asset1;&lt;br /&gt;
        &lt;br /&gt;
        [TestFixtureSetUp]&lt;br /&gt;
        public void Init()&lt;br /&gt;
        {&lt;br /&gt;
            uuid1 = UUID.Random();&lt;br /&gt;
            uuid2 = UUID.Random();&lt;br /&gt;
            uuid3 = UUID.Random();&lt;br /&gt;
            name1 = &amp;quot;asset one&amp;quot;;&lt;br /&gt;
            name2 = &amp;quot;asset two&amp;quot;;&lt;br /&gt;
            name3 = &amp;quot;asset three&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
            asset1 = new byte[100];&lt;br /&gt;
            asset1.Initialize();&lt;br /&gt;
            file = Path.GetTempFileName() + &amp;quot;.db&amp;quot;;&lt;br /&gt;
            connect = &amp;quot;URI=file:&amp;quot; + file + &amp;quot;,version=3&amp;quot;;&lt;br /&gt;
            db = new SQLiteAssetData();&lt;br /&gt;
            db.Initialise(connect);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [TestFixtureTearDown]&lt;br /&gt;
        public void Cleanup()&lt;br /&gt;
        {&lt;br /&gt;
            db.Dispose();&lt;br /&gt;
            System.IO.File.Delete(file);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T001_LoadEmpty()&lt;br /&gt;
        {&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T010_StoreSimpleAsset()&lt;br /&gt;
        {&lt;br /&gt;
            AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
            AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
            AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
            a1.Data = asset1;&lt;br /&gt;
            a2.Data = asset1;&lt;br /&gt;
            a3.Data = asset1;&lt;br /&gt;
            &lt;br /&gt;
            db.CreateAsset(a1);&lt;br /&gt;
            db.CreateAsset(a2);&lt;br /&gt;
            db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
            AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
            Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
            Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
            AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
            Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
            Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
            AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
            Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
            Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T011_ExistsSimpleAsset()&lt;br /&gt;
        {&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid1), Is.True);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid2), Is.True);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid3), Is.True);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can see 4 of the important annotations here:&lt;br /&gt;
* TestFixture - this class is a test suite&lt;br /&gt;
* TestFixtureSetup - this code is always run before any of the tests are executed&lt;br /&gt;
* TestFixtureTearDown - this code is always run after the tests are done executing, even if they fail.&lt;br /&gt;
* Test - this method is a test&lt;br /&gt;
&lt;br /&gt;
== This Test is Flawed ==&lt;br /&gt;
&lt;br /&gt;
There is also a flaw in the tests above, namely the subject under test (the &amp;lt;code&amp;gt;SQLiteAssetData&amp;lt;/code&amp;gt; object &amp;lt;code&amp;gt;db&amp;lt;/code&amp;gt;) is used in the tests as well as the fixture setup. Consider the following scenario: the &amp;lt;code&amp;gt;SQLiteAssetData&amp;lt;/code&amp;gt; has a caching mechanism keeps track of DB rows in memory. When rows are fetched, they are stored into the cache. When new rows are inserted or existing rows updated, the cache is updated, and eventually the cache is synced to disk.&lt;br /&gt;
&lt;br /&gt;
Note that in the test above, all interactions with the database are handled by this &amp;lt;code&amp;gt;SQLiteAssetData&amp;lt;/code&amp;gt; object. First, it's used to create the database and tables:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[TestFixture]&lt;br /&gt;
public class SQLiteAssetTest&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    public AssetDataBase db;&lt;br /&gt;
        &lt;br /&gt;
    [TestFixtureSetUp]&lt;br /&gt;
    public void Init()&lt;br /&gt;
    {&lt;br /&gt;
        // ...&lt;br /&gt;
        connect = &amp;quot;URI=file:&amp;quot; + Path.GetTempFileName() + &amp;quot;.db,version=3&amp;quot;;&lt;br /&gt;
        db = new SQLiteAssetData();&lt;br /&gt;
        db.Initialise(connect);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    [TestFixtureTearDown]&lt;br /&gt;
    public void Cleanup()&lt;br /&gt;
    {&lt;br /&gt;
        db.Dispose();&lt;br /&gt;
        // ...&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, in &amp;lt;code&amp;gt;T010_StoreSimpleAsset()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;db.CreateAsset()&amp;lt;/code&amp;gt; is called, with the intent to persist the asset to the database on disk. However to verify whether this operation succeeded, &amp;lt;code&amp;gt;db.FetchAsset()&amp;lt;/code&amp;gt; is called:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
    [Test]&lt;br /&gt;
    public void T010_StoreSimpleAsset()&lt;br /&gt;
    {&lt;br /&gt;
        // ...&lt;br /&gt;
        db.CreateAsset(a1);&lt;br /&gt;
        db.CreateAsset(a2);&lt;br /&gt;
        db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
        AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
        Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
        Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
        AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
        Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
        Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
        AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
        Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
        Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now assume a change introduced a bug that prevent the cache from being flushed to disk '''ever'''. The tests above would never discover this bug!&lt;br /&gt;
&lt;br /&gt;
=== How to Fix the Flaw ===&lt;br /&gt;
&lt;br /&gt;
Another means of populating the database and verifying the success of the operations performed by &amp;lt;code&amp;gt;SQLiteAssetData&amp;lt;/code&amp;gt; object should be used instead. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[TestFixture]&lt;br /&gt;
public class SQLiteAssetTest&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
    public string filename, connect;&lt;br /&gt;
    public AssetDataBase db;&lt;br /&gt;
        &lt;br /&gt;
    [TestFixtureSetUp]&lt;br /&gt;
    public void Init()&lt;br /&gt;
    {&lt;br /&gt;
        // ...&lt;br /&gt;
        filename = Path.GetTempFileName() + &amp;quot;.db&amp;quot;;&lt;br /&gt;
        connect = &amp;quot;URI=file:&amp;quot; + filename + &amp;quot;,version=3&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        SQLiteDB sqldb = new SQLiteDBAdapter(connect); // ficticious adapter interfacing directly with SQLite database&lt;br /&gt;
        sqldb.createTable(new SQLiteTable(...));&lt;br /&gt;
        sqldb.executeSQL(&amp;quot;INSET INTO assets VALUES(...)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        db = new SQLiteAssetData();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    [TestFixtureTearDown]&lt;br /&gt;
    public void Cleanup()&lt;br /&gt;
    {&lt;br /&gt;
        db.Dispose();&lt;br /&gt;
        System.IO.File.Delete(filename);&lt;br /&gt;
        // ...&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Similarly, to verify that the &amp;lt;code&amp;gt;SQLiteAssetData&amp;lt;/code&amp;gt; object creates and retrieves assets properly, test &amp;lt;code&amp;gt;T010_StoreSimpleAsset()&amp;lt;/code&amp;gt; might be broken up into two tests:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
    [Test]&lt;br /&gt;
    public void T010_StoreSimpleAsset()&lt;br /&gt;
    {&lt;br /&gt;
        AssetBase a1, a2, a3;&lt;br /&gt;
        // initialize a1, a2 and a3&lt;br /&gt;
&lt;br /&gt;
        db.CreateAsset(a1);&lt;br /&gt;
        db.CreateAsset(a2);&lt;br /&gt;
        db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
        SQLiteDB sqldb = new SQLiteDBAdapter(connect); // ficticious adapter interfacing directly with SQLite database&lt;br /&gt;
        AssetBase a1_actual = sqldb.executeSQL(&amp;quot;SELECT * FROM assets WHERE uuid={0}&amp;quot;, a1.uuid);&lt;br /&gt;
&lt;br /&gt;
        Assert.Equals(a1_actual.uuid, a1.uuid);&lt;br /&gt;
        Assert.Equals(a1_actual.Name, a1.Name);&lt;br /&gt;
        // etc&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    [Test]&lt;br /&gt;
    public void T011_FetchSimpleAsset()&lt;br /&gt;
    {&lt;br /&gt;
        AssetBase a1 = new AssetBase(uuid1, name1, ...);&lt;br /&gt;
&lt;br /&gt;
        SQLiteDB sqldb = new SQLiteDBAdapter(connect); // ficticious adapter interfacing directly with SQLite database&lt;br /&gt;
        AssetBase a1_actual = sqldb.executeSQL(&amp;quot;INSERT INTO assets VALUES({0}, ...)&amp;quot;, a1.uuid, ...);&lt;br /&gt;
        // etc&lt;br /&gt;
&lt;br /&gt;
        // ...&lt;br /&gt;
        AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
        Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
        Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
        AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
        Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
        Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
        AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
        Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
        Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This way &amp;lt;code&amp;gt;T010_StoreSimpleAsset&amp;lt;/code&amp;gt; tests &amp;lt;code&amp;gt;SQLiteAssetData.CreateAsset()&amp;lt;/code&amp;gt; '''only''' and &amp;lt;code&amp;gt;T011_FetchSimpleAsset()&amp;lt;/code&amp;gt; tests &amp;lt;code&amp;gt;SQLiteAssetData.FetchAsset()&amp;lt;/code&amp;gt; '''only'''. If there are any problems in either of those methods or all of them, these tests will discover that there is a problem.&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Automated_Testing</id>
		<title>Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Automated_Testing"/>
				<updated>2009-03-12T07:07:13Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* Setup / Teardown */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As OpenSim matures, we are extremely interested in adding more automated verification into the OpenSim source tree.  Test exist not only to prevent bugs from creeping in, but also to provide fair warning that the behavior of the system has changed, and tests may need updating.&lt;br /&gt;
&lt;br /&gt;
In OpenSim today we use NUnit tests.  Our conventions are:&lt;br /&gt;
# Tests should '''not''' exist inside runtime assemblies, as this makes nunit a production requirement&lt;br /&gt;
# Tests should be in .Tests.dll assemblies.  For instance, the tests for OpenSim.Data.SQLite.dll should be in the OpenSim.Data.SQLite.Tests.dll assembly.  This allows for easy removal of test assemblies in products.&lt;br /&gt;
# Tests should be as close to the code as possible, but not intermingled.  So the tests for OpenSim/Data/SQLite should be in OpenSim/Data/SQLite/Tests/.  Through the use of the '''Exclude''' keyword in prebuild.xml you can ensure that directory is part of OpenSim.Data.SQLite.Tests.dll and not OpenSim.Data.SQLite.dll. See exclude clarification in writing unit tests section.&lt;br /&gt;
# Tests testing a class should be grouped into a test class file called xxxTest.cs, where xxx is the name of the class that is being tested.&lt;br /&gt;
# Tests should be able to run safely in a production environment.  That means that care must be taken not to damage data on the machine that it is being run.&lt;br /&gt;
# Tests should be deterministic in other words repeatable. Avoid randomness in tests. See good and bad testing practices below.&lt;br /&gt;
&lt;br /&gt;
== Core Functionality Missing Unit Tests ==&lt;br /&gt;
&lt;br /&gt;
This is a list of functionality which is not covered by unit tests and is identified as highly desireable test target:&lt;br /&gt;
&lt;br /&gt;
# Database Modules (These are mysql tables)&lt;br /&gt;
## region ban&lt;br /&gt;
## land&lt;br /&gt;
## landaccesslist&lt;br /&gt;
&lt;br /&gt;
== Good / Bad Test practices ==&lt;br /&gt;
Creating good tests is an art, not a science.  Tests are useful by how many bugs they find or how many bugs they avoid.  Things you should think about in creating good tests is:&lt;br /&gt;
* Throwing edge cases, like 0, &amp;quot;&amp;quot;, or Null at parameters.  This ensures that people functions are hardened against incomplete data.  Many of our crashes come from the lack of this hardening showing up at just the wrong time.&lt;br /&gt;
* Use stateful testing to build up complex scenarios.  This is more useful than just cursory get / set calls.&lt;br /&gt;
* Random tests are not a good idea. We need test results to be deterministic. In other words tests need to be repeatable. If you want to test for a range it is good idea to make separate tests for min and max values. Random values in fields can fail randomly. When something goes wrong for example in database schema the developer will not necessarily notice if the stored values are random. On the other hand its hard to troubleshoot randomly failing tests as you dont know which specific value caused the failure.&lt;br /&gt;
* Tests should be independent and should not rely on another test being run, passing or failing. An excerpt from [http://xunitpatterns.com/Principles%20of%20Test%20Automation.html#Independent%20Test xUnit Patterns]:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;If tests are interdependent and (even worse) order dependent, we will be depriving ourselves of the useful feedback test failures provide. Interacting Tests [...] tend to fail in a group. The failure of a test that moved the [subject under test] into the state required by the dependent test will lead to the failure of the dependent test too. With both tests failing, how can we tell if it is because of a problem in code that both rely on in some way or is it a problem in code that only the first relies on. With both tests failing we can't tell. We are only talking about two tests here. Imagine how much worse this is with tens or hundreds of tests.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Only one function of the subject under test should be tested in one test. When testing a database access object, for example, write separate tests for creating DB entries, updating them and removing them.&lt;br /&gt;
* Do not use the subject under test to set up the state for the test or to verify the result. Use a different method. When testing a database access object, for example, use raw SQL to insert the initial data into the DB, then run the method being tested. To verify if the operation was successful, use raw SQL again to verify the DB changed as expected.&lt;br /&gt;
&lt;br /&gt;
== Writing Tests ==&lt;br /&gt;
Writing a new unit test is pretty easy, and very helpful in increasing the stability of opensim by nailing down bugs.  I'm going to present an example here of SQLite Asset testing to show how simple such a test case is to write.  The actual in tree SQLite Asset tests are a little different because the code was factored out so that it was easily applied to any database driver, so don't be concerned with the fact that what you see here isn't in the tree.&lt;br /&gt;
&lt;br /&gt;
Exclude clarification: Make sure your master project (not the test project) has an entry for files like the following so that the test code is not included in the master project dll:&lt;br /&gt;
      &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;lt;Files&amp;gt;&lt;br /&gt;
        &amp;lt;Match pattern=&amp;quot;*.cs&amp;quot; recurse=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;Exclude name=&amp;quot;Tests&amp;quot; pattern=&amp;quot;Tests&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/Match&amp;gt;&lt;br /&gt;
      &amp;lt;/Files&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NUnit Conventions ===&lt;br /&gt;
An NUnit test suite:&lt;br /&gt;
* is a class with a default constructor (takes no arguments)&lt;br /&gt;
* has public methods that are tests&lt;br /&gt;
* uses annotations to determine what are tests&lt;br /&gt;
* runs it's tests in '''alphabetical order by method name'''&lt;br /&gt;
&lt;br /&gt;
An NUnit test method:&lt;br /&gt;
* must be public&lt;br /&gt;
* must return void&lt;br /&gt;
* must take no arguments&lt;br /&gt;
* is successful if no exception or assert is thrown while running it&lt;br /&gt;
&lt;br /&gt;
The run order is important if you want to have early tests that setup some complicated state (like creating objects), and have later tests remove or update that state.  For that reason I find it very helpful to name all test methods '''Txxx_somename''' where '''xxx''' is a number between 000 and 999.  That guaruntees no surprises in run order.&lt;br /&gt;
&lt;br /&gt;
==== Setup / Teardown ====&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[TestFixtureSetUp]&lt;br /&gt;
public void Init()&lt;br /&gt;
{&lt;br /&gt;
    uuid1 = UUID.Random();&lt;br /&gt;
    uuid2 = UUID.Random();&lt;br /&gt;
    uuid3 = UUID.Random();&lt;br /&gt;
    name1 = &amp;quot;asset one&amp;quot;;&lt;br /&gt;
    name2 = &amp;quot;asset two&amp;quot;;&lt;br /&gt;
    name3 = &amp;quot;asset three&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    asset1 = new byte[100];&lt;br /&gt;
    asset1.Initialize();&lt;br /&gt;
    file = Path.GetTempFileName() + &amp;quot;.db&amp;quot;;&lt;br /&gt;
    connect = &amp;quot;URI=file:&amp;quot; + file + &amp;quot;,version=3&amp;quot;;&lt;br /&gt;
    db = new SQLiteAssetData();&lt;br /&gt;
    db.Initialise(connect);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[TestFixtureTearDown]&lt;br /&gt;
public void Cleanup()&lt;br /&gt;
{&lt;br /&gt;
    db.Dispose();&lt;br /&gt;
    System.IO.File.Delete(file);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the case of testing something like the database layer, we have to actually attempt to store / retrieve things from a database.  Following from rule #4 of good tests, we want to make sure not to touch the production databases to run our tests, so during startup we generate a temporary file name which is guaranteed not to be an existing file on the system, and use that as our database file name.  By running db.Initialize() the OpenSim migration code will correctly populate that database with the latest schema.&lt;br /&gt;
&lt;br /&gt;
Once we are done with the tests we want to make sure we aren't leaving garbage temp files on the user's system.  So we remove that file we created.&lt;br /&gt;
&lt;br /&gt;
During setup we also create a set of state variables, such as 3 uuids, 3 strings, and a data block.  You could have always just stuck these inline, but variables are there for a reason, so use them.&lt;br /&gt;
&lt;br /&gt;
==== Asserts ====&lt;br /&gt;
You will see scattered through the code '''Assert.That(...)'''.  These will throw an exception if the condition is not valid.  This format of assertions is called the [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 Constraint Model] in NUnit, and provides a large number of tests with the flavor of:&lt;br /&gt;
* Assert.That(foo, Is.Null)&lt;br /&gt;
* Assert.That(foo, Is.Not.Null)&lt;br /&gt;
* Assert.That(foo, Is.True)&lt;br /&gt;
* Assert.That(foo, Is.EqualTo(bar))&lt;br /&gt;
* Assert.That(foo, Text.Matches( &amp;quot;*bar*&amp;quot; ))&lt;br /&gt;
&lt;br /&gt;
Of note, Is.EqualTo uses the Equals function of foo, so this can only be used on objects that are IComparable.  Most of the OpenSim base objects are not, so you'll have to compare fields manually in tests.&lt;br /&gt;
&lt;br /&gt;
For the complete set of conditions you can use see [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 the Constraint Model NUnit documentation].  While there is another syntax for tests, the Constraint Model is preferred as it is far more human readable.&lt;br /&gt;
&lt;br /&gt;
=== Simple Negative Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;[Test]&lt;br /&gt;
public void T001_LoadEmpty()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Test T001 is an example of a simple negative test.  We assume a new database will not have any of those assets in them.  While the value of this test may look low, it does provide a baseline in ensuring that the database connection is there, that these return false correctly, and that no other exception is thrown.  Negative tests are a good way to force bounds conditions and ensure that not only does it  ''return what you expect'' it also ''doesn't return what you don't expect''.  Thought of another way, it ensures your code is somewhat defensive in nature, not coughing on bad or unexpected data.&lt;br /&gt;
&lt;br /&gt;
=== Simple Positive Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T010_StoreSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
    AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
    AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
    a1.Data = asset1;&lt;br /&gt;
    a2.Data = asset1;&lt;br /&gt;
    a3.Data = asset1;&lt;br /&gt;
    &lt;br /&gt;
    db.CreateAsset(a1);&lt;br /&gt;
    db.CreateAsset(a2);&lt;br /&gt;
    db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
    Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
    Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
    Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
    Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
    Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
    Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
T010 is an example of a simple positive test.  In it we create and store 3 assets (ensuring no exceptions), then load those 3 assets back from the database and ensure the fields are correct.  Because AssetBase is not IComparible we just check the ID and Name fields with equals tests.  If any of the Asserts fail, the whole test fails.&lt;br /&gt;
&lt;br /&gt;
=== Stateful Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T011_ExistsSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.True);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
T011 is an example of a stateful test, because it requires the state created by T010 (i.e. the creation of those 3 objects).  In order to test any kind of complicated scenario you will find that you need to use stateful tests to build up various amounts of state (testing along the way), then manipulating and possibly tearing it down.  Without doing this you can't do truly deep testing of function in any complex environment.  This example isn't very stateful (I tried to pick an easy example), but it should give you some ideas.&lt;br /&gt;
&lt;br /&gt;
=== Speculative Tests ===&lt;br /&gt;
Speculative tests are tests that might or might not apply in a given situation.  MySQL testing in the OpenSim tree is done by speculative testing, the tests will only run if there is a properly configured database, otherwise they will not be run.  If you execute '''Assert.Ignore()''' in a '''Test''' the test will end and be ignored.  If you run '''Assert.Ignore()''' in the '''TestFixtureSetup''' all tests in the test fixture will be skipped and ignored.&lt;br /&gt;
&lt;br /&gt;
Speculative testing lets you create tests that require certain preconditions to be met which you can't guarantee on all platforms/configuration, and are an important part of deep testing.&lt;br /&gt;
&lt;br /&gt;
== Adding Tests to the Tree ==&lt;br /&gt;
As we said previously all tests for assembly OpenSim.Foo (in directory OpenSim/Foo) should:&lt;br /&gt;
* be in assembly OpenSim.Foo.Tests.dll&lt;br /&gt;
* not be in the OpenSim.Foo.dll assembly&lt;br /&gt;
* be in OpenSim/Foo/Tests directory&lt;br /&gt;
&lt;br /&gt;
Also, if you have created a new test assembly you must add references to it in both ''.nant/local.include'' and ''.nant/bamboo.build'' to ensure that the assembly is added to the automated bamboo runs as well as the nant test target.&lt;br /&gt;
&lt;br /&gt;
== Executing Tests ==&lt;br /&gt;
&lt;br /&gt;
=== Bamboo ===&lt;br /&gt;
On every commit to opensim all the tests are run on a [http://opensimulator.org:8085 Bamboo build server on opensimulator.org].  The process takes about 5 minutes to build, test, and report the results back out on #opensim-dev via the osmantis bot.&lt;br /&gt;
&lt;br /&gt;
=== Nant ===&lt;br /&gt;
You can manually run all the tests for OpenSim on your system by running '''nant test''' as a nant target.  This will run all the tests that are in the tree, though some speculative tests might be ignored if your platform does not have the right features or configuration to run these tests.&lt;br /&gt;
&lt;br /&gt;
=== NUnit Console ===&lt;br /&gt;
If you only want to run tests for one assembly you can do that using the NUnit Console.  On Linux just run '''nunit-console2 OpenSim.Foo.Tests.dll''' and it will run only the tests for OpenSim.Foo.Tests.dll.  If you are only making changes to 1 dll and just want a quick sanity check, this is the fastest way to do that.&lt;br /&gt;
&lt;br /&gt;
=== Debugging Tests ===&lt;br /&gt;
There is a special page dedicated to this. See [[Debugging Unit Tests]].&lt;br /&gt;
&lt;br /&gt;
== Learning More ==&lt;br /&gt;
You should definitely read the documentation at the [http://www.nunit.org/index.php?p=documentation NUnit homepage] if you want to know more about testing.  It's a very good reference for all the APIs in NUnit that you can use for creating tests.&lt;br /&gt;
&lt;br /&gt;
== Code Coverage ==&lt;br /&gt;
&lt;br /&gt;
A prototype has been included using monocov, which has a profile built-in in mono. Instructions for using monocov can be found on the Mono homepage, in [http://www.mono-project.com/Code_Coverage Code Coverage] section. Unfortunately nunit2 and nant do not support code coverage with monocov (only some other proprietary code coverages), so there is no &amp;lt;monocov&amp;gt; tag. The solution was to implement it using many nunit-console and on &amp;lt;exec&amp;gt; tags. &lt;br /&gt;
&lt;br /&gt;
ATTENTION: Code coverage only works with mono 1.2.x , any other version will most likely not work. Code coverage development is being put on hold for now until it supports newer mono versions.&lt;br /&gt;
&lt;br /&gt;
=== Running ===&lt;br /&gt;
&lt;br /&gt;
Download [http://primates.ximian.com/~lupus/monocov-0.2.tar.gz monocov] and [http://prdownloads.sourceforge.net/nunit/NUnit-2.4.8-net-2.0.zip?download nunit-console] if your nunit-console does not work. To test if it works (my Ubuntu's Hardy version did not), just run one of the tests with nunit-console.&lt;br /&gt;
&lt;br /&gt;
Install monocov (./configure, ./make install, there could be some minor conflicts, I had to add to the compiling line -I/usr/include/mono-1.0/) and make sure the working nunit-console.exe is in /usr/lib/nunit/nunit-console.exe. Now just run nant test-cov and it will generate .cov files and HTML directories in the cov directory. The .cov files can be seen by running monocov on them, and have the same information as the HTML directories.&lt;br /&gt;
&lt;br /&gt;
== Testing Todo ==&lt;br /&gt;
&lt;br /&gt;
=== Coverage ===&lt;br /&gt;
&lt;br /&gt;
A prototype has been done and documented. Now we must keep a look if monocov will evolve to support newer mono versions.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
[[Category:Testing]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Automated_Testing</id>
		<title>Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Automated_Testing"/>
				<updated>2009-03-12T07:03:41Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* Asserts */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As OpenSim matures, we are extremely interested in adding more automated verification into the OpenSim source tree.  Test exist not only to prevent bugs from creeping in, but also to provide fair warning that the behavior of the system has changed, and tests may need updating.&lt;br /&gt;
&lt;br /&gt;
In OpenSim today we use NUnit tests.  Our conventions are:&lt;br /&gt;
# Tests should '''not''' exist inside runtime assemblies, as this makes nunit a production requirement&lt;br /&gt;
# Tests should be in .Tests.dll assemblies.  For instance, the tests for OpenSim.Data.SQLite.dll should be in the OpenSim.Data.SQLite.Tests.dll assembly.  This allows for easy removal of test assemblies in products.&lt;br /&gt;
# Tests should be as close to the code as possible, but not intermingled.  So the tests for OpenSim/Data/SQLite should be in OpenSim/Data/SQLite/Tests/.  Through the use of the '''Exclude''' keyword in prebuild.xml you can ensure that directory is part of OpenSim.Data.SQLite.Tests.dll and not OpenSim.Data.SQLite.dll. See exclude clarification in writing unit tests section.&lt;br /&gt;
# Tests testing a class should be grouped into a test class file called xxxTest.cs, where xxx is the name of the class that is being tested.&lt;br /&gt;
# Tests should be able to run safely in a production environment.  That means that care must be taken not to damage data on the machine that it is being run.&lt;br /&gt;
# Tests should be deterministic in other words repeatable. Avoid randomness in tests. See good and bad testing practices below.&lt;br /&gt;
&lt;br /&gt;
== Core Functionality Missing Unit Tests ==&lt;br /&gt;
&lt;br /&gt;
This is a list of functionality which is not covered by unit tests and is identified as highly desireable test target:&lt;br /&gt;
&lt;br /&gt;
# Database Modules (These are mysql tables)&lt;br /&gt;
## region ban&lt;br /&gt;
## land&lt;br /&gt;
## landaccesslist&lt;br /&gt;
&lt;br /&gt;
== Good / Bad Test practices ==&lt;br /&gt;
Creating good tests is an art, not a science.  Tests are useful by how many bugs they find or how many bugs they avoid.  Things you should think about in creating good tests is:&lt;br /&gt;
* Throwing edge cases, like 0, &amp;quot;&amp;quot;, or Null at parameters.  This ensures that people functions are hardened against incomplete data.  Many of our crashes come from the lack of this hardening showing up at just the wrong time.&lt;br /&gt;
* Use stateful testing to build up complex scenarios.  This is more useful than just cursory get / set calls.&lt;br /&gt;
* Random tests are not a good idea. We need test results to be deterministic. In other words tests need to be repeatable. If you want to test for a range it is good idea to make separate tests for min and max values. Random values in fields can fail randomly. When something goes wrong for example in database schema the developer will not necessarily notice if the stored values are random. On the other hand its hard to troubleshoot randomly failing tests as you dont know which specific value caused the failure.&lt;br /&gt;
* Tests should be independent and should not rely on another test being run, passing or failing. An excerpt from [http://xunitpatterns.com/Principles%20of%20Test%20Automation.html#Independent%20Test xUnit Patterns]:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;If tests are interdependent and (even worse) order dependent, we will be depriving ourselves of the useful feedback test failures provide. Interacting Tests [...] tend to fail in a group. The failure of a test that moved the [subject under test] into the state required by the dependent test will lead to the failure of the dependent test too. With both tests failing, how can we tell if it is because of a problem in code that both rely on in some way or is it a problem in code that only the first relies on. With both tests failing we can't tell. We are only talking about two tests here. Imagine how much worse this is with tens or hundreds of tests.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Only one function of the subject under test should be tested in one test. When testing a database access object, for example, write separate tests for creating DB entries, updating them and removing them.&lt;br /&gt;
* Do not use the subject under test to set up the state for the test or to verify the result. Use a different method. When testing a database access object, for example, use raw SQL to insert the initial data into the DB, then run the method being tested. To verify if the operation was successful, use raw SQL again to verify the DB changed as expected.&lt;br /&gt;
&lt;br /&gt;
== Writing Tests ==&lt;br /&gt;
Writing a new unit test is pretty easy, and very helpful in increasing the stability of opensim by nailing down bugs.  I'm going to present an example here of SQLite Asset testing to show how simple such a test case is to write.  The actual in tree SQLite Asset tests are a little different because the code was factored out so that it was easily applied to any database driver, so don't be concerned with the fact that what you see here isn't in the tree.&lt;br /&gt;
&lt;br /&gt;
Exclude clarification: Make sure your master project (not the test project) has an entry for files like the following so that the test code is not included in the master project dll:&lt;br /&gt;
      &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;lt;Files&amp;gt;&lt;br /&gt;
        &amp;lt;Match pattern=&amp;quot;*.cs&amp;quot; recurse=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;Exclude name=&amp;quot;Tests&amp;quot; pattern=&amp;quot;Tests&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/Match&amp;gt;&lt;br /&gt;
      &amp;lt;/Files&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NUnit Conventions ===&lt;br /&gt;
An NUnit test suite:&lt;br /&gt;
* is a class with a default constructor (takes no arguments)&lt;br /&gt;
* has public methods that are tests&lt;br /&gt;
* uses annotations to determine what are tests&lt;br /&gt;
* runs it's tests in '''alphabetical order by method name'''&lt;br /&gt;
&lt;br /&gt;
An NUnit test method:&lt;br /&gt;
* must be public&lt;br /&gt;
* must return void&lt;br /&gt;
* must take no arguments&lt;br /&gt;
* is successful if no exception or assert is thrown while running it&lt;br /&gt;
&lt;br /&gt;
The run order is important if you want to have early tests that setup some complicated state (like creating objects), and have later tests remove or update that state.  For that reason I find it very helpful to name all test methods '''Txxx_somename''' where '''xxx''' is a number between 000 and 999.  That guaruntees no surprises in run order.&lt;br /&gt;
&lt;br /&gt;
==== Setup / Teardown ====&lt;br /&gt;
In the case of testing something like the database layer, we have to actually attempt to store / retrieve things from a database.  Following from rule #4 of good tests, we want to make sure not to touch the production databases to run our tests, so during startup we generate a temporary file name which is guaranteed not to be an existing file on the system, and use that as our database file name.  By running db.Initialize() the OpenSim migration code will correctly populate that database with the latest schema.&lt;br /&gt;
&lt;br /&gt;
Once we are done with the tests we want to make sure we aren't leaving garbage temp files on the user's system.  So we remove that file we created.&lt;br /&gt;
&lt;br /&gt;
During setup we also create a set of state variables, such as 3 uuids, 3 strings, and a data block.  You could have always just stuck these inline, but variables are there for a reason, so use them.&lt;br /&gt;
&lt;br /&gt;
==== Asserts ====&lt;br /&gt;
You will see scattered through the code '''Assert.That(...)'''.  These will throw an exception if the condition is not valid.  This format of assertions is called the [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 Constraint Model] in NUnit, and provides a large number of tests with the flavor of:&lt;br /&gt;
* Assert.That(foo, Is.Null)&lt;br /&gt;
* Assert.That(foo, Is.Not.Null)&lt;br /&gt;
* Assert.That(foo, Is.True)&lt;br /&gt;
* Assert.That(foo, Is.EqualTo(bar))&lt;br /&gt;
* Assert.That(foo, Text.Matches( &amp;quot;*bar*&amp;quot; ))&lt;br /&gt;
&lt;br /&gt;
Of note, Is.EqualTo uses the Equals function of foo, so this can only be used on objects that are IComparable.  Most of the OpenSim base objects are not, so you'll have to compare fields manually in tests.&lt;br /&gt;
&lt;br /&gt;
For the complete set of conditions you can use see [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 the Constraint Model NUnit documentation].  While there is another syntax for tests, the Constraint Model is preferred as it is far more human readable.&lt;br /&gt;
&lt;br /&gt;
=== Simple Negative Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;[Test]&lt;br /&gt;
public void T001_LoadEmpty()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Test T001 is an example of a simple negative test.  We assume a new database will not have any of those assets in them.  While the value of this test may look low, it does provide a baseline in ensuring that the database connection is there, that these return false correctly, and that no other exception is thrown.  Negative tests are a good way to force bounds conditions and ensure that not only does it  ''return what you expect'' it also ''doesn't return what you don't expect''.  Thought of another way, it ensures your code is somewhat defensive in nature, not coughing on bad or unexpected data.&lt;br /&gt;
&lt;br /&gt;
=== Simple Positive Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T010_StoreSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
    AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
    AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
    a1.Data = asset1;&lt;br /&gt;
    a2.Data = asset1;&lt;br /&gt;
    a3.Data = asset1;&lt;br /&gt;
    &lt;br /&gt;
    db.CreateAsset(a1);&lt;br /&gt;
    db.CreateAsset(a2);&lt;br /&gt;
    db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
    Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
    Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
    Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
    Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
    Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
    Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
T010 is an example of a simple positive test.  In it we create and store 3 assets (ensuring no exceptions), then load those 3 assets back from the database and ensure the fields are correct.  Because AssetBase is not IComparible we just check the ID and Name fields with equals tests.  If any of the Asserts fail, the whole test fails.&lt;br /&gt;
&lt;br /&gt;
=== Stateful Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T011_ExistsSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.True);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
T011 is an example of a stateful test, because it requires the state created by T010 (i.e. the creation of those 3 objects).  In order to test any kind of complicated scenario you will find that you need to use stateful tests to build up various amounts of state (testing along the way), then manipulating and possibly tearing it down.  Without doing this you can't do truly deep testing of function in any complex environment.  This example isn't very stateful (I tried to pick an easy example), but it should give you some ideas.&lt;br /&gt;
&lt;br /&gt;
=== Speculative Tests ===&lt;br /&gt;
Speculative tests are tests that might or might not apply in a given situation.  MySQL testing in the OpenSim tree is done by speculative testing, the tests will only run if there is a properly configured database, otherwise they will not be run.  If you execute '''Assert.Ignore()''' in a '''Test''' the test will end and be ignored.  If you run '''Assert.Ignore()''' in the '''TestFixtureSetup''' all tests in the test fixture will be skipped and ignored.&lt;br /&gt;
&lt;br /&gt;
Speculative testing lets you create tests that require certain preconditions to be met which you can't guarantee on all platforms/configuration, and are an important part of deep testing.&lt;br /&gt;
&lt;br /&gt;
== Adding Tests to the Tree ==&lt;br /&gt;
As we said previously all tests for assembly OpenSim.Foo (in directory OpenSim/Foo) should:&lt;br /&gt;
* be in assembly OpenSim.Foo.Tests.dll&lt;br /&gt;
* not be in the OpenSim.Foo.dll assembly&lt;br /&gt;
* be in OpenSim/Foo/Tests directory&lt;br /&gt;
&lt;br /&gt;
Also, if you have created a new test assembly you must add references to it in both ''.nant/local.include'' and ''.nant/bamboo.build'' to ensure that the assembly is added to the automated bamboo runs as well as the nant test target.&lt;br /&gt;
&lt;br /&gt;
== Executing Tests ==&lt;br /&gt;
&lt;br /&gt;
=== Bamboo ===&lt;br /&gt;
On every commit to opensim all the tests are run on a [http://opensimulator.org:8085 Bamboo build server on opensimulator.org].  The process takes about 5 minutes to build, test, and report the results back out on #opensim-dev via the osmantis bot.&lt;br /&gt;
&lt;br /&gt;
=== Nant ===&lt;br /&gt;
You can manually run all the tests for OpenSim on your system by running '''nant test''' as a nant target.  This will run all the tests that are in the tree, though some speculative tests might be ignored if your platform does not have the right features or configuration to run these tests.&lt;br /&gt;
&lt;br /&gt;
=== NUnit Console ===&lt;br /&gt;
If you only want to run tests for one assembly you can do that using the NUnit Console.  On Linux just run '''nunit-console2 OpenSim.Foo.Tests.dll''' and it will run only the tests for OpenSim.Foo.Tests.dll.  If you are only making changes to 1 dll and just want a quick sanity check, this is the fastest way to do that.&lt;br /&gt;
&lt;br /&gt;
=== Debugging Tests ===&lt;br /&gt;
There is a special page dedicated to this. See [[Debugging Unit Tests]].&lt;br /&gt;
&lt;br /&gt;
== Learning More ==&lt;br /&gt;
You should definitely read the documentation at the [http://www.nunit.org/index.php?p=documentation NUnit homepage] if you want to know more about testing.  It's a very good reference for all the APIs in NUnit that you can use for creating tests.&lt;br /&gt;
&lt;br /&gt;
== Code Coverage ==&lt;br /&gt;
&lt;br /&gt;
A prototype has been included using monocov, which has a profile built-in in mono. Instructions for using monocov can be found on the Mono homepage, in [http://www.mono-project.com/Code_Coverage Code Coverage] section. Unfortunately nunit2 and nant do not support code coverage with monocov (only some other proprietary code coverages), so there is no &amp;lt;monocov&amp;gt; tag. The solution was to implement it using many nunit-console and on &amp;lt;exec&amp;gt; tags. &lt;br /&gt;
&lt;br /&gt;
ATTENTION: Code coverage only works with mono 1.2.x , any other version will most likely not work. Code coverage development is being put on hold for now until it supports newer mono versions.&lt;br /&gt;
&lt;br /&gt;
=== Running ===&lt;br /&gt;
&lt;br /&gt;
Download [http://primates.ximian.com/~lupus/monocov-0.2.tar.gz monocov] and [http://prdownloads.sourceforge.net/nunit/NUnit-2.4.8-net-2.0.zip?download nunit-console] if your nunit-console does not work. To test if it works (my Ubuntu's Hardy version did not), just run one of the tests with nunit-console.&lt;br /&gt;
&lt;br /&gt;
Install monocov (./configure, ./make install, there could be some minor conflicts, I had to add to the compiling line -I/usr/include/mono-1.0/) and make sure the working nunit-console.exe is in /usr/lib/nunit/nunit-console.exe. Now just run nant test-cov and it will generate .cov files and HTML directories in the cov directory. The .cov files can be seen by running monocov on them, and have the same information as the HTML directories.&lt;br /&gt;
&lt;br /&gt;
== Testing Todo ==&lt;br /&gt;
&lt;br /&gt;
=== Coverage ===&lt;br /&gt;
&lt;br /&gt;
A prototype has been done and documented. Now we must keep a look if monocov will evolve to support newer mono versions.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
[[Category:Testing]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Automated_Testing</id>
		<title>Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Automated_Testing"/>
				<updated>2009-03-12T07:02:09Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As OpenSim matures, we are extremely interested in adding more automated verification into the OpenSim source tree.  Test exist not only to prevent bugs from creeping in, but also to provide fair warning that the behavior of the system has changed, and tests may need updating.&lt;br /&gt;
&lt;br /&gt;
In OpenSim today we use NUnit tests.  Our conventions are:&lt;br /&gt;
# Tests should '''not''' exist inside runtime assemblies, as this makes nunit a production requirement&lt;br /&gt;
# Tests should be in .Tests.dll assemblies.  For instance, the tests for OpenSim.Data.SQLite.dll should be in the OpenSim.Data.SQLite.Tests.dll assembly.  This allows for easy removal of test assemblies in products.&lt;br /&gt;
# Tests should be as close to the code as possible, but not intermingled.  So the tests for OpenSim/Data/SQLite should be in OpenSim/Data/SQLite/Tests/.  Through the use of the '''Exclude''' keyword in prebuild.xml you can ensure that directory is part of OpenSim.Data.SQLite.Tests.dll and not OpenSim.Data.SQLite.dll. See exclude clarification in writing unit tests section.&lt;br /&gt;
# Tests testing a class should be grouped into a test class file called xxxTest.cs, where xxx is the name of the class that is being tested.&lt;br /&gt;
# Tests should be able to run safely in a production environment.  That means that care must be taken not to damage data on the machine that it is being run.&lt;br /&gt;
# Tests should be deterministic in other words repeatable. Avoid randomness in tests. See good and bad testing practices below.&lt;br /&gt;
&lt;br /&gt;
== Core Functionality Missing Unit Tests ==&lt;br /&gt;
&lt;br /&gt;
This is a list of functionality which is not covered by unit tests and is identified as highly desireable test target:&lt;br /&gt;
&lt;br /&gt;
# Database Modules (These are mysql tables)&lt;br /&gt;
## region ban&lt;br /&gt;
## land&lt;br /&gt;
## landaccesslist&lt;br /&gt;
&lt;br /&gt;
== Good / Bad Test practices ==&lt;br /&gt;
Creating good tests is an art, not a science.  Tests are useful by how many bugs they find or how many bugs they avoid.  Things you should think about in creating good tests is:&lt;br /&gt;
* Throwing edge cases, like 0, &amp;quot;&amp;quot;, or Null at parameters.  This ensures that people functions are hardened against incomplete data.  Many of our crashes come from the lack of this hardening showing up at just the wrong time.&lt;br /&gt;
* Use stateful testing to build up complex scenarios.  This is more useful than just cursory get / set calls.&lt;br /&gt;
* Random tests are not a good idea. We need test results to be deterministic. In other words tests need to be repeatable. If you want to test for a range it is good idea to make separate tests for min and max values. Random values in fields can fail randomly. When something goes wrong for example in database schema the developer will not necessarily notice if the stored values are random. On the other hand its hard to troubleshoot randomly failing tests as you dont know which specific value caused the failure.&lt;br /&gt;
* Tests should be independent and should not rely on another test being run, passing or failing. An excerpt from [http://xunitpatterns.com/Principles%20of%20Test%20Automation.html#Independent%20Test xUnit Patterns]:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;If tests are interdependent and (even worse) order dependent, we will be depriving ourselves of the useful feedback test failures provide. Interacting Tests [...] tend to fail in a group. The failure of a test that moved the [subject under test] into the state required by the dependent test will lead to the failure of the dependent test too. With both tests failing, how can we tell if it is because of a problem in code that both rely on in some way or is it a problem in code that only the first relies on. With both tests failing we can't tell. We are only talking about two tests here. Imagine how much worse this is with tens or hundreds of tests.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Only one function of the subject under test should be tested in one test. When testing a database access object, for example, write separate tests for creating DB entries, updating them and removing them.&lt;br /&gt;
* Do not use the subject under test to set up the state for the test or to verify the result. Use a different method. When testing a database access object, for example, use raw SQL to insert the initial data into the DB, then run the method being tested. To verify if the operation was successful, use raw SQL again to verify the DB changed as expected.&lt;br /&gt;
&lt;br /&gt;
== Writing Tests ==&lt;br /&gt;
Writing a new unit test is pretty easy, and very helpful in increasing the stability of opensim by nailing down bugs.  I'm going to present an example here of SQLite Asset testing to show how simple such a test case is to write.  The actual in tree SQLite Asset tests are a little different because the code was factored out so that it was easily applied to any database driver, so don't be concerned with the fact that what you see here isn't in the tree.&lt;br /&gt;
&lt;br /&gt;
Exclude clarification: Make sure your master project (not the test project) has an entry for files like the following so that the test code is not included in the master project dll:&lt;br /&gt;
      &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;lt;Files&amp;gt;&lt;br /&gt;
        &amp;lt;Match pattern=&amp;quot;*.cs&amp;quot; recurse=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;Exclude name=&amp;quot;Tests&amp;quot; pattern=&amp;quot;Tests&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/Match&amp;gt;&lt;br /&gt;
      &amp;lt;/Files&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NUnit Conventions ===&lt;br /&gt;
An NUnit test suite:&lt;br /&gt;
* is a class with a default constructor (takes no arguments)&lt;br /&gt;
* has public methods that are tests&lt;br /&gt;
* uses annotations to determine what are tests&lt;br /&gt;
* runs it's tests in '''alphabetical order by method name'''&lt;br /&gt;
&lt;br /&gt;
An NUnit test method:&lt;br /&gt;
* must be public&lt;br /&gt;
* must return void&lt;br /&gt;
* must take no arguments&lt;br /&gt;
* is successful if no exception or assert is thrown while running it&lt;br /&gt;
&lt;br /&gt;
The run order is important if you want to have early tests that setup some complicated state (like creating objects), and have later tests remove or update that state.  For that reason I find it very helpful to name all test methods '''Txxx_somename''' where '''xxx''' is a number between 000 and 999.  That guaruntees no surprises in run order.&lt;br /&gt;
&lt;br /&gt;
==== Setup / Teardown ====&lt;br /&gt;
In the case of testing something like the database layer, we have to actually attempt to store / retrieve things from a database.  Following from rule #4 of good tests, we want to make sure not to touch the production databases to run our tests, so during startup we generate a temporary file name which is guaranteed not to be an existing file on the system, and use that as our database file name.  By running db.Initialize() the OpenSim migration code will correctly populate that database with the latest schema.&lt;br /&gt;
&lt;br /&gt;
Once we are done with the tests we want to make sure we aren't leaving garbage temp files on the user's system.  So we remove that file we created.&lt;br /&gt;
&lt;br /&gt;
During setup we also create a set of state variables, such as 3 uuids, 3 strings, and a data block.  You could have always just stuck these inline, but variables are there for a reason, so use them.&lt;br /&gt;
&lt;br /&gt;
==== Asserts ====&lt;br /&gt;
You will see scattered through the code '''Assert.That(...)'''.  These will throw an exception if the condition is not valid.  This format of assertions is called the [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 Contraint Model] in NUnit, and provides a large number of tests with the flavor of:&lt;br /&gt;
* Assert.That(foo, Is.Null)&lt;br /&gt;
* Assert.That(foo, Is.Not.Null)&lt;br /&gt;
* Assert.That(foo, Is.True)&lt;br /&gt;
* Assert.That(foo, Is.EqualTo(bar))&lt;br /&gt;
* Assert.That(foo, Text.Matches( &amp;quot;*bar*&amp;quot; ))&lt;br /&gt;
&lt;br /&gt;
Of note, Is.EqualTo uses the Equals function of foo, so this can only be used on objects that are IComparable.  Most of the OpenSim base objects are not, so you'll have to compare fields manually in tests.&lt;br /&gt;
&lt;br /&gt;
For the complete set of conditions you can use see [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 the Contraint Model NUnit documentation].  While there is another syntax for tests, the Constraint Model is preferred as it is far more human readable.&lt;br /&gt;
&lt;br /&gt;
=== Simple Negative Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;[Test]&lt;br /&gt;
public void T001_LoadEmpty()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Test T001 is an example of a simple negative test.  We assume a new database will not have any of those assets in them.  While the value of this test may look low, it does provide a baseline in ensuring that the database connection is there, that these return false correctly, and that no other exception is thrown.  Negative tests are a good way to force bounds conditions and ensure that not only does it  ''return what you expect'' it also ''doesn't return what you don't expect''.  Thought of another way, it ensures your code is somewhat defensive in nature, not coughing on bad or unexpected data.&lt;br /&gt;
&lt;br /&gt;
=== Simple Positive Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T010_StoreSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
    AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
    AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
    a1.Data = asset1;&lt;br /&gt;
    a2.Data = asset1;&lt;br /&gt;
    a3.Data = asset1;&lt;br /&gt;
    &lt;br /&gt;
    db.CreateAsset(a1);&lt;br /&gt;
    db.CreateAsset(a2);&lt;br /&gt;
    db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
    Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
    Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
    Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
    Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
    Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
    Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
T010 is an example of a simple positive test.  In it we create and store 3 assets (ensuring no exceptions), then load those 3 assets back from the database and ensure the fields are correct.  Because AssetBase is not IComparible we just check the ID and Name fields with equals tests.  If any of the Asserts fail, the whole test fails.&lt;br /&gt;
&lt;br /&gt;
=== Stateful Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T011_ExistsSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.True);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
T011 is an example of a stateful test, because it requires the state created by T010 (i.e. the creation of those 3 objects).  In order to test any kind of complicated scenario you will find that you need to use stateful tests to build up various amounts of state (testing along the way), then manipulating and possibly tearing it down.  Without doing this you can't do truly deep testing of function in any complex environment.  This example isn't very stateful (I tried to pick an easy example), but it should give you some ideas.&lt;br /&gt;
&lt;br /&gt;
=== Speculative Tests ===&lt;br /&gt;
Speculative tests are tests that might or might not apply in a given situation.  MySQL testing in the OpenSim tree is done by speculative testing, the tests will only run if there is a properly configured database, otherwise they will not be run.  If you execute '''Assert.Ignore()''' in a '''Test''' the test will end and be ignored.  If you run '''Assert.Ignore()''' in the '''TestFixtureSetup''' all tests in the test fixture will be skipped and ignored.&lt;br /&gt;
&lt;br /&gt;
Speculative testing lets you create tests that require certain preconditions to be met which you can't guarantee on all platforms/configuration, and are an important part of deep testing.&lt;br /&gt;
&lt;br /&gt;
== Adding Tests to the Tree ==&lt;br /&gt;
As we said previously all tests for assembly OpenSim.Foo (in directory OpenSim/Foo) should:&lt;br /&gt;
* be in assembly OpenSim.Foo.Tests.dll&lt;br /&gt;
* not be in the OpenSim.Foo.dll assembly&lt;br /&gt;
* be in OpenSim/Foo/Tests directory&lt;br /&gt;
&lt;br /&gt;
Also, if you have created a new test assembly you must add references to it in both ''.nant/local.include'' and ''.nant/bamboo.build'' to ensure that the assembly is added to the automated bamboo runs as well as the nant test target.&lt;br /&gt;
&lt;br /&gt;
== Executing Tests ==&lt;br /&gt;
&lt;br /&gt;
=== Bamboo ===&lt;br /&gt;
On every commit to opensim all the tests are run on a [http://opensimulator.org:8085 Bamboo build server on opensimulator.org].  The process takes about 5 minutes to build, test, and report the results back out on #opensim-dev via the osmantis bot.&lt;br /&gt;
&lt;br /&gt;
=== Nant ===&lt;br /&gt;
You can manually run all the tests for OpenSim on your system by running '''nant test''' as a nant target.  This will run all the tests that are in the tree, though some speculative tests might be ignored if your platform does not have the right features or configuration to run these tests.&lt;br /&gt;
&lt;br /&gt;
=== NUnit Console ===&lt;br /&gt;
If you only want to run tests for one assembly you can do that using the NUnit Console.  On Linux just run '''nunit-console2 OpenSim.Foo.Tests.dll''' and it will run only the tests for OpenSim.Foo.Tests.dll.  If you are only making changes to 1 dll and just want a quick sanity check, this is the fastest way to do that.&lt;br /&gt;
&lt;br /&gt;
=== Debugging Tests ===&lt;br /&gt;
There is a special page dedicated to this. See [[Debugging Unit Tests]].&lt;br /&gt;
&lt;br /&gt;
== Learning More ==&lt;br /&gt;
You should definitely read the documentation at the [http://www.nunit.org/index.php?p=documentation NUnit homepage] if you want to know more about testing.  It's a very good reference for all the APIs in NUnit that you can use for creating tests.&lt;br /&gt;
&lt;br /&gt;
== Code Coverage ==&lt;br /&gt;
&lt;br /&gt;
A prototype has been included using monocov, which has a profile built-in in mono. Instructions for using monocov can be found on the Mono homepage, in [http://www.mono-project.com/Code_Coverage Code Coverage] section. Unfortunately nunit2 and nant do not support code coverage with monocov (only some other proprietary code coverages), so there is no &amp;lt;monocov&amp;gt; tag. The solution was to implement it using many nunit-console and on &amp;lt;exec&amp;gt; tags. &lt;br /&gt;
&lt;br /&gt;
ATTENTION: Code coverage only works with mono 1.2.x , any other version will most likely not work. Code coverage development is being put on hold for now until it supports newer mono versions.&lt;br /&gt;
&lt;br /&gt;
=== Running ===&lt;br /&gt;
&lt;br /&gt;
Download [http://primates.ximian.com/~lupus/monocov-0.2.tar.gz monocov] and [http://prdownloads.sourceforge.net/nunit/NUnit-2.4.8-net-2.0.zip?download nunit-console] if your nunit-console does not work. To test if it works (my Ubuntu's Hardy version did not), just run one of the tests with nunit-console.&lt;br /&gt;
&lt;br /&gt;
Install monocov (./configure, ./make install, there could be some minor conflicts, I had to add to the compiling line -I/usr/include/mono-1.0/) and make sure the working nunit-console.exe is in /usr/lib/nunit/nunit-console.exe. Now just run nant test-cov and it will generate .cov files and HTML directories in the cov directory. The .cov files can be seen by running monocov on them, and have the same information as the HTML directories.&lt;br /&gt;
&lt;br /&gt;
== Testing Todo ==&lt;br /&gt;
&lt;br /&gt;
=== Coverage ===&lt;br /&gt;
&lt;br /&gt;
A prototype has been done and documented. Now we must keep a look if monocov will evolve to support newer mono versions.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
[[Category:Testing]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Automated_Testing</id>
		<title>Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Automated_Testing"/>
				<updated>2009-03-12T07:01:14Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* Stateful Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As OpenSim matures, we are extremely interested in adding more automated verification into the OpenSim source tree.  Test exist not only to prevent bugs from creeping in, but also to provide fair warning that the behavior of the system has changed, and tests may need updating.&lt;br /&gt;
&lt;br /&gt;
In OpenSim today we use NUnit tests.  Our conventions are:&lt;br /&gt;
# Tests should '''not''' exist inside runtime assemblies, as this makes nunit a production requirement&lt;br /&gt;
# Tests should be in .Tests.dll assemblies.  For instance, the tests for OpenSim.Data.SQLite.dll should be in the OpenSim.Data.SQLite.Tests.dll assembly.  This allows for easy removal of test assemblies in products.&lt;br /&gt;
# Tests should be as close to the code as possible, but not intermingled.  So the tests for OpenSim/Data/SQLite should be in OpenSim/Data/SQLite/Tests/.  Through the use of the '''Exclude''' keyword in prebuild.xml you can ensure that directory is part of OpenSim.Data.SQLite.Tests.dll and not OpenSim.Data.SQLite.dll. See exclude clarification in writing unit tests section.&lt;br /&gt;
# Tests testing a class should be grouped into a test class file called xxxTest.cs, where xxx is the name of the class that is being tested.&lt;br /&gt;
# Tests should be able to run safely in a production environment.  That means that care must be taken not to damage data on the machine that it is being run.&lt;br /&gt;
# Tests should be deterministic in other words repeatable. Avoid randomness in tests. See good and bad testing practices below.&lt;br /&gt;
&lt;br /&gt;
== Core Functionality Missing Unit Tests ==&lt;br /&gt;
&lt;br /&gt;
This is a list of functionality which is not covered by unit tests and is identified as highly desireable test target:&lt;br /&gt;
&lt;br /&gt;
# Database Modules (These are mysql tables)&lt;br /&gt;
## region ban&lt;br /&gt;
## land&lt;br /&gt;
## landaccesslist&lt;br /&gt;
&lt;br /&gt;
== Good / Bad Test practices ==&lt;br /&gt;
Creating good tests is an art, not a science.  Tests are useful by how many bugs they find or how many bugs they avoid.  Things you should think about in creating good tests is:&lt;br /&gt;
* Throwing edge cases, like 0, &amp;quot;&amp;quot;, or Null at parameters.  This ensures that people functions are hardened against incomplete data.  Many of our crashes come from the lack of this hardening showing up at just the wrong time.&lt;br /&gt;
* Use stateful testing to build up complex scenarios.  This is more useful than just cursory get / set calls.&lt;br /&gt;
* Random tests are not a good idea. We need test results to be deterministic. In other words tests need to be repeatable. If you want to test for a range it is good idea to make separate tests for min and max values. Random values in fields can fail randomly. When something goes wrong for example in database schema the developer will not necessarily notice if the stored values are random. On the other hand its hard to troubleshoot randomly failing tests as you dont know which specific value caused the failure.&lt;br /&gt;
* Tests should be independent and should not rely on another test being run, passing or failing. An excerpt from [http://xunitpatterns.com/Principles%20of%20Test%20Automation.html#Independent%20Test xUnit Patterns]:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;If tests are interdependent and (even worse) order dependent, we will be depriving ourselves of the useful feedback test failures provide. Interacting Tests [...] tend to fail in a group. The failure of a test that moved the [subject under test] into the state required by the dependent test will lead to the failure of the dependent test too. With both tests failing, how can we tell if it is because of a problem in code that both rely on in some way or is it a problem in code that only the first relies on. With both tests failing we can't tell. We are only talking about two tests here. Imagine how much worse this is with tens or hundreds of tests.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Only one function of the subject under test should be tested in one test. When testing a database access object, for example, write separate tests for creating DB entries, updating them and removing them.&lt;br /&gt;
* Do not use the subject under test to set up the state for the test or to verify the result. Use a different method. When testing a database access object, for example, use raw SQL to insert the initial data into the DB, then run the method being tested. To verify if the operation was successful, use raw SQL again to verify the DB changed as expected.&lt;br /&gt;
&lt;br /&gt;
== Writing Tests ==&lt;br /&gt;
Writing a new unit test is pretty easy, and very helpful in increasing the stability of opensim by nailing down bugs.  I'm going to present an example here of SQLite Asset testing to show how simple such a test case is to write.  The actual in tree SQLite Asset tests are a little different because the code was factored out so that it was easily applied to any database driver, so don't be concerned with the fact that what you see here isn't in the tree.&lt;br /&gt;
&lt;br /&gt;
Exclude clarification: Make sure your master project (not the test project) has an entry for files like the following so that the test code is not included in the master project dll:&lt;br /&gt;
      &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;lt;Files&amp;gt;&lt;br /&gt;
        &amp;lt;Match pattern=&amp;quot;*.cs&amp;quot; recurse=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;Exclude name=&amp;quot;Tests&amp;quot; pattern=&amp;quot;Tests&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/Match&amp;gt;&lt;br /&gt;
      &amp;lt;/Files&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NUnit Conventions ===&lt;br /&gt;
An NUnit test suite:&lt;br /&gt;
* is a class with a default constructor (takes no arguments)&lt;br /&gt;
* has public methods that are tests&lt;br /&gt;
* uses annotations to determine what are tests&lt;br /&gt;
* runs it's tests in '''alphabetical order by method name'''&lt;br /&gt;
&lt;br /&gt;
An NUnit test method:&lt;br /&gt;
* must be public&lt;br /&gt;
* must return void&lt;br /&gt;
* must take no arguments&lt;br /&gt;
* is successful if no exception or assert is thrown while running it&lt;br /&gt;
&lt;br /&gt;
The run order is important if you want to have early tests that setup some complicated state (like creating objects), and have later tests remove or update that state.  For that reason I find it very helpful to name all test methods '''Txxx_somename''' where '''xxx''' is a number between 000 and 999.  That guaruntees no surprises in run order.&lt;br /&gt;
&lt;br /&gt;
==== Setup / Teardown ====&lt;br /&gt;
In the case of testing something like the database layer, we have to actually attempt to store / retrieve things from a database.  Following from rule #4 of good tests, we want to make sure not to touch the production databases to run our tests, so during startup we generate a temporary file name which is guaranteed not to be an existing file on the system, and use that as our database file name.  By running db.Initialize() the OpenSim migration code will correctly populate that database with the latest schema.&lt;br /&gt;
&lt;br /&gt;
Once we are done with the tests we want to make sure we aren't leaving garbage temp files on the user's system.  So we remove that file we created.&lt;br /&gt;
&lt;br /&gt;
During setup we also create a set of state variables, such as 3 uuids, 3 strings, and a data block.  You could have always just stuck these inline, but variables are there for a reason, so use them.&lt;br /&gt;
&lt;br /&gt;
==== Asserts ====&lt;br /&gt;
You will see scattered through the code '''Assert.That(...)'''.  These will throw an exception if the condition is not valid.  This format of assertions is called the [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 Contraint Model] in NUnit, and provides a large number of tests with the flavor of:&lt;br /&gt;
* Assert.That(foo, Is.Null)&lt;br /&gt;
* Assert.That(foo, Is.Not.Null)&lt;br /&gt;
* Assert.That(foo, Is.True)&lt;br /&gt;
* Assert.That(foo, Is.EqualTo(bar))&lt;br /&gt;
* Assert.That(foo, Text.Matches( &amp;quot;*bar*&amp;quot; ))&lt;br /&gt;
&lt;br /&gt;
Of note, Is.EqualTo uses the Equals function of foo, so this can only be used on objects that are IComparable.  Most of the OpenSim base objects are not, so you'll have to compare fields manually in tests.&lt;br /&gt;
&lt;br /&gt;
For the complete set of conditions you can use see [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 the Contraint Model NUnit documentation].  While there is another syntax for tests, the Constraint Model is preferred as it is far more human readable.&lt;br /&gt;
&lt;br /&gt;
=== Simple Negative Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;[Test]&lt;br /&gt;
public void T001_LoadEmpty()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Test T001 is an example of a simple negative test.  We assume a new database will not have any of those assets in them.  While the value of this test may look low, it does provide a baseline in ensuring that the database connection is there, that these return false correctly, and that no other exception is thrown.  Negative tests are a good way to force bounds conditions and ensure that not only does it  ''return what you expect'' it also ''doesn't return what you don't expect''.  Thought of another way, it ensures your code is somewhat defensive in nature, not coughing on bad or unexpected data.&lt;br /&gt;
&lt;br /&gt;
=== Simple Positive Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T010_StoreSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
    AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
    AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
    a1.Data = asset1;&lt;br /&gt;
    a2.Data = asset1;&lt;br /&gt;
    a3.Data = asset1;&lt;br /&gt;
    &lt;br /&gt;
    db.CreateAsset(a1);&lt;br /&gt;
    db.CreateAsset(a2);&lt;br /&gt;
    db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
    Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
    Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
    Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
    Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
    Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
    Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
T010 is an example of a simple positive test.  In it we create and store 3 assets (ensuring no exceptions), then load those 3 assets back from the database and ensure the fields are correct.  Because AssetBase is not IComparible we just check the ID and Name fields with equals tests.  If any of the Asserts fail, the whole test fails.&lt;br /&gt;
&lt;br /&gt;
=== Stateful Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T011_ExistsSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.True);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.True);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
T011 is an example of a stateful test, because it requires the state created by T010 (i.e. the creation of those 3 objects).  In order to test any kind of complicated scenario you will find that you need to use stateful tests to build up various amounts of state (testing along the way), then manipulating and possibly tearing it down.  Without doing this you can't do truly deep testing of function in any complex environment.  This example isn't very stateful (I tried to pick an easy example), but it should give you some ideas.&lt;br /&gt;
&lt;br /&gt;
=== Speculative Tests ===&lt;br /&gt;
Speculative tests are tests that might or might not apply in a given situation.  MySQL testing in the OpenSim tree is done by speculative testing, the tests will only run if there is a properly configured database, otherwise they will not be run.  If you execute '''Assert.Ignore()''' in a '''Test''' the test will end and be ignored.  If you run '''Assert.Ignore()''' in the '''TestFixtureSetup''' all tests in the test fixture will be skipped and ignored.&lt;br /&gt;
&lt;br /&gt;
Speculative testing lets you create tests that require certain preconditions to be met which you can't guarantee on all platforms/configuration, and are an important part of deep testing.&lt;br /&gt;
&lt;br /&gt;
=== An Example Test - SQLite Assets ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
using System;&lt;br /&gt;
using System.IO;&lt;br /&gt;
using System.Collections.Generic;&lt;br /&gt;
using NUnit.Framework;&lt;br /&gt;
using NUnit.Framework.SyntaxHelpers;&lt;br /&gt;
using OpenSim.Framework;&lt;br /&gt;
using OpenSim.Data.Tests;&lt;br /&gt;
using OpenSim.Data.SQLite;&lt;br /&gt;
using OpenSim.Region.Environment.Scenes;&lt;br /&gt;
using OpenMetaverse;&lt;br /&gt;
&lt;br /&gt;
namespace OpenSim.Data.SQLite.Tests&lt;br /&gt;
{&lt;br /&gt;
    [TestFixture]&lt;br /&gt;
    public class SQLiteAssetTest&lt;br /&gt;
    {&lt;br /&gt;
        public string file;&lt;br /&gt;
        public string connect;&lt;br /&gt;
        public AssetDataBase db;&lt;br /&gt;
        public UUID uuid1;&lt;br /&gt;
        public UUID uuid2;&lt;br /&gt;
        public UUID uuid3;&lt;br /&gt;
        public string name1;&lt;br /&gt;
        public string name2;&lt;br /&gt;
        public string name3;&lt;br /&gt;
        public byte[] asset1;&lt;br /&gt;
        &lt;br /&gt;
        [TestFixtureSetUp]&lt;br /&gt;
        public void Init()&lt;br /&gt;
        {&lt;br /&gt;
            uuid1 = UUID.Random();&lt;br /&gt;
            uuid2 = UUID.Random();&lt;br /&gt;
            uuid3 = UUID.Random();&lt;br /&gt;
            name1 = &amp;quot;asset one&amp;quot;;&lt;br /&gt;
            name2 = &amp;quot;asset two&amp;quot;;&lt;br /&gt;
            name3 = &amp;quot;asset three&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
            asset1 = new byte[100];&lt;br /&gt;
            asset1.Initialize();&lt;br /&gt;
            file = Path.GetTempFileName() + &amp;quot;.db&amp;quot;;&lt;br /&gt;
            connect = &amp;quot;URI=file:&amp;quot; + file + &amp;quot;,version=3&amp;quot;;&lt;br /&gt;
            db = new SQLiteAssetData();&lt;br /&gt;
            db.Initialise(connect);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [TestFixtureTearDown]&lt;br /&gt;
        public void Cleanup()&lt;br /&gt;
        {&lt;br /&gt;
            db.Dispose();&lt;br /&gt;
            System.IO.File.Delete(file);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T001_LoadEmpty()&lt;br /&gt;
        {&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T010_StoreSimpleAsset()&lt;br /&gt;
        {&lt;br /&gt;
            AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
            AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
            AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
            a1.Data = asset1;&lt;br /&gt;
            a2.Data = asset1;&lt;br /&gt;
            a3.Data = asset1;&lt;br /&gt;
            &lt;br /&gt;
            db.CreateAsset(a1);&lt;br /&gt;
            db.CreateAsset(a2);&lt;br /&gt;
            db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
            AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
            Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
            Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
            AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
            Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
            Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
            AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
            Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
            Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T011_ExistsSimpleAsset()&lt;br /&gt;
        {&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid1), Is.True);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid2), Is.True);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid3), Is.True);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can see 4 of the important annotations here:&lt;br /&gt;
* TestFixture - this class is a test suite&lt;br /&gt;
* TestFixtureSetup - this code is always run before any of the tests are executed&lt;br /&gt;
* TestFixtureTearDown - this code is always run after the tests are done executing, even if they fail.&lt;br /&gt;
* Test - this method is a test&lt;br /&gt;
&lt;br /&gt;
== Adding Tests to the Tree ==&lt;br /&gt;
As we said previously all tests for assembly OpenSim.Foo (in directory OpenSim/Foo) should:&lt;br /&gt;
* be in assembly OpenSim.Foo.Tests.dll&lt;br /&gt;
* not be in the OpenSim.Foo.dll assembly&lt;br /&gt;
* be in OpenSim/Foo/Tests directory&lt;br /&gt;
&lt;br /&gt;
Also, if you have created a new test assembly you must add references to it in both ''.nant/local.include'' and ''.nant/bamboo.build'' to ensure that the assembly is added to the automated bamboo runs as well as the nant test target.&lt;br /&gt;
&lt;br /&gt;
== Executing Tests ==&lt;br /&gt;
&lt;br /&gt;
=== Bamboo ===&lt;br /&gt;
On every commit to opensim all the tests are run on a [http://opensimulator.org:8085 Bamboo build server on opensimulator.org].  The process takes about 5 minutes to build, test, and report the results back out on #opensim-dev via the osmantis bot.&lt;br /&gt;
&lt;br /&gt;
=== Nant ===&lt;br /&gt;
You can manually run all the tests for OpenSim on your system by running '''nant test''' as a nant target.  This will run all the tests that are in the tree, though some speculative tests might be ignored if your platform does not have the right features or configuration to run these tests.&lt;br /&gt;
&lt;br /&gt;
=== NUnit Console ===&lt;br /&gt;
If you only want to run tests for one assembly you can do that using the NUnit Console.  On Linux just run '''nunit-console2 OpenSim.Foo.Tests.dll''' and it will run only the tests for OpenSim.Foo.Tests.dll.  If you are only making changes to 1 dll and just want a quick sanity check, this is the fastest way to do that.&lt;br /&gt;
&lt;br /&gt;
=== Debugging Tests ===&lt;br /&gt;
There is a special page dedicated to this. See [[Debugging Unit Tests]].&lt;br /&gt;
&lt;br /&gt;
== Learning More ==&lt;br /&gt;
You should definitely read the documentation at the [http://www.nunit.org/index.php?p=documentation NUnit homepage] if you want to know more about testing.  It's a very good reference for all the APIs in NUnit that you can use for creating tests.&lt;br /&gt;
&lt;br /&gt;
== Code Coverage ==&lt;br /&gt;
&lt;br /&gt;
A prototype has been included using monocov, which has a profile built-in in mono. Instructions for using monocov can be found on the Mono homepage, in [http://www.mono-project.com/Code_Coverage Code Coverage] section. Unfortunately nunit2 and nant do not support code coverage with monocov (only some other proprietary code coverages), so there is no &amp;lt;monocov&amp;gt; tag. The solution was to implement it using many nunit-console and on &amp;lt;exec&amp;gt; tags. &lt;br /&gt;
&lt;br /&gt;
ATTENTION: Code coverage only works with mono 1.2.x , any other version will most likely not work. Code coverage development is being put on hold for now until it supports newer mono versions.&lt;br /&gt;
&lt;br /&gt;
=== Running ===&lt;br /&gt;
&lt;br /&gt;
Download [http://primates.ximian.com/~lupus/monocov-0.2.tar.gz monocov] and [http://prdownloads.sourceforge.net/nunit/NUnit-2.4.8-net-2.0.zip?download nunit-console] if your nunit-console does not work. To test if it works (my Ubuntu's Hardy version did not), just run one of the tests with nunit-console.&lt;br /&gt;
&lt;br /&gt;
Install monocov (./configure, ./make install, there could be some minor conflicts, I had to add to the compiling line -I/usr/include/mono-1.0/) and make sure the working nunit-console.exe is in /usr/lib/nunit/nunit-console.exe. Now just run nant test-cov and it will generate .cov files and HTML directories in the cov directory. The .cov files can be seen by running monocov on them, and have the same information as the HTML directories.&lt;br /&gt;
&lt;br /&gt;
== Testing Todo ==&lt;br /&gt;
&lt;br /&gt;
=== Coverage ===&lt;br /&gt;
&lt;br /&gt;
A prototype has been done and documented. Now we must keep a look if monocov will evolve to support newer mono versions.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
[[Category:Testing]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Automated_Testing</id>
		<title>Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Automated_Testing"/>
				<updated>2009-03-12T06:59:13Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* Simple Positive Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As OpenSim matures, we are extremely interested in adding more automated verification into the OpenSim source tree.  Test exist not only to prevent bugs from creeping in, but also to provide fair warning that the behavior of the system has changed, and tests may need updating.&lt;br /&gt;
&lt;br /&gt;
In OpenSim today we use NUnit tests.  Our conventions are:&lt;br /&gt;
# Tests should '''not''' exist inside runtime assemblies, as this makes nunit a production requirement&lt;br /&gt;
# Tests should be in .Tests.dll assemblies.  For instance, the tests for OpenSim.Data.SQLite.dll should be in the OpenSim.Data.SQLite.Tests.dll assembly.  This allows for easy removal of test assemblies in products.&lt;br /&gt;
# Tests should be as close to the code as possible, but not intermingled.  So the tests for OpenSim/Data/SQLite should be in OpenSim/Data/SQLite/Tests/.  Through the use of the '''Exclude''' keyword in prebuild.xml you can ensure that directory is part of OpenSim.Data.SQLite.Tests.dll and not OpenSim.Data.SQLite.dll. See exclude clarification in writing unit tests section.&lt;br /&gt;
# Tests testing a class should be grouped into a test class file called xxxTest.cs, where xxx is the name of the class that is being tested.&lt;br /&gt;
# Tests should be able to run safely in a production environment.  That means that care must be taken not to damage data on the machine that it is being run.&lt;br /&gt;
# Tests should be deterministic in other words repeatable. Avoid randomness in tests. See good and bad testing practices below.&lt;br /&gt;
&lt;br /&gt;
== Core Functionality Missing Unit Tests ==&lt;br /&gt;
&lt;br /&gt;
This is a list of functionality which is not covered by unit tests and is identified as highly desireable test target:&lt;br /&gt;
&lt;br /&gt;
# Database Modules (These are mysql tables)&lt;br /&gt;
## region ban&lt;br /&gt;
## land&lt;br /&gt;
## landaccesslist&lt;br /&gt;
&lt;br /&gt;
== Good / Bad Test practices ==&lt;br /&gt;
Creating good tests is an art, not a science.  Tests are useful by how many bugs they find or how many bugs they avoid.  Things you should think about in creating good tests is:&lt;br /&gt;
* Throwing edge cases, like 0, &amp;quot;&amp;quot;, or Null at parameters.  This ensures that people functions are hardened against incomplete data.  Many of our crashes come from the lack of this hardening showing up at just the wrong time.&lt;br /&gt;
* Use stateful testing to build up complex scenarios.  This is more useful than just cursory get / set calls.&lt;br /&gt;
* Random tests are not a good idea. We need test results to be deterministic. In other words tests need to be repeatable. If you want to test for a range it is good idea to make separate tests for min and max values. Random values in fields can fail randomly. When something goes wrong for example in database schema the developer will not necessarily notice if the stored values are random. On the other hand its hard to troubleshoot randomly failing tests as you dont know which specific value caused the failure.&lt;br /&gt;
* Tests should be independent and should not rely on another test being run, passing or failing. An excerpt from [http://xunitpatterns.com/Principles%20of%20Test%20Automation.html#Independent%20Test xUnit Patterns]:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;If tests are interdependent and (even worse) order dependent, we will be depriving ourselves of the useful feedback test failures provide. Interacting Tests [...] tend to fail in a group. The failure of a test that moved the [subject under test] into the state required by the dependent test will lead to the failure of the dependent test too. With both tests failing, how can we tell if it is because of a problem in code that both rely on in some way or is it a problem in code that only the first relies on. With both tests failing we can't tell. We are only talking about two tests here. Imagine how much worse this is with tens or hundreds of tests.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Only one function of the subject under test should be tested in one test. When testing a database access object, for example, write separate tests for creating DB entries, updating them and removing them.&lt;br /&gt;
* Do not use the subject under test to set up the state for the test or to verify the result. Use a different method. When testing a database access object, for example, use raw SQL to insert the initial data into the DB, then run the method being tested. To verify if the operation was successful, use raw SQL again to verify the DB changed as expected.&lt;br /&gt;
&lt;br /&gt;
== Writing Tests ==&lt;br /&gt;
Writing a new unit test is pretty easy, and very helpful in increasing the stability of opensim by nailing down bugs.  I'm going to present an example here of SQLite Asset testing to show how simple such a test case is to write.  The actual in tree SQLite Asset tests are a little different because the code was factored out so that it was easily applied to any database driver, so don't be concerned with the fact that what you see here isn't in the tree.&lt;br /&gt;
&lt;br /&gt;
Exclude clarification: Make sure your master project (not the test project) has an entry for files like the following so that the test code is not included in the master project dll:&lt;br /&gt;
      &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;lt;Files&amp;gt;&lt;br /&gt;
        &amp;lt;Match pattern=&amp;quot;*.cs&amp;quot; recurse=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;Exclude name=&amp;quot;Tests&amp;quot; pattern=&amp;quot;Tests&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/Match&amp;gt;&lt;br /&gt;
      &amp;lt;/Files&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NUnit Conventions ===&lt;br /&gt;
An NUnit test suite:&lt;br /&gt;
* is a class with a default constructor (takes no arguments)&lt;br /&gt;
* has public methods that are tests&lt;br /&gt;
* uses annotations to determine what are tests&lt;br /&gt;
* runs it's tests in '''alphabetical order by method name'''&lt;br /&gt;
&lt;br /&gt;
An NUnit test method:&lt;br /&gt;
* must be public&lt;br /&gt;
* must return void&lt;br /&gt;
* must take no arguments&lt;br /&gt;
* is successful if no exception or assert is thrown while running it&lt;br /&gt;
&lt;br /&gt;
The run order is important if you want to have early tests that setup some complicated state (like creating objects), and have later tests remove or update that state.  For that reason I find it very helpful to name all test methods '''Txxx_somename''' where '''xxx''' is a number between 000 and 999.  That guaruntees no surprises in run order.&lt;br /&gt;
&lt;br /&gt;
==== Setup / Teardown ====&lt;br /&gt;
In the case of testing something like the database layer, we have to actually attempt to store / retrieve things from a database.  Following from rule #4 of good tests, we want to make sure not to touch the production databases to run our tests, so during startup we generate a temporary file name which is guaranteed not to be an existing file on the system, and use that as our database file name.  By running db.Initialize() the OpenSim migration code will correctly populate that database with the latest schema.&lt;br /&gt;
&lt;br /&gt;
Once we are done with the tests we want to make sure we aren't leaving garbage temp files on the user's system.  So we remove that file we created.&lt;br /&gt;
&lt;br /&gt;
During setup we also create a set of state variables, such as 3 uuids, 3 strings, and a data block.  You could have always just stuck these inline, but variables are there for a reason, so use them.&lt;br /&gt;
&lt;br /&gt;
==== Asserts ====&lt;br /&gt;
You will see scattered through the code '''Assert.That(...)'''.  These will throw an exception if the condition is not valid.  This format of assertions is called the [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 Contraint Model] in NUnit, and provides a large number of tests with the flavor of:&lt;br /&gt;
* Assert.That(foo, Is.Null)&lt;br /&gt;
* Assert.That(foo, Is.Not.Null)&lt;br /&gt;
* Assert.That(foo, Is.True)&lt;br /&gt;
* Assert.That(foo, Is.EqualTo(bar))&lt;br /&gt;
* Assert.That(foo, Text.Matches( &amp;quot;*bar*&amp;quot; ))&lt;br /&gt;
&lt;br /&gt;
Of note, Is.EqualTo uses the Equals function of foo, so this can only be used on objects that are IComparable.  Most of the OpenSim base objects are not, so you'll have to compare fields manually in tests.&lt;br /&gt;
&lt;br /&gt;
For the complete set of conditions you can use see [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 the Contraint Model NUnit documentation].  While there is another syntax for tests, the Constraint Model is preferred as it is far more human readable.&lt;br /&gt;
&lt;br /&gt;
=== Simple Negative Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;[Test]&lt;br /&gt;
public void T001_LoadEmpty()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Test T001 is an example of a simple negative test.  We assume a new database will not have any of those assets in them.  While the value of this test may look low, it does provide a baseline in ensuring that the database connection is there, that these return false correctly, and that no other exception is thrown.  Negative tests are a good way to force bounds conditions and ensure that not only does it  ''return what you expect'' it also ''doesn't return what you don't expect''.  Thought of another way, it ensures your code is somewhat defensive in nature, not coughing on bad or unexpected data.&lt;br /&gt;
&lt;br /&gt;
=== Simple Positive Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
[Test]&lt;br /&gt;
public void T010_StoreSimpleAsset()&lt;br /&gt;
{&lt;br /&gt;
    AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
    AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
    AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
    a1.Data = asset1;&lt;br /&gt;
    a2.Data = asset1;&lt;br /&gt;
    a3.Data = asset1;&lt;br /&gt;
    &lt;br /&gt;
    db.CreateAsset(a1);&lt;br /&gt;
    db.CreateAsset(a2);&lt;br /&gt;
    db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
    AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
    Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
    Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
    Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
    Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
    AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
    Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
    Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
T010 is an example of a simple positive test.  In it we create and store 3 assets (ensuring no exceptions), then load those 3 assets back from the database and ensure the fields are correct.  Because AssetBase is not IComparible we just check the ID and Name fields with equals tests.  If any of the Asserts fail, the whole test fails.&lt;br /&gt;
&lt;br /&gt;
=== Stateful Tests ===&lt;br /&gt;
T011 is an example of a stateful test, because it requires the state created by T010 (i.e. the creation of those 3 objects).  In order to test any kind of complicated scenario you will find that you need to use stateful tests to build up various amounts of state (testing along the way), then manipulating and possibly tearing it down.  Without doing this you can't do truly deep testing of function in any complex environment.  This example isn't very stateful (I tried to pick an easy example), but it should give you some ideas.&lt;br /&gt;
&lt;br /&gt;
=== Speculative Tests ===&lt;br /&gt;
Speculative tests are tests that might or might not apply in a given situation.  MySQL testing in the OpenSim tree is done by speculative testing, the tests will only run if there is a properly configured database, otherwise they will not be run.  If you execute '''Assert.Ignore()''' in a '''Test''' the test will end and be ignored.  If you run '''Assert.Ignore()''' in the '''TestFixtureSetup''' all tests in the test fixture will be skipped and ignored.&lt;br /&gt;
&lt;br /&gt;
Speculative testing lets you create tests that require certain preconditions to be met which you can't guarantee on all platforms/configuration, and are an important part of deep testing.&lt;br /&gt;
&lt;br /&gt;
=== An Example Test - SQLite Assets ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
using System;&lt;br /&gt;
using System.IO;&lt;br /&gt;
using System.Collections.Generic;&lt;br /&gt;
using NUnit.Framework;&lt;br /&gt;
using NUnit.Framework.SyntaxHelpers;&lt;br /&gt;
using OpenSim.Framework;&lt;br /&gt;
using OpenSim.Data.Tests;&lt;br /&gt;
using OpenSim.Data.SQLite;&lt;br /&gt;
using OpenSim.Region.Environment.Scenes;&lt;br /&gt;
using OpenMetaverse;&lt;br /&gt;
&lt;br /&gt;
namespace OpenSim.Data.SQLite.Tests&lt;br /&gt;
{&lt;br /&gt;
    [TestFixture]&lt;br /&gt;
    public class SQLiteAssetTest&lt;br /&gt;
    {&lt;br /&gt;
        public string file;&lt;br /&gt;
        public string connect;&lt;br /&gt;
        public AssetDataBase db;&lt;br /&gt;
        public UUID uuid1;&lt;br /&gt;
        public UUID uuid2;&lt;br /&gt;
        public UUID uuid3;&lt;br /&gt;
        public string name1;&lt;br /&gt;
        public string name2;&lt;br /&gt;
        public string name3;&lt;br /&gt;
        public byte[] asset1;&lt;br /&gt;
        &lt;br /&gt;
        [TestFixtureSetUp]&lt;br /&gt;
        public void Init()&lt;br /&gt;
        {&lt;br /&gt;
            uuid1 = UUID.Random();&lt;br /&gt;
            uuid2 = UUID.Random();&lt;br /&gt;
            uuid3 = UUID.Random();&lt;br /&gt;
            name1 = &amp;quot;asset one&amp;quot;;&lt;br /&gt;
            name2 = &amp;quot;asset two&amp;quot;;&lt;br /&gt;
            name3 = &amp;quot;asset three&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
            asset1 = new byte[100];&lt;br /&gt;
            asset1.Initialize();&lt;br /&gt;
            file = Path.GetTempFileName() + &amp;quot;.db&amp;quot;;&lt;br /&gt;
            connect = &amp;quot;URI=file:&amp;quot; + file + &amp;quot;,version=3&amp;quot;;&lt;br /&gt;
            db = new SQLiteAssetData();&lt;br /&gt;
            db.Initialise(connect);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [TestFixtureTearDown]&lt;br /&gt;
        public void Cleanup()&lt;br /&gt;
        {&lt;br /&gt;
            db.Dispose();&lt;br /&gt;
            System.IO.File.Delete(file);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T001_LoadEmpty()&lt;br /&gt;
        {&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T010_StoreSimpleAsset()&lt;br /&gt;
        {&lt;br /&gt;
            AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
            AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
            AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
            a1.Data = asset1;&lt;br /&gt;
            a2.Data = asset1;&lt;br /&gt;
            a3.Data = asset1;&lt;br /&gt;
            &lt;br /&gt;
            db.CreateAsset(a1);&lt;br /&gt;
            db.CreateAsset(a2);&lt;br /&gt;
            db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
            AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
            Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
            Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
            AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
            Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
            Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
            AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
            Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
            Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T011_ExistsSimpleAsset()&lt;br /&gt;
        {&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid1), Is.True);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid2), Is.True);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid3), Is.True);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can see 4 of the important annotations here:&lt;br /&gt;
* TestFixture - this class is a test suite&lt;br /&gt;
* TestFixtureSetup - this code is always run before any of the tests are executed&lt;br /&gt;
* TestFixtureTearDown - this code is always run after the tests are done executing, even if they fail.&lt;br /&gt;
* Test - this method is a test&lt;br /&gt;
&lt;br /&gt;
== Adding Tests to the Tree ==&lt;br /&gt;
As we said previously all tests for assembly OpenSim.Foo (in directory OpenSim/Foo) should:&lt;br /&gt;
* be in assembly OpenSim.Foo.Tests.dll&lt;br /&gt;
* not be in the OpenSim.Foo.dll assembly&lt;br /&gt;
* be in OpenSim/Foo/Tests directory&lt;br /&gt;
&lt;br /&gt;
Also, if you have created a new test assembly you must add references to it in both ''.nant/local.include'' and ''.nant/bamboo.build'' to ensure that the assembly is added to the automated bamboo runs as well as the nant test target.&lt;br /&gt;
&lt;br /&gt;
== Executing Tests ==&lt;br /&gt;
&lt;br /&gt;
=== Bamboo ===&lt;br /&gt;
On every commit to opensim all the tests are run on a [http://opensimulator.org:8085 Bamboo build server on opensimulator.org].  The process takes about 5 minutes to build, test, and report the results back out on #opensim-dev via the osmantis bot.&lt;br /&gt;
&lt;br /&gt;
=== Nant ===&lt;br /&gt;
You can manually run all the tests for OpenSim on your system by running '''nant test''' as a nant target.  This will run all the tests that are in the tree, though some speculative tests might be ignored if your platform does not have the right features or configuration to run these tests.&lt;br /&gt;
&lt;br /&gt;
=== NUnit Console ===&lt;br /&gt;
If you only want to run tests for one assembly you can do that using the NUnit Console.  On Linux just run '''nunit-console2 OpenSim.Foo.Tests.dll''' and it will run only the tests for OpenSim.Foo.Tests.dll.  If you are only making changes to 1 dll and just want a quick sanity check, this is the fastest way to do that.&lt;br /&gt;
&lt;br /&gt;
=== Debugging Tests ===&lt;br /&gt;
There is a special page dedicated to this. See [[Debugging Unit Tests]].&lt;br /&gt;
&lt;br /&gt;
== Learning More ==&lt;br /&gt;
You should definitely read the documentation at the [http://www.nunit.org/index.php?p=documentation NUnit homepage] if you want to know more about testing.  It's a very good reference for all the APIs in NUnit that you can use for creating tests.&lt;br /&gt;
&lt;br /&gt;
== Code Coverage ==&lt;br /&gt;
&lt;br /&gt;
A prototype has been included using monocov, which has a profile built-in in mono. Instructions for using monocov can be found on the Mono homepage, in [http://www.mono-project.com/Code_Coverage Code Coverage] section. Unfortunately nunit2 and nant do not support code coverage with monocov (only some other proprietary code coverages), so there is no &amp;lt;monocov&amp;gt; tag. The solution was to implement it using many nunit-console and on &amp;lt;exec&amp;gt; tags. &lt;br /&gt;
&lt;br /&gt;
ATTENTION: Code coverage only works with mono 1.2.x , any other version will most likely not work. Code coverage development is being put on hold for now until it supports newer mono versions.&lt;br /&gt;
&lt;br /&gt;
=== Running ===&lt;br /&gt;
&lt;br /&gt;
Download [http://primates.ximian.com/~lupus/monocov-0.2.tar.gz monocov] and [http://prdownloads.sourceforge.net/nunit/NUnit-2.4.8-net-2.0.zip?download nunit-console] if your nunit-console does not work. To test if it works (my Ubuntu's Hardy version did not), just run one of the tests with nunit-console.&lt;br /&gt;
&lt;br /&gt;
Install monocov (./configure, ./make install, there could be some minor conflicts, I had to add to the compiling line -I/usr/include/mono-1.0/) and make sure the working nunit-console.exe is in /usr/lib/nunit/nunit-console.exe. Now just run nant test-cov and it will generate .cov files and HTML directories in the cov directory. The .cov files can be seen by running monocov on them, and have the same information as the HTML directories.&lt;br /&gt;
&lt;br /&gt;
== Testing Todo ==&lt;br /&gt;
&lt;br /&gt;
=== Coverage ===&lt;br /&gt;
&lt;br /&gt;
A prototype has been done and documented. Now we must keep a look if monocov will evolve to support newer mono versions.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
[[Category:Testing]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Automated_Testing</id>
		<title>Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Automated_Testing"/>
				<updated>2009-03-12T06:57:07Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* Simple Negative Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As OpenSim matures, we are extremely interested in adding more automated verification into the OpenSim source tree.  Test exist not only to prevent bugs from creeping in, but also to provide fair warning that the behavior of the system has changed, and tests may need updating.&lt;br /&gt;
&lt;br /&gt;
In OpenSim today we use NUnit tests.  Our conventions are:&lt;br /&gt;
# Tests should '''not''' exist inside runtime assemblies, as this makes nunit a production requirement&lt;br /&gt;
# Tests should be in .Tests.dll assemblies.  For instance, the tests for OpenSim.Data.SQLite.dll should be in the OpenSim.Data.SQLite.Tests.dll assembly.  This allows for easy removal of test assemblies in products.&lt;br /&gt;
# Tests should be as close to the code as possible, but not intermingled.  So the tests for OpenSim/Data/SQLite should be in OpenSim/Data/SQLite/Tests/.  Through the use of the '''Exclude''' keyword in prebuild.xml you can ensure that directory is part of OpenSim.Data.SQLite.Tests.dll and not OpenSim.Data.SQLite.dll. See exclude clarification in writing unit tests section.&lt;br /&gt;
# Tests testing a class should be grouped into a test class file called xxxTest.cs, where xxx is the name of the class that is being tested.&lt;br /&gt;
# Tests should be able to run safely in a production environment.  That means that care must be taken not to damage data on the machine that it is being run.&lt;br /&gt;
# Tests should be deterministic in other words repeatable. Avoid randomness in tests. See good and bad testing practices below.&lt;br /&gt;
&lt;br /&gt;
== Core Functionality Missing Unit Tests ==&lt;br /&gt;
&lt;br /&gt;
This is a list of functionality which is not covered by unit tests and is identified as highly desireable test target:&lt;br /&gt;
&lt;br /&gt;
# Database Modules (These are mysql tables)&lt;br /&gt;
## region ban&lt;br /&gt;
## land&lt;br /&gt;
## landaccesslist&lt;br /&gt;
&lt;br /&gt;
== Good / Bad Test practices ==&lt;br /&gt;
Creating good tests is an art, not a science.  Tests are useful by how many bugs they find or how many bugs they avoid.  Things you should think about in creating good tests is:&lt;br /&gt;
* Throwing edge cases, like 0, &amp;quot;&amp;quot;, or Null at parameters.  This ensures that people functions are hardened against incomplete data.  Many of our crashes come from the lack of this hardening showing up at just the wrong time.&lt;br /&gt;
* Use stateful testing to build up complex scenarios.  This is more useful than just cursory get / set calls.&lt;br /&gt;
* Random tests are not a good idea. We need test results to be deterministic. In other words tests need to be repeatable. If you want to test for a range it is good idea to make separate tests for min and max values. Random values in fields can fail randomly. When something goes wrong for example in database schema the developer will not necessarily notice if the stored values are random. On the other hand its hard to troubleshoot randomly failing tests as you dont know which specific value caused the failure.&lt;br /&gt;
* Tests should be independent and should not rely on another test being run, passing or failing. An excerpt from [http://xunitpatterns.com/Principles%20of%20Test%20Automation.html#Independent%20Test xUnit Patterns]:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;If tests are interdependent and (even worse) order dependent, we will be depriving ourselves of the useful feedback test failures provide. Interacting Tests [...] tend to fail in a group. The failure of a test that moved the [subject under test] into the state required by the dependent test will lead to the failure of the dependent test too. With both tests failing, how can we tell if it is because of a problem in code that both rely on in some way or is it a problem in code that only the first relies on. With both tests failing we can't tell. We are only talking about two tests here. Imagine how much worse this is with tens or hundreds of tests.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Only one function of the subject under test should be tested in one test. When testing a database access object, for example, write separate tests for creating DB entries, updating them and removing them.&lt;br /&gt;
* Do not use the subject under test to set up the state for the test or to verify the result. Use a different method. When testing a database access object, for example, use raw SQL to insert the initial data into the DB, then run the method being tested. To verify if the operation was successful, use raw SQL again to verify the DB changed as expected.&lt;br /&gt;
&lt;br /&gt;
== Writing Tests ==&lt;br /&gt;
Writing a new unit test is pretty easy, and very helpful in increasing the stability of opensim by nailing down bugs.  I'm going to present an example here of SQLite Asset testing to show how simple such a test case is to write.  The actual in tree SQLite Asset tests are a little different because the code was factored out so that it was easily applied to any database driver, so don't be concerned with the fact that what you see here isn't in the tree.&lt;br /&gt;
&lt;br /&gt;
Exclude clarification: Make sure your master project (not the test project) has an entry for files like the following so that the test code is not included in the master project dll:&lt;br /&gt;
      &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;lt;Files&amp;gt;&lt;br /&gt;
        &amp;lt;Match pattern=&amp;quot;*.cs&amp;quot; recurse=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;Exclude name=&amp;quot;Tests&amp;quot; pattern=&amp;quot;Tests&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/Match&amp;gt;&lt;br /&gt;
      &amp;lt;/Files&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NUnit Conventions ===&lt;br /&gt;
An NUnit test suite:&lt;br /&gt;
* is a class with a default constructor (takes no arguments)&lt;br /&gt;
* has public methods that are tests&lt;br /&gt;
* uses annotations to determine what are tests&lt;br /&gt;
* runs it's tests in '''alphabetical order by method name'''&lt;br /&gt;
&lt;br /&gt;
An NUnit test method:&lt;br /&gt;
* must be public&lt;br /&gt;
* must return void&lt;br /&gt;
* must take no arguments&lt;br /&gt;
* is successful if no exception or assert is thrown while running it&lt;br /&gt;
&lt;br /&gt;
The run order is important if you want to have early tests that setup some complicated state (like creating objects), and have later tests remove or update that state.  For that reason I find it very helpful to name all test methods '''Txxx_somename''' where '''xxx''' is a number between 000 and 999.  That guaruntees no surprises in run order.&lt;br /&gt;
&lt;br /&gt;
==== Setup / Teardown ====&lt;br /&gt;
In the case of testing something like the database layer, we have to actually attempt to store / retrieve things from a database.  Following from rule #4 of good tests, we want to make sure not to touch the production databases to run our tests, so during startup we generate a temporary file name which is guaranteed not to be an existing file on the system, and use that as our database file name.  By running db.Initialize() the OpenSim migration code will correctly populate that database with the latest schema.&lt;br /&gt;
&lt;br /&gt;
Once we are done with the tests we want to make sure we aren't leaving garbage temp files on the user's system.  So we remove that file we created.&lt;br /&gt;
&lt;br /&gt;
During setup we also create a set of state variables, such as 3 uuids, 3 strings, and a data block.  You could have always just stuck these inline, but variables are there for a reason, so use them.&lt;br /&gt;
&lt;br /&gt;
==== Asserts ====&lt;br /&gt;
You will see scattered through the code '''Assert.That(...)'''.  These will throw an exception if the condition is not valid.  This format of assertions is called the [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 Contraint Model] in NUnit, and provides a large number of tests with the flavor of:&lt;br /&gt;
* Assert.That(foo, Is.Null)&lt;br /&gt;
* Assert.That(foo, Is.Not.Null)&lt;br /&gt;
* Assert.That(foo, Is.True)&lt;br /&gt;
* Assert.That(foo, Is.EqualTo(bar))&lt;br /&gt;
* Assert.That(foo, Text.Matches( &amp;quot;*bar*&amp;quot; ))&lt;br /&gt;
&lt;br /&gt;
Of note, Is.EqualTo uses the Equals function of foo, so this can only be used on objects that are IComparable.  Most of the OpenSim base objects are not, so you'll have to compare fields manually in tests.&lt;br /&gt;
&lt;br /&gt;
For the complete set of conditions you can use see [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 the Contraint Model NUnit documentation].  While there is another syntax for tests, the Constraint Model is preferred as it is far more human readable.&lt;br /&gt;
&lt;br /&gt;
=== Simple Negative Tests ===&lt;br /&gt;
&lt;br /&gt;
See [[Example Test SQLite Assets]] for this code snipped in context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;[Test]&lt;br /&gt;
public void T001_LoadEmpty()&lt;br /&gt;
{&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
    Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Test T001 is an example of a simple negative test.  We assume a new database will not have any of those assets in them.  While the value of this test may look low, it does provide a baseline in ensuring that the database connection is there, that these return false correctly, and that no other exception is thrown.  Negative tests are a good way to force bounds conditions and ensure that not only does it  ''return what you expect'' it also ''doesn't return what you don't expect''.  Thought of another way, it ensures your code is somewhat defensive in nature, not coughing on bad or unexpected data.&lt;br /&gt;
&lt;br /&gt;
=== Simple Positive Tests ===&lt;br /&gt;
T010 is an example of a simple positive test.  In it we create and store 3 assets (ensuring no exceptions), then load those 3 assets back from the database and ensure the fields are correct.  Because AssetBase is not IComparible we just check the ID and Name fields with equals tests.  If any of the Asserts fail, the whole test fails.&lt;br /&gt;
&lt;br /&gt;
=== Stateful Tests ===&lt;br /&gt;
T011 is an example of a stateful test, because it requires the state created by T010 (i.e. the creation of those 3 objects).  In order to test any kind of complicated scenario you will find that you need to use stateful tests to build up various amounts of state (testing along the way), then manipulating and possibly tearing it down.  Without doing this you can't do truly deep testing of function in any complex environment.  This example isn't very stateful (I tried to pick an easy example), but it should give you some ideas.&lt;br /&gt;
&lt;br /&gt;
=== Speculative Tests ===&lt;br /&gt;
Speculative tests are tests that might or might not apply in a given situation.  MySQL testing in the OpenSim tree is done by speculative testing, the tests will only run if there is a properly configured database, otherwise they will not be run.  If you execute '''Assert.Ignore()''' in a '''Test''' the test will end and be ignored.  If you run '''Assert.Ignore()''' in the '''TestFixtureSetup''' all tests in the test fixture will be skipped and ignored.&lt;br /&gt;
&lt;br /&gt;
Speculative testing lets you create tests that require certain preconditions to be met which you can't guarantee on all platforms/configuration, and are an important part of deep testing.&lt;br /&gt;
&lt;br /&gt;
=== An Example Test - SQLite Assets ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
using System;&lt;br /&gt;
using System.IO;&lt;br /&gt;
using System.Collections.Generic;&lt;br /&gt;
using NUnit.Framework;&lt;br /&gt;
using NUnit.Framework.SyntaxHelpers;&lt;br /&gt;
using OpenSim.Framework;&lt;br /&gt;
using OpenSim.Data.Tests;&lt;br /&gt;
using OpenSim.Data.SQLite;&lt;br /&gt;
using OpenSim.Region.Environment.Scenes;&lt;br /&gt;
using OpenMetaverse;&lt;br /&gt;
&lt;br /&gt;
namespace OpenSim.Data.SQLite.Tests&lt;br /&gt;
{&lt;br /&gt;
    [TestFixture]&lt;br /&gt;
    public class SQLiteAssetTest&lt;br /&gt;
    {&lt;br /&gt;
        public string file;&lt;br /&gt;
        public string connect;&lt;br /&gt;
        public AssetDataBase db;&lt;br /&gt;
        public UUID uuid1;&lt;br /&gt;
        public UUID uuid2;&lt;br /&gt;
        public UUID uuid3;&lt;br /&gt;
        public string name1;&lt;br /&gt;
        public string name2;&lt;br /&gt;
        public string name3;&lt;br /&gt;
        public byte[] asset1;&lt;br /&gt;
        &lt;br /&gt;
        [TestFixtureSetUp]&lt;br /&gt;
        public void Init()&lt;br /&gt;
        {&lt;br /&gt;
            uuid1 = UUID.Random();&lt;br /&gt;
            uuid2 = UUID.Random();&lt;br /&gt;
            uuid3 = UUID.Random();&lt;br /&gt;
            name1 = &amp;quot;asset one&amp;quot;;&lt;br /&gt;
            name2 = &amp;quot;asset two&amp;quot;;&lt;br /&gt;
            name3 = &amp;quot;asset three&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
            asset1 = new byte[100];&lt;br /&gt;
            asset1.Initialize();&lt;br /&gt;
            file = Path.GetTempFileName() + &amp;quot;.db&amp;quot;;&lt;br /&gt;
            connect = &amp;quot;URI=file:&amp;quot; + file + &amp;quot;,version=3&amp;quot;;&lt;br /&gt;
            db = new SQLiteAssetData();&lt;br /&gt;
            db.Initialise(connect);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [TestFixtureTearDown]&lt;br /&gt;
        public void Cleanup()&lt;br /&gt;
        {&lt;br /&gt;
            db.Dispose();&lt;br /&gt;
            System.IO.File.Delete(file);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T001_LoadEmpty()&lt;br /&gt;
        {&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T010_StoreSimpleAsset()&lt;br /&gt;
        {&lt;br /&gt;
            AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
            AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
            AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
            a1.Data = asset1;&lt;br /&gt;
            a2.Data = asset1;&lt;br /&gt;
            a3.Data = asset1;&lt;br /&gt;
            &lt;br /&gt;
            db.CreateAsset(a1);&lt;br /&gt;
            db.CreateAsset(a2);&lt;br /&gt;
            db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
            AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
            Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
            Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
            AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
            Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
            Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
            AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
            Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
            Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T011_ExistsSimpleAsset()&lt;br /&gt;
        {&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid1), Is.True);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid2), Is.True);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid3), Is.True);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can see 4 of the important annotations here:&lt;br /&gt;
* TestFixture - this class is a test suite&lt;br /&gt;
* TestFixtureSetup - this code is always run before any of the tests are executed&lt;br /&gt;
* TestFixtureTearDown - this code is always run after the tests are done executing, even if they fail.&lt;br /&gt;
* Test - this method is a test&lt;br /&gt;
&lt;br /&gt;
== Adding Tests to the Tree ==&lt;br /&gt;
As we said previously all tests for assembly OpenSim.Foo (in directory OpenSim/Foo) should:&lt;br /&gt;
* be in assembly OpenSim.Foo.Tests.dll&lt;br /&gt;
* not be in the OpenSim.Foo.dll assembly&lt;br /&gt;
* be in OpenSim/Foo/Tests directory&lt;br /&gt;
&lt;br /&gt;
Also, if you have created a new test assembly you must add references to it in both ''.nant/local.include'' and ''.nant/bamboo.build'' to ensure that the assembly is added to the automated bamboo runs as well as the nant test target.&lt;br /&gt;
&lt;br /&gt;
== Executing Tests ==&lt;br /&gt;
&lt;br /&gt;
=== Bamboo ===&lt;br /&gt;
On every commit to opensim all the tests are run on a [http://opensimulator.org:8085 Bamboo build server on opensimulator.org].  The process takes about 5 minutes to build, test, and report the results back out on #opensim-dev via the osmantis bot.&lt;br /&gt;
&lt;br /&gt;
=== Nant ===&lt;br /&gt;
You can manually run all the tests for OpenSim on your system by running '''nant test''' as a nant target.  This will run all the tests that are in the tree, though some speculative tests might be ignored if your platform does not have the right features or configuration to run these tests.&lt;br /&gt;
&lt;br /&gt;
=== NUnit Console ===&lt;br /&gt;
If you only want to run tests for one assembly you can do that using the NUnit Console.  On Linux just run '''nunit-console2 OpenSim.Foo.Tests.dll''' and it will run only the tests for OpenSim.Foo.Tests.dll.  If you are only making changes to 1 dll and just want a quick sanity check, this is the fastest way to do that.&lt;br /&gt;
&lt;br /&gt;
=== Debugging Tests ===&lt;br /&gt;
There is a special page dedicated to this. See [[Debugging Unit Tests]].&lt;br /&gt;
&lt;br /&gt;
== Learning More ==&lt;br /&gt;
You should definitely read the documentation at the [http://www.nunit.org/index.php?p=documentation NUnit homepage] if you want to know more about testing.  It's a very good reference for all the APIs in NUnit that you can use for creating tests.&lt;br /&gt;
&lt;br /&gt;
== Code Coverage ==&lt;br /&gt;
&lt;br /&gt;
A prototype has been included using monocov, which has a profile built-in in mono. Instructions for using monocov can be found on the Mono homepage, in [http://www.mono-project.com/Code_Coverage Code Coverage] section. Unfortunately nunit2 and nant do not support code coverage with monocov (only some other proprietary code coverages), so there is no &amp;lt;monocov&amp;gt; tag. The solution was to implement it using many nunit-console and on &amp;lt;exec&amp;gt; tags. &lt;br /&gt;
&lt;br /&gt;
ATTENTION: Code coverage only works with mono 1.2.x , any other version will most likely not work. Code coverage development is being put on hold for now until it supports newer mono versions.&lt;br /&gt;
&lt;br /&gt;
=== Running ===&lt;br /&gt;
&lt;br /&gt;
Download [http://primates.ximian.com/~lupus/monocov-0.2.tar.gz monocov] and [http://prdownloads.sourceforge.net/nunit/NUnit-2.4.8-net-2.0.zip?download nunit-console] if your nunit-console does not work. To test if it works (my Ubuntu's Hardy version did not), just run one of the tests with nunit-console.&lt;br /&gt;
&lt;br /&gt;
Install monocov (./configure, ./make install, there could be some minor conflicts, I had to add to the compiling line -I/usr/include/mono-1.0/) and make sure the working nunit-console.exe is in /usr/lib/nunit/nunit-console.exe. Now just run nant test-cov and it will generate .cov files and HTML directories in the cov directory. The .cov files can be seen by running monocov on them, and have the same information as the HTML directories.&lt;br /&gt;
&lt;br /&gt;
== Testing Todo ==&lt;br /&gt;
&lt;br /&gt;
=== Coverage ===&lt;br /&gt;
&lt;br /&gt;
A prototype has been done and documented. Now we must keep a look if monocov will evolve to support newer mono versions.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
[[Category:Testing]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Example_Test_SQLite_Assets</id>
		<title>Example Test SQLite Assets</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Example_Test_SQLite_Assets"/>
				<updated>2009-03-12T06:54:13Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: New page: === An Example Test - SQLite Assets === &amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt; using System; using System.IO; using System.Collections.Generic; using NUnit.Framework; using NUnit.Framework.SyntaxHelpers; ...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== An Example Test - SQLite Assets ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
using System;&lt;br /&gt;
using System.IO;&lt;br /&gt;
using System.Collections.Generic;&lt;br /&gt;
using NUnit.Framework;&lt;br /&gt;
using NUnit.Framework.SyntaxHelpers;&lt;br /&gt;
using OpenSim.Framework;&lt;br /&gt;
using OpenSim.Data.Tests;&lt;br /&gt;
using OpenSim.Data.SQLite;&lt;br /&gt;
using OpenSim.Region.Environment.Scenes;&lt;br /&gt;
using OpenMetaverse;&lt;br /&gt;
&lt;br /&gt;
namespace OpenSim.Data.SQLite.Tests&lt;br /&gt;
{&lt;br /&gt;
    [TestFixture]&lt;br /&gt;
    public class SQLiteAssetTest&lt;br /&gt;
    {&lt;br /&gt;
        public string file;&lt;br /&gt;
        public string connect;&lt;br /&gt;
        public AssetDataBase db;&lt;br /&gt;
        public UUID uuid1;&lt;br /&gt;
        public UUID uuid2;&lt;br /&gt;
        public UUID uuid3;&lt;br /&gt;
        public string name1;&lt;br /&gt;
        public string name2;&lt;br /&gt;
        public string name3;&lt;br /&gt;
        public byte[] asset1;&lt;br /&gt;
        &lt;br /&gt;
        [TestFixtureSetUp]&lt;br /&gt;
        public void Init()&lt;br /&gt;
        {&lt;br /&gt;
            uuid1 = UUID.Random();&lt;br /&gt;
            uuid2 = UUID.Random();&lt;br /&gt;
            uuid3 = UUID.Random();&lt;br /&gt;
            name1 = &amp;quot;asset one&amp;quot;;&lt;br /&gt;
            name2 = &amp;quot;asset two&amp;quot;;&lt;br /&gt;
            name3 = &amp;quot;asset three&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
            asset1 = new byte[100];&lt;br /&gt;
            asset1.Initialize();&lt;br /&gt;
            file = Path.GetTempFileName() + &amp;quot;.db&amp;quot;;&lt;br /&gt;
            connect = &amp;quot;URI=file:&amp;quot; + file + &amp;quot;,version=3&amp;quot;;&lt;br /&gt;
            db = new SQLiteAssetData();&lt;br /&gt;
            db.Initialise(connect);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [TestFixtureTearDown]&lt;br /&gt;
        public void Cleanup()&lt;br /&gt;
        {&lt;br /&gt;
            db.Dispose();&lt;br /&gt;
            System.IO.File.Delete(file);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T001_LoadEmpty()&lt;br /&gt;
        {&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T010_StoreSimpleAsset()&lt;br /&gt;
        {&lt;br /&gt;
            AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
            AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
            AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
            a1.Data = asset1;&lt;br /&gt;
            a2.Data = asset1;&lt;br /&gt;
            a3.Data = asset1;&lt;br /&gt;
            &lt;br /&gt;
            db.CreateAsset(a1);&lt;br /&gt;
            db.CreateAsset(a2);&lt;br /&gt;
            db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
            AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
            Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
            Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
            AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
            Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
            Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
            AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
            Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
            Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T011_ExistsSimpleAsset()&lt;br /&gt;
        {&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid1), Is.True);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid2), Is.True);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid3), Is.True);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can see 4 of the important annotations here:&lt;br /&gt;
* TestFixture - this class is a test suite&lt;br /&gt;
* TestFixtureSetup - this code is always run before any of the tests are executed&lt;br /&gt;
* TestFixtureTearDown - this code is always run after the tests are done executing, even if they fail.&lt;br /&gt;
* Test - this method is a test&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Automated_Testing</id>
		<title>Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Automated_Testing"/>
				<updated>2009-03-12T06:50:06Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* Good / Bad Test practices */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As OpenSim matures, we are extremely interested in adding more automated verification into the OpenSim source tree.  Test exist not only to prevent bugs from creeping in, but also to provide fair warning that the behavior of the system has changed, and tests may need updating.&lt;br /&gt;
&lt;br /&gt;
In OpenSim today we use NUnit tests.  Our conventions are:&lt;br /&gt;
# Tests should '''not''' exist inside runtime assemblies, as this makes nunit a production requirement&lt;br /&gt;
# Tests should be in .Tests.dll assemblies.  For instance, the tests for OpenSim.Data.SQLite.dll should be in the OpenSim.Data.SQLite.Tests.dll assembly.  This allows for easy removal of test assemblies in products.&lt;br /&gt;
# Tests should be as close to the code as possible, but not intermingled.  So the tests for OpenSim/Data/SQLite should be in OpenSim/Data/SQLite/Tests/.  Through the use of the '''Exclude''' keyword in prebuild.xml you can ensure that directory is part of OpenSim.Data.SQLite.Tests.dll and not OpenSim.Data.SQLite.dll. See exclude clarification in writing unit tests section.&lt;br /&gt;
# Tests testing a class should be grouped into a test class file called xxxTest.cs, where xxx is the name of the class that is being tested.&lt;br /&gt;
# Tests should be able to run safely in a production environment.  That means that care must be taken not to damage data on the machine that it is being run.&lt;br /&gt;
# Tests should be deterministic in other words repeatable. Avoid randomness in tests. See good and bad testing practices below.&lt;br /&gt;
&lt;br /&gt;
== Core Functionality Missing Unit Tests ==&lt;br /&gt;
&lt;br /&gt;
This is a list of functionality which is not covered by unit tests and is identified as highly desireable test target:&lt;br /&gt;
&lt;br /&gt;
# Database Modules (These are mysql tables)&lt;br /&gt;
## region ban&lt;br /&gt;
## land&lt;br /&gt;
## landaccesslist&lt;br /&gt;
&lt;br /&gt;
== Good / Bad Test practices ==&lt;br /&gt;
Creating good tests is an art, not a science.  Tests are useful by how many bugs they find or how many bugs they avoid.  Things you should think about in creating good tests is:&lt;br /&gt;
* Throwing edge cases, like 0, &amp;quot;&amp;quot;, or Null at parameters.  This ensures that people functions are hardened against incomplete data.  Many of our crashes come from the lack of this hardening showing up at just the wrong time.&lt;br /&gt;
* Use stateful testing to build up complex scenarios.  This is more useful than just cursory get / set calls.&lt;br /&gt;
* Random tests are not a good idea. We need test results to be deterministic. In other words tests need to be repeatable. If you want to test for a range it is good idea to make separate tests for min and max values. Random values in fields can fail randomly. When something goes wrong for example in database schema the developer will not necessarily notice if the stored values are random. On the other hand its hard to troubleshoot randomly failing tests as you dont know which specific value caused the failure.&lt;br /&gt;
* Tests should be independent and should not rely on another test being run, passing or failing. An excerpt from [http://xunitpatterns.com/Principles%20of%20Test%20Automation.html#Independent%20Test xUnit Patterns]:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;If tests are interdependent and (even worse) order dependent, we will be depriving ourselves of the useful feedback test failures provide. Interacting Tests [...] tend to fail in a group. The failure of a test that moved the [subject under test] into the state required by the dependent test will lead to the failure of the dependent test too. With both tests failing, how can we tell if it is because of a problem in code that both rely on in some way or is it a problem in code that only the first relies on. With both tests failing we can't tell. We are only talking about two tests here. Imagine how much worse this is with tens or hundreds of tests.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Only one function of the subject under test should be tested in one test. When testing a database access object, for example, write separate tests for creating DB entries, updating them and removing them.&lt;br /&gt;
* Do not use the subject under test to set up the state for the test or to verify the result. Use a different method. When testing a database access object, for example, use raw SQL to insert the initial data into the DB, then run the method being tested. To verify if the operation was successful, use raw SQL again to verify the DB changed as expected.&lt;br /&gt;
&lt;br /&gt;
== Writing Tests ==&lt;br /&gt;
Writing a new unit test is pretty easy, and very helpful in increasing the stability of opensim by nailing down bugs.  I'm going to present an example here of SQLite Asset testing to show how simple such a test case is to write.  The actual in tree SQLite Asset tests are a little different because the code was factored out so that it was easily applied to any database driver, so don't be concerned with the fact that what you see here isn't in the tree.&lt;br /&gt;
&lt;br /&gt;
Exclude clarification: Make sure your master project (not the test project) has an entry for files like the following so that the test code is not included in the master project dll:&lt;br /&gt;
      &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;lt;Files&amp;gt;&lt;br /&gt;
        &amp;lt;Match pattern=&amp;quot;*.cs&amp;quot; recurse=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;Exclude name=&amp;quot;Tests&amp;quot; pattern=&amp;quot;Tests&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/Match&amp;gt;&lt;br /&gt;
      &amp;lt;/Files&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NUnit Conventions ===&lt;br /&gt;
An NUnit test suite:&lt;br /&gt;
* is a class with a default constructor (takes no arguments)&lt;br /&gt;
* has public methods that are tests&lt;br /&gt;
* uses annotations to determine what are tests&lt;br /&gt;
* runs it's tests in '''alphabetical order by method name'''&lt;br /&gt;
&lt;br /&gt;
An NUnit test method:&lt;br /&gt;
* must be public&lt;br /&gt;
* must return void&lt;br /&gt;
* must take no arguments&lt;br /&gt;
* is successful if no exception or assert is thrown while running it&lt;br /&gt;
&lt;br /&gt;
The run order is important if you want to have early tests that setup some complicated state (like creating objects), and have later tests remove or update that state.  For that reason I find it very helpful to name all test methods '''Txxx_somename''' where '''xxx''' is a number between 000 and 999.  That guaruntees no surprises in run order.&lt;br /&gt;
&lt;br /&gt;
==== Setup / Teardown ====&lt;br /&gt;
In the case of testing something like the database layer, we have to actually attempt to store / retrieve things from a database.  Following from rule #4 of good tests, we want to make sure not to touch the production databases to run our tests, so during startup we generate a temporary file name which is guaranteed not to be an existing file on the system, and use that as our database file name.  By running db.Initialize() the OpenSim migration code will correctly populate that database with the latest schema.&lt;br /&gt;
&lt;br /&gt;
Once we are done with the tests we want to make sure we aren't leaving garbage temp files on the user's system.  So we remove that file we created.&lt;br /&gt;
&lt;br /&gt;
During setup we also create a set of state variables, such as 3 uuids, 3 strings, and a data block.  You could have always just stuck these inline, but variables are there for a reason, so use them.&lt;br /&gt;
&lt;br /&gt;
==== Asserts ====&lt;br /&gt;
You will see scattered through the code '''Assert.That(...)'''.  These will throw an exception if the condition is not valid.  This format of assertions is called the [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 Contraint Model] in NUnit, and provides a large number of tests with the flavor of:&lt;br /&gt;
* Assert.That(foo, Is.Null)&lt;br /&gt;
* Assert.That(foo, Is.Not.Null)&lt;br /&gt;
* Assert.That(foo, Is.True)&lt;br /&gt;
* Assert.That(foo, Is.EqualTo(bar))&lt;br /&gt;
* Assert.That(foo, Text.Matches( &amp;quot;*bar*&amp;quot; ))&lt;br /&gt;
&lt;br /&gt;
Of note, Is.EqualTo uses the Equals function of foo, so this can only be used on objects that are IComparable.  Most of the OpenSim base objects are not, so you'll have to compare fields manually in tests.&lt;br /&gt;
&lt;br /&gt;
For the complete set of conditions you can use see [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4 the Contraint Model NUnit documentation].  While there is another syntax for tests, the Constraint Model is preferred as it is far more human readable.&lt;br /&gt;
&lt;br /&gt;
=== Simple Negative Tests ===&lt;br /&gt;
Test T001 is an example of a simple negative test.  We assume a new database will not have any of those assets in them.  While the value of this test may look low, it does provide a baseline in ensuring that the database connection is there, that these return false correctly, and that no other exception is thrown.  Negative tests are a good way to force bounds conditions and ensure that not only does it  ''return what you expect'' it also ''doesn't return what you don't expect''.  Thought of another way, it ensures your code is somewhat defensive in nature, not coughing on bad or unexpected data.&lt;br /&gt;
&lt;br /&gt;
=== Simple Positive Tests ===&lt;br /&gt;
T010 is an example of a simple positive test.  In it we create and store 3 assets (ensuring no exceptions), then load those 3 assets back from the database and ensure the fields are correct.  Because AssetBase is not IComparible we just check the ID and Name fields with equals tests.  If any of the Asserts fail, the whole test fails.&lt;br /&gt;
&lt;br /&gt;
=== Stateful Tests ===&lt;br /&gt;
T011 is an example of a stateful test, because it requires the state created by T010 (i.e. the creation of those 3 objects).  In order to test any kind of complicated scenario you will find that you need to use stateful tests to build up various amounts of state (testing along the way), then manipulating and possibly tearing it down.  Without doing this you can't do truly deep testing of function in any complex environment.  This example isn't very stateful (I tried to pick an easy example), but it should give you some ideas.&lt;br /&gt;
&lt;br /&gt;
=== Speculative Tests ===&lt;br /&gt;
Speculative tests are tests that might or might not apply in a given situation.  MySQL testing in the OpenSim tree is done by speculative testing, the tests will only run if there is a properly configured database, otherwise they will not be run.  If you execute '''Assert.Ignore()''' in a '''Test''' the test will end and be ignored.  If you run '''Assert.Ignore()''' in the '''TestFixtureSetup''' all tests in the test fixture will be skipped and ignored.&lt;br /&gt;
&lt;br /&gt;
Speculative testing lets you create tests that require certain preconditions to be met which you can't guarantee on all platforms/configuration, and are an important part of deep testing.&lt;br /&gt;
&lt;br /&gt;
=== An Example Test - SQLite Assets ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
using System;&lt;br /&gt;
using System.IO;&lt;br /&gt;
using System.Collections.Generic;&lt;br /&gt;
using NUnit.Framework;&lt;br /&gt;
using NUnit.Framework.SyntaxHelpers;&lt;br /&gt;
using OpenSim.Framework;&lt;br /&gt;
using OpenSim.Data.Tests;&lt;br /&gt;
using OpenSim.Data.SQLite;&lt;br /&gt;
using OpenSim.Region.Environment.Scenes;&lt;br /&gt;
using OpenMetaverse;&lt;br /&gt;
&lt;br /&gt;
namespace OpenSim.Data.SQLite.Tests&lt;br /&gt;
{&lt;br /&gt;
    [TestFixture]&lt;br /&gt;
    public class SQLiteAssetTest&lt;br /&gt;
    {&lt;br /&gt;
        public string file;&lt;br /&gt;
        public string connect;&lt;br /&gt;
        public AssetDataBase db;&lt;br /&gt;
        public UUID uuid1;&lt;br /&gt;
        public UUID uuid2;&lt;br /&gt;
        public UUID uuid3;&lt;br /&gt;
        public string name1;&lt;br /&gt;
        public string name2;&lt;br /&gt;
        public string name3;&lt;br /&gt;
        public byte[] asset1;&lt;br /&gt;
        &lt;br /&gt;
        [TestFixtureSetUp]&lt;br /&gt;
        public void Init()&lt;br /&gt;
        {&lt;br /&gt;
            uuid1 = UUID.Random();&lt;br /&gt;
            uuid2 = UUID.Random();&lt;br /&gt;
            uuid3 = UUID.Random();&lt;br /&gt;
            name1 = &amp;quot;asset one&amp;quot;;&lt;br /&gt;
            name2 = &amp;quot;asset two&amp;quot;;&lt;br /&gt;
            name3 = &amp;quot;asset three&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
            asset1 = new byte[100];&lt;br /&gt;
            asset1.Initialize();&lt;br /&gt;
            file = Path.GetTempFileName() + &amp;quot;.db&amp;quot;;&lt;br /&gt;
            connect = &amp;quot;URI=file:&amp;quot; + file + &amp;quot;,version=3&amp;quot;;&lt;br /&gt;
            db = new SQLiteAssetData();&lt;br /&gt;
            db.Initialise(connect);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [TestFixtureTearDown]&lt;br /&gt;
        public void Cleanup()&lt;br /&gt;
        {&lt;br /&gt;
            db.Dispose();&lt;br /&gt;
            System.IO.File.Delete(file);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T001_LoadEmpty()&lt;br /&gt;
        {&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T010_StoreSimpleAsset()&lt;br /&gt;
        {&lt;br /&gt;
            AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
            AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
            AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
            a1.Data = asset1;&lt;br /&gt;
            a2.Data = asset1;&lt;br /&gt;
            a3.Data = asset1;&lt;br /&gt;
            &lt;br /&gt;
            db.CreateAsset(a1);&lt;br /&gt;
            db.CreateAsset(a2);&lt;br /&gt;
            db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
            AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
            Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
            Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
            AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
            Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
            Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
            AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
            Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
            Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T011_ExistsSimpleAsset()&lt;br /&gt;
        {&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid1), Is.True);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid2), Is.True);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid3), Is.True);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can see 4 of the important annotations here:&lt;br /&gt;
* TestFixture - this class is a test suite&lt;br /&gt;
* TestFixtureSetup - this code is always run before any of the tests are executed&lt;br /&gt;
* TestFixtureTearDown - this code is always run after the tests are done executing, even if they fail.&lt;br /&gt;
* Test - this method is a test&lt;br /&gt;
&lt;br /&gt;
== Adding Tests to the Tree ==&lt;br /&gt;
As we said previously all tests for assembly OpenSim.Foo (in directory OpenSim/Foo) should:&lt;br /&gt;
* be in assembly OpenSim.Foo.Tests.dll&lt;br /&gt;
* not be in the OpenSim.Foo.dll assembly&lt;br /&gt;
* be in OpenSim/Foo/Tests directory&lt;br /&gt;
&lt;br /&gt;
Also, if you have created a new test assembly you must add references to it in both ''.nant/local.include'' and ''.nant/bamboo.build'' to ensure that the assembly is added to the automated bamboo runs as well as the nant test target.&lt;br /&gt;
&lt;br /&gt;
== Executing Tests ==&lt;br /&gt;
&lt;br /&gt;
=== Bamboo ===&lt;br /&gt;
On every commit to opensim all the tests are run on a [http://opensimulator.org:8085 Bamboo build server on opensimulator.org].  The process takes about 5 minutes to build, test, and report the results back out on #opensim-dev via the osmantis bot.&lt;br /&gt;
&lt;br /&gt;
=== Nant ===&lt;br /&gt;
You can manually run all the tests for OpenSim on your system by running '''nant test''' as a nant target.  This will run all the tests that are in the tree, though some speculative tests might be ignored if your platform does not have the right features or configuration to run these tests.&lt;br /&gt;
&lt;br /&gt;
=== NUnit Console ===&lt;br /&gt;
If you only want to run tests for one assembly you can do that using the NUnit Console.  On Linux just run '''nunit-console2 OpenSim.Foo.Tests.dll''' and it will run only the tests for OpenSim.Foo.Tests.dll.  If you are only making changes to 1 dll and just want a quick sanity check, this is the fastest way to do that.&lt;br /&gt;
&lt;br /&gt;
=== Debugging Tests ===&lt;br /&gt;
There is a special page dedicated to this. See [[Debugging Unit Tests]].&lt;br /&gt;
&lt;br /&gt;
== Learning More ==&lt;br /&gt;
You should definitely read the documentation at the [http://www.nunit.org/index.php?p=documentation NUnit homepage] if you want to know more about testing.  It's a very good reference for all the APIs in NUnit that you can use for creating tests.&lt;br /&gt;
&lt;br /&gt;
== Code Coverage ==&lt;br /&gt;
&lt;br /&gt;
A prototype has been included using monocov, which has a profile built-in in mono. Instructions for using monocov can be found on the Mono homepage, in [http://www.mono-project.com/Code_Coverage Code Coverage] section. Unfortunately nunit2 and nant do not support code coverage with monocov (only some other proprietary code coverages), so there is no &amp;lt;monocov&amp;gt; tag. The solution was to implement it using many nunit-console and on &amp;lt;exec&amp;gt; tags. &lt;br /&gt;
&lt;br /&gt;
ATTENTION: Code coverage only works with mono 1.2.x , any other version will most likely not work. Code coverage development is being put on hold for now until it supports newer mono versions.&lt;br /&gt;
&lt;br /&gt;
=== Running ===&lt;br /&gt;
&lt;br /&gt;
Download [http://primates.ximian.com/~lupus/monocov-0.2.tar.gz monocov] and [http://prdownloads.sourceforge.net/nunit/NUnit-2.4.8-net-2.0.zip?download nunit-console] if your nunit-console does not work. To test if it works (my Ubuntu's Hardy version did not), just run one of the tests with nunit-console.&lt;br /&gt;
&lt;br /&gt;
Install monocov (./configure, ./make install, there could be some minor conflicts, I had to add to the compiling line -I/usr/include/mono-1.0/) and make sure the working nunit-console.exe is in /usr/lib/nunit/nunit-console.exe. Now just run nant test-cov and it will generate .cov files and HTML directories in the cov directory. The .cov files can be seen by running monocov on them, and have the same information as the HTML directories.&lt;br /&gt;
&lt;br /&gt;
== Testing Todo ==&lt;br /&gt;
&lt;br /&gt;
=== Coverage ===&lt;br /&gt;
&lt;br /&gt;
A prototype has been done and documented. Now we must keep a look if monocov will evolve to support newer mono versions.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
[[Category:Testing]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/How_to_create_a_dynamic_plugin</id>
		<title>How to create a dynamic plugin</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/How_to_create_a_dynamic_plugin"/>
				<updated>2009-03-10T02:06:20Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Quick Start ==&lt;br /&gt;
&lt;br /&gt;
See [[Dynamic Plugin Quickstart]] for a (hopefully) short introduction.&lt;br /&gt;
&lt;br /&gt;
== Current state of Plugin loading ==&lt;br /&gt;
&lt;br /&gt;
The .NET runtime system has always made reflecting and introspecting of assemblies at runtime very easy to do, making dynamic loading of modules possible with very little effort.&lt;br /&gt;
&lt;br /&gt;
This has unfortunately lead to a situation in OpenSim where historically module loading was hard-coded and done by hand, using copy-and-paste code. Clearly this is a suboptimal situation.&lt;br /&gt;
&lt;br /&gt;
Effort was made to find a reusable, cross-platform dynamic assembly loader that could be used as-is, instead of reinventing our own. The only current candidate is Mono.Addins. MS's .NET runtime has its own Addin class, however as of this writing it is not yet implemented in Mono.&lt;br /&gt;
&lt;br /&gt;
A class called PluginLoader has been created to thinly wrap Mono.Addins, and the assemblies loaded by this class have been standardized on the IPlugin interface hierarchy. With the exception of RegionModules, all dynamically loaded assemblies should be called Plugins, and inherit from this base class.&lt;br /&gt;
&lt;br /&gt;
Currently the following interfaces have been converted to IPlugin:&lt;br /&gt;
# OpenSim.IApplicationPlugin&lt;br /&gt;
# OpenSim.Grid.GridServer.IGridPlugin&lt;br /&gt;
# OpenSim.Data.IGridDataPlugin&lt;br /&gt;
# OpenSim.Data.ILogDataPlugin&lt;br /&gt;
&lt;br /&gt;
And the following Assemblies are being loaded by PluginLoader:&lt;br /&gt;
# OpenSim.ApplicationPlugins.LoadRegions.LoadRegionsPlugin&lt;br /&gt;
# OpenSim.ApplicationPlugins.Rest.Regions.RestRegionPlugin&lt;br /&gt;
# OpenSim.ApplicationPlugins.Rest.Inventory.RestHandler&lt;br /&gt;
# OpenSim.ApplicationPlugins.RemoteController.RemoteAdminPlugin&lt;br /&gt;
# OpenSim.Data.MySQL.MySQLGridData&lt;br /&gt;
# OpenSim.Data.MySQL.MySQLLogData&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Why Mono.Addins ==&lt;br /&gt;
&lt;br /&gt;
Mono.Addins offers features outside of being upstream maintained by the Mono project:&lt;br /&gt;
* logically splits up module interfaces from implementations in a cross platform way through the use of text-based &amp;quot;extension points&amp;quot; and &amp;quot;addin manifests&amp;quot;&lt;br /&gt;
* lazily loads assemblies only when finally necessary&lt;br /&gt;
* tracks module dependencies&lt;br /&gt;
* allows customize the addin manifest XML&lt;br /&gt;
* automatically handles module sharing across application domains&lt;br /&gt;
* provides support for downloading assemblies from remote repositories&lt;br /&gt;
&lt;br /&gt;
For more information, please read the [http://www.mono-project.com/Mono.Addins_FAQ Mono.Addins FAQ]&lt;br /&gt;
&lt;br /&gt;
== Mono.Addin concepts ==&lt;br /&gt;
&lt;br /&gt;
Although effort has been made to make PluginLoader independent of the module loading mechanism, there are some concepts that should be understood when learning how to learn the system.&lt;br /&gt;
&lt;br /&gt;
A more detailed (and '''''authoritative'''''!) explanation can be found [http://www.mono-project.com/Mono.Addins_FAQ#Using_Mono.Addins here] and [http://www.mono-project.com/Introduction_to_Mono.Addins here].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Separating Male and Female ===&lt;br /&gt;
&lt;br /&gt;
A good system provides a means of loosely coupling two connected parts with a common interface so that one can be changed easily without affecting the other.&lt;br /&gt;
&lt;br /&gt;
The assembly that consumes a service is called a ''host'', and the provider of a service is called an ''addin''.&lt;br /&gt;
&lt;br /&gt;
A service that can be split into producer/consumer role is called an ''extension''. An extension consists of an ''extension point'' which is essentially a text &amp;quot;path&amp;quot; that give a hierarchical name to the service a consumer requires, and an ''extension node'' which represents an object that can provide that service. If a host asks for the addin(s) corresponding to extension point &amp;quot;/Foo&amp;quot;, and an addin extension node claims to implement &amp;quot;/Foo&amp;quot;, then the two can be joined to make a functioning whole.&lt;br /&gt;
&lt;br /&gt;
All OpenSim extension points start at the root &amp;quot;/OpenSim&amp;quot;. If you wished to create a new service &amp;quot;Foo&amp;quot;, you might choose to name it &amp;quot;/OpenSim/Foo&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In operation the consumer of a service, the host, requests that the system load all addins that claim to extend an extension point, and a list is returned to the consumer, who can choose to load any subset of those providers, the addins, into memory.&lt;br /&gt;
&lt;br /&gt;
=== Describing an Addin ===&lt;br /&gt;
&lt;br /&gt;
Clearly metadata must be associated with both host and addin, in our case this is an XML file that has the extension *.addin.xml, called a ''manifest''. &lt;br /&gt;
&lt;br /&gt;
In practice, the host manifest and addin manifest are so similar as to be almost exactly the same. The principle difference is that host manifests tell Mono.Addins where to find abstract interfaces, and addin manifests tell Mono.Addins where to find concrete implementations of those interfaces.&lt;br /&gt;
&lt;br /&gt;
The manifest has 3 critical parts&lt;br /&gt;
# Name and Version information &amp;lt;br&amp;gt; this is used to check inter-addin dependencies&lt;br /&gt;
# Filename of assemblies where the consumer interfaces or provider implementations can be found &amp;lt;br&amp;gt; this is needed to know which assemblies must be searched&lt;br /&gt;
# Extension Point path and Fully Qualified .NET Class Name of the consumer interface or provider implementation &amp;lt;br&amp;gt; this is needed to load the actual classes into memory&lt;br /&gt;
&lt;br /&gt;
The way to tell a host manifest from an addin manifest is that host manifests will *always* contain an ''isroot=true'' attribute in the &amp;lt;Addin&amp;gt; tag. However this is complicated by the fact that an addin can act as host for another addin in a recursive manner.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Building a model ===&lt;br /&gt;
&lt;br /&gt;
When the PluginLoader is first created within the host, Mono.Addins will search the directory the host was executed and search for all files that end in *.addin.xml. It uses the information to build a ''registry'' about the addins in addin-db-${VERSION}/ directory. The purpose of the registry is to collect all information once, then lazily load assemblies into memory only at the last moment when it is precisely known exactly which class is required by the user.&lt;br /&gt;
&lt;br /&gt;
== How to make your own plugin ==&lt;br /&gt;
&lt;br /&gt;
# Decide on the service you wish to separate into provider and consumer. Ex: &amp;quot;LartMe&amp;quot;&lt;br /&gt;
# Create an extension point to identify that service. Ex: &amp;quot;/OpenSim/LartMe&amp;quot;&lt;br /&gt;
# Create an consumer interface that has the methods needed, and derive it from OpenSim.Framework.IPlugin. Ex: &amp;quot;OpenSim.ILart&amp;quot;&lt;br /&gt;
## If that interface needs a constructor that takes parameters, you will also have to create a class derived from PluginInitialiserBase that can act as a [http://en.wikipedia.org/wiki/Closure_(computer_science) closure] for calling a parameterized constructor. See IApplicationPlugin for an example. Ex: &amp;quot;OpenSim.LartInitializer&amp;quot;&lt;br /&gt;
# Write a provider class that implements that interface. Ex: &amp;quot;OpenSim.LartPlugin&amp;quot;&lt;br /&gt;
# Write a host manifest. See OpenSim.addin.xml as an example.&lt;br /&gt;
## Ensure that /Addin@isroot=true&lt;br /&gt;
## Ensure that /Addin@id is set to a unique name. Ex: &amp;quot;LartMe&amp;quot;&lt;br /&gt;
## Ensure that /Addin/Runtime/Import@assembly exists for each assembly that either hosts the application (host.EXE) or defines an addin consumer interface (Lart.dll) used by the host&lt;br /&gt;
## Ensure that /Addin/ExtensionPoint@path is set. Ex: &amp;quot;&amp;lt;ExtensionPoint path=&amp;quot;/OpenSim/LartMe&amp;quot;&amp;gt;...&amp;quot;&lt;br /&gt;
## Ensure that /Addin/ExtensionPoint/ExtensionNode@name is set to &amp;quot;Plugin&amp;quot;. This is a custom derived node type (OpenSim.Framework.PluginExtensionNode).&lt;br /&gt;
## Ensure that /Addin/ExtensionPoint/ExtensionNode@type is set to &amp;quot;OpenSim.Framework.PluginExtensionNode&amp;quot;&lt;br /&gt;
## Ensure that /Addin/ExtensionPoint/ExtensionNode@objectType is set to the fully qualified name of the consumer interface found in the above assembly import. Ex: &amp;quot;OpenSim.ILart&amp;quot;&lt;br /&gt;
# Write a addin manifest. See LoadRegionsPlugin.addin.xml as an example.&lt;br /&gt;
## Ensure that /Addin/Runtime/Import@assembly exists for the assembly that implements the producer class.&lt;br /&gt;
## Ensure that /Addin/Dependencies/Addin@id exists and is the same as the id of the host manifest. Ex: &amp;quot;Lart&amp;quot;&lt;br /&gt;
## Ensure that /Addin/ExtensionPoint@path is set and is the same as that of the host manifest. Ex: &amp;quot;&amp;lt;ExtensionPoint path=&amp;quot;/OpenSim/LartMe&amp;quot;&amp;gt;...&amp;quot;&lt;br /&gt;
## Ensure that /Addin/Extension/Plugin@type is set to the fully qualified name of the implementing provider class. Ex: &amp;quot;OpenSim.LartPlugin&amp;quot;&lt;br /&gt;
## Optionally, if you wish to discriminate on &amp;quot;provider&amp;quot; you can set /Addin/Extension/Plugin@provider&lt;br /&gt;
# When you need to load the producer, create a PluginLoader of the type defined by the consumer interface. Ex: &amp;quot;new PluginLoader &amp;lt;ILart&amp;gt; ();&amp;quot;&lt;br /&gt;
## If the provider requires a Initializer, it should be passed to the PluginLoader constructor. All plugins will be initialized using this initializer. Ex: &amp;quot;new PluginLoader &amp;lt;ILart&amp;gt; (new LartInitializer (&amp;quot;l4rt&amp;quot;));&amp;quot;&lt;br /&gt;
# Call PluginLoader.Load using the required extension point. Ex: &amp;quot;loader.Load (&amp;quot;/OpenSim/LartMe&amp;quot;)&amp;quot;&lt;br /&gt;
# Instead of putting the plugin manifest into the bin/ directory, it is cleaner to embed it into the plugin dll by specifying buildAction=&amp;quot;EmbeddedResource&amp;quot; in prebuild.xml to the Files section of your project&lt;br /&gt;
## eg &amp;lt;Match pattern=&amp;quot;*.addin.xml&amp;quot; path=&amp;quot;Resources&amp;quot; buildAction=&amp;quot;EmbeddedResource&amp;quot; recurse=&amp;quot;true&amp;quot;/&amp;gt;&lt;br /&gt;
## For host manifests, it usually makes more sense to have them in the bin/ directory (they would otherwise have to be embedded into a number of dlls and exes)&lt;br /&gt;
&lt;br /&gt;
All loaded plugins can now be found in &amp;quot;loader.Plugins&amp;quot; and used as necessary.&lt;br /&gt;
&lt;br /&gt;
If that looks like a lot of work, consider that outside of the normal work of splitting a class into interface and implementation, its really mostly just boilerplate, and can be accomplished by just comparing how things are currently implemented within OpenSim.&lt;br /&gt;
&lt;br /&gt;
== Filtering and Constraining ==&lt;br /&gt;
&lt;br /&gt;
When you ask to load an extension point, you are potentially bringing a lot of assemblies into memory. Before you do that, you will most likely want to have a say about how many assemblies you expect, and which one you need.&lt;br /&gt;
&lt;br /&gt;
You can do this by assigning a IPluginConstraint or IPluginFilter to an extension point.&lt;br /&gt;
&lt;br /&gt;
An IPluginConstraint is applied each time Load() is called on an extension point, but the behavior of the constraint is up to the implementor. It is assumed that a constraint will ask something of Mono.Addins, and throw an exception if it is not happy with the answer.&lt;br /&gt;
&lt;br /&gt;
=== Loading Critical Plugins ===&lt;br /&gt;
&lt;br /&gt;
For some applications we expect precisely a certain amount of plugins to be loaded. Often exactly one. PluginCountConstraint implements precisely this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int n = 1;&lt;br /&gt;
PluginLoader &amp;lt;ILart&amp;gt; loader = new PluginLoader();&lt;br /&gt;
loader.AddConstraint (&amp;quot;/OpenSim/LartMe&amp;quot;, new PluginCountConstraint (n));&lt;br /&gt;
loader.Load (&amp;quot;/OpenSim/LartMe&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the above code is run, and more or less than n plugin could be loaded, the constraint will throw a PluginConstraintViolatedException.&lt;br /&gt;
&lt;br /&gt;
=== Loading Named Plugins ===&lt;br /&gt;
&lt;br /&gt;
Often the reason why more than one plugin is available to load is because we wish to afford choice to the user as to which plugin he prefers, exposed in a configuration file. We read from the file the user's preference, and want to only load the desired plugin.&lt;br /&gt;
&lt;br /&gt;
If we have some addin manifests that look like these:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;Addin id=&amp;quot;OpenSim.Lart&amp;quot; version=&amp;quot;0.1&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;Runtime&amp;gt;&lt;br /&gt;
        &amp;lt;Import assembly=&amp;quot;LartCorp.dll&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/Runtime&amp;gt;&lt;br /&gt;
    &amp;lt;Dependencies&amp;gt;&lt;br /&gt;
        &amp;lt;Addin id=&amp;quot;OpenSim&amp;quot; version=&amp;quot;0.5&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Dependencies&amp;gt;&lt;br /&gt;
    &amp;lt;Extension path = &amp;quot;/OpenSim/LartMe&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;Plugin provider=&amp;quot;LartCorp&amp;quot; type=&amp;quot;Corp.LartMatic&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Extension&amp;gt;&lt;br /&gt;
&amp;lt;/Addin&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;Addin id=&amp;quot;OpenSim.Lart&amp;quot; version=&amp;quot;0.1&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;Runtime&amp;gt;&lt;br /&gt;
        &amp;lt;Import assembly=&amp;quot;OpenSim.Lart.dll&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/Runtime&amp;gt;&lt;br /&gt;
    &amp;lt;Dependencies&amp;gt;&lt;br /&gt;
        &amp;lt;Addin id=&amp;quot;OpenSim&amp;quot; version=&amp;quot;0.5&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Dependencies&amp;gt;&lt;br /&gt;
    &amp;lt;Extension path = &amp;quot;/OpenSim/LartMe&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;Plugin provider=&amp;quot;OpenLart&amp;quot; type=&amp;quot;OpenSim.LartPlugin&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Extension&amp;gt;&lt;br /&gt;
&amp;lt;/Addin&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And loading code that looks like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PluginLoader &amp;lt;ILart&amp;gt; loader = new PluginLoader();&lt;br /&gt;
loader.AddConstraint (&amp;quot;/OpenSim/LartMe&amp;quot;, new PluginProviderFilter (&amp;quot;LartCorp&amp;quot;));&lt;br /&gt;
loader.Load (&amp;quot;/OpenSim/LartMe&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Only the &amp;quot;LartCorp&amp;quot; plugin will be loaded.&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Dynamic_Plugin_Quickstart</id>
		<title>Dynamic Plugin Quickstart</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Dynamic_Plugin_Quickstart"/>
				<updated>2009-03-10T02:06:02Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A quick guide to writing plugins. Please refer to [[How to create a dynamic plugin]] for more in-depth information.&lt;br /&gt;
&lt;br /&gt;
== Defining Extension Points ==&lt;br /&gt;
&lt;br /&gt;
Extension points describe the location in the program where external modules can be plugged-in at runtime. Extension points can be defined in one of two ways:&lt;br /&gt;
&lt;br /&gt;
* decorating interfaces, classes or methods with attributes in the source code&lt;br /&gt;
* embedding an XML file, called a manifest, as a resource in an assembly&lt;br /&gt;
&lt;br /&gt;
In OpenSim, the preferred method is to embed an XML manifest in the assembly. Below is an example manifest defining one extension point in the AssetInventoryServer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&amp;lt;Addin id=&amp;quot;OpenSim.Grid.AssetInventoryServer&amp;quot; isroot=&amp;quot;true&amp;quot; version=&amp;quot;0.1&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;Runtime&amp;gt;&lt;br /&gt;
        &amp;lt;Import assembly=&amp;quot;OpenSim.Grid.AssetInventoryServer.exe&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;Import assembly=&amp;quot;OpenSim.Framework.dll&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Runtime&amp;gt;&lt;br /&gt;
    &amp;lt;ExtensionPoint path=&amp;quot;/OpenSim/AssetInventoryServer/AssetStorageProvider&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;ExtensionNode name=&amp;quot;Plugin&amp;quot;&lt;br /&gt;
                       type=&amp;quot;OpenSim.Framework.PluginExtensionNode&amp;quot;&lt;br /&gt;
                       objectType=&amp;quot;OpenSim.Grid.AssetInventoryServer.IAssetStorageProvider&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/ExtensionPoint&amp;gt;&lt;br /&gt;
&amp;lt;/Addin&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest contains the following elements:&lt;br /&gt;
&lt;br /&gt;
* '''Addin'''&lt;br /&gt;
** '''id''': an identifier describing this addin, used for dependencies in other addins.&lt;br /&gt;
** '''isroot''': set to '''true''' if this manifest does not define any ''extension nodes'', otherwise can be left out completely.&lt;br /&gt;
** '''version''': a version number, also used for dependencies in other addins.&lt;br /&gt;
* '''Runtime''': a list of assemblies that need to be imported by Mono.Addins as it builds the plugin repository. In the example, the &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.exe&amp;lt;/code&amp;gt; assembly contains the definition for &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.IAssetStorageProvider&amp;lt;/code&amp;gt; interface, while &amp;lt;code&amp;gt;OpenSim.Framework.dll&amp;lt;/code&amp;gt; contains a definition for &amp;lt;code&amp;gt;OpenSim.Framework.PluginExtensionNode&amp;lt;/code&amp;gt;.&lt;br /&gt;
* '''ExtensionPoint'''&lt;br /&gt;
** '''path''': the location of the extension point in the extension point tree (see [http://www.mono-project.com/Introduction_to_Mono.Addins#Extension_Paths Extension Paths]).&lt;br /&gt;
* '''ExtensionNode'''&lt;br /&gt;
** '''name''': a name describing this extension node.&lt;br /&gt;
** '''type''': a class that handles plugin loading, this should probably be &amp;lt;code&amp;gt;OpenSim.Framework.PluginExtensionNode&amp;lt;/code&amp;gt; unless you know what you're doing.&lt;br /&gt;
** '''objectType''': an instance of this object will be loaded into this extension point at runtime. This is probably what your plugin will instantiate/subclass/implement.&lt;br /&gt;
&lt;br /&gt;
At this stage, all that is needed is &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.IAssetStorageProvider&amp;lt;/code&amp;gt; defined and present in &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.exe&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''PLEASE NOTE''': embedding XML manifests in .exe assemblies doesn't work. The .addin.xml file must reside in a directory that Mono.Addins will scan for plugins. Currently in OpenSim this is the current working directory (&amp;lt;code&amp;gt;bin/&amp;lt;/code&amp;gt;). Ideally all applications would consist of an .exe assembly and a .dll assembly which contains the embedded XML manifest.&lt;br /&gt;
&lt;br /&gt;
== Defining Extensions ==&lt;br /&gt;
&lt;br /&gt;
Extensions that implement extension points are defined in a similar way. Below is an example corresponding XML file describing a plugin for the above extension point:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&amp;lt;Addin id=&amp;quot;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim&amp;quot; version=&amp;quot;0.1&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;Runtime&amp;gt;&lt;br /&gt;
        &amp;lt;Import assembly=&amp;quot;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;Import assembly=&amp;quot;OpenSim.Data.dll&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Runtime&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Dependencies&amp;gt;&lt;br /&gt;
        &amp;lt;Addin id=&amp;quot;OpenSim.Grid.AssetInventoryServer&amp;quot; version=&amp;quot;0.1&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Dependencies&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;ExtensionPoint path = &amp;quot;/OpenSim/AssetData&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;ExtensionNode name=&amp;quot;Plugin&amp;quot;&lt;br /&gt;
                       type=&amp;quot;OpenSim.Framework.PluginExtensionNode&amp;quot;&lt;br /&gt;
                       objectType=&amp;quot;OpenSim.Data.IAssetDataPlugin&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/ExtensionPoint&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Extension path=&amp;quot;/OpenSim/AssetInventoryServer/AssetStorageProvider&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;Plugin id=&amp;quot;OpenSimAssetStorage&amp;quot;&lt;br /&gt;
                provider=&amp;quot;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll&amp;quot;&lt;br /&gt;
                type=&amp;quot;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.OpenSimAssetStoragePlugin&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Extension&amp;gt;&lt;br /&gt;
&amp;lt;/Addin&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The elements (not in the same order as in the file) are:&lt;br /&gt;
&lt;br /&gt;
* '''Addin'''&lt;br /&gt;
** '''id''': a string identifying this plugin, can be used for dependencies in other plugins.&lt;br /&gt;
** '''version''': a version of this plugin, also used for dependencies in other plugins.&lt;br /&gt;
* '''Runtime''': a list of assemblies to import at runtime while Mono.Addins builds up the plugin registry. In this case, &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll&amp;lt;/code&amp;gt; contains the definition for &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.OpenSimAssetStoragePlugin&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;OpenSim.Framework.dll&amp;lt;/code&amp;gt; contains a definition for &amp;lt;code&amp;gt;OpenSim.Framework.PluginExtensionNode&amp;lt;/code&amp;gt;.&lt;br /&gt;
* '''Dependencies''': describes other addin(s) required to be loaded before this addin can be loaded. The '''id''' and '''version''' is used.&lt;br /&gt;
* '''Extension'''&lt;br /&gt;
** '''path''': the path along the extension point tree to the extension point which this extension implements.&lt;br /&gt;
** '''Plugin'''&lt;br /&gt;
*** '''id''': a string identifying this particular extension. Pretty much an arbitrary string.&lt;br /&gt;
*** '''provider''': another property of the extension, which can be an arbitrary string. In OpenSim, the convention seems to be to place the assembly name here which contains this plugin.&lt;br /&gt;
*** '''type''': the fully qualified class name to be instantiated which implements the extension. In the code, this class will inherit from/implement the class/interface specified in '''objectType''' attribute of the '''ExtensionPath'''.&lt;br /&gt;
* '''NOTE''': this XML file also defines another extension point, meaning that this plugin also takes another plugin. Note the '''isroot''' attribute in the topmost '''Addin''' element is omitted.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
The relevant code which ends up in &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.exe&amp;lt;/code&amp;gt; and loads the AssetStorage plugin looks something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;private IAssetStorageProvider LoadAssetStorageProvider(string addinPath)&lt;br /&gt;
{&lt;br /&gt;
    PluginLoader&amp;lt;IAssetStorageProvider&amp;gt; loader = new PluginLoader&amp;lt;IAssetStorageProvider&amp;gt;();&lt;br /&gt;
    loader.Add(addinPath);&lt;br /&gt;
&lt;br /&gt;
    try&lt;br /&gt;
    {&lt;br /&gt;
        loader.Load();&lt;br /&gt;
    }&lt;br /&gt;
    catch (PluginNotInitialisedException e)&lt;br /&gt;
    {&lt;br /&gt;
        // log the error, clean up, exit if needed, etc&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return loader.Plugin;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Then, from elsewhere in the code:&lt;br /&gt;
IAssetStorageProvider StorageProvider = LoadAssetStorageProvider(&amp;quot;/OpenSim/AssetInventoryServer/AssetStorageProvider&amp;quot;);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;PluginLoader&amp;lt;/code&amp;gt; class lives in &amp;lt;code&amp;gt;OpenSim.Framework&amp;lt;/code&amp;gt;; have a look through the code for more plugin loading options.&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Dynamic_Plugin_Quickstart</id>
		<title>Dynamic Plugin Quickstart</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Dynamic_Plugin_Quickstart"/>
				<updated>2009-03-10T02:05:11Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* Defining Extension Points */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A quick guide to writing plugins. Please refer to [[How to create a dynamic plugin]] for more in-depth information.&lt;br /&gt;
&lt;br /&gt;
=== Defining Extension Points ===&lt;br /&gt;
&lt;br /&gt;
Extension points describe the location in the program where external modules can be plugged-in at runtime. Extension points can be defined in one of two ways:&lt;br /&gt;
&lt;br /&gt;
* decorating interfaces, classes or methods with attributes in the source code&lt;br /&gt;
* embedding an XML file, called a manifest, as a resource in an assembly&lt;br /&gt;
&lt;br /&gt;
In OpenSim, the preferred method is to embed an XML manifest in the assembly. Below is an example manifest defining one extension point in the AssetInventoryServer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&amp;lt;Addin id=&amp;quot;OpenSim.Grid.AssetInventoryServer&amp;quot; isroot=&amp;quot;true&amp;quot; version=&amp;quot;0.1&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;Runtime&amp;gt;&lt;br /&gt;
        &amp;lt;Import assembly=&amp;quot;OpenSim.Grid.AssetInventoryServer.exe&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;Import assembly=&amp;quot;OpenSim.Framework.dll&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Runtime&amp;gt;&lt;br /&gt;
    &amp;lt;ExtensionPoint path=&amp;quot;/OpenSim/AssetInventoryServer/AssetStorageProvider&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;ExtensionNode name=&amp;quot;Plugin&amp;quot;&lt;br /&gt;
                       type=&amp;quot;OpenSim.Framework.PluginExtensionNode&amp;quot;&lt;br /&gt;
                       objectType=&amp;quot;OpenSim.Grid.AssetInventoryServer.IAssetStorageProvider&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/ExtensionPoint&amp;gt;&lt;br /&gt;
&amp;lt;/Addin&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest contains the following elements:&lt;br /&gt;
&lt;br /&gt;
* '''Addin'''&lt;br /&gt;
** '''id''': an identifier describing this addin, used for dependencies in other addins.&lt;br /&gt;
** '''isroot''': set to '''true''' if this manifest does not define any ''extension nodes'', otherwise can be left out completely.&lt;br /&gt;
** '''version''': a version number, also used for dependencies in other addins.&lt;br /&gt;
* '''Runtime''': a list of assemblies that need to be imported by Mono.Addins as it builds the plugin repository. In the example, the &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.exe&amp;lt;/code&amp;gt; assembly contains the definition for &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.IAssetStorageProvider&amp;lt;/code&amp;gt; interface, while &amp;lt;code&amp;gt;OpenSim.Framework.dll&amp;lt;/code&amp;gt; contains a definition for &amp;lt;code&amp;gt;OpenSim.Framework.PluginExtensionNode&amp;lt;/code&amp;gt;.&lt;br /&gt;
* '''ExtensionPoint'''&lt;br /&gt;
** '''path''': the location of the extension point in the extension point tree (see [http://www.mono-project.com/Introduction_to_Mono.Addins#Extension_Paths Extension Paths]).&lt;br /&gt;
* '''ExtensionNode'''&lt;br /&gt;
** '''name''': a name describing this extension node.&lt;br /&gt;
** '''type''': a class that handles plugin loading, this should probably be &amp;lt;code&amp;gt;OpenSim.Framework.PluginExtensionNode&amp;lt;/code&amp;gt; unless you know what you're doing.&lt;br /&gt;
** '''objectType''': an instance of this object will be loaded into this extension point at runtime. This is probably what your plugin will instantiate/subclass/implement.&lt;br /&gt;
&lt;br /&gt;
At this stage, all that is needed is &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.IAssetStorageProvider&amp;lt;/code&amp;gt; defined and present in &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.exe&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''PLEASE NOTE''': embedding XML manifests in .exe assemblies doesn't work. The .addin.xml file must reside in a directory that Mono.Addins will scan for plugins. Currently in OpenSim this is the current working directory (&amp;lt;code&amp;gt;bin/&amp;lt;/code&amp;gt;). Ideally all applications would consist of an .exe assembly and a .dll assembly which contains the embedded XML manifest.&lt;br /&gt;
&lt;br /&gt;
=== Defining Extensions ===&lt;br /&gt;
&lt;br /&gt;
Extensions that implement extension points are defined in a similar way. Below is an example corresponding XML file describing a plugin for the above extension point:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&amp;lt;Addin id=&amp;quot;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim&amp;quot; version=&amp;quot;0.1&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;Runtime&amp;gt;&lt;br /&gt;
        &amp;lt;Import assembly=&amp;quot;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;Import assembly=&amp;quot;OpenSim.Data.dll&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Runtime&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Dependencies&amp;gt;&lt;br /&gt;
        &amp;lt;Addin id=&amp;quot;OpenSim.Grid.AssetInventoryServer&amp;quot; version=&amp;quot;0.1&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Dependencies&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;ExtensionPoint path = &amp;quot;/OpenSim/AssetData&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;ExtensionNode name=&amp;quot;Plugin&amp;quot;&lt;br /&gt;
                       type=&amp;quot;OpenSim.Framework.PluginExtensionNode&amp;quot;&lt;br /&gt;
                       objectType=&amp;quot;OpenSim.Data.IAssetDataPlugin&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/ExtensionPoint&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Extension path=&amp;quot;/OpenSim/AssetInventoryServer/AssetStorageProvider&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;Plugin id=&amp;quot;OpenSimAssetStorage&amp;quot;&lt;br /&gt;
                provider=&amp;quot;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll&amp;quot;&lt;br /&gt;
                type=&amp;quot;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.OpenSimAssetStoragePlugin&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Extension&amp;gt;&lt;br /&gt;
&amp;lt;/Addin&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The elements (not in the same order as in the file) are:&lt;br /&gt;
&lt;br /&gt;
* '''Addin'''&lt;br /&gt;
** '''id''': a string identifying this plugin, can be used for dependencies in other plugins.&lt;br /&gt;
** '''version''': a version of this plugin, also used for dependencies in other plugins.&lt;br /&gt;
* '''Runtime''': a list of assemblies to import at runtime while Mono.Addins builds up the plugin registry. In this case, &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll&amp;lt;/code&amp;gt; contains the definition for &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.OpenSimAssetStoragePlugin&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;OpenSim.Framework.dll&amp;lt;/code&amp;gt; contains a definition for &amp;lt;code&amp;gt;OpenSim.Framework.PluginExtensionNode&amp;lt;/code&amp;gt;.&lt;br /&gt;
* '''Dependencies''': describes other addin(s) required to be loaded before this addin can be loaded. The '''id''' and '''version''' is used.&lt;br /&gt;
* '''Extension'''&lt;br /&gt;
** '''path''': the path along the extension point tree to the extension point which this extension implements.&lt;br /&gt;
** '''Plugin'''&lt;br /&gt;
*** '''id''': a string identifying this particular extension. Pretty much an arbitrary string.&lt;br /&gt;
*** '''provider''': another property of the extension, which can be an arbitrary string. In OpenSim, the convention seems to be to place the assembly name here which contains this plugin.&lt;br /&gt;
*** '''type''': the fully qualified class name to be instantiated which implements the extension. In the code, this class will inherit from/implement the class/interface specified in '''objectType''' attribute of the '''ExtensionPath'''.&lt;br /&gt;
* '''NOTE''': this XML file also defines another extension point, meaning that this plugin also takes another plugin. Note the '''isroot''' attribute in the topmost '''Addin''' element is omitted.&lt;br /&gt;
&lt;br /&gt;
=== Source Code ===&lt;br /&gt;
&lt;br /&gt;
The relevant code which ends up in &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.exe&amp;lt;/code&amp;gt; and loads the AssetStorage plugin looks something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;private IAssetStorageProvider LoadAssetStorageProvider(string addinPath)&lt;br /&gt;
{&lt;br /&gt;
    PluginLoader&amp;lt;IAssetStorageProvider&amp;gt; loader = new PluginLoader&amp;lt;IAssetStorageProvider&amp;gt;();&lt;br /&gt;
    loader.Add(addinPath);&lt;br /&gt;
&lt;br /&gt;
    try&lt;br /&gt;
    {&lt;br /&gt;
        loader.Load();&lt;br /&gt;
    }&lt;br /&gt;
    catch (PluginNotInitialisedException e)&lt;br /&gt;
    {&lt;br /&gt;
        // log the error, clean up, exit if needed, etc&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return loader.Plugin;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Then, from elsewhere in the code:&lt;br /&gt;
IAssetStorageProvider StorageProvider = LoadAssetStorageProvider(&amp;quot;/OpenSim/AssetInventoryServer/AssetStorageProvider&amp;quot;);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;PluginLoader&amp;lt;/code&amp;gt; class lives in &amp;lt;code&amp;gt;OpenSim.Framework&amp;lt;/code&amp;gt;; have a look through the code for more plugin loading options.&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Dynamic_Plugin_Quickstart</id>
		<title>Dynamic Plugin Quickstart</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Dynamic_Plugin_Quickstart"/>
				<updated>2009-03-10T02:02:21Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: New page: A quick guide to writing plugins. Please refer to How to create a dynamic plugin for more in-depth information.  === Defining Extension Points ===  Extension points describe the locati...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A quick guide to writing plugins. Please refer to [[How to create a dynamic plugin]] for more in-depth information.&lt;br /&gt;
&lt;br /&gt;
=== Defining Extension Points ===&lt;br /&gt;
&lt;br /&gt;
Extension points describe the location in the program where external modules can be plugged-in at runtime. Extension points can be defined in one of two ways:&lt;br /&gt;
&lt;br /&gt;
* decorating interfaces, classes or methods with attributes in the source code&lt;br /&gt;
* embedding an XML file, called a manifest, as a resource in an assembly&lt;br /&gt;
&lt;br /&gt;
In OpenSim, the preferred method is to embed an XML manifest in the assembly. Below is an example manifest defining one extension point in the AssetInventoryServer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&amp;lt;Addin id=&amp;quot;OpenSim.Grid.AssetInventoryServer&amp;quot; isroot=&amp;quot;true&amp;quot; version=&amp;quot;0.1&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;Runtime&amp;gt;&lt;br /&gt;
        &amp;lt;Import assembly=&amp;quot;OpenSim.Grid.AssetInventoryServer.exe&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;Import assembly=&amp;quot;OpenSim.Framework.dll&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Runtime&amp;gt;&lt;br /&gt;
    &amp;lt;ExtensionPoint path=&amp;quot;/OpenSim/AssetInventoryServer/AssetStorageProvider&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;ExtensionNode name=&amp;quot;Plugin&amp;quot;&lt;br /&gt;
                       type=&amp;quot;OpenSim.Framework.PluginExtensionNode&amp;quot;&lt;br /&gt;
                       objectType=&amp;quot;OpenSim.Grid.AssetInventoryServer.IAssetStorageProvider&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/ExtensionPoint&amp;gt;&lt;br /&gt;
&amp;lt;/Addin&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest contains the following elements:&lt;br /&gt;
&lt;br /&gt;
* '''Addin'''&lt;br /&gt;
** '''id''': an identifier describing this addin, used for dependencies in other addins.&lt;br /&gt;
** '''isroot''': set to '''true''' if this manifest does not define any ''extension nodes'', otherwise can be left out completely.&lt;br /&gt;
** '''version''': a version number, also used for dependencies in other addins.&lt;br /&gt;
* '''Runtime''': a list of assemblies that need to be imported by Mono.Addins as it builds the plugin repository. In the example, the &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.exe&amp;lt;/code&amp;gt; assembly contains the definition for &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.IAssetStorageProvider&amp;lt;/code&amp;gt; interface, while &amp;lt;code&amp;gt;OpenSim.Framework.dll&amp;lt;/code&amp;gt; contains a definition for &amp;lt;code&amp;gt;OpenSim.Framework.PluginExtensionNode&amp;lt;/code&amp;gt;.&lt;br /&gt;
* '''ExtensionPoint'''&lt;br /&gt;
** '''path''': the location of the extension point in the extension point tree (see [http://www.mono-project.com/Introduction_to_Mono.Addins#Extension_Paths Extension Paths]).&lt;br /&gt;
* '''ExtensionNode'''&lt;br /&gt;
** '''name''': a name describing this extension node.&lt;br /&gt;
** '''type''': a class that handles plugin loading, this should probably be &amp;lt;code&amp;gt;OpenSim.Framework.PluginExtensionNode&amp;lt;/code&amp;gt; unless you know what you're doing.&lt;br /&gt;
** '''objectType''': an instance of this object will be loaded into this extension point at runtime. This is probably what your plugin will instantiate/subclass/implement.&lt;br /&gt;
&lt;br /&gt;
At this stage, all that is needed is &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.IAssetStorageProvider&amp;lt;/code&amp;gt; defined and present in &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.exe&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Defining Extensions ===&lt;br /&gt;
&lt;br /&gt;
Extensions that implement extension points are defined in a similar way. Below is an example corresponding XML file describing a plugin for the above extension point:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&amp;lt;Addin id=&amp;quot;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim&amp;quot; version=&amp;quot;0.1&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;Runtime&amp;gt;&lt;br /&gt;
        &amp;lt;Import assembly=&amp;quot;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;Import assembly=&amp;quot;OpenSim.Data.dll&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Runtime&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Dependencies&amp;gt;&lt;br /&gt;
        &amp;lt;Addin id=&amp;quot;OpenSim.Grid.AssetInventoryServer&amp;quot; version=&amp;quot;0.1&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Dependencies&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;ExtensionPoint path = &amp;quot;/OpenSim/AssetData&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;ExtensionNode name=&amp;quot;Plugin&amp;quot;&lt;br /&gt;
                       type=&amp;quot;OpenSim.Framework.PluginExtensionNode&amp;quot;&lt;br /&gt;
                       objectType=&amp;quot;OpenSim.Data.IAssetDataPlugin&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/ExtensionPoint&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;Extension path=&amp;quot;/OpenSim/AssetInventoryServer/AssetStorageProvider&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;Plugin id=&amp;quot;OpenSimAssetStorage&amp;quot;&lt;br /&gt;
                provider=&amp;quot;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll&amp;quot;&lt;br /&gt;
                type=&amp;quot;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.OpenSimAssetStoragePlugin&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Extension&amp;gt;&lt;br /&gt;
&amp;lt;/Addin&amp;gt;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The elements (not in the same order as in the file) are:&lt;br /&gt;
&lt;br /&gt;
* '''Addin'''&lt;br /&gt;
** '''id''': a string identifying this plugin, can be used for dependencies in other plugins.&lt;br /&gt;
** '''version''': a version of this plugin, also used for dependencies in other plugins.&lt;br /&gt;
* '''Runtime''': a list of assemblies to import at runtime while Mono.Addins builds up the plugin registry. In this case, &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll&amp;lt;/code&amp;gt; contains the definition for &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.OpenSimAssetStoragePlugin&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;OpenSim.Framework.dll&amp;lt;/code&amp;gt; contains a definition for &amp;lt;code&amp;gt;OpenSim.Framework.PluginExtensionNode&amp;lt;/code&amp;gt;.&lt;br /&gt;
* '''Dependencies''': describes other addin(s) required to be loaded before this addin can be loaded. The '''id''' and '''version''' is used.&lt;br /&gt;
* '''Extension'''&lt;br /&gt;
** '''path''': the path along the extension point tree to the extension point which this extension implements.&lt;br /&gt;
** '''Plugin'''&lt;br /&gt;
*** '''id''': a string identifying this particular extension. Pretty much an arbitrary string.&lt;br /&gt;
*** '''provider''': another property of the extension, which can be an arbitrary string. In OpenSim, the convention seems to be to place the assembly name here which contains this plugin.&lt;br /&gt;
*** '''type''': the fully qualified class name to be instantiated which implements the extension. In the code, this class will inherit from/implement the class/interface specified in '''objectType''' attribute of the '''ExtensionPath'''.&lt;br /&gt;
* '''NOTE''': this XML file also defines another extension point, meaning that this plugin also takes another plugin. Note the '''isroot''' attribute in the topmost '''Addin''' element is omitted.&lt;br /&gt;
&lt;br /&gt;
=== Source Code ===&lt;br /&gt;
&lt;br /&gt;
The relevant code which ends up in &amp;lt;code&amp;gt;OpenSim.Grid.AssetInventoryServer.exe&amp;lt;/code&amp;gt; and loads the AssetStorage plugin looks something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;private IAssetStorageProvider LoadAssetStorageProvider(string addinPath)&lt;br /&gt;
{&lt;br /&gt;
    PluginLoader&amp;lt;IAssetStorageProvider&amp;gt; loader = new PluginLoader&amp;lt;IAssetStorageProvider&amp;gt;();&lt;br /&gt;
    loader.Add(addinPath);&lt;br /&gt;
&lt;br /&gt;
    try&lt;br /&gt;
    {&lt;br /&gt;
        loader.Load();&lt;br /&gt;
    }&lt;br /&gt;
    catch (PluginNotInitialisedException e)&lt;br /&gt;
    {&lt;br /&gt;
        // log the error, clean up, exit if needed, etc&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return loader.Plugin;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Then, from elsewhere in the code:&lt;br /&gt;
IAssetStorageProvider StorageProvider = LoadAssetStorageProvider(&amp;quot;/OpenSim/AssetInventoryServer/AssetStorageProvider&amp;quot;);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;PluginLoader&amp;lt;/code&amp;gt; class lives in &amp;lt;code&amp;gt;OpenSim.Framework&amp;lt;/code&amp;gt;; have a look through the code for more plugin loading options.&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/How_to_create_a_dynamic_plugin</id>
		<title>How to create a dynamic plugin</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/How_to_create_a_dynamic_plugin"/>
				<updated>2009-01-27T03:27:18Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* How to make your own plugin */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Current state of Plugin loading ==&lt;br /&gt;
&lt;br /&gt;
The .NET runtime system has always made reflecting and introspecting of assemblies at runtime very easy to do, making dynamic loading of modules possible with very little effort.&lt;br /&gt;
&lt;br /&gt;
This has unfortunately lead to a situation in OpenSim where historically module loading was hard-coded and done by hand, using copy-and-paste code. Clearly this is a suboptimal situation.&lt;br /&gt;
&lt;br /&gt;
Effort was made to find a reusable, cross-platform dynamic assembly loader that could be used as-is, instead of reinventing our own. The only current candidate is Mono.Addins. MS's .NET runtime has its own Addin class, however as of this writing it is not yet implemented in Mono.&lt;br /&gt;
&lt;br /&gt;
A class called PluginLoader has been created to thinly wrap Mono.Addins, and the assemblies loaded by this class have been standardized on the IPlugin interface hierarchy. With the exception of RegionModules, all dynamically loaded assemblies should be called Plugins, and inherit from this base class.&lt;br /&gt;
&lt;br /&gt;
Currently the following interfaces have been converted to IPlugin:&lt;br /&gt;
# OpenSim.IApplicationPlugin&lt;br /&gt;
# OpenSim.Grid.GridServer.IGridPlugin&lt;br /&gt;
# OpenSim.Data.IGridDataPlugin&lt;br /&gt;
# OpenSim.Data.ILogDataPlugin&lt;br /&gt;
&lt;br /&gt;
And the following Assemblies are being loaded by PluginLoader:&lt;br /&gt;
# OpenSim.ApplicationPlugins.LoadRegions.LoadRegionsPlugin&lt;br /&gt;
# OpenSim.ApplicationPlugins.Rest.Regions.RestRegionPlugin&lt;br /&gt;
# OpenSim.ApplicationPlugins.Rest.Inventory.RestHandler&lt;br /&gt;
# OpenSim.ApplicationPlugins.RemoteController.RemoteAdminPlugin&lt;br /&gt;
# OpenSim.Data.MySQL.MySQLGridData&lt;br /&gt;
# OpenSim.Data.MySQL.MySQLLogData&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Why Mono.Addins ==&lt;br /&gt;
&lt;br /&gt;
Mono.Addins offers features outside of being upstream maintained by the Mono project:&lt;br /&gt;
* logically splits up module interfaces from implementations in a cross platform way through the use of text-based &amp;quot;extension points&amp;quot; and &amp;quot;addin manifests&amp;quot;&lt;br /&gt;
* lazily loads assemblies only when finally necessary&lt;br /&gt;
* tracks module dependencies&lt;br /&gt;
* allows customize the addin manifest XML&lt;br /&gt;
* automatically handles module sharing across application domains&lt;br /&gt;
* provides support for downloading assemblies from remote repositories&lt;br /&gt;
&lt;br /&gt;
For more information, please read the [http://www.mono-project.com/Mono.Addins_FAQ Mono.Addins FAQ]&lt;br /&gt;
&lt;br /&gt;
== Mono.Addin concepts ==&lt;br /&gt;
&lt;br /&gt;
Although effort has been made to make PluginLoader independent of the module loading mechanism, there are some concepts that should be understood when learning how to learn the system.&lt;br /&gt;
&lt;br /&gt;
A more detailed (and '''''authoritative'''''!) explanation can be found [http://www.mono-project.com/Mono.Addins_FAQ#Using_Mono.Addins here] and [http://www.mono-project.com/Introduction_to_Mono.Addins here].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Separating Male and Female ===&lt;br /&gt;
&lt;br /&gt;
A good system provides a means of loosely coupling two connected parts with a common interface so that one can be changed easily without affecting the other.&lt;br /&gt;
&lt;br /&gt;
The assembly that consumes a service is called a ''host'', and the provider of a service is called an ''addin''.&lt;br /&gt;
&lt;br /&gt;
A service that can be split into producer/consumer role is called an ''extension''. An extension consists of an ''extension point'' which is essentially a text &amp;quot;path&amp;quot; that give a hierarchical name to the service a consumer requires, and an ''extension node'' which represents an object that can provide that service. If a host asks for the addin(s) corresponding to extension point &amp;quot;/Foo&amp;quot;, and an addin extension node claims to implement &amp;quot;/Foo&amp;quot;, then the two can be joined to make a functioning whole.&lt;br /&gt;
&lt;br /&gt;
All OpenSim extension points start at the root &amp;quot;/OpenSim&amp;quot;. If you wished to create a new service &amp;quot;Foo&amp;quot;, you might choose to name it &amp;quot;/OpenSim/Foo&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In operation the consumer of a service, the host, requests that the system load all addins that claim to extend an extension point, and a list is returned to the consumer, who can choose to load any subset of those providers, the addins, into memory.&lt;br /&gt;
&lt;br /&gt;
=== Describing an Addin ===&lt;br /&gt;
&lt;br /&gt;
Clearly metadata must be associated with both host and addin, in our case this is an XML file that has the extension *.addin.xml, called a ''manifest''. &lt;br /&gt;
&lt;br /&gt;
In practice, the host manifest and addin manifest are so similar as to be almost exactly the same. The principle difference is that host manifests tell Mono.Addins where to find abstract interfaces, and addin manifests tell Mono.Addins where to find concrete implementations of those interfaces.&lt;br /&gt;
&lt;br /&gt;
The manifest has 3 critical parts&lt;br /&gt;
# Name and Version information &amp;lt;br&amp;gt; this is used to check inter-addin dependencies&lt;br /&gt;
# Filename of assemblies where the consumer interfaces or provider implementations can be found &amp;lt;br&amp;gt; this is needed to know which assemblies must be searched&lt;br /&gt;
# Extension Point path and Fully Qualified .NET Class Name of the consumer interface or provider implementation &amp;lt;br&amp;gt; this is needed to load the actual classes into memory&lt;br /&gt;
&lt;br /&gt;
The way to tell a host manifest from an addin manifest is that host manifests will *always* contain an ''isroot=true'' attribute in the &amp;lt;Addin&amp;gt; tag. However this is complicated by the fact that an addin can act as host for another addin in a recursive manner.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Building a model ===&lt;br /&gt;
&lt;br /&gt;
When the PluginLoader is first created within the host, Mono.Addins will search the directory the host was executed and search for all files that end in *.addin.xml. It uses the information to build a ''registry'' about the addins in addin-db-${VERSION}/ directory. The purpose of the registry is to collect all information once, then lazily load assemblies into memory only at the last moment when it is precisely known exactly which class is required by the user.&lt;br /&gt;
&lt;br /&gt;
== How to make your own plugin ==&lt;br /&gt;
&lt;br /&gt;
# Decide on the service you wish to separate into provider and consumer. Ex: &amp;quot;LartMe&amp;quot;&lt;br /&gt;
# Create an extension point to identify that service. Ex: &amp;quot;/OpenSim/LartMe&amp;quot;&lt;br /&gt;
# Create an consumer interface that has the methods needed, and derive it from OpenSim.Framework.IPlugin. Ex: &amp;quot;OpenSim.ILart&amp;quot;&lt;br /&gt;
## If that interface needs a constructor that takes parameters, you will also have to create a class derived from PluginInitialiserBase that can act as a [http://en.wikipedia.org/wiki/Closure_(computer_science) closure] for calling a parameterized constructor. See IApplicationPlugin for an example. Ex: &amp;quot;OpenSim.LartInitializer&amp;quot;&lt;br /&gt;
# Write a provider class that implements that interface. Ex: &amp;quot;OpenSim.LartPlugin&amp;quot;&lt;br /&gt;
# Write a host manifest. See OpenSim.addin.xml as an example.&lt;br /&gt;
## Ensure that /Addin@isroot=true&lt;br /&gt;
## Ensure that /Addin@id is set to a unique name. Ex: &amp;quot;LartMe&amp;quot;&lt;br /&gt;
## Ensure that /Addin/Runtime/Import@assembly exists for each assembly that either hosts the application (host.EXE) or defines an addin consumer interface (Lart.dll) used by the host&lt;br /&gt;
## Ensure that /Addin/ExtensionPoint@path is set. Ex: &amp;quot;&amp;lt;ExtensionPoint path=&amp;quot;/OpenSim/LartMe&amp;quot;&amp;gt;...&amp;quot;&lt;br /&gt;
## Ensure that /Addin/ExtensionPoint/ExtensionNode@name is set to &amp;quot;Plugin&amp;quot;. This is a custom derived node type (OpenSim.Framework.PluginExtensionNode).&lt;br /&gt;
## Ensure that /Addin/ExtensionPoint/ExtensionNode@type is set to &amp;quot;OpenSim.Framework.PluginExtensionNode&amp;quot;&lt;br /&gt;
## Ensure that /Addin/ExtensionPoint/ExtensionNode@objectType is set to the fully qualified name of the consumer interface found in the above assembly import. Ex: &amp;quot;OpenSim.ILart&amp;quot;&lt;br /&gt;
# Write a addin manifest. See LoadRegionsPlugin.addin.xml as an example.&lt;br /&gt;
## Ensure that /Addin/Runtime/Import@assembly exists for the assembly that implements the producer class.&lt;br /&gt;
## Ensure that /Addin/Dependencies/Addin@id exists and is the same as the id of the host manifest. Ex: &amp;quot;Lart&amp;quot;&lt;br /&gt;
## Ensure that /Addin/ExtensionPoint@path is set and is the same as that of the host manifest. Ex: &amp;quot;&amp;lt;ExtensionPoint path=&amp;quot;/OpenSim/LartMe&amp;quot;&amp;gt;...&amp;quot;&lt;br /&gt;
## Ensure that /Addin/Extension/Plugin@type is set to the fully qualified name of the implementing provider class. Ex: &amp;quot;OpenSim.LartPlugin&amp;quot;&lt;br /&gt;
## Optionally, if you wish to discriminate on &amp;quot;provider&amp;quot; you can set /Addin/Extension/Plugin@provider&lt;br /&gt;
# When you need to load the producer, create a PluginLoader of the type defined by the consumer interface. Ex: &amp;quot;new PluginLoader &amp;lt;ILart&amp;gt; ();&amp;quot;&lt;br /&gt;
## If the provider requires a Initializer, it should be passed to the PluginLoader constructor. All plugins will be initialized using this initializer. Ex: &amp;quot;new PluginLoader &amp;lt;ILart&amp;gt; (new LartInitializer (&amp;quot;l4rt&amp;quot;));&amp;quot;&lt;br /&gt;
# Call PluginLoader.Load using the required extension point. Ex: &amp;quot;loader.Load (&amp;quot;/OpenSim/LartMe&amp;quot;)&amp;quot;&lt;br /&gt;
# Instead of putting the plugin manifest into the bin/ directory, it is cleaner to embed it into the plugin dll by specifying buildAction=&amp;quot;EmbeddedResource&amp;quot; in prebuild.xml to the Files section of your project&lt;br /&gt;
## eg &amp;lt;Match pattern=&amp;quot;*.addin.xml&amp;quot; path=&amp;quot;Resources&amp;quot; buildAction=&amp;quot;EmbeddedResource&amp;quot; recurse=&amp;quot;true&amp;quot;/&amp;gt;&lt;br /&gt;
## For host manifests, it usually makes more sense to have them in the bin/ directory (they would otherwise have to be embedded into a number of dlls and exes)&lt;br /&gt;
&lt;br /&gt;
All loaded plugins can now be found in &amp;quot;loader.Plugins&amp;quot; and used as necessary.&lt;br /&gt;
&lt;br /&gt;
If that looks like a lot of work, consider that outside of the normal work of splitting a class into interface and implementation, its really mostly just boilerplate, and can be accomplished by just comparing how things are currently implemented within OpenSim.&lt;br /&gt;
&lt;br /&gt;
== Filtering and Constraining ==&lt;br /&gt;
&lt;br /&gt;
When you ask to load an extension point, you are potentially bringing a lot of assemblies into memory. Before you do that, you will most likely want to have a say about how many assemblies you expect, and which one you need.&lt;br /&gt;
&lt;br /&gt;
You can do this by assigning a IPluginConstraint or IPluginFilter to an extension point.&lt;br /&gt;
&lt;br /&gt;
An IPluginConstraint is applied each time Load() is called on an extension point, but the behavior of the constraint is up to the implementor. It is assumed that a constraint will ask something of Mono.Addins, and throw an exception if it is not happy with the answer.&lt;br /&gt;
&lt;br /&gt;
=== Loading Critical Plugins ===&lt;br /&gt;
&lt;br /&gt;
For some applications we expect precisely a certain amount of plugins to be loaded. Often exactly one. PluginCountConstraint implements precisely this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int n = 1;&lt;br /&gt;
PluginLoader &amp;lt;ILart&amp;gt; loader = new PluginLoader();&lt;br /&gt;
loader.AddConstraint (&amp;quot;/OpenSim/LartMe&amp;quot;, new PluginCountConstraint (n));&lt;br /&gt;
loader.Load (&amp;quot;/OpenSim/LartMe&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the above code is run, and more or less than n plugin could be loaded, the constraint will throw a PluginConstraintViolatedException.&lt;br /&gt;
&lt;br /&gt;
=== Loading Named Plugins ===&lt;br /&gt;
&lt;br /&gt;
Often the reason why more than one plugin is available to load is because we wish to afford choice to the user as to which plugin he prefers, exposed in a configuration file. We read from the file the user's preference, and want to only load the desired plugin.&lt;br /&gt;
&lt;br /&gt;
If we have some addin manifests that look like these:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;Addin id=&amp;quot;OpenSim.Lart&amp;quot; version=&amp;quot;0.1&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;Runtime&amp;gt;&lt;br /&gt;
        &amp;lt;Import assembly=&amp;quot;LartCorp.dll&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/Runtime&amp;gt;&lt;br /&gt;
    &amp;lt;Dependencies&amp;gt;&lt;br /&gt;
        &amp;lt;Addin id=&amp;quot;OpenSim&amp;quot; version=&amp;quot;0.5&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Dependencies&amp;gt;&lt;br /&gt;
    &amp;lt;Extension path = &amp;quot;/OpenSim/LartMe&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;Plugin provider=&amp;quot;LartCorp&amp;quot; type=&amp;quot;Corp.LartMatic&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Extension&amp;gt;&lt;br /&gt;
&amp;lt;/Addin&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;Addin id=&amp;quot;OpenSim.Lart&amp;quot; version=&amp;quot;0.1&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;Runtime&amp;gt;&lt;br /&gt;
        &amp;lt;Import assembly=&amp;quot;OpenSim.Lart.dll&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/Runtime&amp;gt;&lt;br /&gt;
    &amp;lt;Dependencies&amp;gt;&lt;br /&gt;
        &amp;lt;Addin id=&amp;quot;OpenSim&amp;quot; version=&amp;quot;0.5&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Dependencies&amp;gt;&lt;br /&gt;
    &amp;lt;Extension path = &amp;quot;/OpenSim/LartMe&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;Plugin provider=&amp;quot;OpenLart&amp;quot; type=&amp;quot;OpenSim.LartPlugin&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/Extension&amp;gt;&lt;br /&gt;
&amp;lt;/Addin&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And loading code that looks like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PluginLoader &amp;lt;ILart&amp;gt; loader = new PluginLoader();&lt;br /&gt;
loader.AddConstraint (&amp;quot;/OpenSim/LartMe&amp;quot;, new PluginProviderFilter (&amp;quot;LartCorp&amp;quot;));&lt;br /&gt;
loader.Load (&amp;quot;/OpenSim/LartMe&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Only the &amp;quot;LartCorp&amp;quot; plugin will be loaded.&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/AssetServer/DeveloperDocs</id>
		<title>AssetServer/DeveloperDocs</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/AssetServer/DeveloperDocs"/>
				<updated>2009-01-15T02:53:06Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Developer Documentation=&lt;br /&gt;
&lt;br /&gt;
This documentation gives an overview of the distributed asset server inner workings. The asset server uses ExtensionLoader, which implements the [http://en.wikipedia.org/wiki/Inversion_of_control Inversion of Control] design methodology. The result is a series of distinct components referred to in the documentation as interfaces or extensions. Each interface exposes a series of functions and that may be implemented in very different ways by different extensions. Generally, each interface is assigned a single extension through a configuration file*. Most functions return a StorageResponse value, a simple enumeration of the possible success or failure values of a request. Many asset functions use the common Metadata class which is explained below, and inventory functions use the common InventoryFolder and InventoryItem classes.&lt;br /&gt;
&lt;br /&gt;
* An exception to this rule is the MemcacheStorage provider, which stacks on top of another storage provider to provide scalable caching.&lt;br /&gt;
&lt;br /&gt;
==Code Diagram==&lt;br /&gt;
&lt;br /&gt;
The following diagram shows the interaction between the different interfaces, frontends, and external resources.&lt;br /&gt;
&lt;br /&gt;
''WARNING:'' The model has changed to require frontends to contact the authorization provider instead of passing authorization tokens to the backend. This allows insecure frontends such as the OpenSimFrontend and OpenSimInventoryFrontend to function alongside secured frontends. It also allows partial security such as the BrowseFrontend, where asset IDs are shown but no additional metadata. This diagram needs to be updated to reflect the changes.&lt;br /&gt;
&lt;br /&gt;
[[Image:DistributedAssetServer-UML.png]]&lt;br /&gt;
&lt;br /&gt;
==Metadata==&lt;br /&gt;
&lt;br /&gt;
All assets share a basic set of common metadata. Storage backends should make a best attempt to support the entire common metadata set, and use default values for unsupported fields. The common metadata structure is listed below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;public class Metadata&lt;br /&gt;
{&lt;br /&gt;
    public UUID ID;&lt;br /&gt;
    public string Name;&lt;br /&gt;
    public string Description;&lt;br /&gt;
    public DateTime CreationDate;&lt;br /&gt;
    public string ContentType;&lt;br /&gt;
    public byte[] SHA1;&lt;br /&gt;
    public bool Temporary;&lt;br /&gt;
    public Dictionary&amp;lt;string, Uri&amp;gt; Methods;&lt;br /&gt;
    public OSDMap ExtraData;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Content-Type===&lt;br /&gt;
&lt;br /&gt;
Asset type is distinguished with an Internet Media Type (MIME type). For backward compatibility with OpenSim's Second Life(tm) implementation, a set of nonstandard content types map to SL asset types. For reference, here is the function that does the conversion:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;public static string SLAssetTypeToExtraData(int assetType)&lt;br /&gt;
{&lt;br /&gt;
    switch (assetType)&lt;br /&gt;
    {&lt;br /&gt;
        case  0: return &amp;quot;image/jp2&amp;quot;;&lt;br /&gt;
        case  1: return &amp;quot;application/ogg&amp;quot;;&lt;br /&gt;
        case  2: return &amp;quot;application/x-metaverse-callingcard&amp;quot;;&lt;br /&gt;
        case  3: return &amp;quot;application/x-metaverse-landmark&amp;quot;;&lt;br /&gt;
        case  5: return &amp;quot;application/x-metaverse-clothing&amp;quot;;&lt;br /&gt;
        case  6: return &amp;quot;application/x-metaverse-primitive&amp;quot;;&lt;br /&gt;
        case  7: return &amp;quot;application/x-metaverse-notecard&amp;quot;;&lt;br /&gt;
        case 10: return &amp;quot;application/x-metaverse-lsl&amp;quot;;&lt;br /&gt;
        case 11: return &amp;quot;application/x-metaverse-lso&amp;quot;;&lt;br /&gt;
        case 12: return &amp;quot;image/tga&amp;quot;;&lt;br /&gt;
        case 13: return &amp;quot;application/x-metaverse-bodypart&amp;quot;;&lt;br /&gt;
        case 17: return &amp;quot;audio/x-wav&amp;quot;;&lt;br /&gt;
        case 19: return &amp;quot;image/jpeg&amp;quot;;&lt;br /&gt;
        case 20: return &amp;quot;application/x-metaverse-animation&amp;quot;;&lt;br /&gt;
        case 21: return &amp;quot;application/x-metaverse-gesture&amp;quot;;&lt;br /&gt;
        case 22: return &amp;quot;application/x-metaverse-simstate&amp;quot;;&lt;br /&gt;
        default: return &amp;quot;application/octet-stream&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
&lt;br /&gt;
A mapping of strings to URIs holds all of the available methods for an asset. The only common method between all assets is &amp;quot;data&amp;quot;, although access level restrictions may prevent users from seeing any methods at all. The method URIs do not necessarily map to resources on the same server that hosts the metadata.&lt;br /&gt;
&lt;br /&gt;
===ExtraData===&lt;br /&gt;
&lt;br /&gt;
The SimpleStorage field is used to store extended values that can be serialized by a frontend interface without any additional knowledge of the data contained in it. The SimpleStorage backend defines two additional metadata fields for JPEG2000 textures: components and layer_ends. components is an integer type holding the number of components (red, green, blue, alpha, etc.) for a texture. layer_ends is an array of integers denoting byte positions in the file where each quality layer ends. The data is stored as an Open Structured Data (OSD) map, allowing frontends to enumerate over the collection of values and serialize to a wire format without prior knowledge of the structure.&lt;br /&gt;
&lt;br /&gt;
==Storage==&lt;br /&gt;
&lt;br /&gt;
Storage providers are responsible for accessing the metadata and file data for assets. Example storage providers include local file storage (OpenSim), using the Amazon Simple Storage Service to host data and associated metadata (AmazonS3Storage), an existing AssetServer.Grid.OpenSim.exe MySQL database (OpenSimMySQLStorage), or a caching storage provider (MemcacheStorage) that works in conjunction with another storage provider. Storage providers must implement the IStorageProvider interface.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;public interface IStorageProvider&lt;br /&gt;
{&lt;br /&gt;
    BackendResponse TryFetchMetadata(UUID assetID, out Metadata metadata);&lt;br /&gt;
    BackendResponse TryFetchData(UUID assetID, out byte[] assetData);&lt;br /&gt;
    BackendResponse TryFetchDataMetadata(UUID assetID, out Metadata metadata, out byte[] assetData);&lt;br /&gt;
    BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData);&lt;br /&gt;
    BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData, out UUID assetID);&lt;br /&gt;
    int ForEach(Action&amp;lt;Metadata&amp;gt; action, int start, int count);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The StorageResponse enum has the possible values Success, NotFound, AuthNeeded, and Failure.&lt;br /&gt;
&lt;br /&gt;
==Inventory==&lt;br /&gt;
&lt;br /&gt;
Inventory providers are similar to storage providers but implement a set of interface functions for dealing with inventory items. Inventory is a hierarchical (folder-based) storage system for small inventory item files that contain additional metadata and link to assets. Currently the only inventory backend is SimpleInventory, using file-system based storage for inventory items and folders.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;public interface IInventoryProvider&lt;br /&gt;
{&lt;br /&gt;
    BackendResponse TryFetchItem(Uri owner, UUID itemID, out InventoryItem item);&lt;br /&gt;
    BackendResponse TryFetchFolder(Uri owner, UUID folderID, out InventoryFolder folder);&lt;br /&gt;
    BackendResponse TryFetchFolderContents(Uri owner, UUID folderID, out InventoryCollection contents);&lt;br /&gt;
    BackendResponse TryFetchFolderList(Uri owner, out List&amp;lt;InventoryFolder&amp;gt; folders);&lt;br /&gt;
    BackendResponse TryFetchInventory(Uri owner, out InventoryCollection inventory);&lt;br /&gt;
&lt;br /&gt;
    BackendResponse TryFetchActiveGestures(Uri owner, out List&amp;lt;InventoryItem&amp;gt; gestures);&lt;br /&gt;
&lt;br /&gt;
    BackendResponse TryCreateItem(Uri owner, InventoryItem item);&lt;br /&gt;
    BackendResponse TryCreateFolder(Uri owner, InventoryFolder folder);&lt;br /&gt;
    BackendResponse TryCreateInventory(Uri owner, InventoryFolder rootFolder);&lt;br /&gt;
&lt;br /&gt;
    BackendResponse TryDeleteItem(Uri owner, UUID itemID);&lt;br /&gt;
    BackendResponse TryDeleteFolder(Uri owner, UUID folderID);&lt;br /&gt;
    BackendResponse TryPurgeFolder(Uri owner, UUID folderID);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The TryFetchActiveGestures() interface function is currently required by OpenSim, but may be removed in a future release.&lt;br /&gt;
&lt;br /&gt;
==Frontends==&lt;br /&gt;
&lt;br /&gt;
Frontends provide the HTTP interface(s) that users, simulators, and client applications communicate with. Frontends do not implement any interface because no other code depends on them. Unlike the interfaces, many frontends can run at the same time, serving up the same backend content through several different protocols. Source code files implementing frontends typically end with &amp;quot;...Frontend.cs&amp;quot;. The current frontends include a browsing interface for paging through the assets with a web browser, an OpenSim asset frontend to replace OpenSim.Grid.AssetServer.exe, an OpenSim inventory frontend to replace OpenSim.Grid.InventoryServer.exe, and a reference frontend that uses the new JSON-based wire protocol.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
Authentication extensions provide a mapping from authentication tokens to identifiers (URIs). The authentication provider may provide a frontend for authenticating with the asset server (such as the OpenIdAuth extension), but the function interfaces are typically only called by authorization providers to convert authentication tokens to identifiers before performing an authorization check.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;public interface IAuthenticationProvider&lt;br /&gt;
{&lt;br /&gt;
    void AddIdentifier(UUID authToken, Uri identifier);&lt;br /&gt;
    bool RemoveIdentifier(UUID authToken);&lt;br /&gt;
    bool TryGetIdentifier(UUID authToken, out Uri identifier);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Authentication providers should expire UUID to URI mappings after some amount of inactivity.&lt;br /&gt;
&lt;br /&gt;
==Authorization==&lt;br /&gt;
&lt;br /&gt;
Authorization providers determine what actions are allowed for assets and inventory trees. Given an authentication token, an authorization provider will contact the authentication provider and retrieve an identifier. Based on the identifier, the requested resource, and a set of rules in the authorization provider, access is either denied or granted. These interface functions are called from storage providers where a failed authorization translates into a return code of AuthNeeded. Frontend providers can deliver this message with an HTML message, an HTTP response code, or any number of different ways.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;public interface IAuthorizationProvider&lt;br /&gt;
{&lt;br /&gt;
    bool IsMetadataAuthorized(UUID authToken, UUID assetID);&lt;br /&gt;
    bool IsDataAuthorized(UUID authToken, UUID assetID);&lt;br /&gt;
    bool IsCreateAuthorized(UUID authToken);&lt;br /&gt;
&lt;br /&gt;
    bool IsInventoryReadAuthorized(UUID authToken, Uri owner);&lt;br /&gt;
    bool IsInventoryWriteAuthorized(UUID authToken, Uri owner);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= See Also =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[AssetServerProposal|Asset Server Proposal]]&lt;br /&gt;
* [[AssetServerProposal/ClientDocs|Client Documentation]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/AssetServer/ClientDocs</id>
		<title>AssetServer/ClientDocs</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/AssetServer/ClientDocs"/>
				<updated>2009-01-15T02:51:46Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Client Documentation=&lt;br /&gt;
&lt;br /&gt;
Through the variety of extensions that ship with the asset server, several wire protocol formats are supported. Connectors for existing OpenSim grid protocols have been added wherever possible, along with new frontends that support web browsers and extensible metadata through JSON.&lt;br /&gt;
&lt;br /&gt;
==Reference Asset Protocol==&lt;br /&gt;
&lt;br /&gt;
In the previous OpenSim asset model, asset requests and asset data proxied through simulators to a backend asset service. This required sending asset data over UDP and adding unnecessary bandwidth overhead to simulators.&lt;br /&gt;
&lt;br /&gt;
[[Image:Client-sim-assetserver-original.png]]&lt;br /&gt;
Previous OpenSim asset flow diagram&lt;br /&gt;
&lt;br /&gt;
[[Image:Client-sim-assetserver-distributed.png]]&lt;br /&gt;
Distributed Asset Service flow diagram&lt;br /&gt;
&lt;br /&gt;
===Wire Format===&lt;br /&gt;
&lt;br /&gt;
To support the new metadata features and extensible content methods in the asset server, a new wire protocol is being designed. This is referred to in the documentation as the Reference Asset Protocol, and is currently using JSON as the transport format. JSON provides a lightweight markup and is loosely typed, allowing extended metadata to be transferred without breaking compatibility with existing or lightweight clients. Although the markup is pure JSON, some additional &amp;quot;types&amp;quot; are implemented by prefixing strings with type identifiers. This allows data to easily be mapped between [[OpenStructuredData]] and JSON. The types and their prefixes are as follows:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|+ &amp;lt;strong&amp;gt;New JSON Types&amp;lt;/strong&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;strong&amp;gt;uuid::&amp;lt;/strong&amp;gt; || UUID, 128-bit unique identifier&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;strong&amp;gt;uri::&amp;lt;/strong&amp;gt; || Uniform resource identifier&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;strong&amp;gt;date::&amp;lt;/strong&amp;gt; || ISO-8601 numeric encoding in UTC&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;strong&amp;gt;b64::&amp;lt;/strong&amp;gt; || Base64-encoded binary data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Fetching Asset Metadata===&lt;br /&gt;
&lt;br /&gt;
Asset data may be located on the asset server, or scattered all over the world at various URLs. To find the location of the data for each asset, you must first fetch the asset metadata which can be retrieved at a fixed location. The URL for metadata is http://[someserver.com]/[assetid]/metadata. An example request:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;GET /c228d1cf-4b5d-4ba8-84f4-899a0796aa97/metadata HTTP/1.1&lt;br /&gt;
Host: assets.virtualworld.com&lt;br /&gt;
Date: Mon, 22 Sep&amp;amp;nbsp; 2008 12:00:00 GMT&lt;br /&gt;
Authorization: OpenGrid ce9a6995-a737-4206-bae8-910cae310e94&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Authorization header is used to pass an authentication token (a login cookie) to the server. This is covered in detail in the Authentication section.&lt;br /&gt;
&lt;br /&gt;
An example response:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;{&lt;br /&gt;
   &amp;quot;id&amp;quot;:&amp;quot;uuid::c228d1cf-4b5d-4ba8-84f4-899a0796aa97&amp;quot;,&lt;br /&gt;
   &amp;quot;name&amp;quot;:&amp;quot;Default Avatar&amp;quot;,&lt;br /&gt;
   &amp;quot;description&amp;quot;:&amp;quot;&amp;quot;,&lt;br /&gt;
   &amp;quot;creation_date&amp;quot;:&amp;quot;date::2008-11-26T00:49:48.83Z&amp;quot;,&lt;br /&gt;
   &amp;quot;type&amp;quot;:&amp;quot;image/jp2&amp;quot;,&lt;br /&gt;
   &amp;quot;sha1&amp;quot;:&amp;quot;b64::3ftHyRoIfVYSeumfxRcSk4LZVVU=&amp;quot;,&lt;br /&gt;
   &amp;quot;temporary&amp;quot;:false,&lt;br /&gt;
   &amp;quot;methods&amp;quot;:{&lt;br /&gt;
      &amp;quot;data&amp;quot;:&amp;quot;uri::http://assets.virtualworld.com/c228d1cf-4b5d-4ba8-84f4-899a0796aa97/data&amp;quot;&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;extra_data&amp;quot;:{&lt;br /&gt;
      &amp;quot;components&amp;quot;:3,&lt;br /&gt;
      &amp;quot;layer_ends&amp;quot;:[&lt;br /&gt;
         580,&lt;br /&gt;
         1987,&lt;br /&gt;
         7983,&lt;br /&gt;
         31969,&lt;br /&gt;
         36041&lt;br /&gt;
      ]&lt;br /&gt;
   }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this case the metadata is for a texture (type of &amp;quot;image/jp2&amp;quot;, JPEG2000 compressed image). The methods map contains a single key/value pair for &amp;quot;data&amp;quot;, the method used to fetch the actual asset data. The extra_data structure is also used in this example, to carry the number of components in the JPEG2000 data and the byte offsets of each quality layer in the texture.&lt;br /&gt;
&lt;br /&gt;
===Fetching Asset Data===&lt;br /&gt;
&lt;br /&gt;
Once the location of the asset data has been retrieved with a metadata request, a simple HTTP GET will download the content. The Authorization header is still required to fetch content that is not publicly accessible. In a future release, the asset server will support partial downloads with the standard HTTP Range header.&lt;br /&gt;
&lt;br /&gt;
===Creating an Asset===&lt;br /&gt;
&lt;br /&gt;
To create an asset, a simple JSON structure containing the asset metadata and data is POSTed to /createasset. Creating an asset and replacing an existing asset are done through the same interface. The &amp;quot;id&amp;quot; field in the POST data is optional. Specifying a UUID for the new asset may impose additional security restrictions, as this is generally reserved for system users who have been granted permission to replace existing assets. An example POST of a text file called note (specifying a UUID in the request) is shown here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;POST /createasset HTTP/1.1&lt;br /&gt;
Host: assets.virtualworld.com&lt;br /&gt;
Date: Mon, 22 Sep&amp;amp;nbsp; 2008 12:00:00 GMT&lt;br /&gt;
Authorization: OpenGrid http://users.virtualworld.com/users/jhurliman ce9a6995-a737-4206-bae8-910cae310e94&lt;br /&gt;
Content-Type: application/json&lt;br /&gt;
Content-Length: 225&lt;br /&gt;
&lt;br /&gt;
{&lt;br /&gt;
   &amp;quot;id&amp;quot;:&amp;quot;uuid::c228d1cf-4b5d-4ba8-84f4-899a0796aa97&amp;quot;,&lt;br /&gt;
   &amp;quot;name&amp;quot;:&amp;quot;note&amp;quot;,&lt;br /&gt;
   &amp;quot;description&amp;quot;:&amp;quot;A small note containing the word testing&amp;quot;,&lt;br /&gt;
   &amp;quot;type&amp;quot;:&amp;quot;text/plain&amp;quot;,&lt;br /&gt;
   &amp;quot;temporary&amp;quot;:false,&lt;br /&gt;
   &amp;quot;data&amp;quot;:&amp;quot;b64::dGVzdGluZw==&amp;quot;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An HTTP status code 201 (Created) indicates success; all other status code indicate a failure to create the asset. On success, the return data will be a JSON map containing the key &amp;quot;id&amp;quot; with a value of the new asset's ID. If a failure occurred, the HTTP status description may contain more information. An example of a successful response:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;{ &amp;quot;id&amp;quot;:&amp;quot;uuid::c228d1cf-4b5d-4ba8-84f4-899a0796aa97&amp;quot; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Content-Types====&lt;br /&gt;
&lt;br /&gt;
The asset server treats all stored content as binary blobs with content types. Some content types can have special handlers that expose additional methods or metadata, such as image/jp2 returning extended metadata for the number of image components and byte offsets of the quality layers. However, no special handling is needed for storing and serving up data. To store ShockWave Flash files, use the content-type application/x-shockwave-flash and upload a .swf file.&lt;br /&gt;
&lt;br /&gt;
To maintain compatibility with existing virtual worlds, MIME types have been defined for the existing OpenSim asset types. It is important that the correct content-type is used for uploads. The following table shows the mapping between OpenSim assets, commonly used file extensions, and content-types. Note that some of the formats used already have recognized MIME types. Anything starting with application/x-metaverse is ad hoc.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! OpenSim Type&lt;br /&gt;
! File Extensions&lt;br /&gt;
! Content-Type&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0 || jp2,j2c,texture || image/jp2 || JPEG2000 texture. Not actually JP2 files, only the codestream. LRCP ordering&lt;br /&gt;
|-&lt;br /&gt;
| 1 || ogg,sound || application/ogg || OGG Vorbis audio&lt;br /&gt;
|-&lt;br /&gt;
| 2 || callingcard || application/x-metaverse-callingcard || OpenSim calling card. Custom/undocumented text format&lt;br /&gt;
|-&lt;br /&gt;
| 3 || landmark || application/x-metaverse-landmark || OpenSim landmark. Custom/undocumented text format&lt;br /&gt;
|-&lt;br /&gt;
| 5 || clothing || application/x-metaverse-clothing || OpenSim clothing. Custom/undocumented text format&lt;br /&gt;
|-&lt;br /&gt;
| 6 || primitive || application/x-metaverse-primitive || OpenSim primitive. Custom/undocumented XML format&lt;br /&gt;
|-&lt;br /&gt;
| 7 || notecard || application/x-metaverse-notecard || OpenSim notecard. Custom/undocumented text format&lt;br /&gt;
|-&lt;br /&gt;
| 10 || lsl || application/x-metaverse-lsl || OpenSim LSL script&lt;br /&gt;
|-&lt;br /&gt;
| 11 || lso || application/x-metaverse-lso || OpenSim compiled script binary. Currently unused&lt;br /&gt;
|-&lt;br /&gt;
| 12 || tga || image/tga || Targa image. Currently unused&lt;br /&gt;
|-&lt;br /&gt;
| 13 || bodypart || application/x-metaverse-bodypart || OpenSim bodypart. Custom/undocumented text format&lt;br /&gt;
|-&lt;br /&gt;
| 17 || wav || audio/x-wav || WAV audio file&lt;br /&gt;
|-&lt;br /&gt;
| 19 || jpg,jpeg || image/jpeg || JPEG texture&lt;br /&gt;
|-&lt;br /&gt;
| 20 || animation || application/x-metaverse-animation || OpenSim animation. Custom/undocumented binary format&lt;br /&gt;
|-&lt;br /&gt;
| 21 || gesture || application/x-metaverse-gesture || OpenSim gesture. Custom/undocumented format&lt;br /&gt;
|-&lt;br /&gt;
| 22 || simstate || application/x-metaverse-simstate || OpenSim simulator state. Currently unused&lt;br /&gt;
|-&lt;br /&gt;
| -1 || (none,unknown) || application/octet-stream || Arbitrary or unrecognized binary data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Reference Inventory Protocol==&lt;br /&gt;
&lt;br /&gt;
The inventory reference protocol is a work in progress. Leave notes on the discussion page for this document or start a thread on the [https://lists.berlios.de/mailman/listinfo/opensim-dev opensim-dev] mailing list if you'd like to be a part of the process.&lt;br /&gt;
&lt;br /&gt;
==OpenSim Asset Protocol==&lt;br /&gt;
&lt;br /&gt;
The OpenSim.Grid.AssetServer.exe protocol uses a REST interface for retrieving and storing assets. Assets are fetched with a GET to /assets/[assetid] or /assets/[assetid]?texture. The additional ?texture parameter is optional and does not change the response in any way. Asset data and metadata are returned in an XML format, with the asset data base64 encoded as an XML element. To upload, the same XML data structure that is received from a GET is POSTed to /assets/. The XML data is serialized from a class in OpenSim code, therefore the structure is subject to change. The current XML serialization is undocumented outside of source code.&lt;br /&gt;
&lt;br /&gt;
==OpenSim Inventory Protocol==&lt;br /&gt;
&lt;br /&gt;
OpenSim.Grid.InventoryServer.exe supports both a REST-like interface and an XML-RPC interface. Although the former interface shares some similar properties with a REST interface, it defines an additional messaging layer using HTTP POSTs of XML data for all requests. The REST-like interface is actually somewhere between SOAP and XML-RPC.&lt;br /&gt;
&lt;br /&gt;
An example request, passing a single UUID argument in with session information:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;amp;lt;?xml version=&amp;amp;quot;1.0&amp;amp;quot;?&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;RestSessionObjectOfGuid xmlns:xsi=&amp;amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;amp;quot; xmlns:xsd=&amp;amp;quot;http://www.w3.org/2001/XMLSchema&amp;amp;quot;&amp;amp;gt;&lt;br /&gt;
  &amp;amp;lt;SessionID&amp;amp;gt;070b4811-0a57-4fcd-bb3a-a03fbe9106d2&amp;amp;lt;/SessionID&amp;amp;gt;&lt;br /&gt;
  &amp;amp;lt;AvatarID&amp;amp;gt;634ada51-3151-4e6d-a989-309f89f740e0&amp;amp;lt;/AvatarID&amp;amp;gt;&lt;br /&gt;
  &amp;amp;lt;Body&amp;amp;gt;3207551c-da01-49ec-bb6e-f24f9ab36dcb&amp;amp;lt;/Body&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/RestSessionObjectOfGuid&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Another example, passing a single UUID argument with no session information:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;amp;lt;?xml version=&amp;amp;quot;1.0&amp;amp;quot;?&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;guid&amp;amp;gt;3207551c-da01-49ec-bb6e-f24f9ab36dcb&amp;amp;lt;/guid&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
If an asset is protected, an identity must be proven by a client (and that identity authorized to access the asset) before access is granted. Internally the asset server stores identities as URLs. A number of different methods of proving client identity can be used depending on the setup of the asset server. The reference asset server has OpenID login support at http://[yourserver.com]/authenticate. This is a simple OpenID login process that can happen over the reference JSON protocol, or through web forms. If the OpenID provider being used is setup with a well formed login method (such as the current OpenSim user server), the entire process can happen without user intervention. Once the OpenID authentication has completed, a UUID token will be returned to the client. Optionally, a cookie will be returned as well containing the same token. This token is a temporary proof of identity that can be used in the Authorization header when requesting assets.&lt;br /&gt;
&lt;br /&gt;
Instead of directly logging into the asset server, a common grid setup may be that the login server contacts an asset server that it knows about to inform it of a successful login and create a temporary session token. This token could be passed back to the client to avoid having to login to both the login server and asset server. Another setup may involve the client using an SSL client certificate signed by an authority that the asset server trusts. The different methods of authenticating allow flexibility between creating a loose, decentralized set of grids and services and a tightly coupled closed or semi-closed grid.&lt;br /&gt;
&lt;br /&gt;
= See Also =&lt;br /&gt;
&lt;br /&gt;
* [[AssetServerProposal|Asset Server Proposal]]&lt;br /&gt;
* [[AssetServerProposal/DeveloperDocs|Developer Documentation]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/AssetServer</id>
		<title>AssetServer</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/AssetServer"/>
				<updated>2009-01-15T02:50:55Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{proposal}}&lt;br /&gt;
&lt;br /&gt;
=Asset Server Proposal=&lt;br /&gt;
&lt;br /&gt;
==Motivation==&lt;br /&gt;
&lt;br /&gt;
Many virtual worlds are being developed independently with a wide variety of different architectures and protocols. However, one common component across these worlds is an asset service. An asset service is the means of storing and serving static content that populates the world; anything from textures and 3D meshes to clothing definitions can be stored. The current generation of virtual world asset services are implemented as proprietary, behind-the-simulator services that are not directly available to a user.&lt;br /&gt;
&lt;br /&gt;
We believe there are shortcomings with this approach. Specifically:&lt;br /&gt;
&lt;br /&gt;
# Assets are tied to a single grid. Wide availability of content is critical to the growth of virtual worlds, and the inability to share content between grids limits the ability of small providers. Having an asset server closely tied to a grid limits the ability of many small grids to reach critical mass.&lt;br /&gt;
# The current vendor-specific nature of asset storage limits the ability of third-party value added services. Offline content creation, asset archiving, specialized caching, and web service integration are all services that could be added with a more open approach.&lt;br /&gt;
# With assets &amp;quot;locked up&amp;quot; in proprietary asset servers, the ability to combine and re-purpose content is limited. For instance, specialized asset processing tuned to mobile applications.&lt;br /&gt;
# An asset server closely tied to a grid limits the content creator and owner's ability to manage asset lifecycle. An asset owner may wish to have their assets stored, backed up, and tracked from their own servers rather than handing over control to a grid.&lt;br /&gt;
&lt;br /&gt;
==Vision==&lt;br /&gt;
&lt;br /&gt;
We envision virtual world grids modeled after the current World Wide Web, with millions of independent administrative domains. Content will be spread across millions of small, independent domains as well as aggregated on large domains supporting millions of users. A rich community of value added services and the free and open exchange of content will weave the network together, much as the Web 2.0 movement is tying the web together today. Every organization can choose to host an asset service or connect with any number of third party asset providers. Additionally, the content rights decisions are placed in the hands of the content hosts. With the proper authentication users are free to move assets to wherever they roam.&lt;br /&gt;
&lt;br /&gt;
Data services will become as important as data hosting itself. Just as search engines and content portals have changed how we use the web, services that can plug into a common interface in asset hosting will change how we use virtual worlds. Auditing services can provide an approach to rights management and traffic analytics. Existing caching techniques and services that have been built for today's web content can be leveraged for delivery of rich virtual world content.&lt;br /&gt;
&lt;br /&gt;
==Approach==&lt;br /&gt;
&lt;br /&gt;
Most implementations, including Second Life® and its open source derivatives, have opaque asset hosting that is a part of the world itself. The opaque asset hosting model has a choke point at the simulator level. Asset downloads make up the bulk of virtual world bandwidth requirements, and in the current Second Life model all assets must be proxied through the simulator.&lt;br /&gt;
&lt;br /&gt;
In the proposed architecture, control of assets is moved from grid owners to content owners to allow cross-world assets with content authorization management. Protocol enhancements could include better support for content rights, asset hosting as an independent service, asset migration between worlds, and scalable performance by allowing centralized servers to be removed from the equation.&lt;br /&gt;
&lt;br /&gt;
Our approach is to start simple by proposing common interfaces and paths for extensibility. By working with the community to refine these interfaces and explore use cases, we can outline specifications and minimum requirements documents. The short-term goals are to consolidate on a common metadata format with core features for version one, and build a reference asset service that plugs into the OpenSim UGAIM model.&lt;br /&gt;
&lt;br /&gt;
===Asset Hosting as An Independent Service===&lt;br /&gt;
&lt;br /&gt;
The current model of asset hosting approaches trust and permissions from the viewpoint of a grid. Users authenticate with a grid login service, upload assets to grid asset storage, and set permissions that apply to other users of that grid. By moving authorization to the asset storage, an asset service no longer needs to be tied to a specific grid and can serve anyone who is properly authenticated. This opens up the possibility of web service access to assets or asset metadata, or other use cases that do not directly involve logging in to a virtual world.&lt;br /&gt;
&lt;br /&gt;
===Leveraging Existing Infrastructure===&lt;br /&gt;
&lt;br /&gt;
With asset serving separated from grid-specific code, the solution looks similar to existing solutions. Proven infrastructure for asset lookups, authentication, serving metadata, and content distribution can be used as building blocks.&lt;br /&gt;
&lt;br /&gt;
===Scalability===&lt;br /&gt;
&lt;br /&gt;
The difficult research in scalable content distribution has already been done and implemented across the web in various different implementations. The goal is to reuse that existing knowledge for virtual world assets, adding optional features such as identity-based permission levels or new caching strategies.&lt;br /&gt;
&lt;br /&gt;
==Terminology==&lt;br /&gt;
&lt;br /&gt;
* Client: From the asset server's point of view, the networked program that is fetching or storing an asset.&lt;br /&gt;
* Asset Server: The network service that presents an interface allowing fetching and storing of asset items.&lt;br /&gt;
* Asset: A typed blob of data. The actual definition of asset content is left to the asset creator.&lt;br /&gt;
* Asset Metadata: Information stored along with the asset blob which includes type-specific information, ownership information, creation information (creation data), license, and anything else useful in identifying and controlling the asset data.&lt;br /&gt;
* Asset ID: A 128-bit identifier for content in a virtual world. These identifiers may or may not follow RFC 4122; the specific implementation is out of scope of the asset service. Asset IDs only have context in the grid they were created in.&lt;br /&gt;
* Authentication Token: A session cookie that is temporarily stored on the Asset Server and the Client that proves authentication and may grant some level of authorization. These cookies take the same UUID form as Asset IDs.&lt;br /&gt;
* Grid: For the purposes of this document, a grid is defined as the set of services where a particular Asset ID has contextual meaning.&lt;br /&gt;
&lt;br /&gt;
==Protocol Overview==&lt;br /&gt;
&lt;br /&gt;
# The end user retrieves an authorization token to connect to an asset service. This can be returned by directly connecting to an asset service and supplying OpenID credentials, or an out of band method such as logging into a virtual world grid server.&lt;br /&gt;
# The end user does a GET operation, supplying the credentials from step 1, and requests the metadata for an asset ID.&lt;br /&gt;
# The asset service performs a lookup step which resolves the ID to metadata which includes the location of the content, a list of supported REST operations on the content, and additional information, such as the dimensions of a texture.&lt;br /&gt;
# The end user has information on different valid operations on the asset, and in the most common scenario will choose to use the fetch operation to download the asset.&lt;br /&gt;
&lt;br /&gt;
All user-facing services must be available over standard HTTP 1.1, and must adopt at least one common metadata format.&lt;br /&gt;
&lt;br /&gt;
==Asset Metadata Request==&lt;br /&gt;
&lt;br /&gt;
An end user must discover the asset service through some means. The specific means of discovery is out of scope of this document but could for example be built into a client application, provided during grid login, or published on a webpage. To request asset metadata, an HTTP 1.1 GET is made to the asset service with the asset ID and metadata operation specified. For example, a request might look like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;GET /89556747-24cb-43ed-920b-47caed15465f/metadata HTTP/1.1&lt;br /&gt;
Host: assets.virtualworld.com&lt;br /&gt;
Date: Mon, 22 Sep&amp;amp;nbsp; 2008 12:00:00 GMT&lt;br /&gt;
Authorization: OpenGrid ce9a6995-a737-4206-bae8-910cae310e94&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the asset is a protected resource the Authorization header is required. If the resource is publicly accessible, no Authorization header is needed and a normal HTTP GET (such as one generated by a web browser) can be used.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
Access to the asset service methods is controlled with a authentication token, a UUID. This UUID is a non-guessable, temporary token assigned to an end user at the end of a successful authentication process. This token could be granted by authentication through a virtual world login server (where the login server is responsible for transmitting the authentication token to the asset server), or through a direct login to the asset service itself using OpenID. Temporary tokens must only be given out to authenticated end users, and should be expired similar to HTTP cookies.&lt;br /&gt;
&lt;br /&gt;
If the asset service supports direct logins, it may respond to unauthorized requests with a response that includes information about authenticating with OpenID.&lt;br /&gt;
&lt;br /&gt;
Once an authenticated request for an asset has been made, the asset service determines if the authenticated user has authorization for the requested content. If a request is unauthorized, a 403 Forbidden response must be sent back to the end user, optionally including information about authenticating with OpenID so the user can choose to authenticate with another identity.&lt;br /&gt;
&lt;br /&gt;
==Lookup==&lt;br /&gt;
&lt;br /&gt;
Once a request has been authorized, a lookup is performed. This could be as simple as a map&amp;lt;UUID,metadata&amp;gt; or a more scalable solution such as a distributed hash table. The lookup resolves the asset metadata and asset location, and together with the authorization can determine the list of supported actions that are returned in metadata.&lt;br /&gt;
&lt;br /&gt;
==Metadata==&lt;br /&gt;
&lt;br /&gt;
The metadata provides information on supported methods for the resource and information about the resource itself (such as the size and dimensions of a texture, or byte boundaries of quality layers in a JPEG2000 file). One of the goals of this research is to work with the community to develop a common metadata format for requests and responses. The current metadata reference implementation uses JSON for the wire protocol. See [[AssetServerProposal/ClientDocs]] for more information.&lt;br /&gt;
&lt;br /&gt;
The metadata is broken up into three parts. Required fields, methods, and extra fields.&lt;br /&gt;
&lt;br /&gt;
The required fields are basic attributes that all assets share. These are:&lt;br /&gt;
&lt;br /&gt;
 * id - UUID of the asset&lt;br /&gt;
 * name - Name of the asset&lt;br /&gt;
 * description - Description of the asset&lt;br /&gt;
 * creation_date - Timestamp when the asset was created&lt;br /&gt;
 * type - HTTP Content-Type of the asset&lt;br /&gt;
 * sha1 - The SHA-1 hash of the asset data&lt;br /&gt;
 * temporary - Boolean, whether the asset is temporary or not&lt;br /&gt;
&lt;br /&gt;
The methods section is a collection of allowed methods for the asset. The only required method is data, however this method may not be present in the list of returned methods if the client has permission to access an assets metadata but not the data. Each method is a string (such as &amp;quot;data&amp;quot;) that maps to a URL. The URL may exist on the same server as the metadata, but this is not required.&lt;br /&gt;
&lt;br /&gt;
The extra data section is a free-form version of the required fields section. Any fields can be defined, and is most commonly used to add extended data for specific types of assets.&lt;br /&gt;
&lt;br /&gt;
==Data==&lt;br /&gt;
&lt;br /&gt;
Once the metadata has been retrieved, if a data method exists the asset data can be fetched with a simple HTTP GET on the asset data URL. This allows the actual data to optionally be stored on a simple web server, a content distribution network, a third party storage provider, etc.&lt;br /&gt;
&lt;br /&gt;
= See Also =&lt;br /&gt;
&lt;br /&gt;
* [[AssetServerProposal/ClientDocs|Client Documentation]]&lt;br /&gt;
* [[AssetServerProposal/DeveloperDocs|Developer Documentation]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Build_Instructions</id>
		<title>Build Instructions</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Build_Instructions"/>
				<updated>2008-11-11T03:11:23Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* RedHat Enterprise Linux 5 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Users]]&lt;br /&gt;
This page covers building OpenSim from source code on multiple platforms.  Please help us keep this page up to date as the project progresses.&lt;br /&gt;
&lt;br /&gt;
==Download from SVN==&lt;br /&gt;
Check out the [[Download]] Section&lt;br /&gt;
&lt;br /&gt;
==MS Windows==&lt;br /&gt;
&lt;br /&gt;
OpenSim requires either the .Net framework version 2.0, or the latest Mono. It supports the following compilers:&lt;br /&gt;
* [http://msdn2.microsoft.com/en-us/express/aa700756.aspx Microsoft Visual C# Express Edition] (note: not Visual C++)&lt;br /&gt;
* [http://www.mono-project.com/ mono]&lt;br /&gt;
&lt;br /&gt;
Note for people who just downloaded the sources from http://dist.opensimulator.org/ (the &amp;quot;Downloads&amp;quot; link on the left) be advised that some important things are missing (like MySQL template scripts). For such features, you must download using svn!&lt;br /&gt;
&lt;br /&gt;
Additional note: any Microsoft C# Express edition should work (2005 or 2008)&lt;br /&gt;
&lt;br /&gt;
=== Building ===&lt;br /&gt;
&lt;br /&gt;
* In the top-level directory, run the '&amp;lt;tt&amp;gt;runprebuild.bat&amp;lt;/tt&amp;gt;' file. This will create a VS2005 solution file, a nant build file and a '&amp;lt;tt&amp;gt;compile.bat&amp;lt;/tt&amp;gt;' file.&lt;br /&gt;
* If you prefer VS2008, run the '&amp;lt;tt&amp;gt;runprebuild2008.bat&amp;lt;/tt&amp;gt;' instead.&lt;br /&gt;
&lt;br /&gt;
* Open the resulting sln file with visual studio and build it there, or&lt;br /&gt;
* Run the '&amp;lt;tt&amp;gt;compile.bat&amp;lt;/tt&amp;gt;' file. This will build the executable using MSBuild.&lt;br /&gt;
* if you prefer to use nant, run nant in the same top-level directory. This will build the executables.&lt;br /&gt;
&lt;br /&gt;
If you don't care about physics (walking on prims, etc), ignore the rest of this section.&lt;br /&gt;
&lt;br /&gt;
=== Running ===&lt;br /&gt;
&lt;br /&gt;
Recent versions of OpenSim come without an &amp;lt;tt&amp;gt;OpenSim.ini&amp;lt;/tt&amp;gt; file. Copy the &amp;lt;tt&amp;gt;OpenSim.ini.example&amp;lt;/tt&amp;gt; file to &amp;lt;tt&amp;gt;OpenSim.ini&amp;lt;/tt&amp;gt; before making any changes.&lt;br /&gt;
&lt;br /&gt;
Double-click on the &amp;lt;tt&amp;gt;OpenSim.exe&amp;lt;/tt&amp;gt; executable file in the &amp;lt;tt&amp;gt;bin&amp;lt;/tt&amp;gt; directory. This will start up OpenSim in standalone mode.&lt;br /&gt;
&lt;br /&gt;
The debugger in VS2005 C# may be used to step through the code. For those that use a Cygwin shell, you may find that one or more dll's have permissions that cause problems running. Most find that a &amp;quot;&amp;lt;tt&amp;gt;chmod 777 *&amp;lt;/tt&amp;gt;&amp;quot; from the &amp;lt;tt&amp;gt;bin&amp;lt;/tt&amp;gt; directory solves this.&lt;br /&gt;
&lt;br /&gt;
Physics can be invoked by adding the appropriate line to the [Startup] section of &amp;lt;tt&amp;gt;OpenSim.ini&amp;lt;/tt&amp;gt;.  For ODE, that would be:&lt;br /&gt;
&lt;br /&gt;
 physics = OpenDynamicsEngine&lt;br /&gt;
&lt;br /&gt;
You can also add a command line option to a shortcut, or run from a command prompt with:&lt;br /&gt;
&lt;br /&gt;
 -physics=OpenDynamicsEngine&lt;br /&gt;
&lt;br /&gt;
'''''Windows Vista'''''&lt;br /&gt;
&lt;br /&gt;
To run on Windows Vista, you must first disable Windows Firewall.  Under the new &amp;quot;Start&amp;quot; button of Vista, select &amp;quot;Control panel&amp;quot;.  Then double-click &amp;quot;Windows Firewall&amp;quot;.  In the window that pops up, on the left column, select &amp;quot;Turn Windows Firewall on or off&amp;quot;.  You will have to give permission for this to run, then select the option &amp;quot;Off (not recommended)&amp;quot;.  Click &amp;quot;OK&amp;quot; and exit from the Windows Firewall window.&lt;br /&gt;
&lt;br /&gt;
If you have McAfee SecurityCenter, see the description below.&lt;br /&gt;
&lt;br /&gt;
Once all the security features are disabled, right click on &amp;lt;tt&amp;gt;OpenSim.exe&amp;lt;/tt&amp;gt; and select &amp;quot;Run as administrator&amp;quot;.  This will pop up a window asking permission, select &amp;quot;Allow&amp;quot;.  Your OpenSim server should run in a DOS-like window and accept connections.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''''McAfee Security'''''&lt;br /&gt;
&lt;br /&gt;
McAfee Security does not allow applications to listen on ports not explicitly specified.  You have two options: 1) disable firewall protection all together, 2) enable &amp;lt;tt&amp;gt;OpenSim.exe&amp;lt;/tt&amp;gt; to be able to open ports.&lt;br /&gt;
&lt;br /&gt;
''Disable firewall''&lt;br /&gt;
&lt;br /&gt;
Open McAfee SecurityCenter.  Select &amp;quot;Internet &amp;amp; Network&amp;quot;.  In the lower left corner is a small link to &amp;quot;Configure...&amp;quot;.  Select this.  In the right side of the window, select the bar that says &amp;quot;Firewall protection is enabled&amp;quot;.  Here you can select &amp;quot;Off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
''Enable &amp;lt;tt&amp;gt;OpenSim.exe&amp;lt;/tt&amp;gt; to open ports''&lt;br /&gt;
&lt;br /&gt;
Open McAfee SecurityCenter.  Select &amp;quot;Internet &amp;amp; Network&amp;quot;.  In the lower left corner is a small link to &amp;quot;Configure...&amp;quot;.  Select this.  In the right side of the window, select the bar that says &amp;quot;Firewall protection is enabled&amp;quot;.  Select the &amp;quot;Advanced...&amp;quot; button.  This will pop up a new window.&lt;br /&gt;
&lt;br /&gt;
In the new window, on the left side, select &amp;quot;Program Permissions.&amp;quot;  In the middle on the right side of the window, select the &amp;quot;Add Allowed Program&amp;quot; button.  Use the browser that pops up to find the OpenSim executable and select it.&lt;br /&gt;
&lt;br /&gt;
Finally, select &amp;quot;OK&amp;quot; and exit the McAfee SecurityCenter window.&lt;br /&gt;
&lt;br /&gt;
==Linux/Mac OS X/FreeBSD==&lt;br /&gt;
&lt;br /&gt;
The easiest plaform to get running on the Linux side is Ubuntu 8.04, 32bit.  This is what most of the developers running Linux use.  If you are looking for the quick path, start there.&lt;br /&gt;
&lt;br /&gt;
=== Ubuntu 8.04 / 8.10 ===&lt;br /&gt;
&lt;br /&gt;
For Ubuntu 7.10 users '''you need''' to upgrade your mono to 1.9.1.&lt;br /&gt;
&lt;br /&gt;
You can use the built in packages for mono.  However, for better performance, you may want to [http://xyzzyxyzzy.net/2008/05/08/updated-mono-build-script-for-hardy-heron-and-mono-191/ upgrade mono to 1.9.1] ([http://tempvariable.blogspot.com/2008/04/installing-mono-191-on-ubuntu-804-hardy.html Other simple method])&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install subversion nant mono-gmcs libmono-microsoft8.0-cil \&lt;br /&gt;
      libmono-system-runtime2.0-cil libgdiplus libmono-i18n2.0-cil ruby&lt;br /&gt;
 svn co http://opensimulator.org/svn/opensim/trunk opensim&lt;br /&gt;
 cd opensim&lt;br /&gt;
 ./runprebuild.sh&lt;br /&gt;
 nant&lt;br /&gt;
&lt;br /&gt;
=== openSUSE 10.3 and 11 ===&lt;br /&gt;
&lt;br /&gt;
Install an openSUSE 11 or 10.3 with its default options, add the online repositories&lt;br /&gt;
when finished installing do an online update with all the latest packages.&lt;br /&gt;
&lt;br /&gt;
In yast install these packages, for running Opensim in standalone mode.&lt;br /&gt;
(there is a slight diffrence between 10.3 and 11 but following should be same)&lt;br /&gt;
 subversion&lt;br /&gt;
 nant&lt;br /&gt;
 mono-jscript&lt;br /&gt;
 - check that mono-core is installed&lt;br /&gt;
&lt;br /&gt;
If you just want to use SQLite then jump to last section &lt;br /&gt;
within this post.&lt;br /&gt;
&lt;br /&gt;
* Optional mysql - for Opensim running in Grid mode:&lt;br /&gt;
Install these mysql packages via yast&lt;br /&gt;
  mysql&lt;br /&gt;
  mysql-client&lt;br /&gt;
  mysql-administrator&lt;br /&gt;
  mysql-gui-tools&lt;br /&gt;
  mysql-query-browser&lt;br /&gt;
&lt;br /&gt;
Before building create the mysql database.&lt;br /&gt;
 /etc/init.d/mysql start&lt;br /&gt;
 mysql -u root -p -h localhost&lt;br /&gt;
 (when asked for password just hit enter)&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; create database opensim;&lt;br /&gt;
 mysql&amp;gt; quit&lt;br /&gt;
&lt;br /&gt;
set the configuration in bin/mysql_connection.ini&lt;br /&gt;
Or on later builds set the connection string inside bin/OpenSim.ini&lt;br /&gt;
&lt;br /&gt;
Build after installation of above in bash terminal. i save it in /opt&lt;br /&gt;
&lt;br /&gt;
 su -&lt;br /&gt;
 cd /opt&lt;br /&gt;
 svn co http://opensimulator.org/svn/opensim/trunk opensim&lt;br /&gt;
 cd opensim&lt;br /&gt;
 ./runprebuild.sh&lt;br /&gt;
 nant&lt;br /&gt;
&lt;br /&gt;
After this you should be able to continue on starting the diffrent Servers, look in the mysql-config section,or&lt;br /&gt;
just run your OpenSim as a Standalone. By - eagleFX&lt;br /&gt;
&lt;br /&gt;
=== Mac OS X 10.5/10.4 ===&lt;br /&gt;
* OpenSim is now working on PowerPC Macs! Thanks to DrScofield and those who helped him. Current nightly builds for PowerPC are not working, not sure about Intel so use the 0.5 Build. OpenSim works on Intel Macs. I'm testing on PowerBook G4. Tested these step on 10.5, but not 10.4 but should work --[[User:Mokele|Mokele]] 22:36, 14 February 2008 (PST)&lt;br /&gt;
* Install XCode Developers Tools from DVD/CD Installation Disk or download  from http://developer.apple.com/. You have to create an Apple account to access the downloads if you don't have an Apple account.&lt;br /&gt;
* Install X11 for 10.4 from the Optional Install from the DVD/CD Installation Disk. X11 for 10.5 is installed by default.&lt;br /&gt;
* Install Mono 1.2.5 from http://ftp.novell.com/pub/mono/archive/1.2.5/macos-10-universal/5/MonoFramework-1.2.5_5.macos10.novell.universal.dmg and in Terminal or X11 edit the .profile file  and add the following line:&lt;br /&gt;
 export PKG_CONFIG_PATH=&amp;quot;/Library/Frameworks/Mono.framework/Versions/Current/lib/pkgconfig/:${PKG_CONFIG_PATH}&amp;quot;&lt;br /&gt;
* Compile OpenSim&lt;br /&gt;
 svn co http://opensimulator.org/svn/opensim/tags/0.5.0-release opensim&lt;br /&gt;
 cd opensim &lt;br /&gt;
 ./runprebuild.sh&lt;br /&gt;
 nant&lt;br /&gt;
&lt;br /&gt;
* Download and Compile libopenjpeg-libsl-2.1.2.0.dylib and libsecondlife.dll&lt;br /&gt;
* libopenjpeg-libsl-2.1.2.0.dylib:&lt;br /&gt;
 svn co http://opensimulator.org/svn/opensim-libs/libsl1550 opensim-libs&lt;br /&gt;
 cd opensim-libs/openjpeg-libsl&lt;br /&gt;
 make -f Makefile.osx&lt;br /&gt;
 cp libopenjpeg-libsl-2.1.2.0.dylib ../../opensim/bin&lt;br /&gt;
* Note: The Makefile that creates the libopenjpeg-libsl-2.1.2.0.so does not compile on PowerPC, but works properly on Intel Macs. Looks like a gcc issue with compile options.&lt;br /&gt;
&lt;br /&gt;
* libsecondlife.dll: (for PowerPC Only, see  details on this step [http://xyzzyxyzzy.net/2008/02/12/installing-opensim-on-powerpcor-of-eggs-and-virtual-worlds installing OpenSim on PowerPC…or: of eggs and virtual worlds])&lt;br /&gt;
 cd .. (back into opensim-libs)&lt;br /&gt;
 nant&lt;br /&gt;
 cp bin/libsecondlife.dll ../opensim/bin&lt;br /&gt;
&lt;br /&gt;
* Edit the libsecondlife.dll.config (PowerPC Only). Remove the cpu=&amp;quot;x86&amp;quot; tag in the last dllmap line.&lt;br /&gt;
&lt;br /&gt;
=== FreeBSD 6.2 ===&lt;br /&gt;
 su&lt;br /&gt;
 cd /usr/ports/devel/subversion/ &amp;amp;&amp;amp; make install clean (you may also need to rebuild apr-svn if this step fails)&lt;br /&gt;
 cd /usr/ports/lang/mono/ &amp;amp;&amp;amp; make install clean&lt;br /&gt;
 cd /usr/ports/devel/nant/ &amp;amp;&amp;amp; make install clean&lt;br /&gt;
 cd /usr/ports/databases/sqlite3/ &amp;amp;&amp;amp; make install clean&lt;br /&gt;
 cd /usr/ports/x11-toolkits/libgdiplus/ &amp;amp;&amp;amp; make install clean&lt;br /&gt;
 cd /opensim/installation/directory/&lt;br /&gt;
 svn co http://opensimulator.org/svn/opensim/trunk opensim&lt;br /&gt;
 cd opensim&lt;br /&gt;
 ./runprebuild.sh&lt;br /&gt;
 nant&lt;br /&gt;
&lt;br /&gt;
 Note: [http://opensimulator.org/wiki/OpenSim:FAQ#System.DllNotFoundException:_..2Flibopenjpeg-libsl-2.1.2.0.so|Follow the instructions on the FAQ to fix the]&lt;br /&gt;
 &amp;quot;System.DllNotFoundException: ./libopenjpeg-libsl-2.1.2.0.so&amp;quot; issue, but use &amp;quot;gmake&amp;quot; instead of &amp;quot;make&amp;quot;&lt;br /&gt;
&lt;br /&gt;
For ODE Physics you must do the following:&lt;br /&gt;
 cd /usr/ports/graphics/libGL/ &amp;amp;&amp;amp; make install clean&lt;br /&gt;
 cd /usr/ports/graphics/libGLU/ &amp;amp;&amp;amp; make install clean&lt;br /&gt;
 cd /opensim/installation/directory/&lt;br /&gt;
 svn co http://opensimulator.org/svn/opensim-libs/trunk opensim-libs&lt;br /&gt;
 cd opensim-libs/unmanaged/OpenDynamicsEngine2/&lt;br /&gt;
 sh autogen.sh&lt;br /&gt;
 ./configure --enable-shared --enable-release --disable-demos&lt;br /&gt;
 make&lt;br /&gt;
 mv ./ode/src/libode.so /opensim/installation/directory/opensim/bin/&lt;br /&gt;
&lt;br /&gt;
=== RedHat Enterprise Linux 4 ===&lt;br /&gt;
 sudo vi /etc/yum.repos.d/mono.repo&lt;br /&gt;
&lt;br /&gt;
  [mono]&lt;br /&gt;
  name=Mono for rhel-4-i386 (stable)&lt;br /&gt;
  baseurl=http://ftp.novell.com/pub/mono/download-stable/rhel-4-i386/&lt;br /&gt;
  enabled=1&lt;br /&gt;
  gpgcheck=0&lt;br /&gt;
&lt;br /&gt;
 sudo yum install mono-complete monodoc-core nant&lt;br /&gt;
 svn co svn co http://opensimulator.org/svn/opensim/trunk opensim&lt;br /&gt;
 cd opensim&lt;br /&gt;
 ./runprebuild.sh&lt;br /&gt;
 nant&lt;br /&gt;
&lt;br /&gt;
=== RedHat Enterprise Linux 5 ===&lt;br /&gt;
&lt;br /&gt;
The instructions below also work on other RedHat Linux flavors such as CentOS or maybe Fedora.&lt;br /&gt;
&lt;br /&gt;
1. Put the [http://download.opensuse.org/repositories/Mono/RHEL_5/Mono.repo Mono.repo] file in the /etc/yum.repo.d/ directory:&lt;br /&gt;
 $ sudo su -&lt;br /&gt;
 $ cd /etc/yum.repos.d/&lt;br /&gt;
 $ wget http://download.opensuse.org/repositories/Mono/RHEL_5/Mono.repo&lt;br /&gt;
Naturally use the most [http://download.opensuse.org/repositories/Mono up-to-date link for your distribution].&lt;br /&gt;
&lt;br /&gt;
2. Install Mono and related tools with yum:&lt;br /&gt;
 $ yum install mono nant mono-jscript mono-nunit&lt;br /&gt;
Make sure to use nunit-console2 to run your tests.&lt;br /&gt;
&lt;br /&gt;
=== Fedora 5 ===&lt;br /&gt;
* I needed to build latest mono and nant from sources to build OpenSim successfully, the ones available in yum repository didn't work so I had to uninstall and build and configure the packages.&lt;br /&gt;
&lt;br /&gt;
For detailed instructions go [http://ruakuu.blogspot.com/2008/06/installing-and-configuring-opensim-on.html here]&lt;br /&gt;
&lt;br /&gt;
=== Debian 4 ===&lt;br /&gt;
&lt;br /&gt;
The following packages and their dependencies are required to run OpenSim on a default Debian 4 netinstall:&lt;br /&gt;
* mono&lt;br /&gt;
* libmono-corlib2.0-cil&lt;br /&gt;
* libmono-sqlite2.0-cil&lt;br /&gt;
* libmono-system-web2.0-cil&lt;br /&gt;
* libmono-microsoft8.0-cil&lt;br /&gt;
* libmono-system-runtime2.0-cil&lt;br /&gt;
&lt;br /&gt;
=== 64bit ===&lt;br /&gt;
Please note that only 32bit binaries are provided in the bin/ directory of subversion.  If you want to use 64bit, you'll need to rebuild these shared objects.  See [[Installing and running on x86-64]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Physics (Open Dynamics Engine ODE) ===&lt;br /&gt;
As installed from svn, ODE will work on most 32 bit platforms.  If you get an ODE-related crash, and/or a &amp;lt;i&amp;gt;libode.so not found&amp;lt;/i&amp;gt; type of error, you will need to build libode from source.&lt;br /&gt;
&lt;br /&gt;
Remove &amp;lt;tt&amp;gt;libode.so&amp;lt;/tt&amp;gt; from the &amp;lt;tt&amp;gt;./bin&amp;lt;/tt&amp;gt; folder.  (Note that subsequent svn updates may replace it again; best fix is to copy your built &amp;lt;tt&amp;gt;libode.so&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;bin&amp;lt;/tt&amp;gt;).  Do NOT remove &amp;lt;tt&amp;gt;ode.net.dll&amp;lt;/tt&amp;gt;!  Download the latest source from:&lt;br /&gt;
&lt;br /&gt;
 svn co http://opensimulator.org/svn/opensim-libs/trunk/unmanaged/OpenDynamicsEngine&lt;br /&gt;
&lt;br /&gt;
OpenSim requires a couple of patches on top of ODE which are not yet included upstream.  When compiling, make sure to use the following configure options:&lt;br /&gt;
&lt;br /&gt;
 --with-trimesh=gimpact &lt;br /&gt;
 --enable-shared&lt;br /&gt;
&lt;br /&gt;
Make sure the configure script confirms these choices, and always compile with single precision (I believe that's the default).  Try &amp;lt;code&amp;gt; make -k &amp;lt;/code&amp;gt; if you get errors relating to drawstuff, test*, or openGL.  &amp;lt;code&amp;gt; make install &amp;lt;/code&amp;gt; should put &amp;lt;tt&amp;gt;libode.so&amp;lt;/tt&amp;gt; in the proper place (usually &amp;lt;tt&amp;gt;/usr/local/lib&amp;lt;/tt&amp;gt;), and it should be seen by opensim (&amp;lt;tt&amp;gt;ode.net.dll&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
===Running===&lt;br /&gt;
Recent versions of OpenSim come without an &amp;lt;tt&amp;gt;OpenSim.ini&amp;lt;/tt&amp;gt; file. Copy the &amp;lt;tt&amp;gt;OpenSim.ini.example&amp;lt;/tt&amp;gt; file to &amp;lt;tt&amp;gt;OpenSim.ini&amp;lt;/tt&amp;gt; before making any changes.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 cd bin&lt;br /&gt;
 mono OpenSim.exe&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: if you are running a 32bit Server such as Ubuntu 8.0.4 you need the alternative launcher:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
mono OpenSim.32BitLaunch.exe&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* To invoke ODE, add the option:&lt;br /&gt;
 -physics=OpenDynamicsEngine&lt;br /&gt;
to the &amp;lt;tt&amp;gt;mono OpenSim.exe&amp;lt;/tt&amp;gt; line&lt;br /&gt;
&lt;br /&gt;
or add &amp;lt;code&amp;gt;  physics = OpenDynamicsEngine &amp;lt;/code&amp;gt; to the [Startup] section of &amp;lt;tt&amp;gt;OpenSim.ini&amp;lt;/tt&amp;gt;.  Same deal for other physics engines, when available.&lt;br /&gt;
&lt;br /&gt;
On mono 1.2.6, some distributions may see&lt;br /&gt;
 Unhandled Exception: System.NotSupportedException: CodePage 1252 not supported&lt;br /&gt;
on startup when using mysql.  This can be resolved by installing the package libmono-i18n2.0-cil (see http://bugs.mysql.com/bug.php?id=33938).&lt;br /&gt;
&lt;br /&gt;
=== Additional Items ===&lt;br /&gt;
&lt;br /&gt;
* [[GC_NO_EXPLICIT|GC NO EXPLICIT]] - Enable Large Heap in Mono, this has been known to help performance and stability&lt;br /&gt;
&lt;br /&gt;
[[Category:Users]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/OpenSim_0.6_IClientAPI</id>
		<title>OpenSim 0.6 IClientAPI</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/OpenSim_0.6_IClientAPI"/>
				<updated>2008-11-10T01:28:41Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* OnNewClient vs OnClientConnect */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{content}}&lt;br /&gt;
This page is under construction.&lt;br /&gt;
=Porting Guide=&lt;br /&gt;
==OnNewClient vs OnClientConnect==&lt;br /&gt;
* OnNewClient is deprecated, please use OnClientConnect instead.&lt;br /&gt;
** Rationale: OnNewClient passes IClientAPI in it's parameter, IClientAPI is being deprecated.&lt;br /&gt;
** IClientAPI Changes: IClientCore may not contain all the interfaces you want just yet, but if it does (see the list below for what's been ported so far), you should switch to OnClientConnect and then use IClientCore.[Try]Get&amp;lt;IClientInterface&amp;gt;().Method() instead of IClientAPI.Method();&lt;br /&gt;
&lt;br /&gt;
==Instant Message==&lt;br /&gt;
* Dropping fromAgentSession from SendInstantMessage (both overloaded versions)&lt;br /&gt;
** Rationale: Session ID is both linden specific, and something that shouldnt be transmitted to users anyway ('''security''').&lt;br /&gt;
** IClientAPI changes: Insert this parameter into your packets manually if you need it, LLClientView.cs contains a reference to sessionID already. Be advised that this represents a security risk (giving the users one of the two shared secrets).&lt;br /&gt;
* Dropping imSessionID from SendInstantMessage (both overloaded versions)&lt;br /&gt;
** Rationale: IM Session ID's are unique to SL and we just multiplex the two users ID's to form this so it's static anyway.&lt;br /&gt;
** IClientAPI changes: Multiplex the ID inside your own implementations vs relying on the module to do it for you.&lt;br /&gt;
==Bluebox==&lt;br /&gt;
* Dropping sessionID from SendBlueBoxMessage&lt;br /&gt;
** Rationale: Session ID is both linden specific, and something that shouldnt be transmitted to users anyway ('''security''').&lt;br /&gt;
** IClientAPI changes: Insert this parameter into your packets manually if you need it, LLClientView.cs contains a reference to sessionID already. Be advised that this represents a security risk (giving the users one of the two shared secrets).&lt;br /&gt;
==Chat==&lt;br /&gt;
* Dropping SendChatMessage(bytes[]...) - the overload with string still works however.&lt;br /&gt;
** Rationale: We arent using this, and sending the bytes raw instead of a string is poor methodology.&lt;br /&gt;
** IClientAPI Changes: Drop this method if you arent using it.&lt;br /&gt;
&lt;br /&gt;
=Example Conversion=&lt;br /&gt;
==InstantMessageModule.cs==&lt;br /&gt;
===Old===&lt;br /&gt;
        private void OnNewClient(IClientAPI client)&lt;br /&gt;
        {&lt;br /&gt;
            client.OnInstantMessage += OnInstantMessage;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
===New===&lt;br /&gt;
        void OnClientConnect(IClientCore client)&lt;br /&gt;
        {&lt;br /&gt;
            IClientIM clientIM;&lt;br /&gt;
            if(client.TryGet(out clientIM))&lt;br /&gt;
            {&lt;br /&gt;
                clientIM.OnInstantMessage += OnInstantMessage;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
===Comments===&lt;br /&gt;
Isnt this messier? I see more code! What's this IClientIM thing?&lt;br /&gt;
&lt;br /&gt;
The short answer here is we're now using multiple interfaces to represent clients. Rather than dictating that every client must obey IClientAPI.cs - we can say clients can pick and choose the bits and pieces they want to implement. &lt;br /&gt;
&lt;br /&gt;
The extra code is mostly in checking that the client supports Instant Messaging before attempting to handle IM's for it. If the client doesnt support that interface, it will lead to a crash if you try use it.&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/OpenSim_0.6_IClientAPI</id>
		<title>OpenSim 0.6 IClientAPI</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/OpenSim_0.6_IClientAPI"/>
				<updated>2008-11-10T01:28:22Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* OnNewClient vs OnClientConnect */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{content}}&lt;br /&gt;
This page is under construction.&lt;br /&gt;
=Porting Guide=&lt;br /&gt;
==OnNewClient vs OnClientConnect==&lt;br /&gt;
* OnNewClient is deprecated, please use OnClientConnect instead.&lt;br /&gt;
** Rationale: OnNewClient passes IClientAPI in it's parameter, IClientAPI is being depreciated.&lt;br /&gt;
** IClientAPI Changes: IClientCore may not contain all the interfaces you want just yet, but if it does (see the list below for what's been ported so far), you should switch to OnClientConnect and then use IClientCore.[Try]Get&amp;lt;IClientInterface&amp;gt;().Method() instead of IClientAPI.Method();&lt;br /&gt;
&lt;br /&gt;
==Instant Message==&lt;br /&gt;
* Dropping fromAgentSession from SendInstantMessage (both overloaded versions)&lt;br /&gt;
** Rationale: Session ID is both linden specific, and something that shouldnt be transmitted to users anyway ('''security''').&lt;br /&gt;
** IClientAPI changes: Insert this parameter into your packets manually if you need it, LLClientView.cs contains a reference to sessionID already. Be advised that this represents a security risk (giving the users one of the two shared secrets).&lt;br /&gt;
* Dropping imSessionID from SendInstantMessage (both overloaded versions)&lt;br /&gt;
** Rationale: IM Session ID's are unique to SL and we just multiplex the two users ID's to form this so it's static anyway.&lt;br /&gt;
** IClientAPI changes: Multiplex the ID inside your own implementations vs relying on the module to do it for you.&lt;br /&gt;
==Bluebox==&lt;br /&gt;
* Dropping sessionID from SendBlueBoxMessage&lt;br /&gt;
** Rationale: Session ID is both linden specific, and something that shouldnt be transmitted to users anyway ('''security''').&lt;br /&gt;
** IClientAPI changes: Insert this parameter into your packets manually if you need it, LLClientView.cs contains a reference to sessionID already. Be advised that this represents a security risk (giving the users one of the two shared secrets).&lt;br /&gt;
==Chat==&lt;br /&gt;
* Dropping SendChatMessage(bytes[]...) - the overload with string still works however.&lt;br /&gt;
** Rationale: We arent using this, and sending the bytes raw instead of a string is poor methodology.&lt;br /&gt;
** IClientAPI Changes: Drop this method if you arent using it.&lt;br /&gt;
&lt;br /&gt;
=Example Conversion=&lt;br /&gt;
==InstantMessageModule.cs==&lt;br /&gt;
===Old===&lt;br /&gt;
        private void OnNewClient(IClientAPI client)&lt;br /&gt;
        {&lt;br /&gt;
            client.OnInstantMessage += OnInstantMessage;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
===New===&lt;br /&gt;
        void OnClientConnect(IClientCore client)&lt;br /&gt;
        {&lt;br /&gt;
            IClientIM clientIM;&lt;br /&gt;
            if(client.TryGet(out clientIM))&lt;br /&gt;
            {&lt;br /&gt;
                clientIM.OnInstantMessage += OnInstantMessage;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
===Comments===&lt;br /&gt;
Isnt this messier? I see more code! What's this IClientIM thing?&lt;br /&gt;
&lt;br /&gt;
The short answer here is we're now using multiple interfaces to represent clients. Rather than dictating that every client must obey IClientAPI.cs - we can say clients can pick and choose the bits and pieces they want to implement. &lt;br /&gt;
&lt;br /&gt;
The extra code is mostly in checking that the client supports Instant Messaging before attempting to handle IM's for it. If the client doesnt support that interface, it will lead to a crash if you try use it.&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Build_Instructions</id>
		<title>Build Instructions</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Build_Instructions"/>
				<updated>2008-11-04T22:52:27Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Users]]&lt;br /&gt;
This page covers building OpenSim from source code on multiple platforms.  Please help us keep this page up to date as the project progresses.&lt;br /&gt;
&lt;br /&gt;
==Download from SVN==&lt;br /&gt;
Check out the [[Download]] Section&lt;br /&gt;
&lt;br /&gt;
==MS Windows==&lt;br /&gt;
&lt;br /&gt;
OpenSim requires either the .Net framework version 2.0, or the latest Mono. It supports the following compilers:&lt;br /&gt;
* [http://msdn2.microsoft.com/en-us/express/aa700756.aspx Microsoft Visual C# Express Edition] (note: not Visual C++)&lt;br /&gt;
* [http://www.mono-project.com/ mono]&lt;br /&gt;
&lt;br /&gt;
Note for people who just downloaded the sources from http://dist.opensimulator.org/ (the &amp;quot;Downloads&amp;quot; link on the left) be advised that some important things are missing (like MySQL template scripts). For such features, you must download using svn!&lt;br /&gt;
&lt;br /&gt;
Additional note: any Microsoft C# Express edition should work (2005 or 2008)&lt;br /&gt;
&lt;br /&gt;
=== Building ===&lt;br /&gt;
&lt;br /&gt;
* In the top-level directory, run the '&amp;lt;tt&amp;gt;runprebuild.bat&amp;lt;/tt&amp;gt;' file. This will create a VS2005 solution file, a nant build file and a '&amp;lt;tt&amp;gt;compile.bat&amp;lt;/tt&amp;gt;' file.&lt;br /&gt;
* If you prefer VS2008, run the '&amp;lt;tt&amp;gt;runprebuild2008.bat&amp;lt;/tt&amp;gt;' instead.&lt;br /&gt;
&lt;br /&gt;
* Open the resulting sln file with visual studio and build it there, or&lt;br /&gt;
* Run the '&amp;lt;tt&amp;gt;compile.bat&amp;lt;/tt&amp;gt;' file. This will build the executable using MSBuild.&lt;br /&gt;
* if you prefer to use nant, run nant in the same top-level directory. This will build the executables.&lt;br /&gt;
&lt;br /&gt;
If you don't care about physics (walking on prims, etc), ignore the rest of this section.&lt;br /&gt;
&lt;br /&gt;
=== Running ===&lt;br /&gt;
&lt;br /&gt;
Recent versions of OpenSim come without an &amp;lt;tt&amp;gt;OpenSim.ini&amp;lt;/tt&amp;gt; file. Copy the &amp;lt;tt&amp;gt;OpenSim.ini.example&amp;lt;/tt&amp;gt; file to &amp;lt;tt&amp;gt;OpenSim.ini&amp;lt;/tt&amp;gt; before making any changes.&lt;br /&gt;
&lt;br /&gt;
Double-click on the &amp;lt;tt&amp;gt;OpenSim.exe&amp;lt;/tt&amp;gt; executable file in the &amp;lt;tt&amp;gt;bin&amp;lt;/tt&amp;gt; directory. This will start up OpenSim in standalone mode.&lt;br /&gt;
&lt;br /&gt;
The debugger in VS2005 C# may be used to step through the code. For those that use a Cygwin shell, you may find that one or more dll's have permissions that cause problems running. Most find that a &amp;quot;&amp;lt;tt&amp;gt;chmod 777 *&amp;lt;/tt&amp;gt;&amp;quot; from the &amp;lt;tt&amp;gt;bin&amp;lt;/tt&amp;gt; directory solves this.&lt;br /&gt;
&lt;br /&gt;
Physics can be invoked by adding the appropriate line to the [Startup] section of &amp;lt;tt&amp;gt;OpenSim.ini&amp;lt;/tt&amp;gt;.  For ODE, that would be:&lt;br /&gt;
&lt;br /&gt;
 physics = OpenDynamicsEngine&lt;br /&gt;
&lt;br /&gt;
You can also add a command line option to a shortcut, or run from a command prompt with:&lt;br /&gt;
&lt;br /&gt;
 -physics=OpenDynamicsEngine&lt;br /&gt;
&lt;br /&gt;
'''''Windows Vista'''''&lt;br /&gt;
&lt;br /&gt;
To run on Windows Vista, you must first disable Windows Firewall.  Under the new &amp;quot;Start&amp;quot; button of Vista, select &amp;quot;Control panel&amp;quot;.  Then double-click &amp;quot;Windows Firewall&amp;quot;.  In the window that pops up, on the left column, select &amp;quot;Turn Windows Firewall on or off&amp;quot;.  You will have to give permission for this to run, then select the option &amp;quot;Off (not recommended)&amp;quot;.  Click &amp;quot;OK&amp;quot; and exit from the Windows Firewall window.&lt;br /&gt;
&lt;br /&gt;
If you have McAfee SecurityCenter, see the description below.&lt;br /&gt;
&lt;br /&gt;
Once all the security features are disabled, right click on &amp;lt;tt&amp;gt;OpenSim.exe&amp;lt;/tt&amp;gt; and select &amp;quot;Run as administrator&amp;quot;.  This will pop up a window asking permission, select &amp;quot;Allow&amp;quot;.  Your OpenSim server should run in a DOS-like window and accept connections.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''''McAfee Security'''''&lt;br /&gt;
&lt;br /&gt;
McAfee Security does not allow applications to listen on ports not explicitly specified.  You have two options: 1) disable firewall protection all together, 2) enable &amp;lt;tt&amp;gt;OpenSim.exe&amp;lt;/tt&amp;gt; to be able to open ports.&lt;br /&gt;
&lt;br /&gt;
''Disable firewall''&lt;br /&gt;
&lt;br /&gt;
Open McAfee SecurityCenter.  Select &amp;quot;Internet &amp;amp; Network&amp;quot;.  In the lower left corner is a small link to &amp;quot;Configure...&amp;quot;.  Select this.  In the right side of the window, select the bar that says &amp;quot;Firewall protection is enabled&amp;quot;.  Here you can select &amp;quot;Off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
''Enable &amp;lt;tt&amp;gt;OpenSim.exe&amp;lt;/tt&amp;gt; to open ports''&lt;br /&gt;
&lt;br /&gt;
Open McAfee SecurityCenter.  Select &amp;quot;Internet &amp;amp; Network&amp;quot;.  In the lower left corner is a small link to &amp;quot;Configure...&amp;quot;.  Select this.  In the right side of the window, select the bar that says &amp;quot;Firewall protection is enabled&amp;quot;.  Select the &amp;quot;Advanced...&amp;quot; button.  This will pop up a new window.&lt;br /&gt;
&lt;br /&gt;
In the new window, on the left side, select &amp;quot;Program Permissions.&amp;quot;  In the middle on the right side of the window, select the &amp;quot;Add Allowed Program&amp;quot; button.  Use the browser that pops up to find the OpenSim executable and select it.&lt;br /&gt;
&lt;br /&gt;
Finally, select &amp;quot;OK&amp;quot; and exit the McAfee SecurityCenter window.&lt;br /&gt;
&lt;br /&gt;
==Linux/Mac OS X/FreeBSD==&lt;br /&gt;
&lt;br /&gt;
The easiest plaform to get running on the Linux side is Ubuntu 8.04, 32bit.  This is what most of the developers running Linux use.  If you are looking for the quick path, start there.&lt;br /&gt;
&lt;br /&gt;
=== Ubuntu 8.04 / 8.10 ===&lt;br /&gt;
&lt;br /&gt;
For Ubuntu 7.10 users '''you need''' to upgrade your mono to 1.9.1.&lt;br /&gt;
&lt;br /&gt;
You can use the built in packages for mono.  However, for better performance, you may want to [http://xyzzyxyzzy.net/2008/05/08/updated-mono-build-script-for-hardy-heron-and-mono-191/ upgrade mono to 1.9.1] ([http://tempvariable.blogspot.com/2008/04/installing-mono-191-on-ubuntu-804-hardy.html Other simple method])&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install subversion nant mono-gmcs libmono-microsoft8.0-cil \&lt;br /&gt;
      libmono-system-runtime2.0-cil libgdiplus libmono-i18n2.0-cil ruby&lt;br /&gt;
 svn co http://opensimulator.org/svn/opensim/trunk opensim&lt;br /&gt;
 cd opensim&lt;br /&gt;
 ./runprebuild.sh&lt;br /&gt;
 nant&lt;br /&gt;
&lt;br /&gt;
=== openSUSE 10.3 and 11 ===&lt;br /&gt;
&lt;br /&gt;
Install an openSUSE 11 or 10.3 with its default options, add the online repositories&lt;br /&gt;
when finished installing do an online update with all the latest packages.&lt;br /&gt;
&lt;br /&gt;
In yast install these packages, for running Opensim in standalone mode.&lt;br /&gt;
(there is a slight diffrence between 10.3 and 11 but following should be same)&lt;br /&gt;
 subversion&lt;br /&gt;
 nant&lt;br /&gt;
 mono-jscript&lt;br /&gt;
 - check that mono-core is installed&lt;br /&gt;
&lt;br /&gt;
If you just want to use SQLite then jump to last section &lt;br /&gt;
within this post.&lt;br /&gt;
&lt;br /&gt;
* Optional mysql - for Opensim running in Grid mode:&lt;br /&gt;
Install these mysql packages via yast&lt;br /&gt;
  mysql&lt;br /&gt;
  mysql-client&lt;br /&gt;
  mysql-administrator&lt;br /&gt;
  mysql-gui-tools&lt;br /&gt;
  mysql-query-browser&lt;br /&gt;
&lt;br /&gt;
Before building create the mysql database.&lt;br /&gt;
 /etc/init.d/mysql start&lt;br /&gt;
 mysql -u root -p -h localhost&lt;br /&gt;
 (when asked for password just hit enter)&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; create database opensim;&lt;br /&gt;
 mysql&amp;gt; quit&lt;br /&gt;
&lt;br /&gt;
set the configuration in bin/mysql_connection.ini&lt;br /&gt;
Or on later builds set the connection string inside bin/OpenSim.ini&lt;br /&gt;
&lt;br /&gt;
Build after installation of above in bash terminal. i save it in /opt&lt;br /&gt;
&lt;br /&gt;
 su -&lt;br /&gt;
 cd /opt&lt;br /&gt;
 svn co http://opensimulator.org/svn/opensim/trunk opensim&lt;br /&gt;
 cd opensim&lt;br /&gt;
 ./runprebuild.sh&lt;br /&gt;
 nant&lt;br /&gt;
&lt;br /&gt;
After this you should be able to continue on starting the diffrent Servers, look in the mysql-config section,or&lt;br /&gt;
just run your OpenSim as a Standalone. By - eagleFX&lt;br /&gt;
&lt;br /&gt;
=== Mac OS X 10.5/10.4 ===&lt;br /&gt;
* OpenSim is now working on PowerPC Macs! Thanks to DrScofield and those who helped him. Current nightly builds for PowerPC are not working, not sure about Intel so use the 0.5 Build. OpenSim works on Intel Macs. I'm testing on PowerBook G4. Tested these step on 10.5, but not 10.4 but should work --[[User:Mokele|Mokele]] 22:36, 14 February 2008 (PST)&lt;br /&gt;
* Install XCode Developers Tools from DVD/CD Installation Disk or download  from http://developer.apple.com/. You have to create an Apple account to access the downloads if you don't have an Apple account.&lt;br /&gt;
* Install X11 for 10.4 from the Optional Install from the DVD/CD Installation Disk. X11 for 10.5 is installed by default.&lt;br /&gt;
* Install Mono 1.2.5 from http://ftp.novell.com/pub/mono/archive/1.2.5/macos-10-universal/5/MonoFramework-1.2.5_5.macos10.novell.universal.dmg and in Terminal or X11 edit the .profile file  and add the following line:&lt;br /&gt;
 export PKG_CONFIG_PATH=&amp;quot;/Library/Frameworks/Mono.framework/Versions/Current/lib/pkgconfig/:${PKG_CONFIG_PATH}&amp;quot;&lt;br /&gt;
* Compile OpenSim&lt;br /&gt;
 svn co http://opensimulator.org/svn/opensim/tags/0.5.0-release opensim&lt;br /&gt;
 cd opensim &lt;br /&gt;
 ./runprebuild.sh&lt;br /&gt;
 nant&lt;br /&gt;
&lt;br /&gt;
* Download and Compile libopenjpeg-libsl-2.1.2.0.dylib and libsecondlife.dll&lt;br /&gt;
* libopenjpeg-libsl-2.1.2.0.dylib:&lt;br /&gt;
 svn co http://opensimulator.org/svn/opensim-libs/libsl1550 opensim-libs&lt;br /&gt;
 cd opensim-libs/openjpeg-libsl&lt;br /&gt;
 make -f Makefile.osx&lt;br /&gt;
 cp libopenjpeg-libsl-2.1.2.0.dylib ../../opensim/bin&lt;br /&gt;
* Note: The Makefile that creates the libopenjpeg-libsl-2.1.2.0.so does not compile on PowerPC, but works properly on Intel Macs. Looks like a gcc issue with compile options.&lt;br /&gt;
&lt;br /&gt;
* libsecondlife.dll: (for PowerPC Only, see  details on this step [http://xyzzyxyzzy.net/2008/02/12/installing-opensim-on-powerpcor-of-eggs-and-virtual-worlds installing OpenSim on PowerPC…or: of eggs and virtual worlds])&lt;br /&gt;
 cd .. (back into opensim-libs)&lt;br /&gt;
 nant&lt;br /&gt;
 cp bin/libsecondlife.dll ../opensim/bin&lt;br /&gt;
&lt;br /&gt;
* Edit the libsecondlife.dll.config (PowerPC Only). Remove the cpu=&amp;quot;x86&amp;quot; tag in the last dllmap line.&lt;br /&gt;
&lt;br /&gt;
=== FreeBSD 6.2 ===&lt;br /&gt;
 su&lt;br /&gt;
 cd /usr/ports/devel/subversion/ &amp;amp;&amp;amp; make install clean (you may also need to rebuild apr-svn if this step fails)&lt;br /&gt;
 cd /usr/ports/lang/mono/ &amp;amp;&amp;amp; make install clean&lt;br /&gt;
 cd /usr/ports/devel/nant/ &amp;amp;&amp;amp; make install clean&lt;br /&gt;
 cd /usr/ports/databases/sqlite3/ &amp;amp;&amp;amp; make install clean&lt;br /&gt;
 cd /usr/ports/x11-toolkits/libgdiplus/ &amp;amp;&amp;amp; make install clean&lt;br /&gt;
 cd /opensim/installation/directory/&lt;br /&gt;
 svn co http://opensimulator.org/svn/opensim/trunk opensim&lt;br /&gt;
 cd opensim&lt;br /&gt;
 ./runprebuild.sh&lt;br /&gt;
 nant&lt;br /&gt;
&lt;br /&gt;
 Note: [http://opensimulator.org/wiki/OpenSim:FAQ#System.DllNotFoundException:_..2Flibopenjpeg-libsl-2.1.2.0.so|Follow the instructions on the FAQ to fix the]&lt;br /&gt;
 &amp;quot;System.DllNotFoundException: ./libopenjpeg-libsl-2.1.2.0.so&amp;quot; issue, but use &amp;quot;gmake&amp;quot; instead of &amp;quot;make&amp;quot;&lt;br /&gt;
&lt;br /&gt;
For ODE Physics you must do the following:&lt;br /&gt;
 cd /usr/ports/graphics/libGL/ &amp;amp;&amp;amp; make install clean&lt;br /&gt;
 cd /usr/ports/graphics/libGLU/ &amp;amp;&amp;amp; make install clean&lt;br /&gt;
 cd /opensim/installation/directory/&lt;br /&gt;
 svn co http://opensimulator.org/svn/opensim-libs/trunk opensim-libs&lt;br /&gt;
 cd opensim-libs/unmanaged/OpenDynamicsEngine2/&lt;br /&gt;
 sh autogen.sh&lt;br /&gt;
 ./configure --enable-shared --enable-release --disable-demos&lt;br /&gt;
 make&lt;br /&gt;
 mv ./ode/src/libode.so /opensim/installation/directory/opensim/bin/&lt;br /&gt;
&lt;br /&gt;
=== RedHat Enterprise Linux 4 ===&lt;br /&gt;
 sudo vi /etc/yum.repos.d/mono.repo&lt;br /&gt;
&lt;br /&gt;
  [mono]&lt;br /&gt;
  name=Mono for rhel-4-i386 (stable)&lt;br /&gt;
  baseurl=http://ftp.novell.com/pub/mono/download-stable/rhel-4-i386/&lt;br /&gt;
  enabled=1&lt;br /&gt;
  gpgcheck=0&lt;br /&gt;
&lt;br /&gt;
 sudo yum install mono-complete monodoc-core nant&lt;br /&gt;
 svn co svn co http://opensimulator.org/svn/opensim/trunk opensim&lt;br /&gt;
 cd opensim&lt;br /&gt;
 ./runprebuild.sh&lt;br /&gt;
 nant&lt;br /&gt;
&lt;br /&gt;
=== RedHat Enterprise Linux 5 ===&lt;br /&gt;
&lt;br /&gt;
The instructions below also work on other RedHat Linux flavors such as CentOS or maybe Fedora.&lt;br /&gt;
&lt;br /&gt;
1. Put the [http://download.opensuse.org/repositories/Mono/RHEL_5/Mono.repo Mono.repo] file in the /etc/yum.repo.d/ directory:&lt;br /&gt;
 $ sudo su -&lt;br /&gt;
 $ cd /etc/yum.repo.d/&lt;br /&gt;
 $ wget http://download.opensuse.org/repositories/Mono/RHEL_5/Mono.repo&lt;br /&gt;
Naturally use the most [http://download.opensuse.org/repositories/Mono up-to-date link for your distribution].&lt;br /&gt;
&lt;br /&gt;
2. Install Mono and related tools with yum:&lt;br /&gt;
 $ yum install mono nant mono-jscript mono-nunit&lt;br /&gt;
Make sure to use nunit-console2 to run your tests.&lt;br /&gt;
&lt;br /&gt;
=== Fedora 5 ===&lt;br /&gt;
* I needed to build latest mono and nant from sources to build OpenSim successfully, the ones available in yum repository didn't work so I had to uninstall and build and configure the packages.&lt;br /&gt;
&lt;br /&gt;
For detailed instructions go [http://ruakuu.blogspot.com/2008/06/installing-and-configuring-opensim-on.html here]&lt;br /&gt;
&lt;br /&gt;
=== Debian 4 ===&lt;br /&gt;
&lt;br /&gt;
The following packages and their dependencies are required to run OpenSim on a default Debian 4 netinstall:&lt;br /&gt;
* mono&lt;br /&gt;
* libmono-corlib2.0-cil&lt;br /&gt;
* libmono-sqlite2.0-cil&lt;br /&gt;
* libmono-system-web2.0-cil&lt;br /&gt;
* libmono-microsoft8.0-cil&lt;br /&gt;
* libmono-system-runtime2.0-cil&lt;br /&gt;
&lt;br /&gt;
=== 64bit ===&lt;br /&gt;
Please note that only 32bit binaries are provided in the bin/ directory of subversion.  If you want to use 64bit, you'll need to rebuild these shared objects.  See [[Installing and running on x86-64]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Physics (Open Dynamics Engine ODE) ===&lt;br /&gt;
As installed from svn, ODE will work on most 32 bit platforms.  If you get an ODE-related crash, and/or a &amp;lt;i&amp;gt;libode.so not found&amp;lt;/i&amp;gt; type of error, you will need to build libode from source.&lt;br /&gt;
&lt;br /&gt;
Remove &amp;lt;tt&amp;gt;libode.so&amp;lt;/tt&amp;gt; from the &amp;lt;tt&amp;gt;./bin&amp;lt;/tt&amp;gt; folder.  (Note that subsequent svn updates may replace it again; best fix is to copy your built &amp;lt;tt&amp;gt;libode.so&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;bin&amp;lt;/tt&amp;gt;).  Do NOT remove &amp;lt;tt&amp;gt;ode.net.dll&amp;lt;/tt&amp;gt;!  Download the latest source from:&lt;br /&gt;
&lt;br /&gt;
 svn co http://opensimulator.org/svn/opensim-libs/trunk/unmanaged/OpenDynamicsEngine2&lt;br /&gt;
&lt;br /&gt;
OpenSim requires a couple of patches on top of ODE which are not yet included upstream.  When compiling, make sure to use the following configure options:&lt;br /&gt;
&lt;br /&gt;
 --with-trimesh=gimpact &lt;br /&gt;
 --enable-shared&lt;br /&gt;
&lt;br /&gt;
Make sure the configure script confirms these choices, and always compile with single precision (I believe that's the default).  Try &amp;lt;code&amp;gt; make -k &amp;lt;/code&amp;gt; if you get errors relating to drawstuff, test*, or openGL.  &amp;lt;code&amp;gt; make install &amp;lt;/code&amp;gt; should put &amp;lt;tt&amp;gt;libode.so&amp;lt;/tt&amp;gt; in the proper place (usually &amp;lt;tt&amp;gt;/usr/local/lib&amp;lt;/tt&amp;gt;), and it should be seen by opensim (&amp;lt;tt&amp;gt;ode.net.dll&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
===Running===&lt;br /&gt;
Recent versions of OpenSim come without an &amp;lt;tt&amp;gt;OpenSim.ini&amp;lt;/tt&amp;gt; file. Copy the &amp;lt;tt&amp;gt;OpenSim.ini.example&amp;lt;/tt&amp;gt; file to &amp;lt;tt&amp;gt;OpenSim.ini&amp;lt;/tt&amp;gt; before making any changes.&lt;br /&gt;
 cd bin&lt;br /&gt;
 mono OpenSim.exe&lt;br /&gt;
&lt;br /&gt;
* To invoke ODE, add the option:&lt;br /&gt;
 -physics=OpenDynamicsEngine&lt;br /&gt;
to the &amp;lt;tt&amp;gt;mono OpenSim.exe&amp;lt;/tt&amp;gt; line&lt;br /&gt;
&lt;br /&gt;
or add &amp;lt;code&amp;gt;  physics = OpenDynamicsEngine &amp;lt;/code&amp;gt; to the [Startup] section of &amp;lt;tt&amp;gt;OpenSim.ini&amp;lt;/tt&amp;gt;.  Same deal for other physics engines, when available.&lt;br /&gt;
&lt;br /&gt;
On mono 1.2.6, some distributions may see&lt;br /&gt;
 Unhandled Exception: System.NotSupportedException: CodePage 1252 not supported&lt;br /&gt;
on startup when using mysql.  This can be resolved by installing the package libmono-i18n2.0-cil (see http://bugs.mysql.com/bug.php?id=33938).&lt;br /&gt;
&lt;br /&gt;
=== Additional Items ===&lt;br /&gt;
&lt;br /&gt;
* [[GC_NO_EXPLICIT|GC NO EXPLICIT]] - Enable Large Heap in Mono, this has been known to help performance and stability&lt;br /&gt;
&lt;br /&gt;
[[Category:Users]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/LLUDP_Dissector</id>
		<title>LLUDP Dissector</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/LLUDP_Dissector"/>
				<updated>2008-10-14T02:40:18Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== LLUDP protocol dissector ==&lt;br /&gt;
On this page you will find the Lua code for a wireshark protocol dissector that can parse the message_template.msg file and use that information to decode all the message fields from the Linden UDP protocol.&lt;br /&gt;
&lt;br /&gt;
== Installing ==&lt;br /&gt;
* Requires wireshark with Lua 5.1.x support.  [http://wiki.wireshark.org/Lua See this page for getting wireshark to support lua]&lt;br /&gt;
&lt;br /&gt;
=== on Linux ===&lt;br /&gt;
* Copy all four source files into ~/.wireshark&lt;br /&gt;
* edit ''/etc/wireshark/init.lua'' (or equivalent on your system) and change ''disable_lua'' to ''false'' (default is true)&lt;br /&gt;
* If you need to run wireshark as the root user or using sudo then you will need to edit the scripts into one file by replacing the dofile(&amp;quot;script.lua&amp;quot;) calls with the contents of file between the quotes.&lt;br /&gt;
* The other method is to add your user account to the correct group (on Gentoo it is group &amp;quot;wireshark&amp;quot;) that will allow your non-root user to capture packets.&lt;br /&gt;
&lt;br /&gt;
=== on Windows ===&lt;br /&gt;
* Copy all four source files into your user profiles directory &lt;br /&gt;
&lt;br /&gt;
'''Vista*'''&lt;br /&gt;
&lt;br /&gt;
    C:\Users\&amp;lt;username&amp;gt;\AppData\Roaming\Wireshark &lt;br /&gt;
&lt;br /&gt;
'''XP/2000'''&lt;br /&gt;
&lt;br /&gt;
    C:\Documents and Settings\&amp;lt;username&amp;gt;\Application Data\Wireshark&lt;br /&gt;
&lt;br /&gt;
* Edit C:\Program Files\Wireshark\init.lua and change ''disable_lua'' to ''false''  (default is true)&lt;br /&gt;
&lt;br /&gt;
* *Note: I have only tested this on Windows XP&lt;br /&gt;
&lt;br /&gt;
== LLUDP preferences ==&lt;br /&gt;
There are three preferences that can be changed from wiresharks &amp;quot;Preferences&amp;quot; dialog:&lt;br /&gt;
* Message template file: Full path to the message_template.msg file used to decode message name &amp;amp; details from the packets.  On windows XP/Vista use double backslash '\\' instead of single blackslash '\' to separate directories (Example &amp;quot;C:\\Program Files\\SecondLife\\app_settings\\message_template.msg&amp;quot;).&lt;br /&gt;
* UDP port range start: First UDP port to mark as LLUDP packets. (default 13000)&lt;br /&gt;
* UDP port range end: Last UDP port to mark as LLUDP packets. (default 13050)&lt;br /&gt;
&lt;br /&gt;
If your OpenSim regions are using ports 9000-9050 range then change the UDP port range.&lt;br /&gt;
&lt;br /&gt;
== Description of source files ==&lt;br /&gt;
* &amp;quot;init.lua&amp;quot; -- simple script that loads the &amp;quot;lludp.lua&amp;quot; script.&lt;br /&gt;
* &amp;quot;lludp.lua&amp;quot; -- contains the code that decodes each packet header and decompresses zero-encoded packets.  This file uses wireshark only functions for accessing packet bytes and building a tree of information from each packet.&lt;br /&gt;
* &amp;quot;llmessage.lua&amp;quot; -- contains the message_template.msg file parser the decodes the tokens from the lexer into an tree of tables containing all details about each message/block/variable from the template file.  This file only has pure lua code.&lt;br /&gt;
* &amp;quot;lexer.lua&amp;quot; -- contains the template file lexer.  This lexer knows how to tokenize the template file into the follow tokens: IDENTIFIER, NUMBER, COMMENT, EOL.  The stream of tokens produced by this lexer is parsed by the &amp;quot;llmessage.lua&amp;quot; file.  This file only has pure lua code.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== File &amp;quot;init.lua&amp;quot; ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
-- register http to handle tcp ports 8000-8010 and 9000&lt;br /&gt;
do&lt;br /&gt;
  local tcp_port_table = DissectorTable.get(&amp;quot;tcp.port&amp;quot;)&lt;br /&gt;
  local http_dissector = tcp_port_table:get_dissector(80)&lt;br /&gt;
  for port = 8000,8010 do&lt;br /&gt;
    tcp_port_table:add(port,http_dissector)&lt;br /&gt;
  end&lt;br /&gt;
  tcp_port_table:add(9000,http_dissector)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Load lludp protocol dissector.&lt;br /&gt;
dofile(&amp;quot;lludp.lua&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== File &amp;quot;lludp.lua&amp;quot; ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
--[[&lt;br /&gt;
BSD-Licensed:&lt;br /&gt;
Copyright (c) 2008, Robert G. Jakabosky &amp;lt;bobby@sharedrealm.com&amp;gt;&lt;br /&gt;
All rights reserved.&lt;br /&gt;
&lt;br /&gt;
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:&lt;br /&gt;
&lt;br /&gt;
    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.&lt;br /&gt;
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.&lt;br /&gt;
    * Neither the name of the SharedRealm nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.&lt;br /&gt;
&lt;br /&gt;
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &amp;quot;AS IS&amp;quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
dofile(&amp;quot;llmessage.lua&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
-- cache globals to local for speed.&lt;br /&gt;
local str_format=string.format&lt;br /&gt;
&lt;br /&gt;
-- test if ByteArray only has printable ASCII character and ends with '\0'&lt;br /&gt;
local allowed_special = {&lt;br /&gt;
	[0] = true, -- null&lt;br /&gt;
	[9] = true, -- tab&lt;br /&gt;
	[10] = true, -- new line&lt;br /&gt;
	[13] = true, -- carriage return&lt;br /&gt;
}&lt;br /&gt;
local function is_string(bytes)&lt;br /&gt;
	local c&lt;br /&gt;
	local max = bytes:len() - 1&lt;br /&gt;
	for i=0,max do&lt;br /&gt;
		c = bytes:get_index(i)&lt;br /&gt;
		if c &amp;gt;= 127 then -- not ascii character&lt;br /&gt;
			return false&lt;br /&gt;
		elseif c &amp;lt; 32 then  -- control character range&lt;br /&gt;
			if not allowed_special[c] then&lt;br /&gt;
				-- control characters between NULL and Space&lt;br /&gt;
				return false&lt;br /&gt;
			elseif c == 0 and i &amp;lt; max then&lt;br /&gt;
				-- null byte only allowed at end.&lt;br /&gt;
				return false&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- lludp protocol example&lt;br /&gt;
-- declare our protocol&lt;br /&gt;
local lludp_proto = Proto(&amp;quot;lludp&amp;quot;,&amp;quot;LLUDP&amp;quot;,&amp;quot;LindenLabs UDP Protocol&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
-- setup preferences&lt;br /&gt;
lludp_proto.prefs[&amp;quot;template_file&amp;quot;] =&lt;br /&gt;
	Pref.string(&amp;quot;Message template file&amp;quot;, &amp;quot;message_template.msg&amp;quot;, &amp;quot;Message template file&amp;quot;)&lt;br /&gt;
lludp_proto.prefs[&amp;quot;udp_port_start&amp;quot;] =&lt;br /&gt;
	Pref.string(&amp;quot;UDP port range start&amp;quot;, &amp;quot;13000&amp;quot;, &amp;quot;First UDP port to decode as this protocol&amp;quot;)&lt;br /&gt;
lludp_proto.prefs[&amp;quot;udp_port_end&amp;quot;] =&lt;br /&gt;
	Pref.string(&amp;quot;UDP port range end&amp;quot;, &amp;quot;13050&amp;quot;, &amp;quot;Last UDP port to decode as this protocol&amp;quot;)&lt;br /&gt;
-- current preferences settings.&lt;br /&gt;
local current_settings = {&lt;br /&gt;
template_file = &amp;quot;&amp;quot;,&lt;br /&gt;
udp_port_start = -1,&lt;br /&gt;
udp_port_end = -1,&lt;br /&gt;
}&lt;br /&gt;
-- current list of parsed messages.&lt;br /&gt;
local message_details = nil&lt;br /&gt;
&lt;br /&gt;
-- setup protocol fields.&lt;br /&gt;
lludp_proto.fields = {}&lt;br /&gt;
local fds = lludp_proto.fields&lt;br /&gt;
fds.flags = ProtoField.new(&amp;quot;Flags&amp;quot;, &amp;quot;lludp.flags&amp;quot;, &amp;quot;FT_UINT8&amp;quot;, nil, &amp;quot;BASE_HEX&amp;quot;, &amp;quot;0xFF&amp;quot;)&lt;br /&gt;
fds.flags_zero = ProtoField.new(&amp;quot;Zero&amp;quot;, &amp;quot;lludp.flags.zero&amp;quot;, &amp;quot;FT_UINT8&amp;quot;, nil, &amp;quot;BASE_HEX&amp;quot;, &amp;quot;0x80&amp;quot;)&lt;br /&gt;
fds.flags_reliable = ProtoField.new(&amp;quot;Reliable&amp;quot;, &amp;quot;lludp.flags.rel&amp;quot;, &amp;quot;FT_UINT8&amp;quot;, nil, &amp;quot;BASE_HEX&amp;quot;, &amp;quot;0x40&amp;quot;)&lt;br /&gt;
fds.flags_resent = ProtoField.new(&amp;quot;Resent&amp;quot;, &amp;quot;lludp.flags.res&amp;quot;, &amp;quot;FT_UINT8&amp;quot;, nil, &amp;quot;BASE_HEX&amp;quot;, &amp;quot;0x20&amp;quot;)&lt;br /&gt;
fds.flags_ack = ProtoField.new(&amp;quot;Ack&amp;quot;, &amp;quot;lludp.flags.ack&amp;quot;, &amp;quot;FT_UINT8&amp;quot;, nil, &amp;quot;BASE_HEX&amp;quot;, &amp;quot;0x10&amp;quot;)&lt;br /&gt;
fds.sequence = ProtoField.new(&amp;quot;Sequence&amp;quot;, &amp;quot;lludp.sequence&amp;quot;, &amp;quot;FT_UINT32&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
fds.extra_len = ProtoField.new(&amp;quot;Extra length&amp;quot;, &amp;quot;lludp.extra_len&amp;quot;, &amp;quot;FT_UINT8&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
fds.extra_bytes = ProtoField.new(&amp;quot;Extra header&amp;quot;, &amp;quot;lludp.extra_bytes&amp;quot;, &amp;quot;FT_BYTES&amp;quot;, nil, &amp;quot;BASE_HEX&amp;quot;)&lt;br /&gt;
fds.msg_id = ProtoField.new(&amp;quot;Message ID&amp;quot;, &amp;quot;lludp.msg.id&amp;quot;, &amp;quot;FT_UINT32&amp;quot;, nil, &amp;quot;BASE_HEX&amp;quot;)&lt;br /&gt;
fds.msg_name = ProtoField.new(&amp;quot;Message name&amp;quot;, &amp;quot;lludp.msg.name&amp;quot;, &amp;quot;FT_STRINGZ&amp;quot;, nil)&lt;br /&gt;
fds.msg = ProtoField.new(&amp;quot;Message body&amp;quot;, &amp;quot;lludp.msg&amp;quot;, &amp;quot;FT_BYTES&amp;quot;, nil, &amp;quot;BASE_HEX&amp;quot;)&lt;br /&gt;
fds.acks_count = ProtoField.new(&amp;quot;Acks count&amp;quot;, &amp;quot;lludp.acks_count&amp;quot;, &amp;quot;FT_UINT8&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
fds.acks = ProtoField.new(&amp;quot;Acks&amp;quot;, &amp;quot;lludp.acks&amp;quot;, &amp;quot;FT_UINT32&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
fds.block_count = ProtoField.new(&amp;quot;Block count&amp;quot;, &amp;quot;lludp.block_count&amp;quot;, &amp;quot;FT_UINT8&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
fds.block = ProtoField.new(&amp;quot;Block&amp;quot;, &amp;quot;lludp.block&amp;quot;, &amp;quot;FT_BYTES&amp;quot;, nil, &amp;quot;BASE_HEX&amp;quot;)&lt;br /&gt;
fds.var_fixed = ProtoField.new(&amp;quot;Fixed blob&amp;quot;, &amp;quot;lludp.var.fixed&amp;quot;, &amp;quot;FT_BYTES&amp;quot;, nil, &amp;quot;BASE_HEX&amp;quot;)&lt;br /&gt;
fds.var_variable = ProtoField.new(&amp;quot;Variable blob&amp;quot;, &amp;quot;lludp.var.variable&amp;quot;, &amp;quot;FT_BYTES&amp;quot;, nil, &amp;quot;BASE_HEX&amp;quot;)&lt;br /&gt;
fds.var_string = ProtoField.new(&amp;quot;String&amp;quot;, &amp;quot;lludp.var.string&amp;quot;, &amp;quot;FT_STRINGZ&amp;quot;, nil)&lt;br /&gt;
fds.var_u8 = ProtoField.new(&amp;quot;U8&amp;quot;, &amp;quot;lludp.var.u8&amp;quot;, &amp;quot;FT_UINT8&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
fds.var_u16 = ProtoField.new(&amp;quot;U16&amp;quot;, &amp;quot;lludp.var.u16&amp;quot;, &amp;quot;FT_UINT16&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
fds.var_u32 = ProtoField.new(&amp;quot;U32&amp;quot;, &amp;quot;lludp.var.u32&amp;quot;, &amp;quot;FT_UINT32&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
fds.var_u64 = ProtoField.new(&amp;quot;U64&amp;quot;, &amp;quot;lludp.var.u64&amp;quot;, &amp;quot;FT_UINT64&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
fds.var_s8 = ProtoField.new(&amp;quot;S8&amp;quot;, &amp;quot;lludp.var.s8&amp;quot;, &amp;quot;FT_INT8&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
fds.var_s16 = ProtoField.new(&amp;quot;S16&amp;quot;, &amp;quot;lludp.var.s16&amp;quot;, &amp;quot;FT_INT16&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
fds.var_s32 = ProtoField.new(&amp;quot;S32&amp;quot;, &amp;quot;lludp.var.s32&amp;quot;, &amp;quot;FT_INT32&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
fds.var_s64 = ProtoField.new(&amp;quot;S64&amp;quot;, &amp;quot;lludp.var.s64&amp;quot;, &amp;quot;FT_INT64&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
fds.var_f32 = ProtoField.new(&amp;quot;F32&amp;quot;, &amp;quot;lludp.var.f32&amp;quot;, &amp;quot;FT_FLOAT&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
fds.var_f64 = ProtoField.new(&amp;quot;F64&amp;quot;, &amp;quot;lludp.var.f64&amp;quot;, &amp;quot;FT_DOUBLE&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
fds.var_llvector3 = ProtoField.new(&amp;quot;LLVector3&amp;quot;, &amp;quot;lludp.var.llvector3&amp;quot;, &amp;quot;FT_BYTES&amp;quot;, nil, &amp;quot;BASE_HEX&amp;quot;)&lt;br /&gt;
fds.var_llvector3d = ProtoField.new(&amp;quot;LLVector3d&amp;quot;, &amp;quot;lludp.var.llvector3d&amp;quot;, &amp;quot;FT_BYTES&amp;quot;, nil, &amp;quot;BASE_HEX&amp;quot;)&lt;br /&gt;
fds.var_llvector4 = ProtoField.new(&amp;quot;LLVector4&amp;quot;, &amp;quot;lludp.var.llvector4&amp;quot;, &amp;quot;FT_BYTES&amp;quot;, nil, &amp;quot;BASE_HEX&amp;quot;)&lt;br /&gt;
fds.var_llquaternion = ProtoField.new(&amp;quot;LLQuaternion&amp;quot;, &amp;quot;lludp.var.llquaternion&amp;quot;, &amp;quot;FT_BYTES&amp;quot;, nil, &amp;quot;BASE_HEX&amp;quot;)&lt;br /&gt;
fds.var_lluid = ProtoField.new(&amp;quot;LLUID&amp;quot;, &amp;quot;lludp.var.lluid&amp;quot;, &amp;quot;FT_BYTES&amp;quot;, nil, &amp;quot;BASE_HEX&amp;quot;)&lt;br /&gt;
fds.var_bool = ProtoField.new(&amp;quot;BOOL&amp;quot;, &amp;quot;lludp.var.bool&amp;quot;, &amp;quot;FT_UINT8&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
fds.var_ipaddr = ProtoField.new(&amp;quot;IPADDR&amp;quot;, &amp;quot;lludp.var.ipaddr&amp;quot;, &amp;quot;FT_IPv4&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
fds.var_ipport = ProtoField.new(&amp;quot;IPPORT&amp;quot;, &amp;quot;lludp.var.ipport&amp;quot;, &amp;quot;FT_UINT16&amp;quot;, nil, &amp;quot;BASE_DEC&amp;quot;)&lt;br /&gt;
-- variable type handlers.&lt;br /&gt;
local variable_handlers = {&lt;br /&gt;
Fixed = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add_le(fds.var_fixed, rang)&lt;br /&gt;
	if len &amp;lt;= 4 then&lt;br /&gt;
		ti:set_text(str_format(&amp;quot;%s: 0x%08x&amp;quot;,var.name, rang:uint()))&lt;br /&gt;
	else&lt;br /&gt;
		ti:set_text(str_format(&amp;quot;%s: length=%d, Blob:%s&amp;quot;, var.name, len, tostring(rang)))&lt;br /&gt;
	end&lt;br /&gt;
end,&lt;br /&gt;
Variable = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local is_data = false&lt;br /&gt;
	-- try to guess if this field is text.&lt;br /&gt;
	if var.name:find(&amp;quot;Data&amp;quot;) then&lt;br /&gt;
		-- this is a data find.&lt;br /&gt;
		is_data = true&lt;br /&gt;
	end&lt;br /&gt;
	local str_rang = buffer(offset + var.count_length, len - var.count_length)&lt;br /&gt;
	local bytes = str_rang:bytes()&lt;br /&gt;
	if not is_data and is_string(bytes) then&lt;br /&gt;
		local str = str_rang:string()&lt;br /&gt;
		local ti = block_tree:add(fds.var_string, buffer(offset, len), str)&lt;br /&gt;
		ti:set_text(str_format(&amp;quot;%s: %s&amp;quot;, var.name, str))&lt;br /&gt;
	else&lt;br /&gt;
		local rang = buffer(offset, len)&lt;br /&gt;
		local ti = block_tree:add_le(fds.var_variable, rang)&lt;br /&gt;
		if len &amp;lt;= 4 then&lt;br /&gt;
			ti:set_text(str_format(&amp;quot;%s: 0x%08x&amp;quot;,var.name, rang:uint()))&lt;br /&gt;
		else&lt;br /&gt;
			ti:set_text(str_format(&amp;quot;%s: length=%d, Blob:%s&amp;quot;, var.name, len, tostring(rang)))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end,&lt;br /&gt;
U8 = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add_le(fds.var_u8, rang)&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: %d&amp;quot;, var.name, rang:le_uint()))&lt;br /&gt;
end,&lt;br /&gt;
U16 = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add_le(fds.var_u16, rang)&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: %d&amp;quot;, var.name, rang:le_uint()))&lt;br /&gt;
end,&lt;br /&gt;
U32 = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add_le(fds.var_u32, rang)&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: %d&amp;quot;, var.name, rang:le_uint()))&lt;br /&gt;
end,&lt;br /&gt;
U64 = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add_le(fds.var_u64, rang)&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: 0x%s&amp;quot;,var.name, tostring(rang)))&lt;br /&gt;
end,&lt;br /&gt;
S8 = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add_le(fds.var_s8, rang)&lt;br /&gt;
	local num = rang:le_uint()&lt;br /&gt;
	if num &amp;gt; 127 then num = num - 256 end&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: %d&amp;quot;,var.name, num))&lt;br /&gt;
end,&lt;br /&gt;
S16 = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add_le(fds.var_s16, rang)&lt;br /&gt;
	local num = rang:le_uint()&lt;br /&gt;
	if num &amp;gt; 32768 then num = num - 65536 end&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: %d&amp;quot;,var.name, num))&lt;br /&gt;
end,&lt;br /&gt;
S32 = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add_le(fds.var_s32, rang)&lt;br /&gt;
	local num = rang:le_uint()&lt;br /&gt;
	if num &amp;gt; 2147483648 then num = num - 4294967296 end&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: %d&amp;quot;,var.name, num))&lt;br /&gt;
end,&lt;br /&gt;
S64 = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add_le(fds.var_s64, rang)&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: 0x%s&amp;quot;,var.name, tostring(rang)))&lt;br /&gt;
end,&lt;br /&gt;
F32 = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add_le(fds.var_f32, rang)&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: %f&amp;quot;, var.name, rang:le_float()))&lt;br /&gt;
end,&lt;br /&gt;
F64 = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add_le(fds.var_f64, rang)&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: %f&amp;quot;, var.name, rang:le_float()))&lt;br /&gt;
end,&lt;br /&gt;
LLVector3 = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add_le(fds.var_llvector3, rang)&lt;br /&gt;
	-- parse LLVector3&lt;br /&gt;
	local x,y,z&lt;br /&gt;
	x = buffer(offset + 0,4):le_float()&lt;br /&gt;
	y = buffer(offset + 4,4):le_float()&lt;br /&gt;
	z = buffer(offset + 8,4):le_float()&lt;br /&gt;
	-- display&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: &amp;lt;%f,%f,%f&amp;gt;&amp;quot;, var.name, x, y, z))&lt;br /&gt;
end,&lt;br /&gt;
LLVector3d = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add_le(fds.var_llvector3d, rang)&lt;br /&gt;
	-- parse LLVector3d&lt;br /&gt;
	local x,y,z&lt;br /&gt;
	x = buffer(offset + 0,8):le_float()&lt;br /&gt;
	y = buffer(offset + 8,8):le_float()&lt;br /&gt;
	z = buffer(offset + 16,8):le_float()&lt;br /&gt;
	-- display&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: &amp;lt;%f,%f,%f&amp;gt;&amp;quot;, var.name, x, y, z))&lt;br /&gt;
end,&lt;br /&gt;
LLVector4 = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add_le(fds.var_llvector4, rang)&lt;br /&gt;
	-- parse LLVector4&lt;br /&gt;
	local x,y,z,s&lt;br /&gt;
	x = buffer(offset + 0,4):le_float()&lt;br /&gt;
	y = buffer(offset + 4,4):le_float()&lt;br /&gt;
	z = buffer(offset + 8,4):le_float()&lt;br /&gt;
	s = buffer(offset + 12,4):le_float()&lt;br /&gt;
	-- display&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: &amp;lt;%f,%f,%f,%f&amp;gt;&amp;quot;, var.name, x, y, z, s))&lt;br /&gt;
end,&lt;br /&gt;
LLQuaternion = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add_le(fds.var_llquaternion, rang)&lt;br /&gt;
	-- parse LLQuaternion&lt;br /&gt;
	local x,y,z,w&lt;br /&gt;
	x = buffer(offset + 0,4):le_float()&lt;br /&gt;
	y = buffer(offset + 4,4):le_float()&lt;br /&gt;
	z = buffer(offset + 8,4):le_float()&lt;br /&gt;
	-- calculate W&lt;br /&gt;
	w = 1 - (x * x) - (y * y) - (z * z)&lt;br /&gt;
	if w &amp;gt; 0 then&lt;br /&gt;
		w = math.sqrt(w)&lt;br /&gt;
	else&lt;br /&gt;
		w = 0&lt;br /&gt;
	end&lt;br /&gt;
	-- display&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: &amp;lt;%f,%f,%f,%f&amp;gt;&amp;quot;, var.name, x, y, z, w))&lt;br /&gt;
end,&lt;br /&gt;
LLUUID = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add_le(fds.var_lluid, rang)&lt;br /&gt;
	local str = tostring(rang)&lt;br /&gt;
	str = str:sub(1,8) .. '-' ..&lt;br /&gt;
		str:sub(9,12) .. '-' .. str:sub(13,16) .. '-' ..&lt;br /&gt;
		str:sub(17,20) .. '-' .. str:sub(21)&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: %s&amp;quot;, var.name, str))&lt;br /&gt;
end,&lt;br /&gt;
BOOL = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add_le(fds.var_bool, rang)&lt;br /&gt;
	local val = &amp;quot;false&amp;quot;&lt;br /&gt;
	if rang:le_uint() &amp;gt; 0 then&lt;br /&gt;
		val = &amp;quot;true&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: %s&amp;quot;, var.name, val))&lt;br /&gt;
end,&lt;br /&gt;
IPADDR = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add(fds.var_ipaddr, rang)&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: %s&amp;quot;, var.name, tostring(rang:ipv4())))&lt;br /&gt;
end,&lt;br /&gt;
IPPORT = function(block_tree, buffer, offset, len, var)&lt;br /&gt;
	local rang = buffer(offset, len)&lt;br /&gt;
	local ti = block_tree:add(fds.var_ipport, rang)&lt;br /&gt;
	ti:set_text(str_format(&amp;quot;%s: %d&amp;quot;, var.name, rang:uint()))&lt;br /&gt;
end,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
-- un-register lludp to handle udp port range&lt;br /&gt;
local function unregister_udp_port_range(start_port, end_port)&lt;br /&gt;
	if not start_port or start_port &amp;lt;= 0 or not end_port or end_port &amp;lt;= 0 then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
  udp_port_table = DissectorTable.get(&amp;quot;udp.port&amp;quot;)&lt;br /&gt;
  for port = start_port,end_port do&lt;br /&gt;
    udp_port_table:remove(port,lludp_proto)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- register lludp to handle udp port range&lt;br /&gt;
local function register_udp_port_range(start_port, end_port)&lt;br /&gt;
	if not start_port or start_port &amp;lt;= 0 or not end_port or end_port &amp;lt;= 0 then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
  udp_port_table = DissectorTable.get(&amp;quot;udp.port&amp;quot;)&lt;br /&gt;
  for port = start_port,end_port do&lt;br /&gt;
    udp_port_table:add(port,lludp_proto)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- handle preferences changes.&lt;br /&gt;
function lludp_proto.init(arg1, arg2)&lt;br /&gt;
	local old_start, old_end&lt;br /&gt;
	local new_start, new_end&lt;br /&gt;
	-- check if preferences have changed.&lt;br /&gt;
	for pref_name,old_v in pairs(current_settings) do&lt;br /&gt;
		local new_v = lludp_proto.prefs[pref_name]&lt;br /&gt;
		if new_v ~= old_v then&lt;br /&gt;
			if pref_name == &amp;quot;template_file&amp;quot; then&lt;br /&gt;
				-- load &amp;amp; parse message_template.msg file.&lt;br /&gt;
				local file = new_v&lt;br /&gt;
				if file and file:len() &amp;gt; 0 then&lt;br /&gt;
					local new_details = parse_template(file)&lt;br /&gt;
					if new_details then&lt;br /&gt;
						message_details = new_details&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			elseif pref_name == &amp;quot;udp_port_start&amp;quot; then&lt;br /&gt;
				old_start = old_v&lt;br /&gt;
				new_start = new_v&lt;br /&gt;
			elseif pref_name == &amp;quot;udp_port_end&amp;quot; then&lt;br /&gt;
				old_end = old_v&lt;br /&gt;
				new_end = new_v&lt;br /&gt;
			end&lt;br /&gt;
			-- save new value.&lt;br /&gt;
			current_settings[pref_name] = new_v&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	-- un-register old port range&lt;br /&gt;
	if old_start and old_end then&lt;br /&gt;
		unregister_udp_port_range(tonumber(old_start), tonumber(old_end))&lt;br /&gt;
	end&lt;br /&gt;
	-- register new port range.&lt;br /&gt;
	if new_start and new_end then&lt;br /&gt;
		register_udp_port_range(tonumber(new_start), tonumber(new_end))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- parse flag bits.&lt;br /&gt;
local FLAG_ZER = 4&lt;br /&gt;
local FLAG_REL = 3&lt;br /&gt;
local FLAG_RES = 2&lt;br /&gt;
local FLAG_ACK = 1&lt;br /&gt;
local flag_names = {&amp;quot;ACK&amp;quot;, &amp;quot;RES&amp;quot;, &amp;quot;REL&amp;quot;, &amp;quot;ZER&amp;quot;}&lt;br /&gt;
local bits_lookup = {&lt;br /&gt;
	{},&lt;br /&gt;
	{1},&lt;br /&gt;
	{2},&lt;br /&gt;
	{2,1},&lt;br /&gt;
	{3},&lt;br /&gt;
	{3,1},&lt;br /&gt;
	{3,2},&lt;br /&gt;
	{3,2,1},&lt;br /&gt;
	{4},&lt;br /&gt;
	{4,1},&lt;br /&gt;
	{4,2},&lt;br /&gt;
	{4,2,1},&lt;br /&gt;
	{4,3},&lt;br /&gt;
	{4,3,1},&lt;br /&gt;
	{4,3,2},&lt;br /&gt;
	{4,3,2,1},&lt;br /&gt;
}&lt;br /&gt;
local function parse_flags(flags)&lt;br /&gt;
	flags = (flags / 16) + 1&lt;br /&gt;
	local bit_list = bits_lookup[flags]&lt;br /&gt;
	local bits = {}&lt;br /&gt;
	local names = &amp;quot;&amp;quot;&lt;br /&gt;
	for _, bit in ipairs(bit_list) do&lt;br /&gt;
		bits[bit] = true&lt;br /&gt;
		if names:len() &amp;gt; 0 then&lt;br /&gt;
			names = names .. &amp;quot;, &amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
		names = names .. flag_names[bit]&lt;br /&gt;
	end&lt;br /&gt;
	return bits, names&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function grow_buff(buff, size)&lt;br /&gt;
	local old_size = buff:len()&lt;br /&gt;
	if old_size &amp;gt; size then return end&lt;br /&gt;
	-- buffer needs to grow&lt;br /&gt;
	buff:set_size(size)&lt;br /&gt;
	-- fill new space with zeros&lt;br /&gt;
	for i = old_size,size-1 do&lt;br /&gt;
		buff:set_index(i, 0)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function zero_decode(zero_buf)&lt;br /&gt;
	local out_buf = ByteArray.new()&lt;br /&gt;
	local zero_off = 0&lt;br /&gt;
	local zero_len = zero_buf:len()&lt;br /&gt;
	local out_size = 0&lt;br /&gt;
	local out_off = 0&lt;br /&gt;
	local b&lt;br /&gt;
	-- pre-allocate&lt;br /&gt;
	grow_buff(out_buf, zero_len)&lt;br /&gt;
	out_size = zero_len&lt;br /&gt;
	-- zero expand&lt;br /&gt;
	repeat&lt;br /&gt;
		b = zero_buf:get_index(zero_off)&lt;br /&gt;
		if b == 0 then&lt;br /&gt;
			-- get zero count&lt;br /&gt;
			local count = zero_buf:get_index(zero_off + 1)&lt;br /&gt;
			if count == 0 then count = 255 end&lt;br /&gt;
			out_off = out_off + count&lt;br /&gt;
			-- fill zeros&lt;br /&gt;
			if out_off &amp;gt; out_size then&lt;br /&gt;
				out_size = out_off + 128&lt;br /&gt;
				grow_buff(out_buf, out_size)&lt;br /&gt;
			end&lt;br /&gt;
			zero_off = zero_off + 2&lt;br /&gt;
		else&lt;br /&gt;
			if out_off &amp;gt;= out_size then&lt;br /&gt;
				out_size = out_off + (zero_len - zero_off) + 4&lt;br /&gt;
				grow_buff(out_buf, out_size)&lt;br /&gt;
			end&lt;br /&gt;
			-- copy non-zero bytes.&lt;br /&gt;
			out_buf:set_index(out_off,b)&lt;br /&gt;
			zero_off = zero_off + 1&lt;br /&gt;
			out_off = out_off + 1&lt;br /&gt;
		end&lt;br /&gt;
	until zero_off == zero_len&lt;br /&gt;
	-- truncate to real size.&lt;br /&gt;
	out_buf:set_size(out_off)&lt;br /&gt;
&lt;br /&gt;
	return out_buf:tvb(&amp;quot;Decompressed Data&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function parse_msg_id(buff)&lt;br /&gt;
	local b = buff:get_index(0)&lt;br /&gt;
	local msg_id = b&lt;br /&gt;
	local msg_id_len = 1&lt;br /&gt;
	if b == 255 then&lt;br /&gt;
		b = buff:get_index(1)&lt;br /&gt;
		msg_id = msg_id * 256 + b&lt;br /&gt;
		msg_id_len = 2&lt;br /&gt;
		if b == 255 then&lt;br /&gt;
			b = buff:get_index(2)&lt;br /&gt;
			msg_id = msg_id * 256 + b&lt;br /&gt;
			b = buff:get_index(3)&lt;br /&gt;
			msg_id = msg_id * 256 + b&lt;br /&gt;
			msg_id_len = 4&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return msg_id, msg_id_len&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- get message name.&lt;br /&gt;
local function get_msg_name(msg_id)&lt;br /&gt;
	-- check that we have message details&lt;br /&gt;
	if message_details == nil then&lt;br /&gt;
		return str_format(&amp;quot;0x%08x&amp;quot;, msg_id)&lt;br /&gt;
	end&lt;br /&gt;
	-- find message name from id.&lt;br /&gt;
	local msg = message_details.msgs[msg_id]&lt;br /&gt;
	-- Invalid message id&lt;br /&gt;
	if msg == nil then&lt;br /&gt;
		return str_format(&amp;quot;0x%08x&amp;quot;, msg_id)&lt;br /&gt;
	end&lt;br /&gt;
	return msg.name&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
-- calculate length a block.&lt;br /&gt;
local function get_block_length(msg_buffer, start_offset, block)&lt;br /&gt;
	-- check if bock is fixed length.&lt;br /&gt;
	if block.fixed_length then&lt;br /&gt;
		return block.min_length&lt;br /&gt;
	end&lt;br /&gt;
	-- parse block's variables to calculate total block length.&lt;br /&gt;
	local offset = start_offset&lt;br /&gt;
	local rang&lt;br /&gt;
	for _,var in ipairs(block) do&lt;br /&gt;
		local len = 0&lt;br /&gt;
		if var.has_count then&lt;br /&gt;
			-- variable with length bytes.&lt;br /&gt;
			len = var.count_length&lt;br /&gt;
			--print(var.name, offset, &amp;quot;, len:&amp;quot;, len)&lt;br /&gt;
			rang = msg_buffer(offset, len)&lt;br /&gt;
			len = len + rang:le_uint()&lt;br /&gt;
			--print(var.name, var.count_length, &amp;quot;, total:&amp;quot;, len)&lt;br /&gt;
		else&lt;br /&gt;
			-- fixed length variable&lt;br /&gt;
			len = var.length&lt;br /&gt;
			--print(var.name, &amp;quot;, total:&amp;quot;, len)&lt;br /&gt;
		end&lt;br /&gt;
		offset = offset + len&lt;br /&gt;
	end&lt;br /&gt;
	return (offset - start_offset)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- build block tree&lt;br /&gt;
local function build_block_tree(msg_buffer, block_tree, start_offset, block)&lt;br /&gt;
	local offset = start_offset&lt;br /&gt;
	local rang&lt;br /&gt;
	-- parse block's variables&lt;br /&gt;
	for _,var in ipairs(block) do&lt;br /&gt;
		local len = 0&lt;br /&gt;
		if var.has_count then&lt;br /&gt;
			-- variable with length bytes.&lt;br /&gt;
			len = var.count_length&lt;br /&gt;
			rang = msg_buffer(offset, len)&lt;br /&gt;
			len = len + rang:le_uint()&lt;br /&gt;
		else&lt;br /&gt;
			-- fixed length variable&lt;br /&gt;
			len = var.length&lt;br /&gt;
		end&lt;br /&gt;
		-- get variable's type field.&lt;br /&gt;
		local handler = variable_handlers[var.type]&lt;br /&gt;
		-- parse variable.&lt;br /&gt;
		if handler then&lt;br /&gt;
			handler(block_tree, msg_buffer, offset, len, var)&lt;br /&gt;
		end&lt;br /&gt;
		offset = offset + len&lt;br /&gt;
	end&lt;br /&gt;
	return (offset - start_offset)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- buid message tree&lt;br /&gt;
local function build_msg_tree(msg_buffer, msg_tree, msg_id)&lt;br /&gt;
	local offset = 0&lt;br /&gt;
	local rang&lt;br /&gt;
	-- check that we have message details&lt;br /&gt;
	if message_details == nil then&lt;br /&gt;
		msg_tree:set_text(str_format(&amp;quot;Message Id: 0x%08x&amp;quot;, msg_id))&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	-- find message name from id.&lt;br /&gt;
	local msg = message_details.msgs[msg_id]&lt;br /&gt;
	-- Invalid message id&lt;br /&gt;
	if msg == nil then&lt;br /&gt;
		msg = str_format(&amp;quot;Invalid message id: 0x%08x&amp;quot;, msg_id)&lt;br /&gt;
		msg_tree:add_expert_info(PI_MALFORMED, PI_ERROR, msg)&lt;br /&gt;
		msg_tree:set_text(msg)&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	-- skip message id bytes.&lt;br /&gt;
	offset = msg.id_length&lt;br /&gt;
  -- set message name.&lt;br /&gt;
	msg_tree:set_text(msg.name .. &amp;quot;:&amp;quot;)&lt;br /&gt;
	-- proccess message blocks&lt;br /&gt;
	for _,block in ipairs(msg) do&lt;br /&gt;
		local count = block.count&lt;br /&gt;
		if count == nil then&lt;br /&gt;
			-- parse count byte.&lt;br /&gt;
			rang = msg_buffer(offset,1)&lt;br /&gt;
			count = rang:uint()&lt;br /&gt;
  		msg_tree:add(fds.block_count,rang)&lt;br /&gt;
			offset = offset + 1&lt;br /&gt;
		end&lt;br /&gt;
		-- print(&amp;quot;block name: &amp;quot;, block.name, count)&lt;br /&gt;
		for n=1,count do&lt;br /&gt;
			local block_len = get_block_length(msg_buffer, offset, block)&lt;br /&gt;
			-- parse block&lt;br /&gt;
			rang = msg_buffer(offset, block_len)&lt;br /&gt;
  		local block_tree = msg_tree:add(fds.block,rang)&lt;br /&gt;
			if count &amp;gt; 1 then&lt;br /&gt;
				block_tree:set_text(str_format(&amp;quot;%s: %d of %d&amp;quot;,block.name,n,count))&lt;br /&gt;
			else&lt;br /&gt;
				block_tree:set_text(block.name)&lt;br /&gt;
			end&lt;br /&gt;
			-- parse block variables.&lt;br /&gt;
			build_block_tree(msg_buffer, block_tree, offset, block)&lt;br /&gt;
			offset = offset + block_len&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return msg.name&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- packet dissector&lt;br /&gt;
function lludp_proto.dissector(buffer,pinfo,tree)&lt;br /&gt;
	local rang,offset&lt;br /&gt;
  pinfo.cols.protocol = &amp;quot;LLUDP&amp;quot;&lt;br /&gt;
  local lludp_tree = tree:add(lludp_proto,buffer(),&amp;quot;Linden UDP Protocol&amp;quot;)&lt;br /&gt;
	-- Flags byte.&lt;br /&gt;
	offset = 0&lt;br /&gt;
	rang = buffer(offset,1)&lt;br /&gt;
	local flags = rang:uint()&lt;br /&gt;
	local flags_bits, flags_list = parse_flags(flags)&lt;br /&gt;
  flags_tree = lludp_tree:add(fds.flags, rang)&lt;br /&gt;
	flags_tree:set_text(&amp;quot;Flags: &amp;quot; .. str_format('0x%02X (%s)', flags, flags_list))&lt;br /&gt;
  flags_tree:add(fds.flags_zero, rang)&lt;br /&gt;
  flags_tree:add(fds.flags_reliable, rang)&lt;br /&gt;
  flags_tree:add(fds.flags_resent, rang)&lt;br /&gt;
  flags_tree:add(fds.flags_ack, rang)&lt;br /&gt;
	offset = offset + 1&lt;br /&gt;
	-- Sequence number 4 bytes.&lt;br /&gt;
	rang = buffer(offset,4)&lt;br /&gt;
	local sequence = rang:uint()&lt;br /&gt;
  lludp_tree:add(fds.sequence, rang)&lt;br /&gt;
	offset = offset + 4&lt;br /&gt;
	-- Extra header length.&lt;br /&gt;
	rang = buffer(offset,1)&lt;br /&gt;
	local extra_length = rang:uint()&lt;br /&gt;
  lludp_tree:add(fds.extra_len,rang)&lt;br /&gt;
	offset = offset + 1&lt;br /&gt;
	-- Extra header data.&lt;br /&gt;
	if extra_length &amp;gt; 0 then&lt;br /&gt;
		rang = buffer(offset, extra_length)&lt;br /&gt;
		lludp_tree:add(fds.extra_bytes, rang)&lt;br /&gt;
		offset = offset + extra_length&lt;br /&gt;
	end&lt;br /&gt;
	-- Appended Acks. count&lt;br /&gt;
	local acks_bytes = 0&lt;br /&gt;
	local acks_count = 0&lt;br /&gt;
	if flags_bits[FLAG_ACK] then&lt;br /&gt;
		rang = buffer(buffer:len() - 1, 1)&lt;br /&gt;
		acks_count = rang:uint()&lt;br /&gt;
		acks_bytes = (acks_count * 4) + 1&lt;br /&gt;
	end&lt;br /&gt;
	-- Zero Decode&lt;br /&gt;
	local msg_len = (buffer:len() - acks_bytes) - offset&lt;br /&gt;
	if flags_bits[FLAG_ZER] then&lt;br /&gt;
		msg_buffer=zero_decode(buffer(offset,msg_len):bytes())&lt;br /&gt;
		msg_len = msg_buffer:len()&lt;br /&gt;
		offset = 0&lt;br /&gt;
	else&lt;br /&gt;
		msg_buffer = buffer(offset, msg_len):tvb()&lt;br /&gt;
		offset = 0&lt;br /&gt;
	end&lt;br /&gt;
	-- Message ID&lt;br /&gt;
	local msg_id, msg_id_len = -1, 4&lt;br /&gt;
	if msg_id_len &amp;gt; msg_len then&lt;br /&gt;
		msg_id_len = msg_len&lt;br /&gt;
	end&lt;br /&gt;
	msg_id, msg_id_len = parse_msg_id(msg_buffer(offset, msg_id_len):bytes())&lt;br /&gt;
	rang = msg_buffer(offset, msg_id_len)&lt;br /&gt;
	lludp_tree:add(fds.msg_id, rang)&lt;br /&gt;
	local msg_name = get_msg_name(msg_id)&lt;br /&gt;
	if msg_name == nil then&lt;br /&gt;
		msg_name = str_format(&amp;quot;0x%08x&amp;quot;, msg_id)&lt;br /&gt;
	else&lt;br /&gt;
		lludp_tree:add(fds.msg_name, rang, msg_name)&lt;br /&gt;
	end&lt;br /&gt;
	-- Message body.&lt;br /&gt;
	rang = msg_buffer(offset, msg_len)&lt;br /&gt;
	local msg_tree = lludp_tree:add(fds.msg, rang)&lt;br /&gt;
	build_msg_tree(msg_buffer, msg_tree, msg_id)&lt;br /&gt;
	-- Appended Acks. list.&lt;br /&gt;
	if flags_bits[FLAG_ACK] then&lt;br /&gt;
		local acks_off = buffer:len()&lt;br /&gt;
		rang = buffer(acks_off - 1, 1)&lt;br /&gt;
		acks_off = acks_off - acks_bytes&lt;br /&gt;
  	local acks_tree = lludp_tree:add(fds.acks_count, rang)&lt;br /&gt;
		for i = 1,acks_count do&lt;br /&gt;
			rang = buffer(acks_off,4)&lt;br /&gt;
  		acks_tree:add(fds.acks, rang)&lt;br /&gt;
			acks_off = acks_off + 4&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	-- Info column&lt;br /&gt;
  pinfo.cols.info = str_format('[%s] Seq=%u Type=%s', flags_list, sequence, msg_name)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- register lludp to handle udp ports 9000-9003&lt;br /&gt;
register_udp_port_range(9000,9003)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== File &amp;quot;llmessage.lua&amp;quot; ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
--[[&lt;br /&gt;
BSD-Licensed:&lt;br /&gt;
Copyright (c) 2008, Robert G. Jakabosky &amp;lt;bobby@sharedrealm.com&amp;gt;&lt;br /&gt;
All rights reserved.&lt;br /&gt;
&lt;br /&gt;
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:&lt;br /&gt;
&lt;br /&gt;
    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.&lt;br /&gt;
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.&lt;br /&gt;
    * Neither the name of the SharedRealm nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.&lt;br /&gt;
&lt;br /&gt;
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &amp;quot;AS IS&amp;quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
dofile(&amp;quot;lexer.lua&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
local lexer&lt;br /&gt;
local cur_token = nil&lt;br /&gt;
local cur_token_str = nil&lt;br /&gt;
&lt;br /&gt;
local function get_token(skip_tokens)&lt;br /&gt;
	repeat&lt;br /&gt;
	token = lexer.get_token()&lt;br /&gt;
	if token ~= nil then&lt;br /&gt;
		cur_token = token[1]&lt;br /&gt;
		cur_token_str = token[2]&lt;br /&gt;
	end&lt;br /&gt;
	until token == nil or not skip_tokens[cur_token]&lt;br /&gt;
	return token&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function run_parser(parser)&lt;br /&gt;
	local state = parser.init()&lt;br /&gt;
	if parser.skip_tokens == nil then parser.skip_tokens = {} end&lt;br /&gt;
	while get_token(parser.skip_tokens) do&lt;br /&gt;
		-- check what the parser is expecting next.&lt;br /&gt;
		if state.expect then&lt;br /&gt;
			-- check expected type&lt;br /&gt;
			if state.expect ~= cur_token then&lt;br /&gt;
				error(string.format(&amp;quot;state.expected token '%s' instead of '%s'&amp;quot;,&lt;br /&gt;
					TokenNames[state.expect], TokenNames[cur_token]))&lt;br /&gt;
			end&lt;br /&gt;
			-- reset expect field&lt;br /&gt;
			state.expect = nil&lt;br /&gt;
		end&lt;br /&gt;
		if state.expect_str then&lt;br /&gt;
			-- check expected string&lt;br /&gt;
			if state.expect_str ~= cur_token_str then&lt;br /&gt;
				error(string.format(&amp;quot;state.expected token '%s' instead of '%s'&amp;quot;,&lt;br /&gt;
					state.expect_str, cur_token_str))&lt;br /&gt;
			end&lt;br /&gt;
			-- reset expect_str field&lt;br /&gt;
			state.expect_str = nil&lt;br /&gt;
		end&lt;br /&gt;
		-- get handler function for current token.&lt;br /&gt;
		local f = parser[cur_token]&lt;br /&gt;
		if f ~= nil then&lt;br /&gt;
			local ret = f(state)&lt;br /&gt;
			if ret then&lt;br /&gt;
				-- praser finished.&lt;br /&gt;
				return ret&lt;br /&gt;
			end&lt;br /&gt;
		elseif parser.unhandled_error then&lt;br /&gt;
			error(string.format(&amp;quot;unhandled token '%s' when paring '%s'\n&amp;quot;, cur_token_str, parser.name))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return parser.eof(state)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Known variable types and there fixed length.&lt;br /&gt;
--   length == -1, requires a number after the type that is the length of count field&lt;br /&gt;
--   length == -2, requires a number after the type that is the fixed variable length.&lt;br /&gt;
VariableTypes = {&lt;br /&gt;
Null = 0,&lt;br /&gt;
Fixed = -2,&lt;br /&gt;
Variable = -1,&lt;br /&gt;
U8 = 1,&lt;br /&gt;
U16 = 2,&lt;br /&gt;
U32 = 4,&lt;br /&gt;
U64 = 8,&lt;br /&gt;
S8 = 1,&lt;br /&gt;
S16 = 2,&lt;br /&gt;
S32 = 4,&lt;br /&gt;
S64 = 8,&lt;br /&gt;
F32 = 4,&lt;br /&gt;
F64 = 8,&lt;br /&gt;
LLVector3 = 12,&lt;br /&gt;
LLVector3d = 24,&lt;br /&gt;
LLVector4 = 16,&lt;br /&gt;
LLQuaternion = 12,&lt;br /&gt;
LLUUID = 16,&lt;br /&gt;
BOOL = 1,&lt;br /&gt;
IPADDR = 4,&lt;br /&gt;
IPPORT = 2,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
--&lt;br /&gt;
-- Variable parser&lt;br /&gt;
--&lt;br /&gt;
local variable_parser = {&lt;br /&gt;
name = &amp;quot;variable&amp;quot;,&lt;br /&gt;
unhandled_error = false,&lt;br /&gt;
skip_tokens = {[Token.EOL] = true},&lt;br /&gt;
init = function()&lt;br /&gt;
	return {&lt;br /&gt;
		name = &amp;quot;&amp;lt;MISSING VARIABLE NAME&amp;gt;&amp;quot;,&lt;br /&gt;
		type = &amp;quot;Null&amp;quot;,&lt;br /&gt;
		has_count = false,&lt;br /&gt;
		length = 0,&lt;br /&gt;
		expect = Token.IDENTIFIER,&lt;br /&gt;
		expect_field = &amp;quot;name&amp;quot;,&lt;br /&gt;
		required = 2&lt;br /&gt;
	}&lt;br /&gt;
end,&lt;br /&gt;
[Token.IDENTIFIER] 	= function(state)&lt;br /&gt;
	if state.expect_field == &amp;quot;name&amp;quot; then&lt;br /&gt;
		state.name = cur_token_str&lt;br /&gt;
		state.expect = Token.IDENTIFIER&lt;br /&gt;
		state.expect_field = &amp;quot;type&amp;quot;&lt;br /&gt;
		state.required = state.required - 1&lt;br /&gt;
	elseif state.expect_field == &amp;quot;type&amp;quot; then&lt;br /&gt;
		state.type = cur_token_str&lt;br /&gt;
		state.length = VariableTypes[state.type]&lt;br /&gt;
		if state.length == nil then&lt;br /&gt;
			error(&amp;quot;Unknown variable type: &amp;quot; .. cur_token_str)&lt;br /&gt;
		elseif state.length == -1 or state.length == -2 then&lt;br /&gt;
			state.expect = Token.NUMBER&lt;br /&gt;
		else&lt;br /&gt;
			state.required = state.required - 1&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		error(string.format(&amp;quot;unhandled variable identifier: %s\n&amp;quot;,cur_token_str))&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end,&lt;br /&gt;
[Token.NUMBER]			= function(state)&lt;br /&gt;
	if state.expect_field == &amp;quot;type&amp;quot; then&lt;br /&gt;
		if state.length == -1 then&lt;br /&gt;
			-- variable field length uses embedded count field&lt;br /&gt;
			state.has_count = true&lt;br /&gt;
			state.count_length = tonumber(cur_token_str)&lt;br /&gt;
			state.length = nil&lt;br /&gt;
		elseif state.length == -2 then&lt;br /&gt;
			-- fixed field length&lt;br /&gt;
			state.length = tonumber(cur_token_str)&lt;br /&gt;
		end&lt;br /&gt;
		state.required = state.required - 1&lt;br /&gt;
	else&lt;br /&gt;
		error(string.format(&amp;quot;unhandled variable number: %s\n&amp;quot;,cur_token_str))&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end,&lt;br /&gt;
[&amp;quot;{&amp;quot;]		= function(state)&lt;br /&gt;
	error(&amp;quot;sub block not allowed in variable block&amp;quot;)&lt;br /&gt;
end,&lt;br /&gt;
[&amp;quot;}&amp;quot;]		= function(state)&lt;br /&gt;
	if state.required &amp;gt; 0 then&lt;br /&gt;
		error(&amp;quot;missing &amp;quot; .. state.required .. &amp;quot; fields&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	-- clean state.&lt;br /&gt;
	state.required = nil&lt;br /&gt;
	state.expect = nil&lt;br /&gt;
	state.expect_field = nil&lt;br /&gt;
	return state&lt;br /&gt;
end,&lt;br /&gt;
eof = function(state)&lt;br /&gt;
	error(&amp;quot;missing '}' token at end of variable: &amp;quot; .. state.name)&lt;br /&gt;
end,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
-- Block Quantities&lt;br /&gt;
local BlockQuantity = {&lt;br /&gt;
Single = 1,&lt;br /&gt;
Variable = -1,&lt;br /&gt;
Multiple = -2,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
--&lt;br /&gt;
-- Block parser&lt;br /&gt;
--&lt;br /&gt;
local block_parser = {&lt;br /&gt;
name = &amp;quot;block&amp;quot;,&lt;br /&gt;
unhandled_error = false,&lt;br /&gt;
skip_tokens = {[Token.EOL] = true},&lt;br /&gt;
init = function()&lt;br /&gt;
	return {&lt;br /&gt;
		name = &amp;quot;&amp;lt;MISSING BLOCK NAME&amp;gt;&amp;quot;,&lt;br /&gt;
		quantity = &amp;quot;Single&amp;quot;,&lt;br /&gt;
		count = 0,&lt;br /&gt;
		min_length = 0,&lt;br /&gt;
		fixed_length = true,&lt;br /&gt;
		expect = Token.IDENTIFIER,&lt;br /&gt;
		expect_field = &amp;quot;name&amp;quot;,&lt;br /&gt;
		required = 2&lt;br /&gt;
	}&lt;br /&gt;
end,&lt;br /&gt;
[Token.IDENTIFIER] 	= function(state)&lt;br /&gt;
	if state.expect_field == &amp;quot;name&amp;quot; then&lt;br /&gt;
		state.name = cur_token_str&lt;br /&gt;
		state.expect = Token.IDENTIFIER&lt;br /&gt;
		state.expect_field = &amp;quot;quantity&amp;quot;&lt;br /&gt;
		state.required = state.required - 1&lt;br /&gt;
	elseif state.expect_field == &amp;quot;quantity&amp;quot; then&lt;br /&gt;
		state.quantity = cur_token_str&lt;br /&gt;
		state.count = BlockQuantity[cur_token_str]&lt;br /&gt;
		if state.count == nil then&lt;br /&gt;
			error(&amp;quot;Unknown block quantity: &amp;quot; .. cur_token_str)&lt;br /&gt;
		elseif state.count == -2 then&lt;br /&gt;
			state.expect_field = &amp;quot;count&amp;quot;&lt;br /&gt;
			state.expect = Token.NUMBER&lt;br /&gt;
		else&lt;br /&gt;
			if state.count == -1 then&lt;br /&gt;
				state.has_count = true&lt;br /&gt;
				state.count_length = 1&lt;br /&gt;
				state.count = nil&lt;br /&gt;
			end&lt;br /&gt;
			state.required = state.required - 1&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		error(string.format(&amp;quot;unhandled block identifier: %s\n&amp;quot;,cur_token_str))&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end,&lt;br /&gt;
[Token.NUMBER]			= function(state)&lt;br /&gt;
	if state.expect_field == &amp;quot;count&amp;quot; then&lt;br /&gt;
		state.count = tonumber(cur_token_str)&lt;br /&gt;
		state.required = state.required - 1&lt;br /&gt;
	else&lt;br /&gt;
		error(string.format(&amp;quot;unhandled block number: %s\n&amp;quot;,cur_token_str))&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end,&lt;br /&gt;
[&amp;quot;{&amp;quot;]		= function(state)&lt;br /&gt;
	local variable = run_parser(variable_parser)&lt;br /&gt;
	table.insert(state,variable)&lt;br /&gt;
	-- add length of fixed length variables to minimal length of block.&lt;br /&gt;
	if variable.has_count then&lt;br /&gt;
		state.min_length = state.min_length + variable.count_length&lt;br /&gt;
		state.fixed_length = false&lt;br /&gt;
	else&lt;br /&gt;
		state.min_length = state.min_length + variable.length&lt;br /&gt;
	end&lt;br /&gt;
end,&lt;br /&gt;
[&amp;quot;}&amp;quot;]		= function(state)&lt;br /&gt;
	if state.required &amp;gt; 0 then&lt;br /&gt;
		error(&amp;quot;missing &amp;quot; .. state.required .. &amp;quot; fields&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	-- clean state.&lt;br /&gt;
	state.required = nil&lt;br /&gt;
	state.expect = nil&lt;br /&gt;
	state.expect_field = nil&lt;br /&gt;
	return state&lt;br /&gt;
end,&lt;br /&gt;
eof = function(state)&lt;br /&gt;
	error(&amp;quot;missing '}' token at end of block: &amp;quot; .. state.name)&lt;br /&gt;
end,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
--&lt;br /&gt;
-- Message parser&lt;br /&gt;
--&lt;br /&gt;
local message_parser = {&lt;br /&gt;
name = &amp;quot;message&amp;quot;,&lt;br /&gt;
unhandled_error = false,&lt;br /&gt;
skip_tokens = {[Token.EOL] = true},&lt;br /&gt;
init = function()&lt;br /&gt;
	-- create state&lt;br /&gt;
	return {&lt;br /&gt;
		name = &amp;quot;&amp;lt;MISSING MESSAGE NAME&amp;gt;&amp;quot;,&lt;br /&gt;
		expect = Token.IDENTIFIER,&lt;br /&gt;
		expect_field = &amp;quot;name&amp;quot;,&lt;br /&gt;
		fixed_length = true,&lt;br /&gt;
		min_length = 0,&lt;br /&gt;
		required = 5&lt;br /&gt;
	}&lt;br /&gt;
end,&lt;br /&gt;
[Token.IDENTIFIER] 	= function(state)&lt;br /&gt;
	if state.expect_field == &amp;quot;name&amp;quot; then&lt;br /&gt;
		state.name = cur_token_str&lt;br /&gt;
		state.expect = Token.IDENTIFIER&lt;br /&gt;
		state.expect_field = &amp;quot;frequency&amp;quot;&lt;br /&gt;
		state.required = state.required - 1&lt;br /&gt;
	elseif state.expect_field == &amp;quot;frequency&amp;quot; then&lt;br /&gt;
		state.frequency = cur_token_str&lt;br /&gt;
		state.expect = Token.NUMBER&lt;br /&gt;
		state.required = state.required - 1&lt;br /&gt;
	elseif state.expect_field == &amp;quot;trust&amp;quot; then&lt;br /&gt;
		state.trust = cur_token_str&lt;br /&gt;
		state.expect = Token.IDENTIFIER&lt;br /&gt;
		state.expect_field = &amp;quot;compression&amp;quot;&lt;br /&gt;
		state.required = state.required - 1&lt;br /&gt;
	elseif state.expect_field == &amp;quot;compression&amp;quot; then&lt;br /&gt;
		state.compression = cur_token_str&lt;br /&gt;
		state.required = state.required - 1&lt;br /&gt;
	else&lt;br /&gt;
		error(string.format(&amp;quot;unhandled message identifier: %s\n&amp;quot;,cur_token_str))&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end,&lt;br /&gt;
[Token.NUMBER]			= function(state)&lt;br /&gt;
	if state.expect_field == &amp;quot;frequency&amp;quot; then&lt;br /&gt;
		state.number = tonumber(cur_token_str)&lt;br /&gt;
		state.expect = Token.IDENTIFIER&lt;br /&gt;
		state.expect_field = &amp;quot;trust&amp;quot;&lt;br /&gt;
		state.required = state.required - 1&lt;br /&gt;
		-- create true message id from frequency and message number&lt;br /&gt;
		local freq = state.frequency&lt;br /&gt;
		if freq == &amp;quot;High&amp;quot; then&lt;br /&gt;
			-- High is already correct.&lt;br /&gt;
			state.id = state.number&lt;br /&gt;
			state.id_length = 1&lt;br /&gt;
		elseif freq == &amp;quot;Medium&amp;quot; then&lt;br /&gt;
			state.id = tonumber(&amp;quot;0xFF&amp;quot; .. string.format(&amp;quot;%02X&amp;quot;, state.number))&lt;br /&gt;
			state.id_length = 2&lt;br /&gt;
		elseif freq == &amp;quot;Low&amp;quot; then&lt;br /&gt;
			state.id = tonumber(&amp;quot;0xFFFF&amp;quot; .. string.format(&amp;quot;%04X&amp;quot;, state.number))&lt;br /&gt;
			state.id_length = 4&lt;br /&gt;
		else&lt;br /&gt;
			-- Fixed is already correct.&lt;br /&gt;
			state.id = state.number&lt;br /&gt;
			state.id_length = 4&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		error(string.format(&amp;quot;unhandled message number: %s\n&amp;quot;,cur_token_str))&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end,&lt;br /&gt;
[&amp;quot;{&amp;quot;]		= function(state)&lt;br /&gt;
	local block = run_parser(block_parser)&lt;br /&gt;
	table.insert(state,block)&lt;br /&gt;
	-- add min length of block to minimal length of message&lt;br /&gt;
	local min_length = block.min_length&lt;br /&gt;
	if block.has_count then&lt;br /&gt;
		-- add one byte for the block count&lt;br /&gt;
		min_length = min_length + 1&lt;br /&gt;
		state.fixed_length = false&lt;br /&gt;
	else&lt;br /&gt;
		-- if block is not fixed length then message can't be fixed length.&lt;br /&gt;
		if not block.fixed_length then&lt;br /&gt;
			state.fixed_length = false&lt;br /&gt;
		end&lt;br /&gt;
		min_length = min_length * block.count&lt;br /&gt;
	end&lt;br /&gt;
	state.min_length = state.min_length + min_length&lt;br /&gt;
end,&lt;br /&gt;
[&amp;quot;}&amp;quot;]		= function(state)&lt;br /&gt;
	if state.required &amp;gt; 0 then&lt;br /&gt;
		error(&amp;quot;missing &amp;quot; .. state.required .. &amp;quot; fields&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	-- clean state.&lt;br /&gt;
	state.required = nil&lt;br /&gt;
	state.expect = nil&lt;br /&gt;
	state.expect_field = nil&lt;br /&gt;
	return state&lt;br /&gt;
end,&lt;br /&gt;
eof = function(state)&lt;br /&gt;
	error(&amp;quot;missing '}' token at end of message: &amp;quot; .. state.name)&lt;br /&gt;
end,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
--&lt;br /&gt;
-- Template file parser&lt;br /&gt;
--&lt;br /&gt;
local template_parser = {&lt;br /&gt;
name = &amp;quot;message_template&amp;quot;,&lt;br /&gt;
unhandled_error = false,&lt;br /&gt;
init = function()&lt;br /&gt;
	return {&lt;br /&gt;
		version = 0,&lt;br /&gt;
		msg_count = 0,&lt;br /&gt;
		msgs = {}&lt;br /&gt;
	}&lt;br /&gt;
end,&lt;br /&gt;
[Token.IDENTIFIER] 	= function(state)&lt;br /&gt;
	-- handle version&lt;br /&gt;
	if cur_token_str == &amp;quot;version&amp;quot; then&lt;br /&gt;
		state.expect = Token.NUMBER&lt;br /&gt;
		state.last_ident = cur_token_str&lt;br /&gt;
	else&lt;br /&gt;
		error(string.format(&amp;quot;unknown template identifier: %s\n&amp;quot;,cur_token_str))&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end,&lt;br /&gt;
[Token.NUMBER]			= function(state)&lt;br /&gt;
	-- handle version number&lt;br /&gt;
	if state.last_ident == &amp;quot;version&amp;quot; then&lt;br /&gt;
		state.last_ident = nil&lt;br /&gt;
		state.version = tonumber(cur_token_str)&lt;br /&gt;
		-- check version number&lt;br /&gt;
		if state.version ~= 2 then&lt;br /&gt;
			error(&amp;quot;invalid verion: &amp;quot; .. state.version)&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		error(string.format(&amp;quot;unhandled template number: %s\n&amp;quot;,cur_token_str))&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end,&lt;br /&gt;
[&amp;quot;{&amp;quot;]		= function(state)&lt;br /&gt;
	local message = run_parser(message_parser)&lt;br /&gt;
	state.msg_count = state.msg_count + 1&lt;br /&gt;
	state.msgs[message.id] = message&lt;br /&gt;
end,&lt;br /&gt;
[&amp;quot;}&amp;quot;]		= function(state)&lt;br /&gt;
	error(string.format(&amp;quot;unhandled '%s' token&amp;quot;,cur_token_str))&lt;br /&gt;
end,&lt;br /&gt;
eof = function(state)&lt;br /&gt;
	return state&lt;br /&gt;
end,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parse_template(file)&lt;br /&gt;
	-- create lexer&lt;br /&gt;
	local status, ret = pcall(get_lexer,file)&lt;br /&gt;
	if not status then&lt;br /&gt;
		ret = string.format(&amp;quot;LLUDP: Failed parse file into tokens: %s\n%s\n&amp;quot;, file, ret)&lt;br /&gt;
		error(ret, 0)&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	lexer = ret&lt;br /&gt;
	-- parse template file&lt;br /&gt;
	local status, ret = pcall(run_parser,template_parser)&lt;br /&gt;
	if not status then&lt;br /&gt;
		ret = string.format(&amp;quot;LLUDP: Failed parsing on line %s:%d: '%s'\n%s\n&amp;quot;,&lt;br /&gt;
			file, lexer.get_line_number(), lexer.get_line(), ret)&lt;br /&gt;
		error(ret, 0)&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	io.write(&amp;quot;finished parsing: &amp;quot; .. file .. &amp;quot;\n&amp;quot;)&lt;br /&gt;
	-- return list of messages parsed from file.&lt;br /&gt;
	return ret&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--parse_template(&amp;quot;message_template.msg&amp;quot;)&lt;br /&gt;
--print_tokens(&amp;quot;message_template.msg&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== File &amp;quot;lexer.lua&amp;quot; ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
--[[&lt;br /&gt;
BSD-Licensed:&lt;br /&gt;
Copyright (c) 2008, Robert G. Jakabosky &amp;lt;bobby@sharedrealm.com&amp;gt;&lt;br /&gt;
All rights reserved.&lt;br /&gt;
&lt;br /&gt;
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:&lt;br /&gt;
&lt;br /&gt;
    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.&lt;br /&gt;
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.&lt;br /&gt;
    * Neither the name of the SharedRealm nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.&lt;br /&gt;
&lt;br /&gt;
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &amp;quot;AS IS&amp;quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
-- Token types.&lt;br /&gt;
Token = {&lt;br /&gt;
NONE         = -1,&lt;br /&gt;
IDENTIFIER   = -2,&lt;br /&gt;
NUMBER       = -3,&lt;br /&gt;
COMMENT      = -6,&lt;br /&gt;
EOL          = -7,&lt;br /&gt;
[&amp;quot;{&amp;quot;] = &amp;quot;{&amp;quot;,&lt;br /&gt;
[&amp;quot;}&amp;quot;] = &amp;quot;}&amp;quot;,&lt;br /&gt;
}&lt;br /&gt;
TokenNames = {&lt;br /&gt;
[-1] = &amp;quot;NONE&amp;quot;,&lt;br /&gt;
[-2] = &amp;quot;IDENTIFIER&amp;quot;,&lt;br /&gt;
[-3] = &amp;quot;NUMBER&amp;quot;,&lt;br /&gt;
[-6] = &amp;quot;COMMENT&amp;quot;,&lt;br /&gt;
[-7] = &amp;quot;EOL&amp;quot;,&lt;br /&gt;
[&amp;quot;{&amp;quot;] = &amp;quot;{&amp;quot;,&lt;br /&gt;
[&amp;quot;}&amp;quot;] = &amp;quot;}&amp;quot;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
-- parse line into array of tokens.&lt;br /&gt;
local function default_parse_tokens(line)&lt;br /&gt;
	local tokens = {}&lt;br /&gt;
	local comment = nil&lt;br /&gt;
	-- check for a comment on this line.&lt;br /&gt;
	local idx = line:find(&amp;quot;//&amp;quot;)&lt;br /&gt;
	if idx ~= nil then&lt;br /&gt;
		comment = {Token.COMMENT, line:sub(idx)}&lt;br /&gt;
		-- remove comment from line&lt;br /&gt;
		line = line:sub(1,idx - 1)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- split line into tokens using white-space as token delimitator&lt;br /&gt;
	for tok in line:gmatch(&amp;quot;%s?([^%s]+)&amp;quot;) do&lt;br /&gt;
		local tok_type = Token.NONE&lt;br /&gt;
		-- check for number&lt;br /&gt;
		if tonumber(tok) ~= nil then&lt;br /&gt;
			tok_type = Token.NUMBER&lt;br /&gt;
		elseif Token[tok] then&lt;br /&gt;
			-- token is same as type&lt;br /&gt;
			tok_type = Token[tok]&lt;br /&gt;
		else&lt;br /&gt;
			-- token is an identifier&lt;br /&gt;
			tok_type = Token.IDENTIFIER&lt;br /&gt;
		end&lt;br /&gt;
		table.insert(tokens,{tok_type,tok})&lt;br /&gt;
	end&lt;br /&gt;
	-- insert comment token.&lt;br /&gt;
	if comment ~= nil then&lt;br /&gt;
		table.insert(tokens,comment)&lt;br /&gt;
	end&lt;br /&gt;
	-- add token to mark the end of this line&lt;br /&gt;
	table.insert(tokens,{Token.EOL, &amp;quot;&amp;quot;})&lt;br /&gt;
	return tokens&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function get_lexer(file, parse_tokens)&lt;br /&gt;
	-- use the default line tokenizer if one is not provided&lt;br /&gt;
	if parse_tokens == nil then parse_tokens = default_parse_tokens end&lt;br /&gt;
	-- next/current line code&lt;br /&gt;
	local line_num = 0&lt;br /&gt;
	local line = nil&lt;br /&gt;
	local next_line = io.lines(file)&lt;br /&gt;
	-- parse line tokens code&lt;br /&gt;
	local get_next_token = nil&lt;br /&gt;
	local next_tokens = function ()&lt;br /&gt;
		local f, tokens, idx&lt;br /&gt;
		repeat&lt;br /&gt;
			line_num = line_num + 1&lt;br /&gt;
			line = next_line()&lt;br /&gt;
			if line == nil then return nil end&lt;br /&gt;
			tokens = parse_tokens(line)&lt;br /&gt;
		until tokens ~= nil&lt;br /&gt;
		-- create get_next_toekn function from table iterator&lt;br /&gt;
		f, tokens, idx = ipairs(tokens)&lt;br /&gt;
		get_next_token = function()&lt;br /&gt;
			idx, token = f(tokens, idx)&lt;br /&gt;
			return token&lt;br /&gt;
		end&lt;br /&gt;
		return tokens&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- get first group of tokens&lt;br /&gt;
	if next_tokens() == nil then&lt;br /&gt;
		-- error reading file or empty file&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	-- build lexer table.&lt;br /&gt;
	local lexer = {&lt;br /&gt;
	get_token = function ()&lt;br /&gt;
		local token&lt;br /&gt;
		repeat&lt;br /&gt;
			token = get_next_token()&lt;br /&gt;
			if token == nil then&lt;br /&gt;
				-- get next group of tokens&lt;br /&gt;
				if next_tokens() == nil then&lt;br /&gt;
					-- end of file.&lt;br /&gt;
					return nil&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		until token ~= nil&lt;br /&gt;
		return token&lt;br /&gt;
	end,&lt;br /&gt;
	get_line_number = function() return line_num end,&lt;br /&gt;
	get_line = function() return line end&lt;br /&gt;
	}&lt;br /&gt;
	return lexer&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function print_tokens(file)&lt;br /&gt;
	local lexer = get_lexer(file)&lt;br /&gt;
	local num = -1&lt;br /&gt;
	while true do&lt;br /&gt;
		local tok = lexer.get_token()&lt;br /&gt;
		if tok == nil then&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
		if num ~= lexer.get_line_number() then&lt;br /&gt;
			num = lexer.get_line_number()&lt;br /&gt;
			io.write(&amp;quot;\n&amp;quot;)&lt;br /&gt;
			io.write(string.format(&amp;quot;%d: &amp;quot;,num))&lt;br /&gt;
		end&lt;br /&gt;
		io.write(string.format(&amp;quot;%s &amp;quot;,tok[2]))&lt;br /&gt;
	end&lt;br /&gt;
	io.write(&amp;quot;\n&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Talk:Automated_Testing</id>
		<title>Talk:Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Talk:Automated_Testing"/>
				<updated>2008-10-09T08:01:46Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I crossed out a paragraph about naming tests a certain way in order to make sure they're run in a certain order because they depend on each other. This is bad practice. All tests should be able to run independently of one another. For any environment setup, use the SetUp and TearDown NUnit attributes.&lt;br /&gt;
&lt;br /&gt;
[[User:Mikem|Mikem]] 01:01, 9 October 2008 (PDT)&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Talk:Automated_Testing</id>
		<title>Talk:Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Talk:Automated_Testing"/>
				<updated>2008-10-09T08:01:33Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I crossed out a paragraph about naming tests a certain way in order to make sure they're run in a certain order because they depend on each other. This is bad practice. All tests should be able to run independently of one another. For any environment setup, use the SetUp and TearDown NUnit attributes. [[User:Mikem|Mikem]] 01:01, 9 October 2008 (PDT)&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Talk:Automated_Testing</id>
		<title>Talk:Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Talk:Automated_Testing"/>
				<updated>2008-10-09T07:58:36Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: New page: I crossed out a paragraph about naming tests a certain way in order to make sure they're run in a certain order because they depend on each other. This is bad practice. All tests should be...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I crossed out a paragraph about naming tests a certain way in order to make sure they're run in a certain order because they depend on each other. This is bad practice. All tests should be able to run independently of one another. For any environment setup, use the SetUp and TearDown NUnit attributes.&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Automated_Testing</id>
		<title>Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Automated_Testing"/>
				<updated>2008-10-09T07:17:36Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* NUnit Conventions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As OpenSim matures, we are extremely interested in adding more automated verification into the OpenSim source tree.  Test exist not only to prevent bugs from creeping in, but also to provide fair warning that the behavior of the system has changed, and tests may need updating.&lt;br /&gt;
&lt;br /&gt;
In OpenSim today we use NUnit tests.  Our conventions are:&lt;br /&gt;
# Tests should '''not''' exist inside runtime assemblies, as this makes nunit a production requirement&lt;br /&gt;
# Tests should be in .Tests.dll assemblies.  For instance, the tests for OpenSim.Data.SQLite.dll should be in the OpenSim.Data.SQLite.Tests.dll assembly.  This allows for easy removal of test assemblies in products.&lt;br /&gt;
# Tests should be as close to the code as possible, but not intermingled.  So the tests for OpenSim/Data/SQLite should be in OpenSim/Data/SQLite/Tests/.  Through the use of the '''Exclude''' keyword in prebuild.xml you can ensure that directory is part of OpenSim.Data.SQLite.Tests.dll and not OpenSim.Data.SQLite.dll.&lt;br /&gt;
# Tests should be able to run safely in a production environment.  That means that care must be taken not to damage data on the machine that it is being run.&lt;br /&gt;
&lt;br /&gt;
= Writing New Tests =&lt;br /&gt;
Writing a new unit test is pretty easy, and very helpful in increasing the stability of opensim by nailing down bugs.  I'm going to present an example here of SQLite Asset testing to show how simple such a test case is to write.  The actual in tree SQLite Asset tests are a little different because the code was factored out so that it was easily applied to any database driver, so don't be concerned with the fact that what you see here isn't in the tree.&lt;br /&gt;
&lt;br /&gt;
== NUnit Conventions ==&lt;br /&gt;
An NUnit test suite:&lt;br /&gt;
* is a class with a default constructor (takes no arguments)&lt;br /&gt;
* has public methods that are tests&lt;br /&gt;
* uses annotations to determine what are tests&lt;br /&gt;
* runs it's tests in '''alphabetical order by method name'''&lt;br /&gt;
&lt;br /&gt;
An NUnit test method:&lt;br /&gt;
* must be public&lt;br /&gt;
* must return void&lt;br /&gt;
* must take no arguments&lt;br /&gt;
* is successful if no exception or assert is thrown while running it&lt;br /&gt;
&lt;br /&gt;
&amp;lt;s&amp;gt;The run order is important if you want to have early tests that setup some complicated state (like creating objects), and have later tests remove or update that state.  For that reason I find it very helpful to name all test methods '''Txxx_somename''' where '''xxx''' is a number between 000 and 999.  That guaruntees no surprises in run order.&amp;lt;/s&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tests should never rely on the result of another test. If you need the environment set up in a certain way, you can use the SetUp and TearDown method attributes. Only one SetUp method can exist; if more than one is defined, the assembly will compile successfully, but its tests will not run. The SetUp method is run once before every test case, and the TearDown method is run once after each test case, regardless of whether the test passed or failed.&lt;br /&gt;
&lt;br /&gt;
== An Example Test - SQLite Assets ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
using System;&lt;br /&gt;
using System.IO;&lt;br /&gt;
using System.Collections.Generic;&lt;br /&gt;
using NUnit.Framework;&lt;br /&gt;
using NUnit.Framework.SyntaxHelpers;&lt;br /&gt;
using OpenSim.Framework;&lt;br /&gt;
using OpenSim.Data.Tests;&lt;br /&gt;
using OpenSim.Data.SQLite;&lt;br /&gt;
using OpenSim.Region.Environment.Scenes;&lt;br /&gt;
using OpenMetaverse;&lt;br /&gt;
&lt;br /&gt;
namespace OpenSim.Data.SQLite.Tests&lt;br /&gt;
{&lt;br /&gt;
    [TestFixture]&lt;br /&gt;
    public class SQLiteAssetTest&lt;br /&gt;
    {&lt;br /&gt;
        public string file;&lt;br /&gt;
        public string connect;&lt;br /&gt;
        public AssetDataBase db;&lt;br /&gt;
        public UUID uuid1;&lt;br /&gt;
        public UUID uuid2;&lt;br /&gt;
        public UUID uuid3;&lt;br /&gt;
        public string name1;&lt;br /&gt;
        public string name2;&lt;br /&gt;
        public string name3;&lt;br /&gt;
        public byte[] asset1;&lt;br /&gt;
        &lt;br /&gt;
        [TestFixtureSetUp]&lt;br /&gt;
        public void Init()&lt;br /&gt;
        {&lt;br /&gt;
            uuid1 = UUID.Random();&lt;br /&gt;
            uuid2 = UUID.Random();&lt;br /&gt;
            uuid3 = UUID.Random();&lt;br /&gt;
            name1 = &amp;quot;asset one&amp;quot;;&lt;br /&gt;
            name2 = &amp;quot;asset two&amp;quot;;&lt;br /&gt;
            name3 = &amp;quot;asset three&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
            asset1 = new byte[100];&lt;br /&gt;
            asset1.Initialize();&lt;br /&gt;
            file = Path.GetTempFileName() + &amp;quot;.db&amp;quot;;&lt;br /&gt;
            connect = &amp;quot;URI=file:&amp;quot; + file + &amp;quot;,version=3&amp;quot;;&lt;br /&gt;
            db = new SQLiteAssetData();&lt;br /&gt;
            db.Initialise(connect);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [TestFixtureTearDown]&lt;br /&gt;
        public void Cleanup()&lt;br /&gt;
        {&lt;br /&gt;
            db.Dispose();&lt;br /&gt;
            System.IO.File.Delete(file);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T001_LoadEmpty()&lt;br /&gt;
        {&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T010_StoreSimpleAsset()&lt;br /&gt;
        {&lt;br /&gt;
            AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
            AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
            AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
            a1.Data = asset1;&lt;br /&gt;
            a2.Data = asset1;&lt;br /&gt;
            a3.Data = asset1;&lt;br /&gt;
            &lt;br /&gt;
            db.CreateAsset(a1);&lt;br /&gt;
            db.CreateAsset(a2);&lt;br /&gt;
            db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
            AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
            Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
            Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
            AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
            Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
            Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
            AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
            Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
            Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T011_ExistsSimpleAsset()&lt;br /&gt;
        {&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid1), Is.True);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid2), Is.True);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid3), Is.True);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can see 4 of the important annotations here:&lt;br /&gt;
* TestFixture - this class is a test suite&lt;br /&gt;
* TestFixtureSetup - this code is always run before any of the tests are executed&lt;br /&gt;
* TestFixtureTearDown - this code is always run after the tests are done executing, even if they fail.&lt;br /&gt;
* Test - this method is a test&lt;br /&gt;
&lt;br /&gt;
=== Setup / Teardown ===&lt;br /&gt;
In the case of testing something like the database layer, we have to actually attempt to store / retrieve things from a database.  Following from rule #4 of good tests, we want to make sure not to touch the production databases to run our tests, so during startup we generate a temporary file name which is guaranteed not to be an existing file on the system, and use that as our database file name.  By running db.Initialize() the OpenSim migration code will correctly populate that database with the latest schema.&lt;br /&gt;
&lt;br /&gt;
Once we are done with the tests we want to make sure we aren't leaving garbage temp files on the user's system.  So we remove that file we created.&lt;br /&gt;
&lt;br /&gt;
During setup we also create a set of state variables, such as 3 uuids, 3 strings, and a data block.  You could have always just stuck these inline, but variables are there for a reason, so use them.&lt;br /&gt;
&lt;br /&gt;
=== Asserts ===&lt;br /&gt;
You will see scattered through the code '''Assert.That(...)'''.  These will throw an exception if the condition is not valid.  This format of assertions is called the [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4|Contraint Model] in NUnit, and provides a large number of tests with the flavor of:&lt;br /&gt;
* Assert.That(foo, Is.Null)&lt;br /&gt;
* Assert.That(foo, Is.Not.Null)&lt;br /&gt;
* Assert.That(foo, Is.True)&lt;br /&gt;
* Assert.That(foo, Is.EqualTo(bar))&lt;br /&gt;
* Assert.That(foo, Text.Matches( &amp;quot;*bar*&amp;quot; ))&lt;br /&gt;
&lt;br /&gt;
Of note, Is.EqualTo uses the Equals function of foo, so this can only be used on objects that are IComparable.  Most of the OpenSim base objects are not, so you'll have to compare fields manually in tests.&lt;br /&gt;
&lt;br /&gt;
For the complete set of conditions you can use see [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4|the Contraint Model NUnit documentation].  While there is another syntax for tests, the Constraint Model is preferred as it is far more human readable.&lt;br /&gt;
&lt;br /&gt;
=== Simple Negative Tests ===&lt;br /&gt;
Test T001 is an example of a simple negative test.  We assume a new database will not have any of those assets in them.  While the value of this test may look low, it does provide a baseline in ensuring that the database connection is there, that these return false correctly, and that no other exception is thrown.  Negative tests are a good way to force bounds conditions and ensure that not only does it  ''return what you expect'' it also ''doesn't return what you don't expect''.  Thought of another way, it ensures your code is somewhat defensive in nature, not coughing on bad or unexpected data.&lt;br /&gt;
&lt;br /&gt;
=== Simple Positive Tests ===&lt;br /&gt;
T010 is an example of a simple positive test.  In it we create and store 3 assets (ensuring no exceptions), then load those 3 assets back from the database and ensure the fields are correct.  Because AssetBase is not IComparible we just check the ID and Name fields with equals tests.  If any of the Asserts fail, the whole test fails.&lt;br /&gt;
=== Stateful Tests ===&lt;br /&gt;
T011 is an example of a stateful test, because it requires the state created by T010 (i.e. the creation of those 3 objects).  In order to test any kind of complicated scenario you will find that you need to use stateful tests to build up various amounts of state (testing along the way), then manipulating and possibly tearing it down.  Without doing this you can't do truly deep testing of function in any complex environment.  This example isn't very stateful (I tried to pick an easy example), but it should give you some ideas.&lt;br /&gt;
=== Speculative Tests ===&lt;br /&gt;
Speculative tests are tests that might or might not apply in a given situation.  MySQL testing in the OpenSim tree is done by speculative testing, the tests will only run if there is a properly configured database, otherwise they will not be run.  If you execute '''Assert.Ignore()''' in a '''Test''' the test will end and be ignored.  If you run '''Assert.Ignore()''' in the '''TestFixtureSetup''' all tests in the test fixture will be skipped and ignored.&lt;br /&gt;
&lt;br /&gt;
Speculative testing lets you create tests that require certain preconditions to be met which you can't guarantee on all platforms/configuration, and are an important part of deep testing.&lt;br /&gt;
&lt;br /&gt;
== Good / Bad Test practices ==&lt;br /&gt;
Creating good tests is an art, not a science.  Tests are useful by how many bugs they find or how many bugs they avoid.  Things you should think about in creating good tests is:&lt;br /&gt;
* throwing edge cases, like 0, &amp;quot;&amp;quot;, or Null at parameters.  This ensures that people functions are hardened against incomplete data.  Many of our crashes come from the lack of this hardening showing up at just the wrong time.&lt;br /&gt;
* use stateful testing to build up complex scenarios.  This is more useful than just cursory get / set calls.&lt;br /&gt;
&lt;br /&gt;
== Adding Tests to the Tree ==&lt;br /&gt;
As we said previously all tests for assembly OpenSim.Foo (in directory OpenSim/Foo) should:&lt;br /&gt;
* be in assembly OpenSim.Foo.Tests.dll&lt;br /&gt;
* not be in the OpenSim.Foo.dll assembly&lt;br /&gt;
* be in OpenSim/Foo/Tests directory&lt;br /&gt;
&lt;br /&gt;
Also, if you have created a new test assembly you must add references to it in both ''.nant/local.include'' and ''.nant/bamboo.build'' to ensure that the assembly is added to the automated bamboo runs as well as the nant test target.&lt;br /&gt;
&lt;br /&gt;
= Executing Tests =&lt;br /&gt;
== Bamboo ==&lt;br /&gt;
On every commit to opensim all the tests are run on a [http://opensimulator.org:8085|Bamboo build server on opensimulator.org].  The process takes about 5 minutes to build, test, and report the results back out on #opensim-dev via the osmantis bot.&lt;br /&gt;
&lt;br /&gt;
== Nant ==&lt;br /&gt;
You can manually run all the tests for OpenSim on your system by running '''nant test''' as a nant target.  This will run all the tests that are in the tree, though some speculative tests might be ignored if your platform does not have the right features or configuration to run these tests.&lt;br /&gt;
&lt;br /&gt;
== NUnit Console ==&lt;br /&gt;
If you only want to run tests for one assembly you can do that using the NUnit Console.  On Linux just run '''nunit-console2 OpenSim.Foo.Tests.dll''' and it will run only the tests for OpenSim.Foo.Tests.dll.  If you are only making changes to 1 dll and just want a quick sanity check, this is the fastest way to do that.&lt;br /&gt;
&lt;br /&gt;
= Learning More =&lt;br /&gt;
You should definitely read the documentation at the [http://www.nunit.org/index.php?p=documentation|NUnit homepage] if you want to know more about testing.  It's a very good reference for all the APIs in NUnit that you can use for creating tests.&lt;br /&gt;
&lt;br /&gt;
= Testing Todo =&lt;br /&gt;
&lt;br /&gt;
== Coverage ==&lt;br /&gt;
At some point in the future we need to integrate test coverage into the bamboo reports so we can easily see how poorly covered our code is, and look for hotspots where we should focus.  We're still at such an early stage that this is probably overkill to get setup for now.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Automated_Testing</id>
		<title>Automated Testing</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Automated_Testing"/>
				<updated>2008-10-09T07:06:38Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* Writing New Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As OpenSim matures, we are extremely interested in adding more automated verification into the OpenSim source tree.  Test exist not only to prevent bugs from creeping in, but also to provide fair warning that the behavior of the system has changed, and tests may need updating.&lt;br /&gt;
&lt;br /&gt;
In OpenSim today we use NUnit tests.  Our conventions are:&lt;br /&gt;
# Tests should '''not''' exist inside runtime assemblies, as this makes nunit a production requirement&lt;br /&gt;
# Tests should be in .Tests.dll assemblies.  For instance, the tests for OpenSim.Data.SQLite.dll should be in the OpenSim.Data.SQLite.Tests.dll assembly.  This allows for easy removal of test assemblies in products.&lt;br /&gt;
# Tests should be as close to the code as possible, but not intermingled.  So the tests for OpenSim/Data/SQLite should be in OpenSim/Data/SQLite/Tests/.  Through the use of the '''Exclude''' keyword in prebuild.xml you can ensure that directory is part of OpenSim.Data.SQLite.Tests.dll and not OpenSim.Data.SQLite.dll.&lt;br /&gt;
# Tests should be able to run safely in a production environment.  That means that care must be taken not to damage data on the machine that it is being run.&lt;br /&gt;
&lt;br /&gt;
= Writing New Tests =&lt;br /&gt;
Writing a new unit test is pretty easy, and very helpful in increasing the stability of opensim by nailing down bugs.  I'm going to present an example here of SQLite Asset testing to show how simple such a test case is to write.  The actual in tree SQLite Asset tests are a little different because the code was factored out so that it was easily applied to any database driver, so don't be concerned with the fact that what you see here isn't in the tree.&lt;br /&gt;
&lt;br /&gt;
== NUnit Conventions ==&lt;br /&gt;
An NUnit test suite:&lt;br /&gt;
* is a class with a default constructor (takes no arguments)&lt;br /&gt;
* has public methods that are tests&lt;br /&gt;
* uses annotations to determine what are tests&lt;br /&gt;
* runs it's tests in '''alphabetical order by method name'''&lt;br /&gt;
&lt;br /&gt;
An NUnit test method:&lt;br /&gt;
* must be public&lt;br /&gt;
* must return void&lt;br /&gt;
* must take no arguments&lt;br /&gt;
* is successful if no exception or assert is thrown while running it&lt;br /&gt;
&lt;br /&gt;
The run order is important if you want to have early tests that setup some complicated state (like creating objects), and have later tests remove or update that state.  For that reason I find it very helpful to name all test methods '''Txxx_somename''' where '''xxx''' is a number between 000 and 999.  That guaruntees no surprises in run order.&lt;br /&gt;
&lt;br /&gt;
== An Example Test - SQLite Assets ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
using System;&lt;br /&gt;
using System.IO;&lt;br /&gt;
using System.Collections.Generic;&lt;br /&gt;
using NUnit.Framework;&lt;br /&gt;
using NUnit.Framework.SyntaxHelpers;&lt;br /&gt;
using OpenSim.Framework;&lt;br /&gt;
using OpenSim.Data.Tests;&lt;br /&gt;
using OpenSim.Data.SQLite;&lt;br /&gt;
using OpenSim.Region.Environment.Scenes;&lt;br /&gt;
using OpenMetaverse;&lt;br /&gt;
&lt;br /&gt;
namespace OpenSim.Data.SQLite.Tests&lt;br /&gt;
{&lt;br /&gt;
    [TestFixture]&lt;br /&gt;
    public class SQLiteAssetTest&lt;br /&gt;
    {&lt;br /&gt;
        public string file;&lt;br /&gt;
        public string connect;&lt;br /&gt;
        public AssetDataBase db;&lt;br /&gt;
        public UUID uuid1;&lt;br /&gt;
        public UUID uuid2;&lt;br /&gt;
        public UUID uuid3;&lt;br /&gt;
        public string name1;&lt;br /&gt;
        public string name2;&lt;br /&gt;
        public string name3;&lt;br /&gt;
        public byte[] asset1;&lt;br /&gt;
        &lt;br /&gt;
        [TestFixtureSetUp]&lt;br /&gt;
        public void Init()&lt;br /&gt;
        {&lt;br /&gt;
            uuid1 = UUID.Random();&lt;br /&gt;
            uuid2 = UUID.Random();&lt;br /&gt;
            uuid3 = UUID.Random();&lt;br /&gt;
            name1 = &amp;quot;asset one&amp;quot;;&lt;br /&gt;
            name2 = &amp;quot;asset two&amp;quot;;&lt;br /&gt;
            name3 = &amp;quot;asset three&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
            asset1 = new byte[100];&lt;br /&gt;
            asset1.Initialize();&lt;br /&gt;
            file = Path.GetTempFileName() + &amp;quot;.db&amp;quot;;&lt;br /&gt;
            connect = &amp;quot;URI=file:&amp;quot; + file + &amp;quot;,version=3&amp;quot;;&lt;br /&gt;
            db = new SQLiteAssetData();&lt;br /&gt;
            db.Initialise(connect);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [TestFixtureTearDown]&lt;br /&gt;
        public void Cleanup()&lt;br /&gt;
        {&lt;br /&gt;
            db.Dispose();&lt;br /&gt;
            System.IO.File.Delete(file);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T001_LoadEmpty()&lt;br /&gt;
        {&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid1), Is.False);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid2), Is.False);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid3), Is.False);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T010_StoreSimpleAsset()&lt;br /&gt;
        {&lt;br /&gt;
            AssetBase a1 = new AssetBase(uuid1, name1);&lt;br /&gt;
            AssetBase a2 = new AssetBase(uuid2, name2);&lt;br /&gt;
            AssetBase a3 = new AssetBase(uuid3, name3);&lt;br /&gt;
            a1.Data = asset1;&lt;br /&gt;
            a2.Data = asset1;&lt;br /&gt;
            a3.Data = asset1;&lt;br /&gt;
            &lt;br /&gt;
            db.CreateAsset(a1);&lt;br /&gt;
            db.CreateAsset(a2);&lt;br /&gt;
            db.CreateAsset(a3);&lt;br /&gt;
&lt;br /&gt;
            AssetBase a1a = db.FetchAsset(uuid1);&lt;br /&gt;
            Assert.That(a1a.ID, Is.EqualTo(uuid1));&lt;br /&gt;
            Assert.That(a1a.Name, Is.EqualTo(name1));&lt;br /&gt;
&lt;br /&gt;
            AssetBase a2a = db.FetchAsset(uuid2);&lt;br /&gt;
            Assert.That(a2a.ID, Is.EqualTo(uuid2));&lt;br /&gt;
            Assert.That(a2a.Name, Is.EqualTo(name2));&lt;br /&gt;
&lt;br /&gt;
            AssetBase a3a = db.FetchAsset(uuid3);&lt;br /&gt;
            Assert.That(a3a.ID, Is.EqualTo(uuid3));&lt;br /&gt;
            Assert.That(a3a.Name, Is.EqualTo(name3));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        [Test]&lt;br /&gt;
        public void T011_ExistsSimpleAsset()&lt;br /&gt;
        {&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid1), Is.True);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid2), Is.True);&lt;br /&gt;
            Assert.That(db.ExistsAsset(uuid3), Is.True);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can see 4 of the important annotations here:&lt;br /&gt;
* TestFixture - this class is a test suite&lt;br /&gt;
* TestFixtureSetup - this code is always run before any of the tests are executed&lt;br /&gt;
* TestFixtureTearDown - this code is always run after the tests are done executing, even if they fail.&lt;br /&gt;
* Test - this method is a test&lt;br /&gt;
&lt;br /&gt;
=== Setup / Teardown ===&lt;br /&gt;
In the case of testing something like the database layer, we have to actually attempt to store / retrieve things from a database.  Following from rule #4 of good tests, we want to make sure not to touch the production databases to run our tests, so during startup we generate a temporary file name which is guaranteed not to be an existing file on the system, and use that as our database file name.  By running db.Initialize() the OpenSim migration code will correctly populate that database with the latest schema.&lt;br /&gt;
&lt;br /&gt;
Once we are done with the tests we want to make sure we aren't leaving garbage temp files on the user's system.  So we remove that file we created.&lt;br /&gt;
&lt;br /&gt;
During setup we also create a set of state variables, such as 3 uuids, 3 strings, and a data block.  You could have always just stuck these inline, but variables are there for a reason, so use them.&lt;br /&gt;
&lt;br /&gt;
=== Asserts ===&lt;br /&gt;
You will see scattered through the code '''Assert.That(...)'''.  These will throw an exception if the condition is not valid.  This format of assertions is called the [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4|Contraint Model] in NUnit, and provides a large number of tests with the flavor of:&lt;br /&gt;
* Assert.That(foo, Is.Null)&lt;br /&gt;
* Assert.That(foo, Is.Not.Null)&lt;br /&gt;
* Assert.That(foo, Is.True)&lt;br /&gt;
* Assert.That(foo, Is.EqualTo(bar))&lt;br /&gt;
* Assert.That(foo, Text.Matches( &amp;quot;*bar*&amp;quot; ))&lt;br /&gt;
&lt;br /&gt;
Of note, Is.EqualTo uses the Equals function of foo, so this can only be used on objects that are IComparable.  Most of the OpenSim base objects are not, so you'll have to compare fields manually in tests.&lt;br /&gt;
&lt;br /&gt;
For the complete set of conditions you can use see [http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4|the Contraint Model NUnit documentation].  While there is another syntax for tests, the Constraint Model is preferred as it is far more human readable.&lt;br /&gt;
&lt;br /&gt;
=== Simple Negative Tests ===&lt;br /&gt;
Test T001 is an example of a simple negative test.  We assume a new database will not have any of those assets in them.  While the value of this test may look low, it does provide a baseline in ensuring that the database connection is there, that these return false correctly, and that no other exception is thrown.  Negative tests are a good way to force bounds conditions and ensure that not only does it  ''return what you expect'' it also ''doesn't return what you don't expect''.  Thought of another way, it ensures your code is somewhat defensive in nature, not coughing on bad or unexpected data.&lt;br /&gt;
&lt;br /&gt;
=== Simple Positive Tests ===&lt;br /&gt;
T010 is an example of a simple positive test.  In it we create and store 3 assets (ensuring no exceptions), then load those 3 assets back from the database and ensure the fields are correct.  Because AssetBase is not IComparible we just check the ID and Name fields with equals tests.  If any of the Asserts fail, the whole test fails.&lt;br /&gt;
=== Stateful Tests ===&lt;br /&gt;
T011 is an example of a stateful test, because it requires the state created by T010 (i.e. the creation of those 3 objects).  In order to test any kind of complicated scenario you will find that you need to use stateful tests to build up various amounts of state (testing along the way), then manipulating and possibly tearing it down.  Without doing this you can't do truly deep testing of function in any complex environment.  This example isn't very stateful (I tried to pick an easy example), but it should give you some ideas.&lt;br /&gt;
=== Speculative Tests ===&lt;br /&gt;
Speculative tests are tests that might or might not apply in a given situation.  MySQL testing in the OpenSim tree is done by speculative testing, the tests will only run if there is a properly configured database, otherwise they will not be run.  If you execute '''Assert.Ignore()''' in a '''Test''' the test will end and be ignored.  If you run '''Assert.Ignore()''' in the '''TestFixtureSetup''' all tests in the test fixture will be skipped and ignored.&lt;br /&gt;
&lt;br /&gt;
Speculative testing lets you create tests that require certain preconditions to be met which you can't guarantee on all platforms/configuration, and are an important part of deep testing.&lt;br /&gt;
&lt;br /&gt;
== Good / Bad Test practices ==&lt;br /&gt;
Creating good tests is an art, not a science.  Tests are useful by how many bugs they find or how many bugs they avoid.  Things you should think about in creating good tests is:&lt;br /&gt;
* throwing edge cases, like 0, &amp;quot;&amp;quot;, or Null at parameters.  This ensures that people functions are hardened against incomplete data.  Many of our crashes come from the lack of this hardening showing up at just the wrong time.&lt;br /&gt;
* use stateful testing to build up complex scenarios.  This is more useful than just cursory get / set calls.&lt;br /&gt;
&lt;br /&gt;
== Adding Tests to the Tree ==&lt;br /&gt;
As we said previously all tests for assembly OpenSim.Foo (in directory OpenSim/Foo) should:&lt;br /&gt;
* be in assembly OpenSim.Foo.Tests.dll&lt;br /&gt;
* not be in the OpenSim.Foo.dll assembly&lt;br /&gt;
* be in OpenSim/Foo/Tests directory&lt;br /&gt;
&lt;br /&gt;
Also, if you have created a new test assembly you must add references to it in both ''.nant/local.include'' and ''.nant/bamboo.build'' to ensure that the assembly is added to the automated bamboo runs as well as the nant test target.&lt;br /&gt;
&lt;br /&gt;
= Executing Tests =&lt;br /&gt;
== Bamboo ==&lt;br /&gt;
On every commit to opensim all the tests are run on a [http://opensimulator.org:8085|Bamboo build server on opensimulator.org].  The process takes about 5 minutes to build, test, and report the results back out on #opensim-dev via the osmantis bot.&lt;br /&gt;
&lt;br /&gt;
== Nant ==&lt;br /&gt;
You can manually run all the tests for OpenSim on your system by running '''nant test''' as a nant target.  This will run all the tests that are in the tree, though some speculative tests might be ignored if your platform does not have the right features or configuration to run these tests.&lt;br /&gt;
&lt;br /&gt;
== NUnit Console ==&lt;br /&gt;
If you only want to run tests for one assembly you can do that using the NUnit Console.  On Linux just run '''nunit-console2 OpenSim.Foo.Tests.dll''' and it will run only the tests for OpenSim.Foo.Tests.dll.  If you are only making changes to 1 dll and just want a quick sanity check, this is the fastest way to do that.&lt;br /&gt;
&lt;br /&gt;
= Learning More =&lt;br /&gt;
You should definitely read the documentation at the [http://www.nunit.org/index.php?p=documentation|NUnit homepage] if you want to know more about testing.  It's a very good reference for all the APIs in NUnit that you can use for creating tests.&lt;br /&gt;
&lt;br /&gt;
= Testing Todo =&lt;br /&gt;
&lt;br /&gt;
== Coverage ==&lt;br /&gt;
At some point in the future we need to integrate test coverage into the bamboo reports so we can easily see how poorly covered our code is, and look for hotspots where we should focus.  We're still at such an early stage that this is probably overkill to get setup for now.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Security_vulnerability_brought_by_non-check_inventory_service</id>
		<title>Security vulnerability brought by non-check inventory service</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Security_vulnerability_brought_by_non-check_inventory_service"/>
				<updated>2008-08-12T06:57:03Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* *NOTE* */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Problem ==&lt;br /&gt;
&lt;br /&gt;
With the following conditions, one can simply take over the full control(CRUD) of other user's inventory.&lt;br /&gt;
# InventoryServer is exposed to the public.&lt;br /&gt;
# user's UUID is given&lt;br /&gt;
&lt;br /&gt;
Simply describe in the following figure:&lt;br /&gt;
*InventoryServer is a normal http server, the normal way to use it is:&lt;br /&gt;
**user get the authentication from UserServer&lt;br /&gt;
**user control its inventory through RegionServer&lt;br /&gt;
*But since the InventoryServer accepts any request without check if the user is authenticated, or, even it does not check if the request is from a RegionServer.&lt;br /&gt;
*So, if you know other users' UUID, you can send CRUD http requests directly to the InventoryServer without login.&lt;br /&gt;
&lt;br /&gt;
[[Image:secure_inventory_1.PNG]]&lt;br /&gt;
&lt;br /&gt;
And [[Avatar_portability_version_2|AvatarPortability]] needs a public inventory server,&lt;br /&gt;
so we have to make a secure one.&lt;br /&gt;
&lt;br /&gt;
== Solution ==&lt;br /&gt;
&lt;br /&gt;
* every inventory operation packet contains a &amp;quot;session_id&amp;quot; field, but it is never used.&lt;br /&gt;
* so, a secure inventory service could be like this&lt;br /&gt;
[[Image:secure_inventory_2.PNG]]&lt;br /&gt;
* &amp;quot;session_id&amp;quot; is a important information, that is(should be) only transfered in a login session.&lt;br /&gt;
**&amp;quot;expect_user&amp;quot; transfer &amp;quot;session_id&amp;quot; from UserServer to RegionServer only when the authentication is OK, so &amp;quot;expect_user&amp;quot; is safe.&lt;br /&gt;
**method, such like &amp;quot;get_agent_by_uuid&amp;quot; is very dangerous.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== RegionServer side ===&lt;br /&gt;
* in OpenSim.ini, [Network] section,&lt;br /&gt;
 inventory_server_url = http://127.0.0.1:8004&lt;br /&gt;
 '''secure_inventory_server''' = true / false&lt;br /&gt;
* if the inventory server specified by &amp;quot;inventory_server_url&amp;quot; is a &amp;quot;secure&amp;quot; inventory server, set &amp;quot;secure_inventory_server = true&amp;quot;. Then, inventory requests from the region server will have the user's session_id attached&lt;br /&gt;
* else, set &amp;quot;secure_inventory_server = false&amp;quot;. In this case, session_id is not attached to inventory requests.&lt;br /&gt;
** Setting secure_inventory_server to false is only useful when you want your region server to connect to an '''old inventory server''' which does not expect a session_id.&lt;br /&gt;
&lt;br /&gt;
=== InventoryServer side ===&lt;br /&gt;
* in InventoryServer_Config.xml,&lt;br /&gt;
 '''session_lookup''' = true / false&lt;br /&gt;
 (* for session_lookup please also refer the picture above)&lt;br /&gt;
* if you want the inventory server to validate each incoming inventory request by session_id, set session_lookup = true&lt;br /&gt;
* else, set session_lookup = false&lt;br /&gt;
** Setting session_lookup to false makes inventory server accept any request from any client.&lt;br /&gt;
&lt;br /&gt;
=== *NOTE* ===&lt;br /&gt;
* Regardless of whether '''session_lookup''' is true or false, '''new inventory server''' requires a session_id in every inventory request. If you want your region server to connect to a '''new inventory server''', you should always set '''secure_inventory_server = true''' in OpenSim.ini.&lt;br /&gt;
** Here '''new inventory server''' means inventory server after SVN revision 5600.&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Security_vulnerability_brought_by_non-check_inventory_service</id>
		<title>Security vulnerability brought by non-check inventory service</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Security_vulnerability_brought_by_non-check_inventory_service"/>
				<updated>2008-08-12T06:54:30Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* InventoryServer side */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Problem ==&lt;br /&gt;
&lt;br /&gt;
With the following conditions, one can simply take over the full control(CRUD) of other user's inventory.&lt;br /&gt;
# InventoryServer is exposed to the public.&lt;br /&gt;
# user's UUID is given&lt;br /&gt;
&lt;br /&gt;
Simply describe in the following figure:&lt;br /&gt;
*InventoryServer is a normal http server, the normal way to use it is:&lt;br /&gt;
**user get the authentication from UserServer&lt;br /&gt;
**user control its inventory through RegionServer&lt;br /&gt;
*But since the InventoryServer accepts any request without check if the user is authenticated, or, even it does not check if the request is from a RegionServer.&lt;br /&gt;
*So, if you know other users' UUID, you can send CRUD http requests directly to the InventoryServer without login.&lt;br /&gt;
&lt;br /&gt;
[[Image:secure_inventory_1.PNG]]&lt;br /&gt;
&lt;br /&gt;
And [[Avatar_portability_version_2|AvatarPortability]] needs a public inventory server,&lt;br /&gt;
so we have to make a secure one.&lt;br /&gt;
&lt;br /&gt;
== Solution ==&lt;br /&gt;
&lt;br /&gt;
* every inventory operation packet contains a &amp;quot;session_id&amp;quot; field, but it is never used.&lt;br /&gt;
* so, a secure inventory service could be like this&lt;br /&gt;
[[Image:secure_inventory_2.PNG]]&lt;br /&gt;
* &amp;quot;session_id&amp;quot; is a important information, that is(should be) only transfered in a login session.&lt;br /&gt;
**&amp;quot;expect_user&amp;quot; transfer &amp;quot;session_id&amp;quot; from UserServer to RegionServer only when the authentication is OK, so &amp;quot;expect_user&amp;quot; is safe.&lt;br /&gt;
**method, such like &amp;quot;get_agent_by_uuid&amp;quot; is very dangerous.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== RegionServer side ===&lt;br /&gt;
* in OpenSim.ini, [Network] section,&lt;br /&gt;
 inventory_server_url = http://127.0.0.1:8004&lt;br /&gt;
 '''secure_inventory_server''' = true / false&lt;br /&gt;
* if the inventory server specified by &amp;quot;inventory_server_url&amp;quot; is a &amp;quot;secure&amp;quot; inventory server, set &amp;quot;secure_inventory_server = true&amp;quot;. Then, inventory requests from the region server will have the user's session_id attached&lt;br /&gt;
* else, set &amp;quot;secure_inventory_server = false&amp;quot;. In this case, session_id is not attached to inventory requests.&lt;br /&gt;
** Setting secure_inventory_server to false is only useful when you want your region server to connect to an '''old inventory server''' which does not expect a session_id.&lt;br /&gt;
&lt;br /&gt;
=== InventoryServer side ===&lt;br /&gt;
* in InventoryServer_Config.xml,&lt;br /&gt;
 '''session_lookup''' = true / false&lt;br /&gt;
 (* for session_lookup please also refer the picture above)&lt;br /&gt;
* if you want the inventory server to validate each incoming inventory request by session_id, set session_lookup = true&lt;br /&gt;
* else, set session_lookup = false&lt;br /&gt;
** Setting session_lookup to false makes inventory server accept any request from any client.&lt;br /&gt;
&lt;br /&gt;
=== *NOTE* ===&lt;br /&gt;
* no matter '''session_lookup''' is true or false, '''new inventoryserver''' requires session_id in every inventory request. if you want your regionserver to connect to a '''new inventoryserver''', you should always set '''secure_inventory_server = true''' in OpenSim.ini.&lt;br /&gt;
* here '''new inventoryserver''' means inventoryserver after svn revision 5600.&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	<entry>
		<id>http://opensimulator.org/wiki/Security_vulnerability_brought_by_non-check_inventory_service</id>
		<title>Security vulnerability brought by non-check inventory service</title>
		<link rel="alternate" type="text/html" href="http://opensimulator.org/wiki/Security_vulnerability_brought_by_non-check_inventory_service"/>
				<updated>2008-08-12T06:52:42Z</updated>
		
		<summary type="html">&lt;p&gt;Mikem: /* RegionServer side */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Problem ==&lt;br /&gt;
&lt;br /&gt;
With the following conditions, one can simply take over the full control(CRUD) of other user's inventory.&lt;br /&gt;
# InventoryServer is exposed to the public.&lt;br /&gt;
# user's UUID is given&lt;br /&gt;
&lt;br /&gt;
Simply describe in the following figure:&lt;br /&gt;
*InventoryServer is a normal http server, the normal way to use it is:&lt;br /&gt;
**user get the authentication from UserServer&lt;br /&gt;
**user control its inventory through RegionServer&lt;br /&gt;
*But since the InventoryServer accepts any request without check if the user is authenticated, or, even it does not check if the request is from a RegionServer.&lt;br /&gt;
*So, if you know other users' UUID, you can send CRUD http requests directly to the InventoryServer without login.&lt;br /&gt;
&lt;br /&gt;
[[Image:secure_inventory_1.PNG]]&lt;br /&gt;
&lt;br /&gt;
And [[Avatar_portability_version_2|AvatarPortability]] needs a public inventory server,&lt;br /&gt;
so we have to make a secure one.&lt;br /&gt;
&lt;br /&gt;
== Solution ==&lt;br /&gt;
&lt;br /&gt;
* every inventory operation packet contains a &amp;quot;session_id&amp;quot; field, but it is never used.&lt;br /&gt;
* so, a secure inventory service could be like this&lt;br /&gt;
[[Image:secure_inventory_2.PNG]]&lt;br /&gt;
* &amp;quot;session_id&amp;quot; is a important information, that is(should be) only transfered in a login session.&lt;br /&gt;
**&amp;quot;expect_user&amp;quot; transfer &amp;quot;session_id&amp;quot; from UserServer to RegionServer only when the authentication is OK, so &amp;quot;expect_user&amp;quot; is safe.&lt;br /&gt;
**method, such like &amp;quot;get_agent_by_uuid&amp;quot; is very dangerous.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== RegionServer side ===&lt;br /&gt;
* in OpenSim.ini, [Network] section,&lt;br /&gt;
 inventory_server_url = http://127.0.0.1:8004&lt;br /&gt;
 '''secure_inventory_server''' = true / false&lt;br /&gt;
* if the inventory server specified by &amp;quot;inventory_server_url&amp;quot; is a &amp;quot;secure&amp;quot; inventory server, set &amp;quot;secure_inventory_server = true&amp;quot;. Then, inventory requests from the region server will have the user's session_id attached&lt;br /&gt;
* else, set &amp;quot;secure_inventory_server = false&amp;quot;. In this case, session_id is not attached to inventory requests.&lt;br /&gt;
** Setting secure_inventory_server to false is only useful when you want your region server to connect to an '''old inventory server''' which does not expect a session_id.&lt;br /&gt;
&lt;br /&gt;
=== InventoryServer side ===&lt;br /&gt;
* in InventoryServer_Config.xml,&lt;br /&gt;
 '''session_lookup''' = true / false&lt;br /&gt;
 (* for the session_lookup please also refer the above picture.)&lt;br /&gt;
* if you want inventory server to validate the incoming session_id, set session_lookup = true&lt;br /&gt;
* else, set session_lookup = false&lt;br /&gt;
** this makes inventory server accept any request, just like before.&lt;br /&gt;
&lt;br /&gt;
=== *NOTE* ===&lt;br /&gt;
* no matter '''session_lookup''' is true or false, '''new inventoryserver''' requires session_id in every inventory request. if you want your regionserver to connect to a '''new inventoryserver''', you should always set '''secure_inventory_server = true''' in OpenSim.ini.&lt;br /&gt;
* here '''new inventoryserver''' means inventoryserver after svn revision 5600.&lt;/div&gt;</summary>
		<author><name>Mikem</name></author>	</entry>

	</feed>