You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2020/11/11 07:00:48 UTC

[sling-org-apache-sling-feature-extension-apiregions] branch SLING-9867 updated: Add PATH type, rename methods, change defaults

This is an automated email from the ASF dual-hosted git repository.

cziegeler pushed a commit to branch SLING-9867
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-extension-apiregions.git


The following commit(s) were added to refs/heads/SLING-9867 by this push:
     new 3da6027  Add PATH type, rename methods, change defaults
3da6027 is described below

commit 3da60277202da66da0b89502ca561bafa455cc2d
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Wed Nov 11 07:42:07 2020 +0100

    Add PATH type, rename methods, change defaults
---
 pom.xml                                            |  2 +-
 .../apiregions/ConfigurationApiMergeHandler.java   | 52 ++++++++++++++++++++++
 .../config/FactoryConfigurationDescription.java    | 16 +++++--
 .../apiregions/api/config/PropertyDescription.java |  2 +-
 .../apiregions/api/config/PropertyType.java        |  3 +-
 .../validation/ConfigurationValidationResult.java  | 27 +++++++++--
 .../config/validation/ConfigurationValidator.java  | 38 ++++++++++------
 .../config/validation/FeatureValidationResult.java | 15 +++++--
 .../api/config/validation/FeatureValidator.java    | 12 ++---
 .../validation/PropertyValidationResult.java       | 10 +++++
 .../api/config/validation/PropertyValidator.java   | 28 ++++++++++--
 .../api/config/ConfigurableEntityTest.java         |  2 +-
 .../api/config/ConfigurationApiTest.java           |  2 +-
 .../FactoryConfigurationDescriptionTest.java       |  3 +-
 .../apiregions/api/config/PropertyTest.java        |  2 +-
 .../validation/ConfigurationValidatorTest.java     | 48 ++++++++++++++++++++
 .../config/validation/PropertyValidatorTest.java   | 21 +++++++++
 17 files changed, 240 insertions(+), 43 deletions(-)

