package io.swagger.filter; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; import static org.testng.Assert.fail; import io.swagger.core.filter.SpecFilter; import io.swagger.matchers.SerializationMatchers; import io.swagger.models.Model; import io.swagger.models.ModelImpl; import io.swagger.models.Operation; import io.swagger.models.Path; import io.swagger.models.Swagger; import io.swagger.models.Tag; import io.swagger.models.parameters.Parameter; import io.swagger.util.Json; import io.swagger.util.ResourceUtils; import com.google.common.collect.Sets; import org.testng.annotations.Test; import java.io.IOException; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; public class SpecFilterTest { @Test(description = "it should clone everything") public void cloneEverything() throws IOException { final Swagger swagger = getSwagger("specFiles/petstore.json"); final Swagger filtered = new SpecFilter().filter(swagger, new NoOpOperationsFilter(), null, null, null); assertEquals(Json.pretty(swagger), Json.pretty(filtered)); } @Test(description = "it should clone everything concurrently") public void cloneEverythingConcurrent() throws IOException { final Swagger swagger = getSwagger("specFiles/petstore.json"); ThreadGroup tg = new ThreadGroup("SpecFilterTest" + "|" + System.currentTimeMillis()); final Map<String, Swagger> filteredMap = new ConcurrentHashMap<String, Swagger>(); for (int i = 0; i < 10; i++) { final int id = i; new Thread(tg, "SpecFilterTest"){ public void run(){ try { filteredMap.put("filtered " + id, new SpecFilter().filter(swagger, new NoOpOperationsFilter(), null, null, null)); } catch (Exception e) { e.printStackTrace(); } } }.start(); } new Thread(new FailureHandler(tg, filteredMap, swagger)).start(); } class FailureHandler implements Runnable { ThreadGroup tg; Map<String, Swagger> filteredMap; private Swagger swagger; public FailureHandler(ThreadGroup tg, Map<String, Swagger> filteredMap, Swagger swagger) { this.tg = tg; this.filteredMap = filteredMap; this.swagger = swagger; } @Override public void run() { try { Thread[] thds = new Thread[tg.activeCount()]; tg.enumerate(thds); for (Thread t : thds) { if (t != null) { t.join(10000); } } } catch (Exception e) { e.printStackTrace(); } for (Swagger filtered: filteredMap.values()) { assertEquals(Json.pretty(swagger), Json.pretty(filtered)); } } } @Test(description = "it should clone everything from JSON without models") public void cloneWithoutModels() throws IOException { final String json = ResourceUtils.loadClassResource(getClass(), "specFiles/noModels.json"); final Swagger swagger = Json.mapper().readValue(json, Swagger.class); final Swagger filtered = new SpecFilter().filter(swagger, new NoOpOperationsFilter(), null, null, null); SerializationMatchers.assertEqualsToJson(filtered, json); } @Test(description = "it should filter away get operations in a resource") public void filterAwayGetOperations() throws IOException { final Swagger swagger = getSwagger("specFiles/petstore.json"); final NoGetOperationsFilter filter = new NoGetOperationsFilter(); final Swagger filtered = new SpecFilter().filter(swagger, filter, null, null, null); if (filtered.getPaths() != null) { for (Map.Entry<String, Path> entry : filtered.getPaths().entrySet()) { assertNull(entry.getValue().getGet()); } } else { fail("paths should not be null"); } } @Test(description = "it should filter away the store resource") public void filterAwayStoreResource() throws IOException { final Swagger swagger = getSwagger("specFiles/petstore.json"); final NoUserOperationsFilter filter = new NoUserOperationsFilter(); final Swagger filtered = new SpecFilter().filter(swagger, filter, null, null, null); if (filtered.getPaths() != null) { for (Map.Entry<String, Path> entry : filtered.getPaths().entrySet()) { assertNotEquals(entry.getKey(), "/user"); } } else { fail("paths should not be null"); } } @Test(description = "it should filter away secret parameters") public void filterAwaySecretParameters() throws IOException { final Swagger swagger = getSwagger("specFiles/sampleSpec.json"); final RemoveInternalParamsFilter filter = new RemoveInternalParamsFilter(); final Swagger filtered = new SpecFilter().filter(swagger, filter, null, null, null); if (filtered.getPaths() != null) { for (Map.Entry<String, Path> entry : filtered.getPaths().entrySet()) { final Operation get = entry.getValue().getGet(); for (Parameter param : get.getParameters()) { final String description = param.getDescription(); assertNotNull(description); assertFalse(description.startsWith("secret")); } } } else { fail("paths should not be null"); } } @Test(description = "it should filter away internal model properties") public void filterAwayInternalModelProperties() throws IOException { final Swagger swagger = getSwagger("specFiles/sampleSpec.json"); final InternalModelPropertiesRemoverFilter filter = new InternalModelPropertiesRemoverFilter(); final Swagger filtered = new SpecFilter().filter(swagger, filter, null, null, null); for (Map.Entry<String, Model> entry : filtered.getDefinitions().entrySet()) { for (String propName : entry.getValue().getProperties().keySet()) { assertFalse(propName.startsWith("_")); } } } @Test(description = "it should filter away broken reference model properties") public void filterAwayBrokenReferenceModelProperties() throws IOException { final Swagger swagger = getSwagger("specFiles/paramAndResponseRef.json"); assertNotNull(swagger.getDefinitions().get("Order")); assertNotNull(swagger.getDefinitions().get("NoPropertiesModel")); assertNotNull(swagger.getDefinitions().get("OrderTag")); assertNotNull(swagger.getDefinitions().get("Tag")); final NoOpOperationsFilter noOpfilter = new NoOpOperationsFilter(); Swagger filtered = new SpecFilter().filter(swagger, noOpfilter, null, null, null); assertNotNull(filtered.getDefinitions().get("Order")); assertNotNull(filtered.getDefinitions().get("NoPropertiesModel")); assertNotNull(filtered.getDefinitions().get("OrderTag")); assertNotNull(filtered.getDefinitions().get("Tag")); final RemoveUnreferencedDefinitionsFilter refFilter = new RemoveUnreferencedDefinitionsFilter(); filtered = new SpecFilter().filter(swagger, refFilter, null, null, null); assertNull(filtered.getDefinitions().get("Order")); assertNull(filtered.getDefinitions().get("NoPropertiesModel")); assertNull(filtered.getDefinitions().get("OrderTag")); assertNotNull(filtered.getDefinitions().get("Tag")); } @Test(description = "it should retain non-broken reference model properties") public void retainNonBrokenReferenceModelProperties() throws IOException { final Swagger swagger = getSwagger("specFiles/paramAndResponseRefArray.json"); assertNotNull(swagger.getDefinitions().get("User")); final NoOpOperationsFilter noOpfilter = new NoOpOperationsFilter(); Swagger filtered = new SpecFilter().filter(swagger, noOpfilter, null, null, null); assertNotNull(filtered.getDefinitions().get("User")); final RemoveUnreferencedDefinitionsFilter refFilter = new RemoveUnreferencedDefinitionsFilter(); filtered = new SpecFilter().filter(swagger, refFilter, null, null, null); assertNotNull(filtered.getDefinitions().get("User")); // ArrayProperty assertNotNull(filtered.getDefinitions().get("Pet")); // ArrayModel } @Test(description = "it should retain non-broken reference model composed properties") public void retainNonBrokenReferenceModelComposedProperties() throws IOException { final Swagger swagger = getSwagger("specFiles/paramAndResponseRefComposed.json"); assertNotNull(swagger.getDefinitions().get("User")); final NoOpOperationsFilter noOpfilter = new NoOpOperationsFilter(); Swagger filtered = new SpecFilter().filter(swagger, noOpfilter, null, null, null); assertNotNull(filtered.getDefinitions().get("User")); final RemoveUnreferencedDefinitionsFilter refFilter = new RemoveUnreferencedDefinitionsFilter(); filtered = new SpecFilter().filter(swagger, refFilter, null, null, null); assertNotNull(filtered.getDefinitions().get("User")); assertNotNull(filtered.getDefinitions().get("Pet")); } @Test(description = "recursive models, e.g. A-> A or A-> B and B -> A should not result in stack overflow") public void removeUnreferencedDefinitionsOfRecuriveModels() throws IOException { final Swagger swagger = getSwagger("specFiles/recursivemodels.json"); final RemoveUnreferencedDefinitionsFilter remover = new RemoveUnreferencedDefinitionsFilter(); final Swagger filtered = new SpecFilter().filter(swagger, remover, null, null, null); assertNotNull(filtered.getDefinitions().get("SelfReferencingModel")); assertNotNull(filtered.getDefinitions().get("IndirectRecursiveModelA")); assertNotNull(filtered.getDefinitions().get("IndirectRecursiveModelB")); } @Test(description = "broken references should not result in NPE") public void removeUnreferencedModelOverride() throws IOException { final Swagger swagger = getSwagger("specFiles/brokenrefmodel.json"); final RemoveUnreferencedDefinitionsFilter remover = new RemoveUnreferencedDefinitionsFilter(); final Swagger filtered = new SpecFilter().filter(swagger, remover, null, null, null); assertNotNull(filtered.getDefinitions().get("RootModel")); } @Test(description = "Retain models referenced from additonalProperties") public void retainModelsReferencesFromAdditionalProperties() throws IOException { final Swagger swagger = getSwagger("specFiles/additionalpropsmodel.json"); final RemoveUnreferencedDefinitionsFilter remover = new RemoveUnreferencedDefinitionsFilter(); final Swagger filtered = new SpecFilter().filter(swagger, remover, null, null, null); assertNotNull(filtered.getDefinitions().get("A")); assertNotNull(filtered.getDefinitions().get("B")); } @Test(description = "Clone should retain any 'deperecated' flags present on operations") public void cloneRetainDeperecatedFlags() throws IOException { final Swagger swagger = getSwagger("specFiles/deprecatedoperationmodel.json"); final RemoveUnreferencedDefinitionsFilter remover = new RemoveUnreferencedDefinitionsFilter(); final Swagger filtered = new SpecFilter().filter(swagger, remover, null, null, null); Operation operation = filtered.getPath("/test").getOperations().get(0); Boolean deprectedFlag = operation.isDeprecated(); assertNotNull(deprectedFlag); assertEquals(deprectedFlag, Boolean.TRUE); } @Test(description = "it should filter models where some fields have no properties") public void filterNoPropertiesModels() throws IOException { final String modelName = "Array"; final ModelImpl model = new ModelImpl().type(ModelImpl.OBJECT).name(modelName); final Swagger swagger = new Swagger(); swagger.addDefinition(modelName, model); final Map<String, Model> filtered = new SpecFilter().filterDefinitions(new NoOpOperationsFilter(), swagger.getDefinitions(), null, null, null); if (filtered.size() != 1) { fail("ModelImpl with no properties failed to filter"); } } @Test(description = "it should contain all tags in the top level Swagger object") public void shouldContainAllTopLevelTags() throws IOException { final Swagger swagger = getSwagger("specFiles/petstore.json"); final NoOpOperationsFilter filter = new NoOpOperationsFilter(); final Swagger filtered = new SpecFilter().filter(swagger, filter, null, null, null); assertEquals(getTagNames(filtered), Sets.newHashSet("pet", "user", "store")); } @Test(description = "it should not contain user tags in the top level Swagger object") public void shouldNotContainTopLevelUserTags() throws IOException { final Swagger swagger = getSwagger("specFiles/petstore.json"); final NoUserOperationsFilter filter = new NoUserOperationsFilter(); final Swagger filtered = new SpecFilter().filter(swagger, filter, null, null, null); assertEquals(getTagNames(filtered), Sets.newHashSet("pet", "store")); } @Test(description = "it should filter with null definitions") public void filterWithNullDefinitions() throws IOException { final Swagger swagger = getSwagger("specFiles/petstore.json"); swagger.setDefinitions(null); final InternalModelPropertiesRemoverFilter filter = new InternalModelPropertiesRemoverFilter(); final Swagger filtered = new SpecFilter().filter(swagger, filter, null, null, null); assertNotNull(filtered); } private Set getTagNames(Swagger swagger) { Set<String> result = new HashSet<String>(); for (Tag item : swagger.getTags()) { result.add(item.getName()); } return result; } private Swagger getSwagger(String path) throws IOException { final String json = ResourceUtils.loadClassResource(getClass(), path); return Json.mapper().readValue(json, Swagger.class); } }