blob: ddb88f3ac0107940e8c8f5fe653fb3461102f631 [file] [log] [blame]
Scott Bakerd85a25d2019-02-07 17:43:59 -08001# Copyright 2017-present Open Networking Foundation
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
Zack Williams5c2ea232019-01-30 15:23:01 -070015from __future__ import absolute_import
Scott Bakerd85a25d2019-02-07 17:43:59 -080016import unittest
17from mock import patch, Mock, MagicMock
18
19from io import StringIO
20import functools
21import os
22import sys
23
Zack Williams5c2ea232019-01-30 15:23:01 -070024# Python 3 renamed __builtin__ -> builtins
25# py_builtins is used to help with mocking 'open'
26try:
27 import builtins
28 py_builtins = "builtins"
29except ImportError:
30 import __builtin__ as builtins
31 py_builtins = "__builtin__"
32
Scott Bakerd85a25d2019-02-07 17:43:59 -080033test_path = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
34
35
36def mock_listdir(dir_map, dir):
37 """ mock os.listdir() """
38 return dir_map.get(dir, [])
39
40
41def mock_exists(file_map, fn):
42 """ mock os.path.exists() """
Zack Williams5c2ea232019-01-30 15:23:01 -070043 return fn in file_map
Scott Bakerd85a25d2019-02-07 17:43:59 -080044
45
46def mock_open(orig_open, file_map, fn, *args, **kwargs):
47 """ mock file open() """
48 if fn in file_map:
49 return StringIO(file_map[fn])
50 else:
51 return orig_open(fn, *args, **kwargs)
52
53
54class ItemList(object):
55 """ mock the various items within a LoadModelsRequest protobuf """
56
57 def __init__(self):
58 self.items = []
59
60 def add(self):
61 item = Mock()
62 self.items.append(item)
63 return item
64
65
66class MockLoadModelsRequest(object):
67 """ mock a LoadModelsRequest protobuf """
68
69 def __init__(self, *args, **kwargs):
70 for (k, v) in kwargs.items():
71 setattr(self, k, v)
72 self.xprotos = ItemList()
73 self.decls = ItemList()
74 self.attics = ItemList()
75 self.convenience_methods = ItemList()
76 self.migrations = ItemList()
77
78
79class TestLoadModels(unittest.TestCase):
80 def setUp(self):
81 self.sys_path_save = sys.path
82 self.cwd_save = os.getcwd()
83
84 config = os.path.join(test_path, "test_config.yaml")
85 from xosconfig import Config
86
87 Config.clear()
88 Config.init(config, "synchronizer-config-schema.yaml")
89
90 from xossynchronizer import loadmodels
91 from xossynchronizer.loadmodels import ModelLoadClient
Zack Williams5c2ea232019-01-30 15:23:01 -070092
Scott Bakerd85a25d2019-02-07 17:43:59 -080093 self.loadmodels = loadmodels
94
95 self.api = MagicMock()
96 self.api.dynamicload_pb2.LoadModelsRequest = MockLoadModelsRequest
97 self.loader = ModelLoadClient(self.api)
98
99 def tearDown(self):
100 sys.path = self.sys_path_save
101 os.chdir(self.cwd_save)
102
103 def test_upload_models(self):
Zack Williams5c2ea232019-01-30 15:23:01 -0700104 dir_map = {
105 "models_dir": ["models.xproto", "models.py"],
106 "models_dir/convenience": ["convenience1.py"],
107 "models_dir/../migrations": ["migration1.py", "migration2.py"],
108 }
Scott Bakerd85a25d2019-02-07 17:43:59 -0800109
Zack Williams5c2ea232019-01-30 15:23:01 -0700110 file_map = {
111 "models_dir/models.xproto": u"some xproto",
112 "models_dir/models.py": u"print `python models file`",
113 "models_dir/convenience": u"directory",
114 "models_dir/convenience/convenience1.py": u"print `python convenience file`",
115 "models_dir/../migrations": u"directory",
116 "models_dir/../migrations/migration1.py": u"print `first migration`",
117 "models_dir/../migrations/migration2.py": u"print `second migration`",
118 }
Scott Bakerd85a25d2019-02-07 17:43:59 -0800119
Zack Williams5c2ea232019-01-30 15:23:01 -0700120 orig_open = builtins.open
121 with patch(
122 "os.listdir", side_effect=functools.partial(mock_listdir, dir_map)
123 ), patch(
124 "os.path.exists", side_effect=functools.partial(mock_exists, file_map)
125 ), patch(
126 py_builtins + ".open",
127 side_effect=functools.partial(mock_open, orig_open, file_map),
128 ):
Scott Bakerd85a25d2019-02-07 17:43:59 -0800129 self.loader.upload_models("myservice", "models_dir", "1.2")
130
131 request = self.api.dynamicload.LoadModels.call_args[0][0]
132 self.assertEqual(request.name, "myservice")
133 self.assertEqual(request.version, "1.2")
134
135 self.assertEqual(len(request.xprotos.items), 1)
136 self.assertEqual(request.xprotos.items[0].filename, "models.xproto")
137 self.assertEqual(request.xprotos.items[0].contents, u"some xproto")
138
139 self.assertEqual(len(request.decls.items), 1)
140 self.assertEqual(request.decls.items[0].filename, "models.py")
Zack Williams5c2ea232019-01-30 15:23:01 -0700141 self.assertEqual(
142 request.decls.items[0].contents, u"print `python models file`"
143 )
Scott Bakerd85a25d2019-02-07 17:43:59 -0800144
145 self.assertEqual(len(request.convenience_methods.items), 1)
Zack Williams5c2ea232019-01-30 15:23:01 -0700146 self.assertEqual(
147 request.convenience_methods.items[0].filename, "convenience1.py"
148 )
149 self.assertEqual(
150 request.convenience_methods.items[0].contents,
151 u"print `python convenience file`",
152 )
Scott Bakerd85a25d2019-02-07 17:43:59 -0800153
154 self.assertEqual(len(request.migrations.items), 2)
155 self.assertEqual(request.migrations.items[0].filename, "migration1.py")
Zack Williams5c2ea232019-01-30 15:23:01 -0700156 self.assertEqual(
157 request.migrations.items[0].contents, u"print `first migration`"
158 )
Scott Bakerd85a25d2019-02-07 17:43:59 -0800159 self.assertEqual(request.migrations.items[1].filename, "migration2.py")
Zack Williams5c2ea232019-01-30 15:23:01 -0700160 self.assertEqual(
161 request.migrations.items[1].contents, u"print `second migration`"
162 )
Scott Bakerd85a25d2019-02-07 17:43:59 -0800163
164
165if __name__ == "__main__":
166 unittest.main()