diff --git a/pom.xml b/pom.xml
index 2a337b4..0a929c5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -56,7 +56,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.feature</artifactId>
-            <version>1.2.10</version>
+            <version>1.2.13-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/ConfigurationApiMergeHandler.java b/src/main/java/org/apache/sling/feature/extension/apiregions/ConfigurationApiMergeHandler.java
new file mode 100644
index 0000000..7c83c71
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/ConfigurationApiMergeHandler.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.feature.extension.apiregions;
+
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionType;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.builder.HandlerContext;
+import org.apache.sling.feature.builder.MergeHandler;
+import org.apache.sling.feature.extension.apiregions.api.config.ConfigurationApi;
+
+/**
+ * Merge the configuration api extension
+ */
+public class ConfigurationApiMergeHandler implements MergeHandler {
+
+    @Override
+    public boolean canMerge(final Extension extension) {
+        return ConfigurationApi.EXTENSION_NAME.equals(extension.getName());
+    }
+
+    @Override
+    public void merge(final HandlerContext context, 
+        final Feature targetFeature, 
+        final Feature sourceFeature, 
+        final Extension targetExtension, 
+        final Extension sourceExtension) {
+
+        if ( targetExtension == null ) {
+            // no target available yet, just copy source
+            final Extension ext = new Extension(ExtensionType.JSON, ConfigurationApi.EXTENSION_NAME, sourceExtension.getState());
+            ext.setJSON(sourceExtension.getJSON());
+        } else {
+            final ConfigurationApi sourceApi = ConfigurationApi.getConfigurationApi(sourceExtension);
+            final ConfigurationApi targetApi = ConfigurationApi.getConfigurationApi(targetExtension);
+        }
+    }
+}
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/FactoryConfigurationDescription.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/FactoryConfigurationDescription.java
index 4991d2e..6ce6936 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/FactoryConfigurationDescription.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/FactoryConfigurationDescription.java
@@ -35,13 +35,22 @@ public class FactoryConfigurationDescription extends ConfigurableEntity {
 
     private final List<String> internalNames = new ArrayList<>();
 
+    public FactoryConfigurationDescription() {
+        this.setDefaults();
+    }
+
+    void setDefaults() {
+        this.getOperations().add(Operation.CREATE);
+        this.getOperations().add(Operation.UPDATE);
+    }
+    
     /**
      * Clear the object and remove all metadata
      */
     public void clear() {
         super.clear();
-		this.operations.clear();
-		this.internalNames.clear();
+        this.setDefaults();
+        this.internalNames.clear();
     }
 
 	/**
@@ -56,6 +65,7 @@ public class FactoryConfigurationDescription extends ConfigurableEntity {
             JsonValue val;
             val = this.getAttributes().remove(InternalConstants.KEY_OPERATIONS);
             if ( val != null ) {
+                this.getOperations().clear();
                 for(final JsonValue innerVal : val.asJsonArray()) {
                     final String v = getString(innerVal).toUpperCase();
                     this.getOperations().add(Operation.valueOf(v));
@@ -97,7 +107,7 @@ public class FactoryConfigurationDescription extends ConfigurableEntity {
     JsonObjectBuilder createJson() throws IOException {
 		final JsonObjectBuilder objBuilder = super.createJson();
 		
-		if ( !this.getOperations().isEmpty() ) {
+		if ( !this.getOperations().isEmpty() && this.getOperations().size() != 2 ) {
             final JsonArrayBuilder arrayBuilder = Json.createArrayBuilder();
             for(final Operation op : this.getOperations()) {
                 arrayBuilder.add(op.name());
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyDescription.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyDescription.java
index 3ae8a5c..571c9c9 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyDescription.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyDescription.java
@@ -148,7 +148,7 @@ public class PropertyDescription extends DescribableEntity {
     JsonObjectBuilder createJson() throws IOException {
 		final JsonObjectBuilder objectBuilder = super.createJson();
 
-		if ( this.getType() != null ) {
+		if ( this.getType() != null && this.getType() != PropertyType.STRING ) {
 			this.setString(objectBuilder, InternalConstants.KEY_TYPE, this.getType().name());
 	    }
 		if ( this.getCardinality() != 1 ) {
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyType.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyType.java
index fd8e971..899f93a 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyType.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyType.java
@@ -32,6 +32,7 @@ public enum PropertyType {
     BOOLEAN,
     PASSWORD,
     URL,
-    EMAIL;
+    EMAIL,
+    PATH;
  
 }
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidationResult.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidationResult.java
index 4adf24d..8765347 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidationResult.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidationResult.java
@@ -23,19 +23,38 @@ import java.util.Map;
 
 public class ConfigurationValidationResult {
 
-    private final Map<String, PropertyValidationResult> propertyErrors = new HashMap<>();
+    private final Map<String, PropertyValidationResult> propertyResults = new HashMap<>();
 
     private final List<String> globalErrors = new ArrayList<>();
     
+    private final List<String> warnings = new ArrayList<>();
+
     public boolean isValid() {
-        return propertyErrors.isEmpty() && globalErrors.isEmpty();
+        boolean valid = globalErrors.isEmpty();
+        if ( valid ) {
+            for(final PropertyValidationResult r : this.propertyResults.values()) {
+                if ( r.isValid() ) {
+                    valid = false;
+                    break;
+                }
+            }
+        }
+        return valid;
     }
 
     public List<String> getGlobalErrors() {
         return this.globalErrors;
     }
     
-    public Map<String, PropertyValidationResult> getPropertyErrors() {
-        return propertyErrors;
+    public Map<String, PropertyValidationResult> getPropertyResults() {
+        return propertyResults;
+    }
+
+    /**
+     * Return the list of warnings
+     * @return The list of warnings - might be empty
+     */
+    public List<String> getWarnings() {
+        return this.warnings;
     }
 }
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidator.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidator.java
index ab5aa6b..53ea26c 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidator.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidator.java
@@ -30,10 +30,13 @@ import org.apache.sling.feature.extension.apiregions.api.config.PropertyDescript
 import org.osgi.framework.Constants;
 
 /**
- * Validate values
+ * Validator to validate a configuration
  */
 public class ConfigurationValidator {
     
+    /**
+     * List of properties which are always allowed
+     */
     public static final List<String> ALLOWED_PROPERTIES = Arrays.asList(Constants.SERVICE_DESCRIPTION,
         Constants.SERVICE_VENDOR,
         Constants.SERVICE_RANKING);
@@ -43,6 +46,9 @@ public class ConfigurationValidator {
 
     /**
      * Validate a configuration
+     * @param The configuration description 
+     * @param config The OSGi configuration
+     * @return The result
      */
     public ConfigurationValidationResult validate(final ConfigurableEntity desc, final Configuration config) {
         final ConfigurationValidationResult result = new ConfigurationValidationResult();
@@ -56,40 +62,46 @@ public class ConfigurationValidator {
                 } else if ( fDesc.getInternalNames().contains(config.getName())) {
                     result.getGlobalErrors().add("Factory configuration with name " + config.getName() + " not allowed");
                 } else {
-                    validateProperties(desc, config, result.getPropertyErrors());
+                    validateProperties(desc, config, result.getPropertyResults());
                 }
             }
         } else {
             if ( !(desc instanceof ConfigurationDescription) ) {
                 result.getGlobalErrors().add("Configuration cannot be validated against factory configuration description");
             } else {
-                validateProperties(desc, config, result.getPropertyErrors());
+                validateProperties(desc, config, result.getPropertyResults());
             }
         }
 
+        if ( desc.getDeprecated() != null ) {
+            result.getWarnings().add(desc.getDeprecated());
+        }
         return result;
     }
 
     void validateProperties(final ConfigurableEntity desc, 
             final Configuration configuration, 
-            final Map<String, PropertyValidationResult> errors) {
+            final Map<String, PropertyValidationResult> results) {
         final Dictionary<String, Object> properties = configuration.getConfigurationProperties();
         for(final Map.Entry<String, PropertyDescription> propEntry : desc.getPropertyDescriptions().entrySet()) {
             final Object value = properties.get(propEntry.getKey());
             final PropertyValidationResult result = propertyValidator.validate(propEntry.getValue(), value);
-            if ( !result.isValid()) {
-                errors.put(propEntry.getKey(), result);
-            }
+            results.put(propEntry.getKey(), result);
         }
         final Enumeration<String> keyEnum = properties.keys();
         while ( keyEnum.hasMoreElements() ) {
             final String propName = keyEnum.nextElement();
-            if ( !desc.getPropertyDescriptions().containsKey(propName) && !ALLOWED_PROPERTIES.contains(propName)) {
-                errors.computeIfAbsent(propName, key -> new PropertyValidationResult()).getErrors().add("Property is not allowed");
-            } else if ( Constants.SERVICE_RANKING.equals(propName) ) {
-                final Object value = properties.get(propName);
-                if ( !(value instanceof Integer) ) {
-                    errors.computeIfAbsent(propName, key -> new PropertyValidationResult()).getErrors().add("service.ranking must be of type Integer");
+            if ( !desc.getPropertyDescriptions().containsKey(propName) ) {
+                final PropertyValidationResult result = new PropertyValidationResult();
+                results.put(propName, result);
+                if ( Constants.SERVICE_RANKING.equals(propName) ) {
+                    final Object value = properties.get(propName);
+                    if ( !(value instanceof Integer) ) {
+                        result.getErrors().add("service.ranking must be of type Integer");
+                    }    
+                } else if ( !ALLOWED_PROPERTIES.contains(propName) ) {
+                    result.getErrors().add("Property is not allowed");
+
                 }
             }
         }
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/FeatureValidationResult.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/FeatureValidationResult.java
index 81b03c4..257df68 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/FeatureValidationResult.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/FeatureValidationResult.java
@@ -21,13 +21,20 @@ import java.util.Map;
 
 public class FeatureValidationResult {
 
-    private final Map<String, ConfigurationValidationResult> configurationErrors = new HashMap<>();
+    private final Map<String, ConfigurationValidationResult> configurationResults = new HashMap<>();
 
     public boolean isValid() {
-        return configurationErrors.isEmpty();
+        boolean valid = true;
+        for(final ConfigurationValidationResult r : this.configurationResults.values()) {
+            if ( r.isValid() ) {
+                valid = false;
+                break;
+            }
+        }
+        return valid;
     }
 
-    public Map<String, ConfigurationValidationResult> getConfigurationErrors() {
-        return this.configurationErrors;
+    public Map<String, ConfigurationValidationResult> getConfigurationResults() {
+        return this.configurationResults;
     }
 }
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/FeatureValidator.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/FeatureValidator.java
index 229587b..770bc60 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/FeatureValidator.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/FeatureValidator.java
@@ -43,25 +43,21 @@ public class FeatureValidator {
                 final FactoryConfigurationDescription desc = api.getFactoryConfigurationDescriptions().get(config.getFactoryPid());
                 if ( desc != null ) {
                     final ConfigurationValidationResult r = configurationValidator.validate(desc, config);
-                    if ( !r.isValid()) {
-                        result.getConfigurationErrors().put(config.getPid(), r);
-                    }
+                    result.getConfigurationResults().put(config.getPid(), r);
                 } else if ( api.getInternalFactoryConfigurations().contains(config.getFactoryPid())) {
                     final ConfigurationValidationResult cvr = new ConfigurationValidationResult();
                     cvr.getGlobalErrors().add("Factory configuration is not allowed");
-                    result.getConfigurationErrors().put(config.getPid(), cvr);
+                    result.getConfigurationResults().put(config.getPid(), cvr);
                 }
             } else {
                 final ConfigurationDescription desc = api.getConfigurationDescriptions().get(config.getPid());
                 if ( desc != null ) {
                     final ConfigurationValidationResult r = configurationValidator.validate(desc, config);
-                    if ( !r.isValid()) {
-                        result.getConfigurationErrors().put(config.getPid(), r);
-                    }
+                    result.getConfigurationResults().put(config.getPid(), r);
                 } else if ( api.getInternalConfigurations().contains(config.getPid())) {
                     final ConfigurationValidationResult cvr = new ConfigurationValidationResult();
                     cvr.getGlobalErrors().add("Configuration is not allowed");
-                    result.getConfigurationErrors().put(config.getPid(), cvr);
+                    result.getConfigurationResults().put(config.getPid(), cvr);
                 }
             }
         }
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidationResult.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidationResult.java
index a048cc8..b68ef2e 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidationResult.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidationResult.java
@@ -23,6 +23,8 @@ public class PropertyValidationResult {
 
     private final List<String> errors = new ArrayList<>();
 
+    private final List<String> warnings = new ArrayList<>();
+
     /**
      * Is the property value valid?
      * @return {@code true} if the value is valid
@@ -39,4 +41,12 @@ public class PropertyValidationResult {
 	public List<String> getErrors() {
         return errors;
     }
+
+    /**
+     * Return the list of warnings
+     * @return The list of warnings - might be empty
+     */
+    public List<String> getWarnings() {
+        return this.warnings;
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidator.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidator.java
index b609cc2..3bd72d8 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidator.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidator.java
@@ -27,7 +27,7 @@ import org.apache.sling.feature.extension.apiregions.api.config.Option;
 import org.apache.sling.feature.extension.apiregions.api.config.PropertyDescription;
 
 /**
- * Validate values
+ * Validate a configuration property
  */
 public class PropertyValidator {
     
@@ -68,11 +68,21 @@ public class PropertyValidator {
                     validateValue(prop, val, result.getErrors());
                 }
                 validateList(prop, values, result.getErrors());
-			}
+            }
+            
+            if ( prop.getDeprecated() != null ) {
+                result.getWarnings().add(prop.getDeprecated());
+            }
 		}
 		return result;
 	}
 
+    /**
+     * Validate a multi value
+     * @param prop The property description
+     * @param values The values
+     * @param messages The messages to record errors
+     */
     void validateList(final PropertyDescription prop, final List<Object> values, final List<String> messages) {
         if ( prop.getCardinality() > 0 && values.size() > prop.getCardinality() ) {
             messages.add("Array/collection contains too many elements, only " + prop.getCardinality() + " allowed");
@@ -132,7 +142,9 @@ public class PropertyValidator {
 							break;
 				case PASSWORD : validatePassword(prop, value, messages);
 							break;
-				case URL : validateURL(prop, value, messages);
+                case URL : validateURL(prop, value, messages);
+                           break;
+                case PATH : validatePath(prop, value, messages);
 							break;
 				default : messages.add("Unable to validate value - unknown property type : " + prop.getType());
             }
@@ -306,7 +318,15 @@ public class PropertyValidator {
 		}
 	}
 
-	void validateRange(final PropertyDescription prop, final Number value, final List<String> messages) {
+	void validatePath(final PropertyDescription prop, final Object value, final List<String> messages) {
+		final String val = value.toString();
+		// poor man's validation 
+		if ( !val.startsWith("/") ) {
+			messages.add("Not a valid path " + val);
+		}
+	}
+
+    void validateRange(final PropertyDescription prop, final Number value, final List<String> messages) {
 	    if ( prop.getRange() != null ) {
             if ( prop.getRange().getMin() != null ) {
                 if ( value instanceof Float || value instanceof Double ) {
diff --git a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/ConfigurableEntityTest.java b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/ConfigurableEntityTest.java
index caf06d4..896afc0 100644
--- a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/ConfigurableEntityTest.java
+++ b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/ConfigurableEntityTest.java
@@ -68,7 +68,7 @@ public class ConfigurableEntityTest {
         entity.getPropertyDescriptions().put("b", new PropertyDescription());
 
         final Extension ext = new Extension(ExtensionType.JSON, "a", ExtensionState.OPTIONAL);
-        ext.setJSON("{ \"properties\" : { \"a\" : {\"type\":\"STRING\"}, \"b\" : {\"type\":\"STRING\"}}}");
+        ext.setJSON("{ \"properties\" : { \"a\" : {}, \"b\" : {}}}");
 
         assertEquals(ext.getJSONStructure().asJsonObject(), entity.toJSONObject());
     }
diff --git a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/ConfigurationApiTest.java b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/ConfigurationApiTest.java
index 8568c24..f6beac6 100644
--- a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/ConfigurationApiTest.java
+++ b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/ConfigurationApiTest.java
@@ -108,7 +108,7 @@ public class ConfigurationApiTest {
         final Extension ext = new Extension(ExtensionType.JSON, "a", ExtensionState.OPTIONAL);
         ext.setJSON("{ \"a\" : 5, \"configurations\" : { \"pid\": {}}, " +
             "\"factory-configurations\" : { \"factory\" : {}}," +
-            "\"framework-properties\" : { \"prop\" : { \"type\" : \"STRING\"}}," +
+            "\"framework-properties\" : { \"prop\" : {}}," +
             "\"internal-configurations\" : [\"ipid\"],"+
             "\"internal-factory-configurations\" : [\"ifactory\"],"+
             "\"internal-framework-properties\" : [\"iprop\"]}");
diff --git a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/FactoryConfigurationDescriptionTest.java b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/FactoryConfigurationDescriptionTest.java
index fb0f2b6..d396a71 100644
--- a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/FactoryConfigurationDescriptionTest.java
+++ b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/FactoryConfigurationDescriptionTest.java
@@ -46,7 +46,7 @@ public class FactoryConfigurationDescriptionTest {
         assertNull(entity.getTitle());
         assertNull(entity.getDescription());
         assertTrue(entity.getPropertyDescriptions().isEmpty());
-        assertTrue(entity.getOperations().isEmpty());
+        assertEquals(2, entity.getOperations().size());
         assertTrue(entity.getInternalNames().isEmpty());
     }
 
@@ -67,6 +67,7 @@ public class FactoryConfigurationDescriptionTest {
         final FactoryConfigurationDescription entity = new FactoryConfigurationDescription();
         entity.getInternalNames().add("a");
         entity.getInternalNames().add("b");
+        entity.getOperations().clear();
         entity.getOperations().add(Operation.UPDATE);
 
         final Extension ext = new Extension(ExtensionType.JSON, "a", ExtensionState.OPTIONAL);
diff --git a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyTest.java b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyTest.java
index e895023..515d68d 100644
--- a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyTest.java
+++ b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyTest.java
@@ -129,7 +129,7 @@ public class PropertyTest {
         entity.setExcludes(null);
         entity.setIncludes(null);
 
-        ext.setJSON("{ \"type\" : \"STRING\", \"variable\" : \"var\", \"regex\": \".\"}");
+        ext.setJSON("{ \"variable\" : \"var\", \"regex\": \".\"}");
 
         assertEquals(ext.getJSONStructure().asJsonObject(), entity.toJSONObject());
     }
diff --git a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidatorTest.java b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidatorTest.java
new file mode 100644
index 0000000..1a451b2
--- /dev/null
+++ b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidatorTest.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.feature.extension.apiregions.api.config.validation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import org.apache.sling.feature.Configuration;
+import org.apache.sling.feature.extension.apiregions.api.config.ConfigurationDescription;
+import org.apache.sling.feature.extension.apiregions.api.config.FactoryConfigurationDescription;
+import org.junit.Test;
+
+public class ConfigurationValidatorTest {
+
+    private final ConfigurationValidator validator = new ConfigurationValidator();
+
+    @Test public void testWrongDescriptionTypeForConfiguration() {
+        final Configuration cfg = new Configuration("org.apache");
+        final FactoryConfigurationDescription fcd = new FactoryConfigurationDescription();
+
+        final ConfigurationValidationResult result = validator.validate(fcd, cfg);
+        assertFalse(result.isValid());
+        assertEquals(1, result.getGlobalErrors().size());
+    }
+
+    @Test public void testWrongDescriptionTypeForFactoryConfiguration() {
+        final Configuration cfg = new Configuration("org.apache~foo");
+        final ConfigurationDescription fcd = new ConfigurationDescription();
+
+        final ConfigurationValidationResult result = validator.validate(fcd, cfg);
+        assertFalse(result.isValid());
+        assertEquals(1, result.getGlobalErrors().size());
+    }
+}
diff --git a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidatorTest.java b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidatorTest.java
index 4ce08aa..64cbddb 100644
--- a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidatorTest.java
+++ b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidatorTest.java
@@ -245,6 +245,17 @@ public class PropertyValidatorTest {
         assertTrue(messages.isEmpty());
     }
 
+    @Test public void testValidatePath() {
+        final List<String> messages = new ArrayList<>();
+
+        validator.validatePath(null, "/a/b/c", messages);
+        assertTrue(messages.isEmpty());
+
+        validator.validateEmail(null, "hello world", messages);
+        assertEquals(1, messages.size());
+        messages.clear();
+    }
+    
     @Test public void testValidateRange() {
         final List<String> messages = new ArrayList<>();
         final PropertyDescription prop = new PropertyDescription();
@@ -389,4 +400,14 @@ public class PropertyValidatorTest {
         validator.validateList(prop, values, messages);
         assertTrue(messages.isEmpty());
     }
+
+    @Test public void testDeprecation() {
+        final PropertyDescription prop = new PropertyDescription();
+        prop.setDeprecated("This is deprecated");
+
+        final PropertyValidationResult result = validator.validate(prop, "foo");
+        assertTrue(result.isValid());
+        assertEquals(1, result.getWarnings().size());
+        assertEquals("This is deprecated", result.getWarnings().get(0));
+    }
 }