class PresenterTestCleanup(ioflo.base.deeding.Deed): ''' Clean up after a test ''' Ioinits = { 'presence_req': '.salt.presence.event_req', 'alloweds': { 'ipath': '.salt.var.presence.alloweds', 'ival': odict() }, 'aliveds': { 'ipath': '.salt.var.presence.aliveds', 'ival': odict() }, 'reapeds': { 'ipath': '.salt.var.presence.reapeds', 'ival': odict() }, 'availables': { 'ipath': '.salt.var.presence.availables', 'ival': set() } } def action(self): self.presence_req.value = deque() self.availables.value = set() self.alloweds.value = odict() self.aliveds.value = odict() self.reapeds.value = odict()
def testODict(self): """ Test the odict class """ console.terse("{0}\n".format(self.testODict.__doc__)) x = odicting.odict() x["a"] = 5 self.assertEqual(x.items(), [('a', 5)]) x["a"] = 6 self.assertEqual(x.items(), [('a', 6)]) items = [("x", 1), ("y", 2), ("a", 3)] keys = [key for key, val in items] values = [val for key, val in items] od = odicting.odict(items) self.assertEqual(od.keys(), keys) self.assertEqual(od.values(), values) self.assertEqual(od.items(), items) fields = ['y', 'x'] stuff = od.sift(fields) self.assertEqual(stuff.items(), [('y', 2), ('x', 1)]) stuff = od.sift() self.assertEqual(stuff.items(), od.items())
class RaetRoadStackAllowed(deeding.Deed): ''' Updates status field in share with .allowed of zeroth remote estate (main) FloScript: do raet road stack allowed go next if allowed in .raet.road.stack.status ''' Ioinits = odict(inode=".raet.road.stack.", stack='stack', status=odict(ipath='status', ival=odict( joined=False, allowed=False, idle=False, ))) def action(self, **kwa): ''' Update .status share ''' stack = self.stack.value allowed = False if stack and isinstance(stack, RoadStack): if stack.remotes: allowed = stack.remotes.values()[0].allowed self.status.update(allowed=allowed)
def manage(self, cascade=False, immediate=False): ''' Manage remote estates. Time based processing of remote status such as presence (keep alive) etc. cascade induces the alive transactions to run join, allow, alive until failure or alive success immediate indicates to run first attempt immediately and not wait for timer availables = dict of remotes that are both alive and allowed ''' alloweds = odict() aliveds = odict() reapeds = odict() for remote in self.remotes.values(): # should not start anything remote.manage(cascade=cascade, immediate=immediate) if remote.allowed: alloweds[remote.name] = remote if remote.alived: aliveds[remote.name] = remote if remote.reaped: reapeds[remote.name] = remote old = set(self.aliveds.keys()) current = set(aliveds.keys()) plus = current.difference(old) minus = old.difference(current) self.availables = current self.changeds = odict(plus=plus, minus=minus) self.alloweds = alloweds self.aliveds = aliveds self.reapeds = reapeds
class RaetRoadStackIdled(deeding.Deed): ''' Updates idle status field in shate to true if there are no outstanding transactions in the associated stack FloScript: do raet road stack idled go next if idled in .raet.road.stack.status ''' Ioinits = odict(inode=".raet.road.stack.", stack='stack', status=odict(ipath='status', ival=odict( joined=False, allowed=False, idle=False, ))) def action(self, **kwa): ''' Update .status share ''' stack = self.stack.value idled = False if stack and isinstance(stack, RoadStack): if not stack.transactions: idled = True self.status.update(idled=idled)
def action(self): self.presence_req.value = deque() self.availables.value = set() self.alloweds.value = odict() self.aliveds.value = odict() self.reapeds.value = odict() # Create event stack name = 'event' + nacling.uuid(size=18) lanename = self.lane_stack.value.local.lanename sock_dir = self.lane_stack.value.local.dirpath ryn = 'manor' console.terse("Create stack: name = {0}, lanename = {1}, sock_dir = {2}\n". format(name, lanename, sock_dir)) stack = LaneStack( name=name, lanename=lanename, sockdirpath=sock_dir) stack.addRemote(RemoteYard(stack=stack, lanename=lanename, name=ryn, dirpath=sock_dir)) self.event_stack.value = stack route = {'dst': (None, ryn, 'presence_req'), 'src': (None, stack.local.name, None)} msg = {'route': route} stack.transmit(msg, stack.nameRemotes[ryn].uid) serviceLanes([stack, self.lane_stack.value])
def action(self): self.presence_req.value = deque() self.availables.value = set() self.alloweds.value = odict() self.aliveds.value = odict() self.reapeds.value = odict()
def testPackParseMsgpack(self): ''' Test basic page pack and parse ''' console.terse("{0}\n".format(self.testPackParseMsgpack.__doc__)) data = odict(pk=raeting.PackKind.pack.value) sid = nacling.uuid(size=18) data.update(odict(sn="boy", dn='girl', si=sid, bi=1)) src = ['mayor', 'main', None] dst = ['citizen', 'other', None] route = odict([('src', src), ('dst', dst)]) body = odict([('route', route), ('content', "Hello all yards.")]) page0 = paging.TxPage(data=data, embody=body) self.assertDictEqual(page0.body.data, body) page0.pack() self.assertEqual(len(page0.packed), 147) self.assertEqual( page0.packed, ns2b( 'ri RAET\nvn 0\npk 1\nsn boy\ndn girl\nsi {0:.18s}\nbi 1\npn 0000\npc 0001\n\n\x82\xa5route\x82\xa3src\x93\xa5mayor\xa4main\xc0\xa3dst\x93\xa7citizen\xa5other\xc0\xa7content\xb0Hello all yards.' .format(sid))) page1 = paging.RxPage(packed=page0.packed) page1.parse() self.assertDictEqual(page1.body.data, body)
class RaetLaneStackYardAdd(deeding.Deed): ''' Adds yard to lane stack. Where lane is the lane name and name is the yard name in the parameters FloScript: do raet lane stack yard add to lane "ash" name "lord" at enter ''' Ioinits = odict(inode=".raet.lane.stack.", stack='stack', local=odict( ipath='local', ival=odict(sockdirpath="/tmp/raet/test/lane/"))) def action(self, lane="lane", name=None, **kwa): ''' Adds new yard to stack on lane with name ''' stack = self.stack.value sockdirpath = self.local.data.sockdirpath if stack and isinstance(stack, LaneStack): yard = yarding.RemoteYard(stack=stack, lanename=lane, name=name, dirpath=sockdirpath) stack.addRemote(yard) self.local.value = yard
def testMessageSectionedMsgpack(self): ''' Sectioned messages with msgpack packing ''' console.terse("{0}\n".format(self.testMessageSectionedMsgpack.__doc__)) self.bootstrap(kind=raeting.PackKind.pack.value) #big packets stuff = [] for i in range(10000): stuff.append(str(i).rjust(10, " ")) stuff = "".join(stuff) src = ['mayor', self.main.local.name, None] dst = ['citizen', self.other.local.name, None] route = odict([('src', src), ('dst', dst)]) mains = [] mains.append(odict([('route', route), ('content', stuff)])) src = ['citizen', self.other.local.name, None] dst = ['mayor', self.main.local.name, None] route = odict([('src', src), ('dst', dst)]) others = [] others.append(odict([('route', route), ('content', stuff)])) self.message(mains=mains, others=others, duration=2.0)
class RaetLaneStackPrinter(deeding.Deed): ''' Prints out messages on rxMsgs queue FloScript: do raet lane stack printer ''' Ioinits = odict( inode=".raet.lane.stack.", total=odict(ipath="totalRxMsg", ival=odict(value=0)), stack="stack", rxmsgs=odict(ipath='rxmsgs', ival=deque()), ) def action(self, **kwa): ''' Receive message ''' rxMsgs = self.rxmsgs.value stack = self.stack.value while rxMsgs: msg, name = rxMsgs.popleft() console.terse("\n{0} Received....\n{1}\n".format(stack.name, msg)) self.total.value += 1
def testSegmentedMsgpackBurst(self): ''' Test segmented message transactions with burst count limiting ''' console.terse("{0}\n".format(self.testSegmentedMsgpackBurst.__doc__)) stuff = [] for i in range(300): stuff.append(str(i).rjust(10, " ")) stuff = "".join(stuff) others = [] mains = [] others.append(odict(house="Snake eyes", queue="near stuff", stuff=stuff)) mains.append(odict(house="Craps", queue="far stuff", stuff=stuff)) bloat = [] for i in range(300): bloat.append(str(i).rjust(100, " ")) bloat = "".join(bloat) others.append(odict(house="Other", queue="big stuff", bloat=bloat)) mains.append(odict(house="Main", queue="gig stuff", bloat=bloat)) stacking.RoadStack.BurstSize = 16 self.assertEqual(stacking.RoadStack.BurstSize, 16) self.bidirectional(bk=raeting.BodyKind.msgpack.value, mains=mains, others=others, duration=20.0) stacking.RoadStack.BurstSize = 0 self.assertEqual(stacking.RoadStack.BurstSize, 0)
def testPackParseMsgpack(self): """ Test basic page pack and parse """ console.terse("{0}\n".format(self.testPackParseMsgpack.__doc__)) data = odict(pk=raeting.PackKind.pack.value) sid = nacling.uuid(size=18) data.update(odict(sn="boy", dn="girl", si=sid, bi=1)) src = ["mayor", "main", None] dst = ["citizen", "other", None] route = odict([("src", src), ("dst", dst)]) body = odict([("route", route), ("content", "Hello all yards.")]) page0 = paging.TxPage(data=data, embody=body) self.assertDictEqual(page0.body.data, body) page0.pack() self.assertEqual(len(page0.packed), 147) self.assertEqual( page0.packed, ns2b( "ri RAET\nvn 0\npk 1\nsn boy\ndn girl\nsi {0:.18s}\nbi 1\npn 0000\npc 0001\n\n\x82\xa5route\x82\xa3src\x93\xa5mayor\xa4main\xc0\xa3dst\x93\xa7citizen\xa5other\xc0\xa7content\xb0Hello all yards.".format( sid ) ), ) page1 = paging.RxPage(packed=page0.packed) page1.parse() self.assertDictEqual(page1.body.data, body)
def authTest(token=None): """ Auth credentials in body data as json or query parameters or token from end of url path or token from X-Auth-Token header """ if not token: token = bottle.request.get_header('X-Auth-Token') data = bottle.request.json if not token: user = data.get('user') password = data.get('password') query = odict(bottle.request.query.items()) if not user or not password: user = query.get('user') password = query.get('password') if not token and (not user or not password): bottle.abort(400, "Authentication credentials missing.") result = odict(token=token, user=user, password=password, headers=odict(bottle.request.headers.items()), query=query, data=data, ) return result
def action(self): self.presence_req.value = deque() self.availables.value = set() self.alloweds.value = odict() self.aliveds.value = odict() self.reapeds.value = odict() # Create event stack name = 'event' + nacling.uuid(size=18) lanename = self.lane_stack.value.local.lanename sock_dir = self.lane_stack.value.local.dirpath ryn = 'manor' console.terse( "Create stack: name = {0}, lanename = {1}, sock_dir = {2}\n". format(name, lanename, sock_dir)) stack = LaneStack(name=name, lanename=lanename, sockdirpath=sock_dir) stack.addRemote( RemoteYard(stack=stack, lanename=lanename, name=ryn, dirpath=sock_dir)) self.event_stack.value = stack route = { 'dst': (None, ryn, 'presence_req'), 'src': (None, stack.local.name, None) } msg = {'route': route} stack.transmit(msg, stack.nameRemotes[ryn].uid) serviceLanes([stack, self.lane_stack.value])
def __init__(self, store=None, version=raeting.VERSION, main=None, puid=None, local=None, #passed up from subclass name='', uid=None, server=None, ha=None, bufcnt=2, rxMsgs=None, txMsgs=None, rxes=None, txes=None, stats=None, ): ''' Setup Stack instance ''' self.store = store or Store(stamp=0.0) self.version = version self.main = main if getattr(self, 'puid', None) is None: self.puid = puid if puid is not None else self.Uid self.local = local or lotting.Lot(stack=self, name=name, uid=uid, ha=ha,) self.local.stack = self self.remotes = self.uidRemotes = odict() # remotes indexed by uid self.nameRemotes = odict() # remotes indexed by name self.bufcnt = bufcnt if not server: server = self.serverFromLocal() self.server = server if self.server: if not self.server.reopen(): # open socket raise raeting.StackError("Stack '{0}': Failed opening server at" " '{1}'\n".format(self.name, self.server.ha)) self.ha = self.server.ha # update local host address after open console.verbose("Stack '{0}': Opened server at '{1}'\n".format(self.name, self.ha)) self.rxMsgs = rxMsgs if rxMsgs is not None else deque() # messages received self.txMsgs = txMsgs if txMsgs is not None else deque() # messages to transmit self.rxes = rxes if rxes is not None else deque() # udp packets received self.txes = txes if txes is not None else deque() # udp packet to transmit self.stats = stats if stats is not None else odict() # udp statistics self.statTimer = StoreTimer(self.store)
def testMinionStatsUnknownRemote(self): """ Test Minion Stats request with unknown remote (B1) """ console.terse("{0}\n".format( self.testMinionStatsUnknownRemote.__doc__)) # Bootstrap self.addEnterDeed("TestOptsSetupMinion") self.addEnterDeed("SaltRaetManorLaneSetup") self.addEnterDeed("SaltRaetRoadStackSetup") self.addEnterDeed("StatsMinionTestSetup") act = self.addRecurDeed("SaltRaetStatsEventerMinion") self.resolve() # resolve House, Framer, Frame, Acts, Actors self.frame.enter() # Prepare # add a test stat key-value roadStack = self.store.fetch('.salt.road.manor.stack') laneStack = self.store.fetch('.salt.lane.manor.stack') roadStack.value.stats = odict({'test_road_stats_event': 111}) laneStack.value.stats = odict({'test_lane_stats_event': 222}) # ensure stats are equal to expected self.assertDictEqual(roadStack.value.stats, {'test_road_stats_event': 111}) self.assertDictEqual(laneStack.value.stats, {'test_lane_stats_event': 222}) # add stats request testStack = self.store.fetch('.salt.test.road.stack').value statsReq = self.store.fetch('.salt.stats.event_req').value tag = tagify('road', 'stats') minionName = roadStack.value.local.name # unknown remote (src) name in stats request unknownName = 'unknownName' statsReq.append({ 'route': { 'dst': (minionName, None, 'stats_req'), 'src': (unknownName, None, None) }, 'tag': tag }) # Test self.frame.recur() # run in frame # Check self.assertEqual(len(testStack.rxMsgs), 0) testStack.serviceAll() self.assertEqual(len(testStack.rxMsgs), 0) # Close active stacks servers act.actor.lane_stack.value.server.close() act.actor.road_stack.value.server.close() testStack = self.store.fetch('.salt.test.road.stack') if testStack: testStack.value.server.close()
class PresenterTestSetup(ioflo.base.deeding.Deed): ''' Setup shares for presence tests ''' Ioinits = { 'presence_req': '.salt.presence.event_req', 'lane_stack': '.salt.lane.manor.stack', 'event_stack': '.salt.test.lane.stack', 'alloweds': { 'ipath': '.salt.var.presence.alloweds', 'ival': odict() }, 'aliveds': { 'ipath': '.salt.var.presence.aliveds', 'ival': odict() }, 'reapeds': { 'ipath': '.salt.var.presence.reapeds', 'ival': odict() }, 'availables': { 'ipath': '.salt.var.presence.availables', 'ival': set() } } def action(self): self.presence_req.value = deque() self.availables.value = set() self.alloweds.value = odict() self.aliveds.value = odict() self.reapeds.value = odict() # Create event stack name = 'event' + nacling.uuid(size=18) lanename = self.lane_stack.value.local.lanename sock_dir = self.lane_stack.value.local.dirpath ryn = 'manor' console.terse( "Create stack: name = {0}, lanename = {1}, sock_dir = {2}\n". format(name, lanename, sock_dir)) stack = LaneStack(name=name, lanename=lanename, sockdirpath=sock_dir) stack.addRemote( RemoteYard(stack=stack, lanename=lanename, name=ryn, dirpath=sock_dir)) self.event_stack.value = stack route = { 'dst': (None, ryn, 'presence_req'), 'src': (None, stack.local.name, None) } msg = {'route': route} stack.transmit(msg, stack.nameRemotes[ryn].uid) serviceLanes([stack, self.lane_stack.value])
def testMinionLaneStats(self): """ Test Minion Road Stats request (A2) """ console.terse("{0}\n".format(self.testMinionLaneStats.__doc__)) # Bootstrap self.addEnterDeed("TestOptsSetupMinion") self.addEnterDeed("SaltRaetManorLaneSetup") self.addEnterDeed("SaltRaetRoadStackSetup") self.addEnterDeed("StatsMinionTestSetup") act = self.addRecurDeed("SaltRaetStatsEventerMinion") self.resolve() # resolve House, Framer, Frame, Acts, Actors self.frame.enter() # Prepare # add a test stat key-value roadStack = self.store.fetch('.salt.road.manor.stack') laneStack = self.store.fetch('.salt.lane.manor.stack') roadStack.value.stats = odict() laneStack.value.stats = odict({'test_stats_event': 111}) # ensure stats are equal to expected self.assertDictEqual(roadStack.value.stats, {}) self.assertDictEqual(laneStack.value.stats, {'test_stats_event': 111}) # add stats request testStack = self.store.fetch('.salt.test.road.stack').value statsReq = self.store.fetch('.salt.stats.event_req').value tag = tagify('lane', 'stats') minionName = roadStack.value.local.name masterName = testStack.local.name # lane stats request statsReq.append({'route': {'dst': (minionName, None, 'stats_req'), 'src': (masterName, None, None)}, 'tag': tag}) # Test self.frame.recur() # run in frame # Check self.assertEqual(len(testStack.rxMsgs), 0) testStack.serviceAll() self.assertEqual(len(testStack.rxMsgs), 1) msg, sender = testStack.rxMsgs.popleft() self.assertDictEqual(msg, {u'route': {u'src': [ns2u(minionName), u'manor', None], u'dst': [ns2u(masterName), None, u'event_fire']}, u'tag': ns2u(tag), u'data': {u'test_stats_event': 111}}) # Close active stacks servers act.actor.lane_stack.value.server.close() act.actor.road_stack.value.server.close() testStack = self.store.fetch('.salt.test.road.stack') if testStack: testStack.value.server.close()
def testBasicJson(self): ''' Basic pack parse with header json and body json ''' console.terse("{0}\n".format(self.testBasicJson.__doc__)) stack = MockStack(store=self.store, veritive=False) hk = raeting.HeadKind.json.value bk = raeting.BodyKind.json.value data = odict(hk=hk, bk=bk) #body = odict(msg='Hello Raet World', extra='Goodby Big Moon') body = odict([('msg', 'Hello Raet World'), ('extra', 'Goodby Big Moon')]) packet0 = packeting.TxPacket(stack=stack, embody=body, data=data, ) self.assertDictEqual(packet0.body.data, body) packet0.pack() self.assertEqual(packet0.packed, b'{"ri":"RAET","pl":"0000076","hl":"42","fg":"00","hk":1,"bk":1}\r\n\r\n{"msg":"Hello Raet World","extra":"Goodby Big Moon"}') packet1 = packeting.RxPacket(stack=stack, packed=packet0.packed) packet1.parse() self.assertDictEqual(packet1.data, {'sh': '', 'sp': 7530, 'dh': '127.0.0.1', 'dp': 7530, 'ri':'RAET', 'vn': 0, 'pk': 0, 'pl': 118, 'hk': 1, 'hl': 66, 'se': 0, 'de': 0, 'cf': False, 'bf': False, 'nf': False, 'df': False, 'vf': False, 'si': 0, 'ti': 0, 'tk': 0, 'dt': 0, 'oi': 0, 'wf': False, 'sn': 0, 'sc': 1, 'ml': 0, 'sf': False, 'af': False, 'bk': 1, 'ck': 0, 'fk': 0, 'fl': 0, 'fg': '00'}) self.assertDictEqual(packet1.body.data, body)
def testBasicRaetMsgpack(self): ''' Basic pack parse with header json and body msgpack ''' console.terse("{0}\n".format(self.testBasicRaetMsgpack.__doc__)) stack = MockStack(store=self.store, veritive=False) hk = raeting.HeadKind.raet.value bk = raeting.BodyKind.msgpack.value data = odict(hk=hk, bk=bk) #body = odict(msg='Hello Raet World', extra='Goodby Big Moon') body = odict([('msg', 'Hello Raet World'), ('extra', 'Goodby Big Moon')]) packet0 = packeting.TxPacket(stack=stack, embody=body, data=data, ) self.assertDictEqual(packet0.body.data, body) packet0.pack() self.assertEqual(packet0.packed, b'ri RAET\npl 004e\nhl 22\nfg 00\nbk 3\n\n\x82\xa3msg\xb0Hello Raet World\xa5extra\xafGoodby Big Moon') packet1 = packeting.RxPacket(stack=stack, packed=packet0.packed) packet1.parse() self.assertDictEqual(packet1.data, {'sh': '', 'sp': 7530, 'dh': '127.0.0.1', 'dp': 7530, 'ri':'RAET', 'vn': 0, 'pk': 0, 'pl': 78, 'hk': 0, 'hl': 34, 'se': 0, 'de': 0, 'cf': False, 'bf': False, 'nf': False, 'df': False, 'vf': False, 'si': 0, 'ti': 0, 'tk': 0, 'dt': 0, 'oi': 0, 'wf': False, 'sn': 0, 'sc': 1, 'ml': 0, 'sf': False, 'af': False, 'bk': 3, 'ck': 0, 'fk': 0, 'fl': 0, 'fg': '00'}) self.assertDictEqual(packet1.body.data, body)
def testMinionLaneStats(self): ''' Test Minion Road Stats request (A2) ''' console.terse("{0}\n".format(self.testMinionLaneStats.__doc__)) # Bootstrap self.addEnterDeed("TestOptsSetupMinion") self.addEnterDeed("SaltRaetManorLaneSetup") self.addEnterDeed("SaltRaetRoadStackSetup") self.addEnterDeed("StatsMinionTestSetup") act = self.addRecurDeed("SaltRaetStatsEventerMinion") self.resolve() # resolve House, Framer, Frame, Acts, Actors self.frame.enter() # Prepare # add a test stat key-value roadStack = self.store.fetch('.salt.road.manor.stack') laneStack = self.store.fetch('.salt.lane.manor.stack') roadStack.value.stats = odict() laneStack.value.stats = odict({'test_stats_event': 111}) # ensure stats are equal to expected self.assertDictEqual(roadStack.value.stats, {}) self.assertDictEqual(laneStack.value.stats, {'test_stats_event': 111}) # add stats request testStack = self.store.fetch('.salt.test.road.stack').value statsReq = self.store.fetch('.salt.stats.event_req').value tag = tagify('lane', 'stats') minionName = roadStack.value.local.name masterName = testStack.local.name # lane stats request statsReq.append({'route': {'dst': (minionName, None, 'stats_req'), 'src': (masterName, None, None)}, 'tag': tag}) # Test self.frame.recur() # run in frame # Check self.assertEqual(len(testStack.rxMsgs), 0) testStack.serviceAll() self.assertEqual(len(testStack.rxMsgs), 1) msg, sender = testStack.rxMsgs.popleft() self.assertDictEqual(msg, {'route': {'src': [ns2u(minionName), 'manor', None], 'dst': [ns2u(masterName), None, 'event_fire']}, 'tag': ns2u(tag), 'data': {'test_stats_event': 111}}) # Close active stacks servers act.actor.lane_stack.value.server.close() act.actor.road_stack.value.server.close() testStack = self.store.fetch('.salt.test.road.stack') if testStack: testStack.value.server.close()
def loadLocalRoleData(self): ''' Load and return the role data ''' keydata = self.saltRaetKey.read_local() if not keydata: keydata = odict([('sign', None), ('priv', None)]) data = odict([('sighex', keydata['sign']), ('prihex', keydata['priv'])]) return data
def testMinionStatsWrongMissingTag(self): """ Test Minion Stats requests with unknown and missing tag (A3, A4) """ console.terse("{0}\n".format(self.testMinionStatsWrongMissingTag.__doc__)) # Bootstrap self.addEnterDeed("TestOptsSetupMinion") self.addEnterDeed("SaltRaetManorLaneSetup") self.addEnterDeed("SaltRaetRoadStackSetup") self.addEnterDeed("StatsMinionTestSetup") act = self.addRecurDeed("SaltRaetStatsEventerMinion") self.resolve() # resolve House, Framer, Frame, Acts, Actors self.frame.enter() # Prepare # add a test stat key-value roadStack = self.store.fetch('.salt.road.manor.stack') laneStack = self.store.fetch('.salt.lane.manor.stack') roadStack.value.stats = odict({'test_road_stats_event': 111}) laneStack.value.stats = odict({'test_lane_stats_event': 222}) # ensure stats are equal to expected self.assertDictEqual(roadStack.value.stats, {'test_road_stats_event': 111}) self.assertDictEqual(laneStack.value.stats, {'test_lane_stats_event': 222}) # add stats request testStack = self.store.fetch('.salt.test.road.stack').value statsReq = self.store.fetch('.salt.stats.event_req').value tag = 'salt/unknown/tag' self.assertNotEqual(tag, tagify('lane', 'stats')) self.assertNotEqual(tag, tagify('road', 'stats')) minionName = roadStack.value.local.name masterName = testStack.local.name # unknown tag in stats request statsReq.append({'route': {'dst': (minionName, None, 'stats_req'), 'src': (masterName, None, None)}, 'tag': tag}) # no tag in stats request statsReq.append({'route': {'dst': (minionName, None, 'stats_req'), 'src': (masterName, None, None)}}) # Test self.frame.recur() # run in frame # Check self.assertEqual(len(testStack.rxMsgs), 0) testStack.serviceAll() self.assertEqual(len(testStack.rxMsgs), 0) # Close active stacks servers act.actor.lane_stack.value.server.close() act.actor.road_stack.value.server.close() testStack = self.store.fetch('.salt.test.road.stack') if testStack: testStack.value.server.close()
def __init__(self, stack, name="", prefix='estate', ha=None, iha=None, natted=None, fqdn='', dyned=None, uid=None, tid=0, role=None, **kwa): ''' Setup instance stack is required parameter ''' name = name or self.nameGuid(prefix=prefix) uid = uid if uid is not None else stack.nextUid() super(Estate, self).__init__(stack=stack, name=name, ha=ha, uid=uid, **kwa) self.tid = tid # current transaction ID # if host is unspecified or all then use loopback address as host if ha: host, port = ha host = self.normalizeHost(host) if host in ('0.0.0.0', ): host = '127.0.0.1' elif host in ("::", "0:0:0:0:0:0:0:0"): host = "::1" ha = (host, port) self.ha = ha if iha: # future iha should take precedence host, port = iha host = self.normalizeHost(host) if host in ('0.0.0.0', ): host = '127.0.0.1' elif host in ("::", "0:0:0:0:0:0:0:0"): host = "::1" iha = (host, port) self.iha = iha # internal host address duple (host, port) self.natted = natted # is estate behind nat router self.fqdn = fqdn or socket.getfqdn(self.ha[0]) if self.ha else '' self.dyned = dyned self.role = role if role is not None else self.name self.transactions = odict( ) # estate transactions keyed by transaction index self.doneTransactions = odict( ) # temporary storage for done transaction ids
def testAutoAccept(self): ''' Basic send auto accept message ''' console.terse("{0}\n".format(self.testAutoAccept.__doc__)) self.assertTrue(self.main.accept) # Don't add remote yard to main so only way to get message from other is # if auto acccept works self.other.addRemote(yarding.RemoteYard(stack=self.other, ha=self.main.ha)) self.assertEqual(self.main.name, 'main') self.assertEqual(self.main.local.name, 'main') self.assertEqual(self.main.ha, os.path.join(self.baseDirpath, 'cherry.main.uxd')) self.assertEqual(len(self.main.remotes), 0) self.assertEqual(self.other.name, 'other') self.assertEqual(self.other.local.name, 'other') self.assertEqual(self.other.ha, os.path.join(self.baseDirpath, 'cherry.other.uxd')) self.assertEqual(len(self.other.remotes), 1) remote = self.other.remotes.values()[0] self.assertEqual(remote.ha, os.path.join(self.baseDirpath, 'cherry.main.uxd')) self.assertEqual(remote.name, 'main') self.assertTrue(remote.uid in self.other.remotes) self.assertTrue(remote.name in self.other.nameRemotes) self.assertTrue(remote.ha in self.other.haRemotes) self.assertIs(self.other.nameRemotes[remote.name], remote) self.assertIs(self.other.haRemotes[remote.ha], remote) stacking.LaneStack.Pk = raeting.PackKind.pack.value others = [] others.append(odict(what="This is a message to the lord. Let me be", extra="Go away.")) self.message(mains=[], others=others) self.assertEqual(len(self.main.remotes), 1) remote = self.main.remotes.values()[0] self.assertEqual(remote.ha, os.path.join(self.baseDirpath, 'cherry.other.uxd')) self.assertEqual(remote.name, 'other') self.assertTrue(remote.uid in self.main.remotes) self.assertTrue(remote.name in self.main.nameRemotes) self.assertTrue(remote.ha in self.main.haRemotes) self.assertIs(self.main.nameRemotes[remote.name], remote) self.assertIs(self.main.haRemotes[remote.ha], remote) self.main.rxMsgs = deque() self.other.rxMsgs = deque() mains = [] mains.append(odict(what="This is a message to the serf. Get to Work", extra="Fix the fence.")) self.message(mains=mains, others=[])
def testBasicJson(self): ''' Basic pack parse with header json and body json ''' console.terse("{0}\n".format(self.testBasicJson.__doc__)) hk = raeting.HeadKind.json.value bk = raeting.BodyKind.json.value data = odict(hk=hk, bk=bk) #body = odict(msg='Hello Raet World', extra='Goodby Big Moon') body = odict([('msg', 'Hello Raet World'), ('extra', 'Goodby Big Moon')]) packet0 = packeting.TxPacket(embody=body, data=data, ) self.assertDictEqual(packet0.body.data, body) packet0.pack() self.assertEqual(packet0.packed, b'{"ri":"RAET","pl":"0000076","hl":"42","fg":"00","hk":1,"bk":1}\r\n\r\n{"msg":"Hello Raet World","extra":"Goodby Big Moon"}') packet1 = packeting.RxPacket(packed=packet0.packed) packet1.parse() self.assertDictEqual(packet1.data, {'sh': '', 'sp': 7530, 'dh': '127.0.0.1', 'dp': 7530, 'ri':'RAET', 'vn': 0, 'pk': 0, 'pl': 118, 'hk': 1, 'hl': 66, 'se': 0, 'de': 0, 'cf': False, 'bf': False, 'nf': False, 'df': False, 'vf': False, 'si': 0, 'ti': 0, 'tk': 0, 'dt': 0, 'oi': 0, 'wf': False, 'sn': 0, 'sc': 1, 'ml': 0, 'sf': False, 'af': False, 'bk': 1, 'ck': 0, 'fk': 0, 'fl': 0, 'fg': '00'}) self.assertDictEqual(packet1.body.data, body)
def testBasicRaetMsgpack(self): ''' Basic pack parse with header json and body msgpack ''' console.terse("{0}\n".format(self.testBasicRaetMsgpack.__doc__)) hk = raeting.HeadKind.raet.value bk = raeting.BodyKind.msgpack.value data = odict(hk=hk, bk=bk) #body = odict(msg='Hello Raet World', extra='Goodby Big Moon') body = odict([('msg', 'Hello Raet World'), ('extra', 'Goodby Big Moon')]) packet0 = packeting.TxPacket(embody=body, data=data, ) self.assertDictEqual(packet0.body.data, body) packet0.pack() self.assertEqual(packet0.packed, b'ri RAET\npl 004e\nhl 22\nfg 00\nbk 3\n\n\x82\xa3msg\xb0Hello Raet World\xa5extra\xafGoodby Big Moon') packet1 = packeting.RxPacket(packed=packet0.packed) packet1.parse() self.assertDictEqual(packet1.data, {'sh': '', 'sp': 7530, 'dh': '127.0.0.1', 'dp': 7530, 'ri':'RAET', 'vn': 0, 'pk': 0, 'pl': 78, 'hk': 0, 'hl': 34, 'se': 0, 'de': 0, 'cf': False, 'bf': False, 'nf': False, 'df': False, 'vf': False, 'si': 0, 'ti': 0, 'tk': 0, 'dt': 0, 'oi': 0, 'wf': False, 'sn': 0, 'sc': 1, 'ml': 0, 'sf': False, 'af': False, 'bk': 3, 'ck': 0, 'fk': 0, 'fl': 0, 'fg': '00'}) self.assertDictEqual(packet1.body.data, body)
def testBasicRaetJson(self): ''' Basic pack parse with header raet and body json ''' console.terse("{0}\n".format(self.testBasicRaetJson.__doc__)) hk = raeting.HeadKind.raet.value bk = raeting.BodyKind.json.value data = odict(hk=hk, bk=bk) #body = odict(msg='Hello Raet World', extra='Goodby Big Moon') body = odict([('msg', 'Hello Raet World'), ('extra', 'Goodby Big Moon')]) packet0 = packeting.TxPacket(embody=body, data=data, ) self.assertDictEqual(packet0.body.data, body) packet0.pack() self.assertEqual(packet0.packed, b'ri RAET\npl 0056\nhl 22\nfg 00\nbk 1\n\n{"msg":"Hello Raet World","extra":"Goodby Big Moon"}') packet1 = packeting.RxPacket(packed=packet0.packed) packet1.parse() self.assertDictEqual(packet1.data, {'sh': '', 'sp': 7530, 'dh': '127.0.0.1', 'dp': 7530, 'ri':'RAET', 'vn': 0, 'pk': 0, 'pl': 86, 'hk': 0, 'hl': 34, 'se': 0, 'de': 0, 'cf': False, 'bf': False, 'nf': False, 'df': False, 'vf': False, 'si': 0, 'ti': 0, 'tk': 0, 'dt': 0, 'oi': 0, 'wf': False, 'sn': 0, 'sc': 1, 'ml': 0, 'sf': False, 'af': False, 'bk': 1, 'ck': 0, 'fk': 0, 'fl': 0, 'fg': '00'}) self.assertDictEqual(packet1.body.data, body)
def testBasicMsgpack(self): ''' Basic pack parse with header json and body msgpack ''' console.terse("{0}\n".format(self.testBasicMsgpack.__doc__)) hk = raeting.HeadKind.json.value bk = raeting.BodyKind.msgpack.value data = odict(hk=hk, bk=bk) #body = odict(msg='Hello Raet World', extra='Goodby Big Moon') body = odict([('msg', 'Hello Raet World'), ('extra', 'Goodby Big Moon')]) packet0 = packeting.TxPacket(embody=body, data=data, ) self.assertDictEqual(packet0.body.data, body) packet0.pack() self.assertEqual(packet0.packed, b'{"ri":"RAET","pl":"000006e","hl":"42","fg":"00","hk":1,"bk":3}\r\n\r\n\x82\xa3msg\xb0Hello Raet World\xa5extra\xafGoodby Big Moon') packet1 = packeting.RxPacket(packed=packet0.packed) packet1.parse() self.assertDictEqual(packet1.data, {'sh': '', 'sp': 7530, 'dh': '127.0.0.1', 'dp': 7530, 'ri':'RAET', 'vn': 0, 'pk': 0, 'pl': 110, 'hk': 1, 'hl': 66, 'se': 0, 'de': 0, 'cf': False, 'bf': False, 'nf': False, 'df': False, 'vf': False, 'si': 0, 'ti': 0, 'tk': 0, 'dt': 0, 'oi': 0, 'wf': False, 'sn': 0, 'sc': 1, 'ml': 0, 'sf': False, 'af': False, 'bk': 3, 'ck': 0, 'fk': 0, 'fl': 0, 'fg': '00'}) self.assertDictEqual(packet1.body.data, body)
def testBasic(self): """ Test Basic """ console.terse("{0}\n".format(self.testBasic.__doc__)) console.terse("{0}\n".format("Connecting ...\n")) hc = HTTPConnection('127.0.0.1', port=8080, timeout=1.0,) hc.connect() console.terse("{0}\n".format("Get '/echo?name=fame' ...\n")) headers = odict([('Accept', 'application/json')]) hc.request(method='GET', path='/echo?name=fame', body=None, headers=headers ) response = hc.getresponse() console.terse(str(response.fileno()) + "\n") # must call this before read console.terse(str(response.getheaders()) + "\n") console.terse(str(response.msg) + "\n") console.terse(str(response.version) + "\n") console.terse(str(response.status) + "\n") console.terse(response.reason + "\n") console.terse(str(response.read()) + "\n") console.terse("{0}\n".format("Post ...\n")) headers = odict([('Accept', 'application/json'), ('Content-Type', 'application/json')]) body = odict([('name', 'Peter'), ('occupation', 'Engineer')]) body = ns2b(json.dumps(body, separators=(',', ':'))) hc.request(method='POST', path='/demo', body=body, headers=headers ) response = hc.getresponse() console.terse(str(response.fileno()) + "\n") # must call this before read console.terse(str(response.getheaders()) + "\n") console.terse(str(response.msg) + "\n") console.terse(str(response.version) + "\n") console.terse(str(response.status) + "\n") console.terse(response.reason+ "\n") console.terse(str(response.read()) + "\n") #console.terse("{0}\n".format("SSE stream ...\n")) #body = b'' #headers = odict([('Accept', 'application/json'), ('Content-Type', 'application/json')]) #hc.request(method='GET', path='/stream', body=body, headers=headers ) #response = hc.getresponse() #console.terse(str(response.fileno()) + "\n") # must call this before read #console.terse(str(response.getheaders()) + "\n") #console.terse(str(response.msg) + "\n") #console.terse(str(response.version) + "\n") #console.terse(str(response.status) + "\n") #console.terse(response.reason+ "\n") #console.terse(str(response.read()) + "\n") hc.close()
def __init__(self, stack, name="", prefix='estate', ha=None, iha=None, natted=None, fqdn='', dyned=None, uid=None, tid=0, role=None, **kwa): ''' Setup instance stack is required parameter ''' name = name or self.nameGuid(prefix=prefix) uid = uid if uid is not None else stack.nextUid() super(Estate, self).__init__(stack=stack, name=name, ha=ha, uid=uid, **kwa) self.tid = tid # current transaction ID if ha: host, port = ha host = socket.gethostbyname(host) if host in ['0.0.0.0', '']: host = '127.0.0.1' ha = (host, port) self.ha = ha if iha: # takes precedence host, port = iha host = socket.gethostbyname(host) if host in ['0.0.0.0', '']: host = '127.0.0.1' iha = (host, port) self.iha = iha # internal host address duple (host, port) self.natted = natted # is estate behind nat router self.fqdn = fqdn or socket.getfqdn(self.ha[0]) if self.ha else '' self.dyned = dyned self.role = role if role is not None else self.name self.transactions = odict( ) # estate transactions keyed by transaction index self.doneTransactions = odict( ) # temporary storage for done transaction ids
def testMessageMsgpack(self): ''' Basic messaging with msgpack packing ''' console.terse("{0}\n".format(self.testMessageMsgpack.__doc__)) self.bootstrap(kind=raeting.PackKind.pack.value) mains = [] mains.append(odict(what="This is a message to the serf. Get to Work", extra="Fix the fence.")) others = [] others.append(odict(what="This is a message to the lord. Let me be", extra="Go away.")) self.message(mains=mains, others=others)
def __init__(self, stack, name="", prefix='estate', ha=None, iha=None, natted=None, fqdn='', dyned=None, uid=None, tid=0, role=None, **kwa): ''' Setup instance stack is required parameter ''' name = name or self.nameGuid(prefix=prefix) uid = uid if uid is not None else stack.nextUid() super(Estate, self).__init__(stack=stack, name=name, ha=ha, uid=uid, **kwa) self.tid = tid # current transaction ID # if host is unspecified or all then use loopback address as host if ha: host, port = ha host = self.normalizeHost(host) if host in ('0.0.0.0',): host = '127.0.0.1' elif host in ("::", "0:0:0:0:0:0:0:0"): host = "::1" ha = (host, port) self.ha = ha if iha: # future iha should take precedence host, port = iha host = self.normalizeHost(host) if host in ('0.0.0.0',): host = '127.0.0.1' elif host in ("::", "0:0:0:0:0:0:0:0"): host = "::1" iha = (host, port) self.iha = iha # internal host address duple (host, port) self.natted = natted # is estate behind nat router self.fqdn = fqdn or socket.getfqdn(self.ha[0]) if self.ha else '' self.dyned = dyned self.role = role if role is not None else self.name self.transactions = odict() # estate transactions keyed by transaction index self.doneTransactions = odict() # temporary storage for done transaction ids
def testMinionStatsNoRequest(self): """ Test Minion Stats no requests (nothing to do) (B2) """ console.terse("{0}\n".format(self.testMinionStatsNoRequest.__doc__)) # Bootstrap self.addEnterDeed("TestOptsSetupMinion") self.addEnterDeed("SaltRaetManorLaneSetup") self.addEnterDeed("SaltRaetRoadStackSetup") self.addEnterDeed("StatsMinionTestSetup") act = self.addRecurDeed("SaltRaetStatsEventerMinion") self.resolve() # resolve House, Framer, Frame, Acts, Actors self.frame.enter() # Prepare # add a test stat key-value roadStack = self.store.fetch('.salt.road.manor.stack') laneStack = self.store.fetch('.salt.lane.manor.stack') roadStack.value.stats = odict({'test_road_stats_event': 111}) laneStack.value.stats = odict({'test_lane_stats_event': 222}) # ensure stats are equal to expected self.assertDictEqual(roadStack.value.stats, {'test_road_stats_event': 111}) self.assertDictEqual(laneStack.value.stats, {'test_lane_stats_event': 222}) # clear lane stack remotes # add stats request testStack = self.store.fetch('.salt.test.road.stack').value statsReq = self.store.fetch('.salt.stats.event_req').value # no request self.assertEqual(len(statsReq), 0) # Test self.frame.recur() # run in frame # Check self.assertEqual(len(testStack.rxMsgs), 0) testStack.serviceAll() self.assertEqual(len(testStack.rxMsgs), 0) # Close active stacks servers act.actor.lane_stack.value.server.close() act.actor.road_stack.value.server.close() testStack = self.store.fetch('.salt.test.road.stack') if testStack: testStack.value.server.close()
def stale(self, packet): ''' Initiate stale transaction in order to nack a stale correspondent packet but only for preexisting remotes ''' if packet.data['pk'] in [ PcktKind.nack, PcktKind.unjoined, PcktKind.unallowed, PcktKind.renew, PcktKind.refuse, PcktKind.reject, ]: return # ignore stale nacks create = False uid = packet.data['de'] remote = self.retrieveRemote(uid=uid) if not remote: emsg = "Stack '{0}'. Unknown remote id '{1}', fail to nack stale\n".format( self.name, uid) console.terse(emsg) self.incStat('invalid_remote_eid') return data = odict(hk=self.Hk, bk=self.Bk) staler = transacting.Staler(stack=self, remote=remote, kind=packet.data['tk'], sid=packet.data['si'], tid=packet.data['ti'], txData=data, rxPacket=packet) staler.nack()
def __init__(self, stack=None, data=None): ''' Setup Page instance. Meta data for a packet. ''' self.stack = stack self.data = odict(raeting.PAGE_DEFAULTS) if data: self.data.update(data) self.packed = b'' # packed string
def echoGet(action=None): """ Echo back request data """ query = dict(bottle.request.query.items()) body = bottle.request.json raw = bottle.request.body.read() form = odict(bottle.request.forms) data = odict(verb=bottle.request.method, url=bottle.request.url, action=action, query=query, form=form, content=body) return data
def dumpRemote(self, remote): ''' Dump remote estate ''' data = odict([ ('name', remote.name), ('uid', remote.uid), ('fuid', remote.fuid), ('ha', remote.ha), ('iha', remote.iha), ('natted', remote.natted), ('fqdn', remote.fqdn), ('dyned', remote.dyned), ('sid', remote.sid), ('main', remote.main), ('kind', remote.kind), ('joined', remote.joined), ('role', remote.role), ]) if self.verifyRemoteData(data, remoteFields=self.RemoteDumpFields): self.dumpRemoteData(data, remote.name) if remote.pubber.keyhex and remote.verfer.keyhex: # kludge to persist the keys since no way to write self.saltRaetKey.status(remote.role, remote.pubber.keyhex, remote.verfer.keyhex)
def parse(self): ''' Parses body. Assumes already unpacked. Results in updated .data ''' self.data = odict() pk = self.page.data['pk'] if pk not in list(PackKind): emsg = "Unrecognizable page body." raise raeting.PageError(emsg) if pk == PackKind.json: if self.packed: self.data = json.loads(self.packed.decode(encoding='utf-8'), object_pairs_hook=odict) elif pk == PackKind.pack: if self.packed: if not msgpack: emsg = "Msgpack not installed." raise raeting.PacketError(emsg) self.data = msgpack.loads(self.packed, object_pairs_hook=odict, encoding='utf-8') if not isinstance(self.data, Mapping): emsg = "Message body not a mapping\n" console.terse(emsg) raise raeting.PageError(emsg)
def message(self, body, uid=None): ''' Sends message body to yard given by uid and manages paging of long messages ''' if uid is None: if not self.remotes: emsg = "No yard to send to\n" console.terse(emsg) self.incStat("invalid_destination") return uid = self.remotes.values()[0].uid if uid not in self.remotes: emsg = "Invalid destination yard '{0}'\n".format(uid) console.terse(emsg) self.incStat("invalid_destination") return remote = self.remotes[uid] data = odict(pk=self.Pk, sn=self.local.name, dn=remote.name, si=remote.sid, bi=remote.nextBid()) book = paging.TxBook(data=data, body=body) try: book.pack() except raeting.PageError as ex: console.terse(str(ex) + '\n') self.incStat("packing_error") return for page in book.pages: self.txes.append((page.packed, remote.ha))
def echoTest(action=None): """ Ajax test endpoint for web application service Echos back args as content """ # convert to json serializible dict result = odict(verb=bottle.request.method, url=bottle.request.url, action=action, query=odict(bottle.request.query.items()), headers=odict(bottle.request.headers.items()), data=bottle.request.json, form=odict(bottle.request.forms), body=bottle.request.body.read()) return result
def stale(self, packet): ''' Initiate stale transaction in order to nack a stale correspondent packet but only for preexisting remotes ''' if packet.data['pk'] in [PcktKind.nack, PcktKind.unjoined, PcktKind.unallowed, PcktKind.renew, PcktKind.refuse, PcktKind.reject,]: return # ignore stale nacks create = False uid = packet.data['de'] remote = self.retrieveRemote(uid=uid) if not remote: emsg = "Stack '{0}'. Unknown remote id '{1}', fail to nack stale\n".format( self.name, uid) console.terse(emsg) self.incStat('invalid_remote_eid') return data = odict(hk=self.Hk, bk=self.Bk) staler = transacting.Staler(stack=self, remote=remote, kind=packet.data['tk'], sid=packet.data['si'], tid=packet.data['ti'], txData=data, rxPacket=packet) staler.nack()
def __init__(self, local=None, #passed up from subclass name='', puid=None, uid=None, lanename='lane', sockdirpath='', ha='', bufcnt=100, accept=None, **kwa ): ''' Setup LaneStack instance ''' if getattr(self, 'puid', None) is None: self.puid = puid if puid is not None else self.Uid local = local or yarding.Yard(stack=self, name=name, uid=uid, ha=ha, dirpath=sockdirpath, lanename=lanename) super(LaneStack, self).__init__(puid=puid, local=local, bufcnt=bufcnt, **kwa) self.haRemotes = odict() # remotes indexed by ha host address self.accept = self.Accept if accept is None else accept #accept uxd msg if not in lane
def testEventify(self): """ Test eventify function """ console.terse("{0}\n".format(self.testEventify.__doc__)) console.reinit(verbosity=console.Wordage.profuse) dt = datetime.datetime.utcnow() stamp = dt.isoformat() time.sleep(0.01) event = eventing.eventify('hello') self.assertEqual(event['tag'], 'hello') self.assertEqual(event['data'], {}) #"YYYY-MM-DDTHH:MM:SS.mmmmmm" tdt = datetime.datetime.strptime(event['stamp'], "%Y-%m-%dT%H:%M:%S.%f") self.assertGreater(tdt, dt) event = eventing.eventify(tag=eventing.tagify(head='exchange', tail='started'), stamp=stamp) self.assertEqual(event['tag'], 'exchange.started') self.assertEqual(event['stamp'], stamp) event = eventing.eventify(tag=eventing.tagify(tail='started', head='exchange'), stamp=stamp, data=odict(name='John')) self.assertEqual(event['tag'], 'exchange.started') self.assertEqual(event['stamp'], stamp) self.assertEqual(event['data'], { 'name': 'John', }) stamp = '2015-08-10T19:26:47.194736' event = eventing.eventify(tag='process.started', stamp=stamp, data={ 'name': 'Jill', }) self.assertEqual( event, { 'tag': 'process.started', 'stamp': '2015-08-10T19:26:47.194736', 'data': { 'name': 'Jill', }, }) event = eventing.eventify(tag="with uid", stamp=stamp, uid="abcde") self.assertEqual( event, { 'data': {}, 'stamp': '2015-08-10T19:26:47.194736', 'tag': 'with uid', 'uid': 'abcde' }) console.reinit(verbosity=console.Wordage.concise)
def __init__(self, data=None, **kwa): ''' Setup Body instance ''' super(Body, self).__init__(**kwa) if data is None: data = odict() self.data = data
def refresh(self, data=None): ''' Refresh .data to defaults and update if data ''' self.data = odict(raeting.PACKET_DEFAULTS) if data: self.data.update(data) return self # so can method chain
def defaults(self): ''' Return odict with items preloaded with defaults ''' data = odict() for field in fields: data[field] = None return data