The Assimilation Project  based on Assimilation version 1.1.7.1474836767
assimevent_test.py
Go to the documentation of this file.
1 #!/usr/bin/python
2 # vim: smartindent tabstop=4 shiftwidth=4 expandtab number
3 #
4 # This file is part of the Assimilation Project.
5 #
6 # Author: Alan Robertson <alanr@unix.sh>
7 # Copyright (C) 2013 - Assimilation Systems Limited
8 #
9 # Free support is available from the Assimilation Project community - http://assimproj.org
10 # Paid support is available from Assimilation Systems Limited - http://assimilationsystems.com
11 #
12 # The Assimilation software is free software: you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation, either version 3 of the License, or
15 # (at your option) any later version.
16 #
17 # The Assimilation software is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
21 #
22 # You should have received a copy of the GNU General Public License
23 # along with the Assimilation Project software. If not, see http://www.gnu.org/licenses/
24 #
25 #
26 _suites = ['all', 'events']
27 import sys
28 sys.path.append("..")
29 sys.path.append("../cma")
30 sys.path.append("/usr/local/lib/python2.7/dist-packages")
31 import os, sys, tempfile, time, signal
32 from assimevent import AssimEvent
33 from assimeventobserver import ForkExecObserver
34 
35 DEBUG=False
36 
37 AssimEvent.enable_all_observers()
38 
39 def makescript(createdscriptname, outfile):
40  'Create the requested script - outputting to requested file'
41  script='''#!/bin/sh
42  # Simple script to test external event interfaces
43  ( echo "====START===="
44  j=1
45  for arg
46  do
47  echo "ARG${j}=$arg"
48  j=$(expr $j + 1)
49  done
50  env | grep '^ASSIM_' | LC_ALL=C sort
51  echo "==== JSON START ===="
52  cat
53  printf '\n==== JSON END ====\n'
54  echo "====END===="
55  ) >> %s 2>&1
56 '''
57  f = open(createdscriptname, 'w')
58  f.write(script % outfile)
59  f.close()
60  os.chmod(createdscriptname, 0755)
61 
63  def __init__(self):
64  self.nodetype = 'ClientClass'
65  pass
66 
67 
69  'An observer class for testing AssimEvents - we just keep a list of notifications'
70  def __init__(self):
71  self.events = []
72  pass
73 
74  def notifynewevent(self, event):
75  self.events.append(event)
76 
77 
79  "An un-observer class for testing AssimEvent failures - doesn't do anything"
80  def __init__(self):
81  pass
82 
83 class TestCase(object):
84  def assertEqual(self, a, b):
85  assert a == b
86  def assertTrue(self, a):
87  assert a is True
88  def assertFalse(self, a):
89  assert a is False
90  def assertRaises(self, exception, function, *args):
91  try:
92  function(*args)
93  raise Exception('Did not raise exception %s: %s(%s)', exception, function, str(args))
94  except exception as e:
95  return True
96 
98  'Class for basic AssimEvent testing'
99 
100  @staticmethod
101  def waitfor(pathname, expectedcontent, timeout=20):
102  for j in range(0, timeout):
103  f=open(pathname, 'r')
104  content=f.read()
105  f.close()
106  if content == expectedcontent:
107  return
108  time.sleep(0.1)
109  return
110 
112  'Perform a few simple AssimEvent good initializations'
113  AssimEvent.enable_all_observers()
114  AssimEvent.observers = []
115  observer=DummyObserver()
116  AssimEvent.registerobserver(observer)
117  event1 = AssimEvent('first', AssimEvent.CREATEOBJ)
118  self.assertEqual(len(observer.events), 1)
119  self.assertEqual(observer.events[0], event1)
120  self.assertEqual(AssimEvent.unregisterobserver(observer), True)
121  event2 = AssimEvent('second', AssimEvent.CREATEOBJ)
122  self.assertEqual(len(observer.events), 1)
123  self.assertEqual(observer.events[0], event1)
124  AssimEvent.registerobserver(observer)
125  event3 = AssimEvent('third', AssimEvent.CREATEOBJ)
126  self.assertEqual(len(observer.events), 2)
127  self.assertEqual(observer.events[1], event3)
128 
130  'Perform a few simple AssimEvent bad initializations'
131  AssimEvent.enable_all_observers()
132  AssimEvent.observers = []
133  observer=DummyObserver()
134  badobserver=BadObserver()
135  AssimEvent.registerobserver(observer)
136  self.assertRaises(ValueError, AssimEvent, 'first', 999)
137  self.assertRaises(AttributeError, AssimEvent.registerobserver, badobserver)
138 
140  '''This test will create a fork/exec event observer script
141  and then test to see if its getting invoked properly...
142  '''
143  AssimEvent.enable_all_observers()
144  tmpdir = tempfile.mkdtemp('.d', 'testexec_')
145  (fd, pathname) = tempfile.mkstemp('.out.txt')
146  execscript = os.path.join(tmpdir, 'observer.sh')
147  makescript(execscript, pathname)
148  AssimEvent.observers = []
149  observer=ForkExecObserver(scriptdir=tmpdir)
150  dummyclient = ClientClass()
151  dummyclient.fred='fred'
152  dummyclient.sevenofnine='Annika'
153  dummyclient.foo = {'foo': 'bar'}
154 
155  self.assertEqual(observer.listscripts(), [execscript,])
156  AssimEvent.registerobserver(observer)
157  AssimEvent(dummyclient, AssimEvent.CREATEOBJ)
158  AssimEvent(dummyclient, AssimEvent.OBJUP, extrainfo={'origaddr': '10.10.10.254'})
159  os.close(fd)
160  expectedcontent=\
161 '''====START====
162 ARG1=create
163 ARG2=ClientClass
164 ASSIM_fred=fred
165 ASSIM_nodetype=ClientClass
166 ASSIM_sevenofnine=Annika
167 ==== JSON START ====
168 {"associatedobject":{"foo":{"foo":"bar"},"fred":"fred","nodetype":"ClientClass","sevenofnine":"Annika"},"eventtype":0,"extrainfo":null}
169 ==== JSON END ====
170 ====END====
171 ====START====
172 ARG1=up
173 ARG2=ClientClass
174 ASSIM_fred=fred
175 ASSIM_nodetype=ClientClass
176 ASSIM_origaddr=10.10.10.254
177 ASSIM_sevenofnine=Annika
178 ==== JSON START ====
179 {"associatedobject":{"foo":{"foo":"bar"},"fred":"fred","nodetype":"ClientClass","sevenofnine":"Annika"},"eventtype":1,"extrainfo":{"origaddr":"10.10.10.254"}}
180 ==== JSON END ====
181 ====END====
182 '''
183  TestAssimEvent.waitfor(pathname, expectedcontent)
184  f=open(pathname, 'r')
185  content=f.read()
186  f.close()
187  self.assertEqual(content, expectedcontent)
188  os.unlink(execscript)
189  os.unlink(pathname)
190  os.rmdir(tmpdir)
191 
193  '''This test will create a fork/exec event observer script
194  and then kill the child listener and verify that it is handled
195  correctly.
196  '''
197  AssimEvent.enable_all_observers()
198  tmpdir = tempfile.mkdtemp('.d', 'testexec_')
199  (fd, pathname) = tempfile.mkstemp('.out.txt')
200  execscript = os.path.join(tmpdir, 'observer.sh')
201  makescript(execscript, pathname)
202  AssimEvent.observers = []
203  observer=ForkExecObserver(scriptdir=tmpdir)
204  dummyclient = ClientClass()
205  dummyclient.fred='fred'
206  dummyclient.sevenofnine='Annika'
207  dummyclient.foo = {'foo': 'bar'}
208  AssimEvent.registerobserver(observer)
209  try:
210  os.kill(observer.childpid, signal.SIGKILL)
211  except OSError:
212  # "docker build" doesn't let us kill processes...
213  # so we give up on this test and call it good...
214  os.unlink(execscript)
215  os.unlink(pathname)
216  os.rmdir(tmpdir)
217  return
218  time.sleep(0.1)
219  AssimEvent(dummyclient, AssimEvent.CREATEOBJ)
220  # Death of our FIFO child will cause it to get respawned, and
221  # message sent to new child. No messages should be lost.
222  expectedcontent=\
223 '''====START====
224 ARG1=create
225 ARG2=ClientClass
226 ASSIM_fred=fred
227 ASSIM_nodetype=ClientClass
228 ASSIM_sevenofnine=Annika
229 ==== JSON START ====
230 {"associatedobject":{"foo":{"foo":"bar"},"fred":"fred","nodetype":"ClientClass","sevenofnine":"Annika"},"eventtype":0,"extrainfo":null}
231 ==== JSON END ====
232 ====END====
233 '''
234  TestAssimEvent.waitfor(pathname, expectedcontent)
235  f=open(pathname, 'r')
236  content=f.read()
237  f.close()
238  self.assertEqual(content, expectedcontent)
239  os.close(fd)
240  os.unlink(execscript)
241  os.unlink(pathname)
242  os.rmdir(tmpdir)
def assertRaises(self, exception, function, args)
def waitfor(pathname, expectedcontent, timeout=20)
def makescript(createdscriptname, outfile)