1- """ Test for Meshroom Plugins.
2- """
31#!/usr/bin/env python
42# coding:utf-8
3+ """ Test for Meshroom Plugins.
4+ """
5+ # STD
6+ import os
7+ import shutil
8+ import tempfile
59
10+ # Internal
611from meshroom .core import _plugins
712from meshroom .core import desc , registerNodeType , unregisterNodeType
13+ from meshroom .core .graph import Graph
14+ from meshroom .core .node import Node , IncompatiblePluginNode
815
916
1017class SampleNode (desc .Node ):
@@ -47,6 +54,7 @@ def test_plugin_management():
4754 assert not pluginManager .registered (name )
4855 assert name not in pluginManager .descriptors
4956
57+
5058def test_descriptor ():
5159 """ Tests the Descriptor and NodeDescriptor instances.
5260 """
@@ -65,3 +73,145 @@ def test_descriptor():
6573
6674 # Finally unregister the plugin
6775 unregisterNodeType (SampleNode )
76+
77+
78+ def _setup_temp_package (directory , name ):
79+ """ Sets up a temporary meshroom package structure which can be loaded as plugins.
80+ """
81+ package = os .path .join (directory , name )
82+
83+ # Create the base package in the directory
84+ os .makedirs (package )
85+
86+ # The very first file that we need is probably empty __init__.py
87+ init = os .path .join (package , "__init__.py" )
88+
89+ # The second thing we need is a directory inside
90+ packageDir = os .path .join (package , "TesingPackage" )
91+
92+ # Third would be another init for the package
93+ packinit = os .path .join (packageDir , "__init__.py" )
94+
95+ # Then comes the main module which will hold the plugin
96+ pluginMod = os .path .join (packageDir , "TestInput.py" )
97+
98+ # Now start constructing stuff here
99+ os .makedirs (packageDir )
100+
101+ with open (init , "w" ) as f :
102+ f .write ("__version__ =\" 1.0\" " )
103+
104+ with open (packinit , "w" ) as f :
105+ f .write ("__version__ =\" 1.0\" " )
106+
107+ contents = """
108+ from meshroom.core import desc
109+
110+
111+ class SampleTroubledNode(desc.Node):
112+ \" "" Sample Node for unit testing a reload process.
113+ Defaults to having an invalid input param value. Which gets updated later on.
114+ \" ""
115+
116+ category = "Sample"
117+
118+ inputs = [
119+ # A Float param having the value as a string will cause the plugin to be loaded in an Error state
120+ desc.FloatParam(name='paramA', label='ParamA', description='', value='4.0')
121+ ]
122+ outputs = [
123+ desc.File(name='output', label='Output', description='', value=desc.Node.internalFolder)
124+ ]
125+ """
126+
127+ with open (pluginMod , "w" ) as f :
128+ f .write (contents )
129+
130+ return package
131+
132+ def _correctify_plugin (pluginPath ):
133+ contents = """
134+ from meshroom.core import desc
135+
136+
137+ class SampleTroubledNode(desc.Node):
138+ \" "" Sample Node for unit testing a reload process.
139+ Defaults to having an invalid input param value. Which gets updated later on.
140+ \" ""
141+
142+ category = "Sample"
143+
144+ inputs = [
145+ # A Float param having the value as a string will cause the plugin to be loaded in an Error state
146+ desc.FloatParam(name='paramA', label='ParamA', description='', value=4.0)
147+ ]
148+ outputs = [
149+ desc.File(name='output', label='Output', description='', value=desc.Node.internalFolder)
150+ ]
151+ """
152+
153+ with open (pluginPath , "w" ) as f :
154+ f .write (contents )
155+
156+
157+ def _cleaup_package (directory ):
158+ """ Cleans up the Package
159+ """
160+ shutil .rmtree (directory )
161+
162+ def test_reload_with_graph ():
163+ """ Tests Reloading of a plugin and how does the change propagate to a graph.
164+ """
165+ # Create a temp directory
166+ directory = tempfile .mkdtemp ()
167+
168+ package = _setup_temp_package (directory , "MTest" )
169+
170+ # Since the Node Plugin Manager is a singleton instance
171+ # We should still be able to instantiate and have a look at out registered plugins directly
172+ pluginManager = _plugins .NodePluginManager ()
173+
174+ pluginManager .load (package )
175+
176+ # Sample Node name
177+ name = "SampleTroubledNode"
178+
179+ # Assert that the plugin we have registered above is indeed registered
180+ assert pluginManager .registered (name )
181+
182+ # But the status of the plugin would be errored
183+ assert pluginManager .status (name ) == _plugins .Status .ERRORED
184+
185+ # Graph for usage
186+ g = Graph ("" )
187+
188+ # Create Nodes in the Graph
189+ n = g .addNewNode (name )
190+
191+ # Assert that the node is of an Incompatible Plugin type as the plugin had errors while loading
192+ assert isinstance (n , IncompatiblePluginNode )
193+
194+ descriptor = pluginManager .descriptors .get (name )
195+ # Test that the plugin would not get reloaded
196+ # unless either the source has been modified or the plugin is forced to be loaded
197+ assert not descriptor .reload ()
198+
199+ # Modify the Source of the Troubled Node before we reload the plugin
200+ # This updates the source of the plugin and ensures that the plugin can now be loaded as expected
201+ _correctify_plugin (os .path .join (package , "TesingPackage" , "TestInput.py" ))
202+
203+ # Reload the plugin as the source has been modified
204+ assert descriptor .reload ()
205+
206+ # Now the plugin has been reloaded
207+ assert pluginManager .status (name ) == _plugins .Status .LOADED
208+
209+ # Now reload the nodes of the provided type in the graph
210+ g .reloadNodes (name )
211+
212+ # Get all the nodes and assert that they have been upgraded to Standard Nodes
213+ for node in g .nodesOfType (name ):
214+ assert isinstance (node , Node )
215+
216+ # Once the tests are concluded -> Cleanup
217+ _cleaup_package (package )
0 commit comments