diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dd8286ce8e..8123193b8e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,8 +21,7 @@ jobs: - name: Dependency Test run: mvn test -Dtest=org.myrobotlab.framework.DependencyTest -q - - - name: Build and Test with Maven + - name: Build with Maven run: mvn --batch-mode -Dtest=!**/OpenCV* test -q - name: Get next version diff --git a/make_web_dev.bat b/make_web_dev.bat index 5c0b1c1ea9..9d3c5e8126 100644 --- a/make_web_dev.bat +++ b/make_web_dev.bat @@ -6,6 +6,6 @@ git clone https://github.com/MyRobotLab/myrobotlab.git cd myrobotlab git pull git status -curl -LOJ http://build.myrobotlab.org:8080/job/myrobotlab/job/develop/lastSuccessfulBuild/artifact/target/myrobotlab.jar +curl -LOJ https://github.com/MyRobotLab/myrobotlab/releases/latest/download/myrobotlab.jar java -jar myrobotlab.jar --install && java -jar myrobotlab.jar -s webgui WebGui python Python i01 InMoov2 intro Intro diff --git a/pom.xml b/pom.xml index 28f05b627c..7acbce2abb 100644 --- a/pom.xml +++ b/pom.xml @@ -13,6 +13,9 @@ # fast build mvn -DskipTests package -o + # execute + mvn exec:java -Dexec.mainClass=org.myrobotlab.service.Runtime -Dexec.args="-s webgui WebGui intro Intro python Python" + # specific test mvn test -Dtest="org.myrobotlab.service.WebGuiTest#postTest" diff --git a/src/main/java/org/myrobotlab/framework/Service.java b/src/main/java/org/myrobotlab/framework/Service.java index 5e6ef5ef10..b3309bbcc3 100644 --- a/src/main/java/org/myrobotlab/framework/Service.java +++ b/src/main/java/org/myrobotlab/framework/Service.java @@ -101,11 +101,11 @@ public abstract class Service implements Runnable, Seri protected MetaData serviceType; /** - * Config member - configuration of type {ServiceType}Config - * Runtime applys either the default config or a saved config during service creation + * Config member - configuration of type {ServiceType}Config Runtime applys + * either the default config or a saved config during service creation */ protected T config; - + private static final long serialVersionUID = 1L; transient public final static Logger log = LoggerFactory.getLogger(Service.class); @@ -190,8 +190,8 @@ public abstract class Service implements Runnable, Seri /** * This is the map of interfaces - its really "static" information, since its - * a definition. However, since serialization will not process statics - we are making - * it a member variable + * a definition. However, since serialization will not process statics - we + * are making it a member variable */ // FIXME - this should be a map protected Map interfaceSet; @@ -279,11 +279,7 @@ public static Object copyShallowFrom(Object target, Object source) { * ){ log.info("here"); } */ - if (Modifier.isPrivate(modifiers) - || fname.equals("log") - || Modifier.isTransient(modifiers) - || Modifier.isStatic(modifiers) - || Modifier.isFinal(modifiers)) { + if (Modifier.isPrivate(modifiers) || fname.equals("log") || Modifier.isTransient(modifiers) || Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) { log.debug("skipping {}", field.getName()); continue; } else { @@ -472,18 +468,17 @@ static public String getResourceDir(Class clazz, String additionalPath) { * to glue together * @return the full resolved path * - * FIXME - DO NOT USE STATIC !!!! - * all instances of services should be able to get the resource directory - * If its static and "configurable" then it needs an instance of Runtime - * which is not available. + * FIXME - DO NOT USE STATIC !!!! all instances of services should be + * able to get the resource directory If its static and "configurable" + * then it needs an instance of Runtime which is not available. * */ @Deprecated /* this should not be static - remove it */ static public String getResourceDir(String serviceType, String additionalPath) { - // setting resource directory + // setting resource directory String resourceDir = null; - + // stupid solution to get past static problem if (!"Runtime".equals(serviceType)) { resourceDir = Runtime.getInstance().getConfig().resource + fs + serviceType; @@ -495,6 +490,7 @@ static public String getResourceDir(String serviceType, String additionalPath) { } return resourceDir; } + /** * non static get resource path return the path to a resource - since the root * can change depending if in debug or runtime - it gets the appropriate root @@ -997,47 +993,49 @@ public String[] getMethodNames() { public Method[] getMethods() { return this.getClass().getMethods(); } - + /** - * Returns a map containing all interface names from the class hierarchy and the interface hierarchy of the - * current class. + * Returns a map containing all interface names from the class hierarchy and + * the interface hierarchy of the current class. * * @return A map containing all interface names. */ public Map getInterfaceSet() { - Map ret = new TreeMap<>(); - Set> visitedClasses = new HashSet<>(); - getAllInterfacesHelper(getClass(), ret, visitedClasses); - return ret; + Map ret = new TreeMap<>(); + Set> visitedClasses = new HashSet<>(); + getAllInterfacesHelper(getClass(), ret, visitedClasses); + return ret; } /** - * Recursively traverses the class hierarchy and the interface hierarchy to add all interface names to the - * specified map. + * Recursively traverses the class hierarchy and the interface hierarchy to + * add all interface names to the specified map. * - * @param c The class to start the traversal from. - * @param ret The map to store the interface names. - * @param visitedClasses A set to keep track of visited classes to avoid infinite loops. + * @param c + * The class to start the traversal from. + * @param ret + * The map to store the interface names. + * @param visitedClasses + * A set to keep track of visited classes to avoid infinite loops. */ private void getAllInterfacesHelper(Class c, Map ret, Set> visitedClasses) { - if (c != null && !visitedClasses.contains(c)) { - // Add interfaces from the current class - Class[] interfaces = c.getInterfaces(); - for (Class interfaze : interfaces) { - ret.put(interfaze.getName(), interfaze.getName()); - } - - // Add interfaces from interfaces implemented by the current class - for (Class interfaze : interfaces) { - getAllInterfacesHelper(interfaze, ret, visitedClasses); - } + if (c != null && !visitedClasses.contains(c)) { + // Add interfaces from the current class + Class[] interfaces = c.getInterfaces(); + for (Class interfaze : interfaces) { + ret.put(interfaze.getName(), interfaze.getName()); + } - // Recursively traverse the superclass hierarchy - visitedClasses.add(c); - getAllInterfacesHelper(c.getSuperclass(), ret, visitedClasses); + // Add interfaces from interfaces implemented by the current class + for (Class interfaze : interfaces) { + getAllInterfacesHelper(interfaze, ret, visitedClasses); } + + // Recursively traverse the superclass hierarchy + visitedClasses.add(c); + getAllInterfacesHelper(c.getSuperclass(), ret, visitedClasses); + } } - public Message getMsg() throws InterruptedException { return inbox.getMsg(); @@ -1296,12 +1294,11 @@ final public Object invokeOn(boolean blockLocally, Object obj, String methodName if (blockLocally) { Outbox outbox = null; if (obj instanceof ServiceInterface) { - outbox = ((ServiceInterface)obj).getOutbox(); + outbox = ((ServiceInterface) obj).getOutbox(); } else { return retobj; } - - + List subList = outbox.notifyList.get(methodName); // correct? get local (default?) gateway Runtime runtime = Runtime.getInstance(); @@ -1381,27 +1378,88 @@ public boolean isRunning() { /** * getConfig returns current config of the service. This default super method - * will also filter webgui subscriptions out, in addition for any local subscriptions it - * will remove the instance "id" from any service. The reason it removes the webgui - * subscriptions is to avoid overwelming the user when modifying config. UI subscriptions - * tend to be very numerous and not very useful to the user. The reason it removes the - * instance id from local subscriptions is to allow the config to be used with any instance. - * Unless the user is controlling instance id, its random every restart. + * will also filter webgui subscriptions out, in addition for any local + * subscriptions it will remove the instance "id" from any service. The reason + * it removes the webgui subscriptions is to avoid overwelming the user when + * modifying config. UI subscriptions tend to be very numerous and not very + * useful to the user. The reason it removes the instance id from local + * subscriptions is to allow the config to be used with any instance. Unless + * the user is controlling instance id, its random every restart. */ public T getConfig() { return config; } /** - * Super class apply using template type. The default assigns config of the templated type, and also - * add listeners from subscriptions found on the base class ServiceConfig.listeners + * Get a service's peer's configuration. This method is used to get the + * configuration of a peer service regarless if it is currently running or + * not. If the peer is running the configuration is pulled from the active + * peer service, if it is not currently running the configuration is read from + * the current config set's service configuration file, if that does not exist + * the default configuration for this peer is used. + * + * @param peerKey + * - key of the peer service. e.g. "opencv" in the case of + * i01."opencv" + * @return */ - public T apply(T c) { - config = c; - addConfigListeners(c); - return config; + public ServiceConfig getPeerConfig(String peerKey) { + String peerName = getPeerName(peerKey); + if (peerName == null) { + error("peer name not found for peer key %s", peerKey); + return null; + } + + ServiceInterface si = Runtime.getService(peerName); + if (si != null) { + // peer is currently running - get its config + return si.getConfig(); + } + + // peer is not currently running attempt to read from config + Runtime runtime = Runtime.getInstance(); + // read current service config for this peer service + ServiceConfig sc = runtime.readServiceConfig(peerName); + if (sc == null) { + error("peer service %s is defined, but %s.yml not available on filesystem", peerKey, peerName); + return null; + } + return sc; } + public void setPeerConfigValue(String peerKey, String fieldname, Object value) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + ServiceConfig sc = getPeerConfig(peerKey); + if (sc == null) { + error("invalid config for peer key %s field name %s", peerKey, fieldname); + return; + } + Field field = sc.getClass().getDeclaredField(fieldname); + field.set(sc, value); + savePeerConfig(peerKey, sc); + String peerName = getPeerName(peerKey); + ConfigurableService cs = (ConfigurableService) Runtime.getService(peerName); + if (cs != null) { + cs.apply(sc); // TODO - look for applies if its read from the file system + // it needs to update Runtime.plan + } + + // broadcast change + invoke("getPeerConfig", peerKey); + Runtime.getPlan().put(peerName, sc); + Runtime runtime = Runtime.getInstance(); + runtime.broadcastState(); + } + + /** + * Super class apply using template type. The default assigns config of the + * templated type, and also add listeners from subscriptions found on the base + * class ServiceConfig.listeners + */ + public T apply(T c) { + config = c; + addConfigListeners(c); + return config; + } /** * The basic ServiceConfig has a list of listeners. These are definitions of @@ -1418,7 +1476,8 @@ public ServiceConfig addConfigListeners(ServiceConfig config) { } /** - * Default filtered config, used when saving, can be overriden by concrete class + * Default filtered config, used when saving, can be overriden by concrete + * class */ @Override public ServiceConfig getFilteredConfig() { @@ -1449,7 +1508,6 @@ public ServiceConfig getFilteredConfig() { return sc; } - @Override public void setConfigValue(String fieldname, Object value) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException { log.info("setting field name fieldname {} to {}", fieldname, value); @@ -1457,6 +1515,7 @@ public void setConfigValue(String fieldname, Object value) throws IllegalArgumen Field field = getConfig().getClass().getDeclaredField(fieldname); // field.setAccessible(true); should not need this - it "should" be public field.set(getConfig(), value); + save(); } @Override @@ -1561,11 +1620,12 @@ public void removeListener(String outMethod, String serviceName, String inMethod return true; } - // Previously we were not checking inMethod, which meant if a service had multiple - // subscriptions to the same topic (one to many mapping), the first in the list would be removed + // Previously we were not checking inMethod, which meant if a service + // had multiple + // subscriptions to the same topic (one to many mapping), the first in + // the list would be removed // instead of the requested one. - if (listener.callbackMethod.equals(inMethod) - && CodecUtils.checkServiceNameEquality(listener.callbackName, fullName)) { + if (listener.callbackMethod.equals(inMethod) && CodecUtils.checkServiceNameEquality(listener.callbackName, fullName)) { log.info("removeListener requested {}.{} to be removed", fullName, outMethod); return true; } @@ -1641,6 +1701,24 @@ public boolean save() { return runtime.saveService(runtime.getConfigName(), getName(), null); } + /** + * Save a service's peer's config to current config set + * + * @param peerKey + */ + public void savePeerConfig(String peerKey, ServiceConfig config) { + try { + Runtime runtime = Runtime.getInstance(); + String peerName = getPeerName(peerKey); + String data = CodecUtils.toYaml(config); + String ymlFileName = runtime.getConfigPath() + fs + CodecUtils.getShortName(peerName) + ".yml"; + FileIO.toFile(ymlFileName, data.getBytes()); + info("saved %s", ymlFileName); + } catch (Exception e) { + error(e); + } + } + public ServiceInterface getPeer(String peerKey) { String actualName = getPeerName(peerKey); return Runtime.getService(actualName); @@ -1991,7 +2069,7 @@ public void subscribe(String topicName, String topicMethod) { String callbackMethod = CodecUtils.getCallbackTopicName(topicMethod); subscribe(topicName, topicMethod, getFullName(), callbackMethod); } - + @Override public void subscribe(String service, String method, String callback) { subscribe(service, method, getFullName(), callback); @@ -2050,7 +2128,7 @@ public void unsubscribe(String topicName, String topicMethod) { String callbackMethod = CodecUtils.getCallbackTopicName(topicMethod); unsubscribe(topicName, topicMethod, getFullName(), callbackMethod); } - + @Override public void unsubscribe(String topicName, String topicMethod, String callback) { unsubscribe(topicName, topicMethod, getFullName(), callback); @@ -2078,10 +2156,13 @@ public Status error(Exception e) { @Override public Status error(String format, Object... args) { - String msg = String.format( - Objects.requireNonNullElse(format, ""), - args); - return error(msg); + Status ret; + ret = Status.error(String.format(Objects.requireNonNullElse(format, ""), args)); + ret.name = getName(); + log.error(ret.toString()); + lastError = ret; + invoke("publishStatus", ret); + return ret; } public Status error(String msg) { @@ -2577,7 +2658,10 @@ public String localize(String key, Object... args) { } @Override - @Deprecated /* this system should be removed in favor of a ProgramAB instance with ability to translate */ + @Deprecated /* + * this system should be removed in favor of a ProgramAB instance + * with ability to translate + */ public void loadLocalizations() { if (defaultLocalization == null) { @@ -2749,16 +2833,36 @@ public void apply() { Runtime runtime = Runtime.getInstance(); String configName = runtime.getConfigName(); ServiceConfig sc = runtime.readServiceConfig(configName, name); - + if (sc == null) { error("config file %s not found", Runtime.getConfigRoot() + fs + configName + fs + name + ".yml"); return; } - - // updating plan + + // updating plan - FIXME remove plan Runtime.getPlan().put(getName(), sc); + // applying config to self - apply((T)sc); + apply((T) sc); + } + + /** + * Apply the config to a peer, regardless if the peer is currently running or + * not + * + * @param peerKey + * @param config + */ + public void applyPeerConfig(String peerKey, ServiceConfig config) { + String peerName = getPeerName(peerKey); + + Runtime.getPlan().put(peerName, config); + + // meh - templating is not very helpful here + ConfigurableService si = (ConfigurableService) Runtime.getService(peerName); + if (si != null) { + si.apply(config); + } } /** @@ -2779,11 +2883,11 @@ public void setPeerName(String key, String fullName) { // should we also make or update a config file - if the config path is set? info("updated %s name to %s", oldName, peer.name); } - + /** * get all the subscriptions to this service */ - public Map> getNotifyList(){ + public Map> getNotifyList() { return getOutbox().getNotifyList(); } diff --git a/src/main/java/org/myrobotlab/service/InMoov2.java b/src/main/java/org/myrobotlab/service/InMoov2.java index 9e851a80ea..92e060dee2 100644 --- a/src/main/java/org/myrobotlab/service/InMoov2.java +++ b/src/main/java/org/myrobotlab/service/InMoov2.java @@ -189,7 +189,6 @@ public static void main(String[] args) { protected String voiceSelected; - public InMoov2(String n, String id) { super(n, id); @@ -227,6 +226,7 @@ public InMoov2(String n, String id) { } + // should be removed in favor of general listeners public void addTextListener(TextListener service) { // CORRECT WAY ! - no direct reference - just use the name in a subscription addListener("publishText", service.getName()); @@ -1868,7 +1868,7 @@ public void setTorsoSpeed(Integer topStom, Integer midStom, Integer lowStom) { setTorsoSpeed((double) topStom, (double) midStom, (double) lowStom); } - @Deprecated + @Deprecated /* use setTorsoSpeed */ public void setTorsoVelocity(Double topStom, Double midStom, Double lowStom) { setTorsoSpeed(topStom, midStom, lowStom); } @@ -2364,4 +2364,5 @@ public void wake() { } } + } diff --git a/src/main/java/org/myrobotlab/service/OpenCV.java b/src/main/java/org/myrobotlab/service/OpenCV.java index ba1edc8f93..88deb97360 100644 --- a/src/main/java/org/myrobotlab/service/OpenCV.java +++ b/src/main/java/org/myrobotlab/service/OpenCV.java @@ -2012,6 +2012,19 @@ public void enableFilter(String name) { } } + /** + * flip the video display vertically + * @param toFlip + */ + public void flip(boolean toFlip) { + config.flip = toFlip; + if (config.flip) { + addFilter("Flip"); + } else { + removeFilter("Flip"); + } + } + @Override public void disableFilter(String name) { OpenCVFilter f = filters.get(name); @@ -2107,6 +2120,8 @@ public OpenCVConfig apply(OpenCVConfig c) { // TODO: better configuration of the filter when it's added. } } + + flip(c.flip); if (c.capturing) { capture(); diff --git a/src/main/java/org/myrobotlab/service/Runtime.java b/src/main/java/org/myrobotlab/service/Runtime.java index c1f845abee..d8abae8ed5 100644 --- a/src/main/java/org/myrobotlab/service/Runtime.java +++ b/src/main/java/org/myrobotlab/service/Runtime.java @@ -139,7 +139,7 @@ public class Runtime extends Service implements MessageListener, * all these requests. */ @Deprecated /* use the filesystem only no memory plan */ - transient Plan masterPlan = new Plan("runtime"); + protected final Plan masterPlan = new Plan("runtime"); /** * thread for non-blocking install of services @@ -2627,6 +2627,7 @@ synchronized static public ServiceInterface start(String name, String type) { } Runtime.load(name, type); + Runtime.savePlan(null); // FIXME - does some order need to be maintained Map services = createServicesFromPlan(Runtime.getPlan(), null, name); @@ -4759,6 +4760,16 @@ synchronized private Plan loadService(Plan plan, String name, String type, boole return plan; } + + /** + * read a service's configuration, in the context + * of current config set name or default + * @param name + * @return + */ + public ServiceConfig readServiceConfig(String name) { + return readServiceConfig(null, name); + } /** * @@ -4799,19 +4810,6 @@ public String publishConfigLoaded(String name) { return name; } - // @Override - // public ServiceConfig getConfig() { - // RuntimeConfig config = (RuntimeConfig)super.getConfig(); - // List listeners = new - // ArrayList - // for (org.myrobotlab.service.config.ServiceConfig.Listener listener: - // config.listeners) { - // if (listener.equals("stopped") || listener.equals("created")|| - // listener.equals("registered")|| listener.equals("released")) { - // - // } - // } - // } public String setAllIds(String id) { Platform.getLocalInstance().setId(id); @@ -5108,6 +5106,10 @@ private void savePlanInternal(String configName) { for (String s : masterPlan.keySet()) { String filename = CONFIG_ROOT + fs + configName + fs + s + ".yml"; + File check = new File(filename); + if (check.exists()) { + continue; + } String data = CodecUtils.toYaml(masterPlan.get(s)); try { FileIO.toFile(filename, data.getBytes()); @@ -5289,7 +5291,6 @@ public RuntimeConfig getConfig() { config = super.getConfig(); config.locale = getLocaleTag(); config.virtual = isVirtual; - config.id = getId(); return config; } diff --git a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java index d48554891b..6625e37096 100644 --- a/src/main/java/org/myrobotlab/service/config/InMoov2Config.java +++ b/src/main/java/org/myrobotlab/service/config/InMoov2Config.java @@ -85,11 +85,9 @@ public class InMoov2Config extends ServiceConfig { public boolean neoPixelErrorRed = true; public boolean neoPixelFlashWhenSpeaking = true; - - public boolean openCVFaceRecognizerActivated = true; - - public boolean openCVFlipPicture = false; - + + public boolean openCVFaceRecognizerActivated=true; + public boolean pirEnableTracking = false; public boolean pirOnFlash = true; diff --git a/src/main/java/org/myrobotlab/service/config/OpenCVConfig.java b/src/main/java/org/myrobotlab/service/config/OpenCVConfig.java index 2c786aa648..2087539836 100644 --- a/src/main/java/org/myrobotlab/service/config/OpenCVConfig.java +++ b/src/main/java/org/myrobotlab/service/config/OpenCVConfig.java @@ -15,5 +15,9 @@ public class OpenCVConfig extends ServiceConfig { public boolean webViewer = false; public boolean capturing = false; public Map filters = new LinkedHashMap<>(); + /** + * flip the video vertically + */ + public boolean flip = false; } diff --git a/src/main/resources/resource/WebGui/app/peer.js b/src/main/resources/resource/WebGui/app/peer.js index 78c15f5da3..e033693b52 100644 --- a/src/main/resources/resource/WebGui/app/peer.js +++ b/src/main/resources/resource/WebGui/app/peer.js @@ -4,7 +4,7 @@ console.info('peer') -angular.module('peer', []).service('peer', function( mrl /*$rootScope, $log*/ +angular.module('peer', []).service('peer', function( mrl ) { service = {}; @@ -40,6 +40,20 @@ angular.module('peer', []).service('peer', function( mrl /*$rootScope, $log*/ return null } + service.getPeerConfig = function(service, key) { + try { + if (service && service.config && service.config.peers && service.config.peers[key]){ + return mrl.getService('runtime').masterPlan['config'][service.config.peers[key].name] + // return mrl.getService(service.config.peers[key].name).config + } else { + // if peer is not started - return the filesystem config + } + } catch (error) { + console.error(error); + } + return null + } + service.changePeerTab = function(service, key) { try { diff --git a/src/main/resources/resource/WebGui/app/service/js/RuntimeGui.js b/src/main/resources/resource/WebGui/app/service/js/RuntimeGui.js index e54e06e36b..143f739d3f 100644 --- a/src/main/resources/resource/WebGui/app/service/js/RuntimeGui.js +++ b/src/main/resources/resource/WebGui/app/service/js/RuntimeGui.js @@ -132,6 +132,10 @@ angular.module('mrlapp.service.RuntimeGui', []).controller('RuntimeGuiCtrl', ['$ _self.updateState(data) $scope.$apply() break + case 'onPlan': + $scope.plan = data + $scope.$apply() + break case 'onLocalServices': $scope.registry = data // $scope.$apply() @@ -410,6 +414,7 @@ angular.module('mrlapp.service.RuntimeGui', []).controller('RuntimeGuiCtrl', ['$ msg.subscribe("publishStatus") msg.subscribe('publishConfigList') msg.subscribe('publishInterfaceToNames') + // msg.subscribe("getPlan") //msg.send("getLocalServices") msg.send("getStartYml") @@ -419,6 +424,7 @@ angular.module('mrlapp.service.RuntimeGui', []).controller('RuntimeGuiCtrl', ['$ msg.send("getLocales") msg.send("publishInterfaceToNames") msg.send("getConfigName") + // msg.send("getPlan") // msg.send("getHosts") msg.subscribe(this) diff --git a/src/main/resources/resource/framework/pom.xml.template b/src/main/resources/resource/framework/pom.xml.template index ce45f6285a..f0ae2b4183 100644 --- a/src/main/resources/resource/framework/pom.xml.template +++ b/src/main/resources/resource/framework/pom.xml.template @@ -13,6 +13,9 @@ # fast build mvn -DskipTests package -o + # execute + mvn exec:java -Dexec.mainClass=org.myrobotlab.service.Runtime -Dexec.args="-s webgui WebGui intro Intro python Python" + # specific test mvn test -Dtest="org.myrobotlab.service.WebGuiTest#postTest" diff --git a/src/test/java/org/myrobotlab/service/InMoov2Test.java b/src/test/java/org/myrobotlab/service/InMoov2Test.java new file mode 100644 index 0000000000..9be0e28537 --- /dev/null +++ b/src/test/java/org/myrobotlab/service/InMoov2Test.java @@ -0,0 +1,28 @@ +package org.myrobotlab.service; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.myrobotlab.service.config.OpenCVConfig; + +public class InMoov2Test { + + @Test + public void testCvFilters() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + + InMoov2 i01 = (InMoov2)Runtime.start("i01", "InMoov2"); + + // flip + i01.setPeerConfigValue("opencv", "flip", true); + OpenCVConfig cvconfig = (OpenCVConfig)i01.getPeerConfig("opencv"); + assertTrue(cvconfig.flip); + + i01.setPeerConfigValue("opencv", "flip", false); + cvconfig = (OpenCVConfig)i01.getPeerConfig("opencv"); + assertFalse(cvconfig.flip); + + } + + +} +