OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
CoopTerminationTests.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections.Generic;
30 using System.Threading;
31 using Nini.Config;
32 using NUnit.Framework;
33 using OpenMetaverse;
34 using OpenSim.Framework;
35 using OpenSim.Region.CoreModules.Scripting.WorldComm;
36 using OpenSim.Region.Framework.Scenes;
37 using OpenSim.Region.Framework.Interfaces;
38 using OpenSim.Region.ScriptEngine.XEngine;
39 using OpenSim.Tests.Common;
40 
41 namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests
42 {
46  [TestFixture]
48  {
49  private TestScene m_scene;
51 
52  private AutoResetEvent m_chatEvent;
53  private AutoResetEvent m_stoppedEvent;
54 
55  private OSChatMessage m_osChatMessageReceived;
56 
60  private int m_chatMessagesReceived;
61 
65  private int m_chatMessagesThreshold;
66 
67  [SetUp]
68  public void Init()
69  {
70  m_osChatMessageReceived = null;
71  m_chatMessagesReceived = 0;
72  m_chatMessagesThreshold = 0;
73  m_chatEvent = new AutoResetEvent(false);
74  m_stoppedEvent = new AutoResetEvent(false);
75 
76  //AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory + "/bin");
77 // Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory);
79  m_xEngine.DebugLevel = 1;
80 
81  IniConfigSource configSource = new IniConfigSource();
82 
83  IConfig startupConfig = configSource.AddConfig("Startup");
84  startupConfig.Set("DefaultScriptEngine", "XEngine");
85 
86  IConfig xEngineConfig = configSource.AddConfig("XEngine");
87  xEngineConfig.Set("Enabled", "true");
88  xEngineConfig.Set("StartDelay", "0");
89 
90  // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call
91  // to AssemblyResolver.OnAssemblyResolve fails.
92  xEngineConfig.Set("AppDomainLoading", "false");
93 
94  xEngineConfig.Set("ScriptStopStrategy", "co-op");
95 
96  // Make sure loops aren't actually being terminated by a script delay wait.
97  xEngineConfig.Set("ScriptDelayFactor", 0);
98 
99  // This is really just set for debugging the test.
100  xEngineConfig.Set("WriteScriptSourceToDebugFile", true);
101 
102  // Set to false if we need to debug test so the old scripts don't get wiped before each separate test
103 // xEngineConfig.Set("DeleteScriptsOnStartup", false);
104 
105  // This is not currently used at all for co-op termination. Bumping up to demonstrate that co-op termination
106  // has an effect - without it tests will fail due to a 120 second wait for the event to finish.
107  xEngineConfig.Set("WaitForEventCompletionOnScriptStop", 120000);
108 
109  m_scene = new SceneHelpers().SetupScene("My Test", TestHelpers.ParseTail(0x9999), 1000, 1000, configSource);
110  SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine);
111  m_scene.StartScripts();
112  }
113 
121  [Test]
122  public void TestStopOnLongSleep()
123  {
124  TestHelpers.InMethod();
125 // TestHelpers.EnableLogging();
126 
127  string script =
128 @"default
129 {
130  state_entry()
131  {
132  llSay(0, ""Thin Lizzy"");
133  llSleep(60);
134  }
135 }";
136 
137  TestStop(script);
138  }
139 
140  [Test]
142  {
143  TestHelpers.InMethod();
144 // TestHelpers.EnableLogging();
145 
146  string script =
147 @"default
148 {
149  state_entry()
150  {
151  integer i = 0;
152  for (i = 0; i <= 1; i++) llSay(0, ""Iter "" + (string)i);
153  }
154 }";
155 
156  TestSingleStatementNoStop(script);
157  }
158 
159  [Test]
161  {
162  TestHelpers.InMethod();
163 // TestHelpers.EnableLogging();
164 
165  string script =
166 @"default
167 {
168  state_entry()
169  {
170  integer i = 0;
171  llSay(0, ""Thin Lizzy"");
172 
173  for (i = 0; i < 2147483647; i++) llSay(0, ""Iter "" + (string)i);
174  }
175 }";
176 
177  TestStop(script);
178  }
179 
180  [Test]
182  {
183  TestHelpers.InMethod();
184 // TestHelpers.EnableLogging();
185 
186  string script =
187 @"default
188 {
189  state_entry()
190  {
191  integer i = 0;
192  llSay(0, ""Thin Lizzy"");
193 
194  for (i = 0; i < 2147483647; i++)
195  {
196  llSay(0, ""Iter "" + (string)i);
197  }
198  }
199 }";
200 
201  TestStop(script);
202  }
203 
204  [Test]
206  {
207  TestHelpers.InMethod();
208 // TestHelpers.EnableLogging();
209 
210  string script =
211 @"default
212 {
213  state_entry()
214  {
215  integer i = 0;
216  while (i < 2) llSay(0, ""Iter "" + (string)i++);
217  }
218 }";
219 
220  TestSingleStatementNoStop(script);
221  }
222 
223  [Test]
225  {
226  TestHelpers.InMethod();
227 // TestHelpers.EnableLogging();
228 
229  string script =
230 @"default
231 {
232  state_entry()
233  {
234  integer i = 0;
235  llSay(0, ""Thin Lizzy"");
236 
237  while (1 == 1)
238  llSay(0, ""Iter "" + (string)i++);
239  }
240 }";
241 
242  TestStop(script);
243  }
244 
245  [Test]
247  {
248  TestHelpers.InMethod();
249 // TestHelpers.EnableLogging();
250 
251  string script =
252 @"default
253 {
254  state_entry()
255  {
256  integer i = 0;
257  llSay(0, ""Thin Lizzy"");
258 
259  while (1 == 1)
260  {
261  llSay(0, ""Iter "" + (string)i++);
262  }
263  }
264 }";
265 
266  TestStop(script);
267  }
268 
269  [Test]
271  {
272  TestHelpers.InMethod();
273 // TestHelpers.EnableLogging();
274 
275  string script =
276 @"default
277 {
278  state_entry()
279  {
280  integer i = 0;
281 
282  do llSay(0, ""Iter "" + (string)i++);
283  while (i < 2);
284  }
285 }";
286 
287  TestSingleStatementNoStop(script);
288  }
289 
290  [Test]
292  {
293  TestHelpers.InMethod();
294 // TestHelpers.EnableLogging();
295 
296  string script =
297 @"default
298 {
299  state_entry()
300  {
301  integer i = 0;
302  llSay(0, ""Thin Lizzy"");
303 
304  do llSay(0, ""Iter "" + (string)i++);
305  while (1 == 1);
306  }
307 }";
308 
309  TestStop(script);
310  }
311 
312  [Test]
314  {
315  TestHelpers.InMethod();
316 // TestHelpers.EnableLogging();
317 
318  string script =
319 @"default
320 {
321  state_entry()
322  {
323  integer i = 0;
324  llSay(0, ""Thin Lizzy"");
325 
326  do
327  {
328  llSay(0, ""Iter "" + (string)i++);
329  } while (1 == 1);
330  }
331 }";
332 
333  TestStop(script);
334  }
335 
336  [Test]
338  {
339  TestHelpers.InMethod();
340  TestHelpers.EnableLogging();
341 
342  string script =
343 @"default
344 {
345  state_entry()
346  {
347  integer i = 0;
348  llSay(0, ""Thin Lizzy"");
349 
350  @p1;
351  llSay(0, ""Iter "" + (string)i++);
352  jump p1;
353  }
354 }";
355 
356  TestStop(script);
357  }
358 
359  // Disabling for now as these are not particularly useful tests (since they fail due to stack overflow before
360  // termination can even be tried.
361 // [Test]
363  {
364  TestHelpers.InMethod();
365 // TestHelpers.EnableLogging();
366 
367  string script =
368 @"
369 integer i = 0;
370 
371 ufn1()
372 {
373  llSay(0, ""Iter ufn1() "" + (string)i++);
374  ufn1();
375 }
376 
377 default
378 {
379  state_entry()
380  {
381  integer i = 0;
382  llSay(0, ""Thin Lizzy"");
383 
384  ufn1();
385  }
386 }";
387 
388  TestStop(script);
389  }
390 
391  // Disabling for now as these are not particularly useful tests (since they fail due to stack overflow before
392  // termination can even be tried.
393 // [Test]
395  {
396  TestHelpers.InMethod();
397 // TestHelpers.EnableLogging();
398 
399  string script =
400 @"default
401 {
402  state_entry()
403  {
404  integer i = 0;
405  llSay(0, ""Thin Lizzy"");
406 
407  llSay(0, ""Iter"" + (string)i++);
408  default_event_state_entry();
409  }
410 }";
411 
412  TestStop(script);
413  }
414 
415  private SceneObjectPart CreateScript(string script, string itemName, UUID userId)
416  {
417 // UUID objectId = TestHelpers.ParseTail(0x100);
418 // UUID itemId = TestHelpers.ParseTail(0x3);
419 
420  SceneObjectGroup so
421  = SceneHelpers.CreateSceneObject(1, userId, string.Format("Object for {0}", itemName), 0x100);
422  m_scene.AddNewSceneObject(so, true);
423 
424  InventoryItemBase itemTemplate = new InventoryItemBase();
425 // itemTemplate.ID = itemId;
426  itemTemplate.Name = itemName;
427  itemTemplate.Folder = so.UUID;
428  itemTemplate.InvType = (int)InventoryType.LSL;
429 
430  m_scene.EventManager.OnChatFromWorld += OnChatFromWorld;
431 
432  return m_scene.RezNewScript(userId, itemTemplate, script);
433  }
434 
435  private void TestSingleStatementNoStop(string script)
436  {
437  // In these tests we expect to see at least 2 chat messages to confirm that the loop is working properly.
438  m_chatMessagesThreshold = 2;
439 
440  UUID userId = TestHelpers.ParseTail(0x1);
441 // UUID objectId = TestHelpers.ParseTail(0x100);
442 // UUID itemId = TestHelpers.ParseTail(0x3);
443  string itemName = "TestNoStop";
444 
445  SceneObjectPart partWhereRezzed = CreateScript(script, itemName, userId);
446 
447  // Wait for the script to start the event before we try stopping it.
448  m_chatEvent.WaitOne(60000);
449 
450  if (m_osChatMessageReceived == null)
451  Assert.Fail("Script did not start");
452  else
453  Assert.That(m_chatMessagesReceived, Is.EqualTo(2));
454 
455  bool running;
456  TaskInventoryItem scriptItem = partWhereRezzed.Inventory.GetInventoryItem(itemName);
457  Assert.That(
458  SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, scriptItem, out running), Is.True);
459  Assert.That(running, Is.True);
460  }
461 
462  private void TestStop(string script)
463  {
464  // In these tests we're only interested in the first message to confirm that the script has started.
465  m_chatMessagesThreshold = 1;
466 
467  UUID userId = TestHelpers.ParseTail(0x1);
468 // UUID objectId = TestHelpers.ParseTail(0x100);
469 // UUID itemId = TestHelpers.ParseTail(0x3);
470  string itemName = "TestStop";
471 
472  SceneObjectPart partWhereRezzed = CreateScript(script, itemName, userId);
473  TaskInventoryItem rezzedItem = partWhereRezzed.Inventory.GetInventoryItem(itemName);
474 
475  // Wait for the script to start the event before we try stopping it.
476  m_chatEvent.WaitOne(60000);
477 
478  if (m_osChatMessageReceived != null)
479  Console.WriteLine("Script started with message [{0}]", m_osChatMessageReceived.Message);
480  else
481  Assert.Fail("Script did not start");
482 
483  // FIXME: This is a very poor way of trying to avoid a low-probability race condition where the script
484  // executes llSay() but has not started the next statement before we try to stop it.
485  Thread.Sleep(1000);
486 
487  // We need a way of carrying on if StopScript() fail, since it won't return if the script isn't actually
488  // stopped. This kind of multi-threading is far from ideal in a regression test.
489  new Thread(() => { m_xEngine.StopScript(rezzedItem.ItemID); m_stoppedEvent.Set(); }).Start();
490 
491  if (!m_stoppedEvent.WaitOne(30000))
492  Assert.Fail("Script did not co-operatively stop.");
493 
494  bool running;
495  TaskInventoryItem scriptItem = partWhereRezzed.Inventory.GetInventoryItem(itemName);
496  Assert.That(
497  SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, scriptItem, out running), Is.True);
498  Assert.That(running, Is.False);
499  }
500 
501  private void OnChatFromWorld(object sender, OSChatMessage oscm)
502  {
503  Console.WriteLine("Got chat [{0}]", oscm.Message);
504  m_osChatMessageReceived = oscm;
505 
506  if (++m_chatMessagesReceived >= m_chatMessagesThreshold)
507  {
508  m_scene.EventManager.OnChatFromWorld -= OnChatFromWorld;
509  m_chatEvent.Set();
510  }
511  }
512  }
513 }
void TestStopOnLongSleep()
Test co-operative termination on derez of an object containing a script with a long-running event...
A scene object group is conceptually an object in the scene. The object is constituted of SceneObject...
Represents an item in a task inventory
ChatFromViewer Arguments
Inventory Item - contains all the properties associated with an individual inventory piece...
Helpers for setting up scenes.
Definition: SceneHelpers.cs:60
Interactive OpenSim region server
Definition: OpenSim.cs:55
Test that co-operative script thread termination is working correctly.