class DataTest(unittest.TestCase): def setUp(self): self.ctx = Context(YANG_DIR) mod = self.ctx.load_module('yolo-system') mod.feature_enable_all() def tearDown(self): self.ctx.destroy() self.ctx = None JSON_CONFIG = '''{ "yolo-system:conf": { "hostname": "foo", "speed": 1234, "number": [ 1000, 2000, 3000 ], "url": [ { "proto": "https", "host": "github.com", "path": "/rjarry/libyang-cffi", "enabled": false }, { "proto": "http", "host": "foobar.com", "port": 8080, "path": "/index.html", "enabled": true } ] } } ''' def test_data_parse_config_json(self): dnode = self.ctx.parse_data_mem(self.JSON_CONFIG, 'json', config=True) self.assertIsInstance(dnode, DContainer) try: j = dnode.print_mem('json', pretty=True) self.assertEqual(j, self.JSON_CONFIG) finally: dnode.free() JSON_STATE = '''{ "yolo-system:state": { "hostname": "foo", "speed": 1234, "number": [ 1000, 2000, 3000 ], "url": [ { "proto": "https", "host": "github.com", "path": "/rjarry/libyang-cffi", "enabled": false }, { "proto": "http", "host": "foobar.com", "port": 8080, "path": "/index.html", "enabled": true } ] } } ''' def test_data_parse_state_json(self): dnode = self.ctx.parse_data_mem(self.JSON_STATE, 'json', data=True, no_yanglib=True) self.assertIsInstance(dnode, DContainer) try: j = dnode.print_mem('json', pretty=True) self.assertEqual(j, self.JSON_STATE) finally: dnode.free() XML_CONFIG = '''<conf xmlns="urn:yang:yolo:system"> <hostname>foo</hostname> <speed>1234</speed> <number>1000</number> <number>2000</number> <number>3000</number> <url> <proto>https</proto> <host>github.com</host> <path>/rjarry/libyang-cffi</path> <enabled>false</enabled> </url> <url> <proto>http</proto> <host>foobar.com</host> <port>8080</port> <path>/index.html</path> <enabled>true</enabled> </url> </conf> ''' def test_data_parse_config_xml(self): dnode = self.ctx.parse_data_mem(self.XML_CONFIG, 'xml', config=True) self.assertIsInstance(dnode, DContainer) try: xml = dnode.print_mem('xml', pretty=True) self.assertEqual(xml, self.XML_CONFIG) finally: dnode.free() XML_STATE = '''<state xmlns="urn:yang:yolo:system"> <hostname>foo</hostname> <speed>1234</speed> <number>1000</number> <number>2000</number> <number>3000</number> <url> <proto>https</proto> <host>github.com</host> <path>/rjarry/libyang-cffi</path> <enabled>false</enabled> </url> <url> <proto>http</proto> <host>foobar.com</host> <port>8080</port> <path>/index.html</path> <enabled>true</enabled> </url> </state> ''' def test_data_parse_data_xml(self): dnode = self.ctx.parse_data_mem(self.XML_STATE, 'xml', data=True, no_yanglib=True) self.assertIsInstance(dnode, DContainer) try: xml = dnode.print_mem('xml', pretty=True) self.assertEqual(xml, self.XML_STATE) finally: dnode.free() def test_data_create_paths(self): state = self.ctx.create_data_path('/yolo-system:state') try: state.create_path('hostname', 'foo') state.create_path('speed', 1234) state.create_path('number', 1000) state.create_path('number', 2000) state.create_path('number', 3000) u = state.create_path('url[proto="https"][host="github.com"]') u.create_path('path', '/rjarry/libyang-cffi') u.create_path('enabled', False) u = state.create_path('url[proto="http"][host="foobar.com"]') u.create_path('port', 8080) u.create_path('path', '/index.html') u.create_path('enabled', True) state.validate(strict=True) self.assertEqual(state.print_mem('json', pretty=True), self.JSON_STATE) finally: state.free() def test_data_create_invalid_type(self): s = self.ctx.create_data_path('/yolo-system:state') try: with self.assertRaises(LibyangError): s.create_path('speed', 1234000000000000000000000000) finally: s.free() def test_data_create_invalid_regexp(self): s = self.ctx.create_data_path('/yolo-system:state') try: with self.assertRaises(LibyangError): s.create_path('hostname', 'INVALID.HOST') finally: s.free() DICT_CONFIG = { 'conf': { 'hostname': 'foo', 'speed': 1234, 'number': [1000, 2000, 3000], 'url': [ { 'proto': 'https', 'host': 'github.com', 'path': '/rjarry/libyang-cffi', 'enabled': False, }, { 'proto': 'http', 'host': 'foobar.com', 'port': 8080, 'path': '/index.html', 'enabled': True, }, ], }, } def test_data_to_dict_config(self): dnode = self.ctx.parse_data_mem(self.JSON_CONFIG, 'json', config=True) self.assertIsInstance(dnode, DContainer) try: dic = dnode.print_dict() finally: dnode.free() self.assertEqual(dic, self.DICT_CONFIG) def test_data_to_dict_rpc_input(self): dnode = self.ctx.parse_data_mem( '{"yolo-system:format-disk": {"disk": "/dev/sda"}}', 'json', rpc=True) self.assertIsInstance(dnode, DRpc) try: dic = dnode.print_dict() finally: dnode.free() self.assertEqual(dic, {'format-disk': {'disk': '/dev/sda'}}) def test_data_from_dict_module(self): module = self.ctx.get_module('yolo-system') dnode = module.parse_data_dict(self.DICT_CONFIG) self.assertIsInstance(dnode, DContainer) try: j = dnode.print_mem('json', pretty=True) finally: dnode.free() self.assertEqual(json.loads(j), json.loads(self.JSON_CONFIG)) def test_data_from_dict_invalid(self): try: from unittest.mock import patch except ImportError: self.skipTest('unittest.mock not available') module = self.ctx.get_module('yolo-system') orig_create = Context.create_data_path orig_free = DNode.free created = [] freed = [] def wrapped_create(self, *args, **kwargs): c = orig_create(self, *args, **kwargs) if c is not None: created.append(c) return c def wrapped_free(self, *args, **kwargs): freed.append(self) orig_free(self, *args, **kwargs) root = module.parse_data_dict({ 'conf': { 'hostname': 'foo', 'speed': 1234, 'number': [1000, 2000, 3000], } }) invalid_dict = { 'conf': { 'url': [ { 'proto': 'https', 'host': 'github.com', 'path': '/rjarry/libyang-cffi', 'enabled': False, }, { 'proto': 'http', 'host': 'foobar.com', 'port': 'INVALID.PORT', 'path': '/index.html', 'enabled': True, }, ], }, } try: with patch.object(Context, 'create_data_path', wrapped_create), \ patch.object(DNode, 'free', wrapped_free): with self.assertRaises(LibyangError): module.parse_data_dict(invalid_dict, parent=root) self.assertGreater(len(created), 0) self.assertGreater(len(freed), 0) self.assertEqual(freed, list(reversed(created))) finally: root.free() def test_data_from_dict_container(self): snode = next(self.ctx.find_path('/yolo-system:conf')) self.assertIsInstance(snode, SContainer) dnode = snode.parse_data_dict(self.DICT_CONFIG) self.assertIsInstance(dnode, DContainer) try: j = dnode.print_mem('json', pretty=True) finally: dnode.free() self.assertEqual(json.loads(j), json.loads(self.JSON_CONFIG)) def test_data_from_dict_leaf(self): snode = next( self.ctx.find_path('/yolo-system:state/yolo-system:hostname')) self.assertIsInstance(snode, SLeaf) dnode = snode.parse_data_dict({'hostname': 'foo'}) try: j = dnode.print_mem('json') finally: dnode.free() self.assertEqual(j, '{"yolo-system:state":{"hostname":"foo"}}') def test_data_from_dict_rpc(self): snode = next(self.ctx.find_path('/yolo-system:format-disk')) self.assertIsInstance(snode, SRpc) dnode = snode.parse_data_dict({'format-disk': { 'duration': 42 }}, rpc_output=True) self.assertIsInstance(dnode, DRpc) try: j = dnode.print_mem('json') finally: dnode.free() self.assertEqual(j, '{"yolo-system:format-disk":{"duration":42}}')
def test_ctx_get_invalid_module(self): ctx = Context(YANG_DIR) ctx.load_module('wtf-types') with self.assertRaises(LibyangError): ctx.get_module('yolo-system')
class DataTest(unittest.TestCase): def setUp(self): self.ctx = Context(YANG_DIR) mod = self.ctx.load_module("yolo-system") mod.feature_enable_all() def tearDown(self): self.ctx.destroy() self.ctx = None JSON_CONFIG = """{ "yolo-system:conf": { "hostname": "foo", "speed": 1234, "number": [ 1000, 2000, 3000 ], "url": [ { "proto": "https", "host": "github.com", "path": "/CESNET/libyang-python", "enabled": false }, { "proto": "http", "host": "foobar.com", "port": 8080, "path": "/index.html", "enabled": true } ] } } """ def test_data_parse_config_json(self): dnode = self.ctx.parse_data_mem(self.JSON_CONFIG, "json", config=True) self.assertIsInstance(dnode, DContainer) try: j = dnode.print_mem("json", pretty=True) self.assertEqual(j, self.JSON_CONFIG) finally: dnode.free() JSON_STATE = """{ "yolo-system:state": { "hostname": "foo", "speed": 1234, "number": [ 1000, 2000, 3000 ], "url": [ { "proto": "https", "host": "github.com", "path": "/CESNET/libyang-python", "enabled": false }, { "proto": "http", "host": "foobar.com", "port": 8080, "path": "/index.html", "enabled": true } ] } } """ def test_data_parse_state_json(self): dnode = self.ctx.parse_data_mem(self.JSON_STATE, "json", data=True, no_yanglib=True) self.assertIsInstance(dnode, DContainer) try: j = dnode.print_mem("json", pretty=True) self.assertEqual(j, self.JSON_STATE) finally: dnode.free() XML_CONFIG = """<conf xmlns="urn:yang:yolo:system"> <hostname>foo</hostname> <speed>1234</speed> <number>1000</number> <number>2000</number> <number>3000</number> <url> <proto>https</proto> <host>github.com</host> <path>/CESNET/libyang-python</path> <enabled>false</enabled> </url> <url> <proto>http</proto> <host>foobar.com</host> <port>8080</port> <path>/index.html</path> <enabled>true</enabled> </url> </conf> """ def test_data_parse_config_xml(self): dnode = self.ctx.parse_data_mem(self.XML_CONFIG, "xml", config=True) self.assertIsInstance(dnode, DContainer) try: xml = dnode.print_mem("xml", pretty=True) self.assertEqual(xml, self.XML_CONFIG) finally: dnode.free() XML_STATE = """<state xmlns="urn:yang:yolo:system"> <hostname>foo</hostname> <speed>1234</speed> <number>1000</number> <number>2000</number> <number>3000</number> <url> <proto>https</proto> <host>github.com</host> <path>/CESNET/libyang-python</path> <enabled>false</enabled> </url> <url> <proto>http</proto> <host>foobar.com</host> <port>8080</port> <path>/index.html</path> <enabled>true</enabled> </url> </state> """ def test_data_parse_data_xml(self): dnode = self.ctx.parse_data_mem(self.XML_STATE, "xml", data=True, no_yanglib=True) self.assertIsInstance(dnode, DContainer) try: xml = dnode.print_mem("xml", pretty=True) self.assertEqual(xml, self.XML_STATE) finally: dnode.free() def test_data_parse_duplicate_data_type(self): with self.assertRaises(ValueError): self.ctx.parse_data_mem("", "xml", edit=True, rpc=True) XML_EDIT = """<conf xmlns="urn:yang:yolo:system"> <hostname-ref>notdefined</hostname-ref> </conf> """ def test_data_parse_edit(self): dnode = self.ctx.parse_data_mem(self.XML_EDIT, "xml", edit=True) self.assertIsInstance(dnode, DContainer) try: xml = dnode.print_mem("xml", pretty=True) self.assertEqual(xml, self.XML_EDIT) finally: dnode.free() def test_data_create_paths(self): state = self.ctx.create_data_path("/yolo-system:state") try: state.create_path("hostname", "foo") state.create_path("speed", 1234) state.create_path("number", 1000) state.create_path("number", 2000) state.create_path("number", 3000) u = state.create_path('url[proto="https"][host="github.com"]') u.create_path("path", "/CESNET/libyang-python") u.create_path("enabled", False) u = state.create_path('url[proto="http"][host="foobar.com"]') u.create_path("port", 8080) u.create_path("path", "/index.html") u.create_path("enabled", True) self.assertEqual(state.print_mem("json", pretty=True), self.JSON_STATE) finally: state.free() def test_data_create_invalid_type(self): s = self.ctx.create_data_path("/yolo-system:state") try: with self.assertRaises(LibyangError): s.create_path("speed", 1234000000000000000000000000) finally: s.free() def test_data_create_invalid_regexp(self): s = self.ctx.create_data_path("/yolo-system:state") try: with self.assertRaises(LibyangError): s.create_path("hostname", "INVALID.HOST") finally: s.free() DICT_CONFIG = { "conf": { "hostname": "foo", "speed": 1234, "number": [1000, 2000, 3000], "url": [ { "enabled": False, "path": "/CESNET/libyang-python", "host": "github.com", "proto": "https", }, { "port": 8080, "proto": "http", "path": "/index.html", "enabled": True, "host": "foobar.com", }, ], } } def test_data_to_dict_config(self): dnode = self.ctx.parse_data_mem(self.JSON_CONFIG, "json", config=True) self.assertIsInstance(dnode, DContainer) try: dic = dnode.print_dict() finally: dnode.free() self.assertEqual(dic, self.DICT_CONFIG) def test_data_to_dict_rpc_input(self): dnode = self.ctx.parse_data_mem( '{"yolo-system:format-disk": {"disk": "/dev/sda"}}', "json", rpc=True) self.assertIsInstance(dnode, DRpc) try: dic = dnode.print_dict() finally: dnode.free() self.assertEqual(dic, {"format-disk": {"disk": "/dev/sda"}}) def test_data_from_dict_module(self): module = self.ctx.get_module("yolo-system") dnode = module.parse_data_dict(self.DICT_CONFIG, strict=True, config=True) self.assertIsInstance(dnode, DContainer) try: j = dnode.print_mem("json", pretty=True) finally: dnode.free() self.assertEqual(json.loads(j), json.loads(self.JSON_CONFIG)) DICT_EDIT = {"conf": {"hostname-ref": "notdefined"}} def test_data_from_dict_edit(self): module = self.ctx.get_module("yolo-system") dnode = module.parse_data_dict(self.DICT_EDIT, strict=True, edit=True) self.assertIsInstance(dnode, DContainer) try: xml = dnode.print_mem("xml", pretty=True) finally: dnode.free() self.assertEqual(xml, self.XML_EDIT) def test_data_from_dict_invalid(self): module = self.ctx.get_module("yolo-system") created = [] freed = [] class FakeLib: def __init__(self, orig): self.orig = orig def lyd_new(self, *args): c = self.orig.lyd_new(*args) if c: created.append(c) return c def lyd_new_leaf(self, *args): c = self.orig.lyd_new_leaf(*args) if c: created.append(c) return c def lyd_free(self, dnode): freed.append(dnode) self.orig.lyd_free(dnode) def __getattr__(self, name): return getattr(self.orig, name) fake_lib = FakeLib(lib) root = module.parse_data_dict( { "conf": { "hostname": "foo", "speed": 1234, "number": [1000, 2000, 3000] } }, strict=True, config=True, ) invalid_dict = { "url": [ { "host": "github.com", "proto": "https", "enabled": False, "path": "/CESNET/libyang-python", }, { "proto": "http", "path": "/index.html", "enabled": True, "host": "foobar.com", "port": "INVALID.PORT", }, ] } try: with patch("libyang.data.lib", fake_lib): with self.assertRaises(LibyangError): root.merge_data_dict(invalid_dict, strict=True, config=True) self.assertGreater(len(created), 0) self.assertGreater(len(freed), 0) self.assertEqual(freed, list(reversed(created))) finally: root.free() def test_data_from_dict_container(self): dnode = self.ctx.create_data_path("/yolo-system:conf") self.assertIsInstance(dnode, DContainer) subtree = dnode.merge_data_dict(self.DICT_CONFIG["conf"], strict=True, config=True, validate=False) # make sure subtree validation is forbidden with self.assertRaises(LibyangError): subtree.validate(config=True) try: dnode.validate(config=True) j = dnode.print_mem("json", pretty=True) finally: dnode.free() self.assertEqual(json.loads(j), json.loads(self.JSON_CONFIG)) def test_data_from_dict_leaf(self): dnode = self.ctx.create_data_path("/yolo-system:state") self.assertIsInstance(dnode, DContainer) dnode.merge_data_dict({"hostname": "foo"}, strict=True, data=True, no_yanglib=True) try: j = dnode.print_mem("json") finally: dnode.free() self.assertEqual(j, '{"yolo-system:state":{"hostname":"foo"}}') def test_data_from_dict_rpc(self): dnode = self.ctx.create_data_path("/yolo-system:format-disk") self.assertIsInstance(dnode, DRpc) dnode.merge_data_dict({"duration": 42}, rpcreply=True, strict=True) try: j = dnode.print_mem("json") finally: dnode.free() self.assertEqual(j, '{"yolo-system:format-disk":{"duration":42}}') def test_data_from_dict_action(self): module = self.ctx.get_module("yolo-system") dnode = module.parse_data_dict( { "conf": { "url": [ { "proto": "https", "host": "github.com", "fetch": { "timeout": 42 }, }, ], }, }, rpc=True, strict=True, ) self.assertIsInstance(dnode, DContainer) try: j = dnode.print_mem("json") finally: dnode.free() self.assertEqual( j, '{"yolo-system:conf":{"url":[{"proto":"https","host":"github.com","fetch":{"timeout":42}}]}}', ) def test_data_to_dict_action(self): module = self.ctx.get_module("yolo-system") request = module.parse_data_dict( { "conf": { "url": [ { "proto": "https", "host": "github.com", "fetch": { "timeout": 42 }, }, ], }, }, rpc=True, strict=True, ) dnode = self.ctx.parse_data_mem( '{"yolo-system:result":"not found"}', "json", rpcreply=True, rpc_request=request, ) try: dic = dnode.print_dict() finally: dnode.free() request.free() self.assertEqual( dic, { "conf": { "url": [ { "proto": "https", "host": "github.com", "fetch": { "result": "not found" }, }, ], }, }, )
def test_ctx_get_module(self): ctx = Context(YANG_DIR) ctx.load_module('yolo-system') mod = ctx.get_module('wtf-types') self.assertIsInstance(mod, Module)