mirror of
https://github.com/valitydev/openapi-generator.git
synced 2024-11-06 18:45:23 +00:00
Fixed codege issues and complete testing framework implementation
This commit is contained in:
parent
10ffad369c
commit
97e7e0b583
16
bin/generate-java-lib.sh
Executable file
16
bin/generate-java-lib.sh
Executable file
@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
echo "" > classpath.txt
|
||||
for file in `ls lib`;
|
||||
do echo -n 'lib/' >> classpath.txt;
|
||||
echo -n $file >> classpath.txt;
|
||||
echo -n ':' >> classpath.txt;
|
||||
done
|
||||
for file in `ls build`;
|
||||
do echo -n 'build/' >> classpath.txt;
|
||||
echo -n $file >> classpath.txt;
|
||||
echo -n ':' >> classpath.txt;
|
||||
done
|
||||
|
||||
export CLASSPATH=$(cat classpath.txt):conf/java/templates
|
||||
export JAVA_OPTS="${JAVA_OPTS} -DrulePath=data -Dproperty=Xmx2g -DloggerPath=$BUILD_COMMON/test-config/log4j.properties"
|
||||
java $WORDNIK_OPTS $JAVA_CONFIG_OPTIONS $JAVA_OPTS -cp $CLASSPATH com.wordnik.swagger.codegen.config.java.JavaLibCodeGen "$@"
|
0
bin/test-java-lib.sh
Executable file
0
bin/test-java-lib.sh
Executable file
36
build.xml
36
build.xml
@ -31,15 +31,15 @@
|
||||
</taskdef>
|
||||
|
||||
|
||||
<target name="resolve" description="retreive dependencies with ivy">
|
||||
<delete>
|
||||
<fileset dir="lib">
|
||||
<include name="*.jar" />
|
||||
<include name="*.zip" />
|
||||
</fileset>
|
||||
</delete>
|
||||
<ivy:retrieve pattern="${basedir}/lib/[artifact]-[revision].[ext]" conf="build" />
|
||||
</target>
|
||||
<target name="resolve" description="retreive dependencies with ivy">
|
||||
<delete>
|
||||
<fileset dir="lib">
|
||||
<include name="*.jar" />
|
||||
<include name="*.zip" />
|
||||
</fileset>
|
||||
</delete>
|
||||
<ivy:retrieve pattern="${basedir}/lib/[artifact]-[revision].[ext]" conf="build" />
|
||||
</target>
|
||||
|
||||
<target name="compile" description="builds the module without artifact resolution or cleaning">
|
||||
<echo message="building ${module}-${version.identifier}.${artifact.ext}"/>
|
||||
@ -80,7 +80,7 @@
|
||||
</target>
|
||||
|
||||
<!-- generates the classes -->
|
||||
<target name="generate-java" depends="compile" description="generates APIs and model classes for java language">
|
||||
<target name="generate-java" depends="resolve, compile" description="generates APIs and model classes for java language">
|
||||
<fail unless="apiConfiguration.set">
|
||||
Must specify the parameter for apiConfiguration
|
||||
eg. -DapiConfiguration==../api-server-lib/java/config/apiConfiguration.json
|
||||
@ -99,5 +99,21 @@
|
||||
</java>
|
||||
</target>
|
||||
|
||||
<target name="deploy" depends="resolve, compile" description="builds and copies the artifact to the local ivy cache">
|
||||
<echo message="building pom file" />
|
||||
<property name="ivy.pom.version" value="${version.identifier}" />
|
||||
<ivy:makepom ivyfile="ivy.xml" pomfile="build/${module}-${version.identifier}.pom" />
|
||||
|
||||
<echo message="publishing module ${module}" />
|
||||
<ivy:publish resolver="local" organisation="${organization}" conf="source,test,build,pom,common" pubrevision="${version.identifier}" overwrite="true">
|
||||
<artifacts pattern="build/[artifact]-[revision].[ext]" />
|
||||
</ivy:publish>
|
||||
<echo message="project ${module} published locally with version lib/${version.identifier}" />
|
||||
</target>
|
||||
|
||||
<target name="dependency.tree" description="builds a graphml dependency diagram for viewing with yEd">
|
||||
<ivy:report conf="build" graph="true" todir="." outputpattern="[artifact]-[revision].[ext]" />
|
||||
</target>
|
||||
|
||||
</project>
|
||||
|
||||
|
27
conf/java/sample/java_code_gen_conf.json
Normal file
27
conf/java/sample/java_code_gen_conf.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"apiUrl":"http://localhost:8002/api/",
|
||||
|
||||
"apiKey":"special-key",
|
||||
|
||||
"defaultServiceBaseClass":"Object",
|
||||
|
||||
"defaultModelBaseClass":"Object",
|
||||
|
||||
"serviceBaseClasses":{},
|
||||
|
||||
"defaultModelImports":[],
|
||||
|
||||
"defaultServiceImports":[],
|
||||
|
||||
"modelPackageName":"com.wordnik.swagger.sample.sdk.java.model",
|
||||
|
||||
"apiPackageName":"com.wordnik.swagger.sample.sdk.java.api",
|
||||
|
||||
"ignoreMethods":[],
|
||||
|
||||
"ignoreModels":[],
|
||||
|
||||
"outputDirectory":"../swagger-sample-app/sdk-libs/src/main/java/com/wordnik/swagger/sample/sdk/java",
|
||||
|
||||
"libraryHome":"../swagger-sample-app/sdk-libs"
|
||||
}
|
42
conf/java/sample/lib-test-data.json
Normal file
42
conf/java/sample/lib-test-data.json
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
"userList":[
|
||||
{
|
||||
"userName":"testuser1",
|
||||
"password":"password1",
|
||||
"email":"test1@dummy.com"
|
||||
},
|
||||
{
|
||||
"userName":"testuser2",
|
||||
"password":"password2",
|
||||
"email":"test2@dummy.com"
|
||||
}
|
||||
],
|
||||
"petList":[
|
||||
{
|
||||
"id":101,
|
||||
"name":"pet1",
|
||||
"photoUrls":["url1","url2"],
|
||||
"tags":[
|
||||
{
|
||||
"id":1,
|
||||
"name":"tag1"
|
||||
},
|
||||
{
|
||||
"id":2,
|
||||
"name":"tag2"
|
||||
}
|
||||
],
|
||||
"status":"available",
|
||||
"category":{"id":1,"name":"cat1"}
|
||||
}
|
||||
],
|
||||
"orderList":[
|
||||
{
|
||||
"id":101,
|
||||
"petId":1,
|
||||
"quantity":1,
|
||||
"status":"placed",
|
||||
"shipDate":13456789
|
||||
}
|
||||
]
|
||||
}
|
265
conf/java/sample/lib-test-script.json
Normal file
265
conf/java/sample/lib-test-script.json
Normal file
@ -0,0 +1,265 @@
|
||||
{
|
||||
"resources" : [
|
||||
{
|
||||
"id" : 1,
|
||||
"name" : "Find Per by Id",
|
||||
"httpMethod" : "GET",
|
||||
"path" : "/pet.{format}/{petId}",
|
||||
"suggestedMethodName" : "getPetById"
|
||||
},
|
||||
{
|
||||
"id" : 2,
|
||||
"name" : "Find pets by status",
|
||||
"httpMethod" : "GET",
|
||||
"path" : "/pet.{format}/findByStatus",
|
||||
"suggestedMethodName" : "findPetsByStatus"
|
||||
},
|
||||
{
|
||||
"id" : 3,
|
||||
"name" : "Find pets by tags",
|
||||
"httpMethod" : "GET",
|
||||
"path" : "/pet.{format}/findByTags",
|
||||
"suggestedMethodName" : "findPetsByTags"
|
||||
},
|
||||
{
|
||||
"id" : 4,
|
||||
"name" : "Add a pet",
|
||||
"httpMethod" : "POST",
|
||||
"path" : "/pet.{format}",
|
||||
"suggestedMethodName" : "addPet"
|
||||
},
|
||||
{
|
||||
"id" : 5,
|
||||
"name" : "Update a pet",
|
||||
"httpMethod" : "PUT",
|
||||
"path" : "/pet.{format}",
|
||||
"suggestedMethodName" : "updatePet"
|
||||
},
|
||||
{
|
||||
"id" : 6,
|
||||
"name" : "Create user",
|
||||
"httpMethod" : "POST",
|
||||
"path" : "/user.{format}",
|
||||
"suggestedMethodName" : "createUser"
|
||||
},
|
||||
{
|
||||
"id" : 7,
|
||||
"name" : "Update user",
|
||||
"httpMethod" : "PUT",
|
||||
"path" : "/user.{format}/{username}",
|
||||
"suggestedMethodName" : "updateUser"
|
||||
},
|
||||
{
|
||||
"id" : 8,
|
||||
"name" : "Delete user",
|
||||
"httpMethod" : "DELETE",
|
||||
"path" : "/user.{format}/{username}",
|
||||
"suggestedMethodName" : "deleteUser"
|
||||
},
|
||||
{
|
||||
"id" : 9,
|
||||
"name" : "Get user by user name",
|
||||
"httpMethod" : "GET",
|
||||
"path" : "/user.{format}/{username}",
|
||||
"suggestedMethodName" : "getUserByName"
|
||||
},
|
||||
{
|
||||
"id" : 10,
|
||||
"name" : "Login",
|
||||
"httpMethod" : "GET",
|
||||
"path" : "/user.{format}/login",
|
||||
"suggestedMethodName" : "loginUser"
|
||||
},
|
||||
{
|
||||
"id" : 11,
|
||||
"name" : "Logout",
|
||||
"httpMethod" : "GET",
|
||||
"path" : "/user.{format}/logout",
|
||||
"suggestedMethodName" : "logoutUser"
|
||||
},
|
||||
{
|
||||
"id" : 12,
|
||||
"name" : "Find order by id",
|
||||
"httpMethod" : "GET",
|
||||
"path" : "/store.{format}/order/{orderId}",
|
||||
"suggestedMethodName" : "getOrderById"
|
||||
},
|
||||
{
|
||||
"id" : 13,
|
||||
"name" : "Delete order by id",
|
||||
"httpMethod" : "DELETE",
|
||||
"path" : "/store.{format}/order/{orderId}",
|
||||
"suggestedMethodName" : "deleteOrder"
|
||||
},
|
||||
{
|
||||
"id" : 14,
|
||||
"name" : "Create order",
|
||||
"httpMethod" : "POST",
|
||||
"path" : "/store.{format}/order",
|
||||
"suggestedMethodName" : "placeOrder"
|
||||
}
|
||||
],
|
||||
"testSuites" : [
|
||||
{
|
||||
"id" : 1,
|
||||
"name" : "Test User service related APIs",
|
||||
"testCases" : [
|
||||
{
|
||||
"name" : "Create User",
|
||||
"id" : 1,
|
||||
"resourceId" : 6,
|
||||
"input" : {
|
||||
"postData":"${input.userList[0]}"
|
||||
},
|
||||
"assertions" : [
|
||||
{
|
||||
"actualOutput" : "${output(1.1)}",
|
||||
"condition" : "!=",
|
||||
"expectedOutput" : "EXCEPTION"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "Login User",
|
||||
"id" : 2,
|
||||
"resourceId" : 10,
|
||||
"input" : {
|
||||
"username":"${input.userList[0].username}",
|
||||
"password":"${input.userList[0].password}"
|
||||
},
|
||||
"assertions" : [
|
||||
{
|
||||
"actualOutput" : "${output(1.2)}",
|
||||
"condition" : "!=",
|
||||
"expectedOutput" : "EXCEPTION"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "Find user by name",
|
||||
"id" : 3,
|
||||
"resourceId" : 9,
|
||||
"input" : {
|
||||
"username":"${input.userList[0].username}"
|
||||
},
|
||||
"assertions" : [
|
||||
{
|
||||
"actualOutput" : "${output(1.3).username}",
|
||||
"condition" : "!=",
|
||||
"expectedOutput" : "${input.userList[0].username}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "Delete user by name",
|
||||
"id" : 4,
|
||||
"resourceId" : 9,
|
||||
"input" : {
|
||||
"username":"${input.userList[0].username}"
|
||||
},
|
||||
"assertions" : [
|
||||
{
|
||||
"actualOutput" : "${output(1.4)}",
|
||||
"condition" : "!=",
|
||||
"expectedOutput" : "EXCEPTION"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : 2,
|
||||
"name" : "Test Pet service related APIs",
|
||||
"testCases" : [
|
||||
{
|
||||
"name" : "Add pet",
|
||||
"id" : 1,
|
||||
"resourceId" : 4,
|
||||
"input" : {
|
||||
"postData":"${input.petList[0]}"
|
||||
},
|
||||
"assertions" : [
|
||||
{
|
||||
"actualOutput" : "${output(2.1)}",
|
||||
"condition" : "!=",
|
||||
"expectedOutput" : "EXCEPTION"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "Find pet by id",
|
||||
"id" : 2,
|
||||
"resourceId" : 1,
|
||||
"input" : {
|
||||
"petId":"1"
|
||||
},
|
||||
"assertions" : [
|
||||
{
|
||||
"actualOutput" : "${output(2.2)}",
|
||||
"condition" : "!=",
|
||||
"expectedOutput" : "NULL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "Find pet by status",
|
||||
"id" : 3,
|
||||
"resourceId" : 2,
|
||||
"input" : {
|
||||
"status":"available,sold,pending"
|
||||
},
|
||||
"assertions" : [
|
||||
{
|
||||
"actualOutput" : "${output(2.3).size}",
|
||||
"condition" : ">",
|
||||
"expectedOutput" : "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : 3,
|
||||
"name" : "Test Store service related APIs",
|
||||
"testCases" : [
|
||||
{
|
||||
"name" : "Find order by id",
|
||||
"id" : 1,
|
||||
"resourceId" : 12,
|
||||
"input" : {
|
||||
"orderId":"1"
|
||||
},
|
||||
"assertions" : [
|
||||
{
|
||||
"actualOutput" : "${output(3.1)}",
|
||||
"condition" : "!=",
|
||||
"expectedOutput" : "NULL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "PLace order",
|
||||
"id" : 2,
|
||||
"resourceId" : 14,
|
||||
"input" : {
|
||||
"postData":"${input.orderList[0]}"
|
||||
},
|
||||
"assertions" : [
|
||||
{
|
||||
"actualOutput" : "${output(1.2)}",
|
||||
"condition" : "!=",
|
||||
"expectedOutput" : "EXCEPTION"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -136,7 +136,7 @@ public class APIInvoker {
|
||||
* @throws com.wordnik.swagger.exception.APIException if the call to API server fails.
|
||||
*/
|
||||
public static String invokeAPI(String resourceURL, String method, Map<String,
|
||||
String> queryParams, Object postObject) throws APIException {
|
||||
String> queryParams, Object postData) throws APIException {
|
||||
|
||||
|
||||
Client apiClient = Client.create();
|
||||
@ -186,9 +186,9 @@ public class APIInvoker {
|
||||
if(method.equals(GET)) {
|
||||
clientResponse = builder.get(ClientResponse.class);
|
||||
}else if (method.equals(POST)) {
|
||||
clientResponse = builder.post(ClientResponse.class, serialize(postObject));
|
||||
clientResponse = builder.post(ClientResponse.class, serialize(postData));
|
||||
}else if (method.equals(PUT)) {
|
||||
clientResponse = builder.put(ClientResponse.class, serialize(postObject));
|
||||
clientResponse = builder.put(ClientResponse.class, serialize(postData));
|
||||
}else if (method.equals(DELETE)) {
|
||||
clientResponse = builder.delete(ClientResponse.class);
|
||||
}
|
||||
|
@ -16,8 +16,7 @@
|
||||
|
||||
package $packageName$;
|
||||
|
||||
import $annotationPackageName$.AllowableValues;
|
||||
import $annotationPackageName$.Required;
|
||||
import com.wordnik.swagger.runtime.annotations.*;
|
||||
|
||||
$imports:{ import |
|
||||
import $import$;
|
||||
|
@ -17,17 +17,19 @@
|
||||
package $packageName$;
|
||||
|
||||
|
||||
import $annotationPackageName$.MethodArgumentNames;
|
||||
import $exceptionPackageName$.APIExceptionCodes;
|
||||
import $exceptionPackageName$.APIException;
|
||||
//import $annotationPackageName$.MethodArgumentNames;
|
||||
//import $exceptionPackageName$.APIExceptionCodes;
|
||||
//import $exceptionPackageName$.APIException;
|
||||
|
||||
|
||||
import $modelPackageName$.*;
|
||||
|
||||
import org.codehaus.jackson.map.DeserializationConfig.Feature;
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.codehaus.jackson.type.TypeReference;
|
||||
import com.wordnik.swagger.annotations.*;
|
||||
import com.wordnik.swagger.common.*;
|
||||
import com.wordnik.swagger.exception.*;
|
||||
import com.wordnik.swagger.runtime.annotations.*;
|
||||
import com.wordnik.swagger.runtime.common.*;
|
||||
import com.wordnik.swagger.runtime.exception.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
@ -95,7 +97,7 @@ $method.pathParameters:{ argument |
|
||||
$endif$
|
||||
//make the API Call
|
||||
$if(method.postObject)$
|
||||
String response = APIInvoker.invokeAPI(resourcePath, method, queryParams, postObject);
|
||||
String response = APIInvoker.invokeAPI(resourcePath, method, queryParams, postData);
|
||||
$endif$
|
||||
|
||||
$if(!method.postObject)$
|
||||
|
2
ivy.xml
2
ivy.xml
@ -10,7 +10,7 @@
|
||||
|
||||
<publications>
|
||||
<artifact name="swagger-libs-gen" type="jar" conf="build" ext="jar"/>
|
||||
<artifact name="swagger-libs-gen" type="pom" conf="pom" ext="pom"/>
|
||||
<!-- artifact name="swagger-libs-gen" type="pom" conf="pom" ext="pom"/ -->
|
||||
</publications>
|
||||
|
||||
<dependencies>
|
||||
|
@ -20,9 +20,9 @@ import com.wordnik.swagger.codegen.config.*;
|
||||
import com.wordnik.swagger.codegen.config.ApiConfiguration;
|
||||
import com.wordnik.swagger.codegen.config.common.CamelCaseNamingPolicyProvider;
|
||||
import com.wordnik.swagger.codegen.config.java.JavaDataTypeMappingProvider;
|
||||
import com.wordnik.swagger.codegen.exception.CodeGenerationException;
|
||||
import com.wordnik.swagger.codegen.resource.*;
|
||||
import com.wordnik.swagger.codegen.util.FileUtil;
|
||||
import com.wordnik.swagger.exception.CodeGenerationException;
|
||||
import org.antlr.stringtemplate.StringTemplate;
|
||||
import org.antlr.stringtemplate.StringTemplateGroup;
|
||||
import org.codehaus.jackson.map.DeserializationConfig;
|
||||
@ -70,6 +70,28 @@ public class LibraryCodeGenerator {
|
||||
this.setNameGenerator(new CamelCaseNamingPolicyProvider());
|
||||
}
|
||||
|
||||
public LibraryCodeGenerator(String apiServerURL, String apiKey, String modelPackageName, String apiPackageName, String classOutputDir, String libraryHome){
|
||||
|
||||
final ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
ApiConfiguration aApiConfiguration = new ApiConfiguration();
|
||||
aApiConfiguration.setApiKey(apiKey);
|
||||
aApiConfiguration.setApiPackageName(apiPackageName);
|
||||
aApiConfiguration.setModelPackageName(modelPackageName);
|
||||
aApiConfiguration.setApiUrl(apiServerURL);
|
||||
this.setApiConfig(aApiConfiguration);
|
||||
CodeGenRulesProvider codeGenRules = new CodeGenRulesProvider();
|
||||
this.setCodeGenRulesProvider(codeGenRules);
|
||||
LanguageConfiguration aLanguageConfiguration = new LanguageConfiguration();
|
||||
aLanguageConfiguration.setOutputDirectory(classOutputDir);
|
||||
aLanguageConfiguration.setLibraryHome(libraryHome);
|
||||
initializeLangConfig(aLanguageConfiguration);
|
||||
this.setLanguageConfig(aLanguageConfiguration);
|
||||
|
||||
this.setDataTypeMappingProvider(new JavaDataTypeMappingProvider());
|
||||
this.setNameGenerator(new CamelCaseNamingPolicyProvider());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate classes needed for the model and API invocation
|
||||
*/
|
||||
@ -324,6 +346,7 @@ public class LibraryCodeGenerator {
|
||||
|
||||
private void writeFile(File aFile, String content, String classType){
|
||||
try{
|
||||
System.out.println("Writing to the file " + aFile.getAbsolutePath());
|
||||
FileWriter aWriter = new FileWriter(aFile);
|
||||
BufferedWriter bufWriter = new BufferedWriter(aWriter);
|
||||
bufWriter.write(content);
|
||||
|
@ -20,11 +20,11 @@ import com.sun.jersey.api.client.Client;
|
||||
import com.sun.jersey.api.client.ClientResponse;
|
||||
import com.sun.jersey.api.client.WebResource;
|
||||
import com.wordnik.swagger.codegen.config.DataTypeMappingProvider;
|
||||
import com.wordnik.swagger.codegen.exception.CodeGenerationException;
|
||||
import com.wordnik.swagger.codegen.resource.Endpoint;
|
||||
import com.wordnik.swagger.codegen.resource.Resource;
|
||||
import com.wordnik.swagger.codegen.config.ApiConfiguration;
|
||||
import com.wordnik.swagger.codegen.config.NamingPolicyProvider;
|
||||
import com.wordnik.swagger.exception.CodeGenerationException;
|
||||
import org.codehaus.jackson.map.DeserializationConfig;
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
|
||||
|
@ -16,8 +16,9 @@
|
||||
|
||||
package com.wordnik.swagger.codegen.config;
|
||||
|
||||
import com.wordnik.swagger.exception.CodeGenerationException;
|
||||
import com.wordnik.swagger.codegen.exception.CodeGenerationException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -39,13 +40,13 @@ public class ApiConfiguration {
|
||||
* we may need to write custom classes and those classes will not be known to code generation. To import those
|
||||
* classes in service classes we use this property
|
||||
*/
|
||||
private List<String> defaultModelImports;
|
||||
private List<String> defaultModelImports = new ArrayList<String>();
|
||||
/**
|
||||
* Default service imports that we need to include in all service classes. This is needed because some times,
|
||||
* we may need to write custom classes ans those classes will not be known to code generation. To import those
|
||||
* classes in service classes we use this property
|
||||
*/
|
||||
private List<String> defaultServiceImports;
|
||||
private List<String> defaultServiceImports = new ArrayList<String>();
|
||||
private String modelPackageName;
|
||||
private String apiPackageName;
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
package com.wordnik.swagger.codegen.config;
|
||||
|
||||
import com.wordnik.swagger.exception.CodeGenerationException;
|
||||
import com.wordnik.swagger.codegen.exception.CodeGenerationException;
|
||||
|
||||
/**
|
||||
* User: deepakmichael
|
||||
|
@ -16,9 +16,8 @@
|
||||
|
||||
package com.wordnik.swagger.codegen.config.common;
|
||||
|
||||
import com.wordnik.swagger.codegen.resource.Model;
|
||||
import com.wordnik.swagger.codegen.exception.CodeGenerationException;
|
||||
import com.wordnik.swagger.codegen.config.NamingPolicyProvider;
|
||||
import com.wordnik.swagger.exception.CodeGenerationException;
|
||||
|
||||
/**
|
||||
* User: ramesh
|
||||
@ -111,7 +110,7 @@ public class CamelCaseNamingPolicyProvider implements NamingPolicyProvider {
|
||||
/**
|
||||
* For input UserAPI and resource path /findUserById the suggested input object name will be: UserFindUserByIdInput
|
||||
*
|
||||
* If the input path is /{userId}/delete the sugegsted name will be UserDeleteInput. The path parameters are ignored
|
||||
* If the input path is /{userId}/delete the suggested name will be UserDeleteInput. The path parameters are ignored
|
||||
* in generating the input object name
|
||||
*
|
||||
* Note: Input objects are only created when the number of input arguments in a method exceeds certain number so <br/> that the method signatures are clean
|
||||
@ -123,7 +122,7 @@ public class CamelCaseNamingPolicyProvider implements NamingPolicyProvider {
|
||||
*/
|
||||
public String getInputObjectName(String serviceName, String resourcePath) {
|
||||
|
||||
//Since service name has API at the end remove that fromt he name
|
||||
//Since service name has API at the end remove that format he name
|
||||
String inputobjectName = serviceName.substring(0, serviceName.length() - 3);
|
||||
|
||||
String[] pathElements = resourcePath.split("/");
|
||||
|
@ -53,24 +53,29 @@ public class JavaDataTypeMappingProvider implements DataTypeMappingProvider {
|
||||
static{
|
||||
primitiveObjectMap.put("string", "String");
|
||||
primitiveObjectMap.put("String", "String");
|
||||
primitiveObjectMap.put("java.lang.String", "String");
|
||||
primitiveObjectMap.put("int", "Integer");
|
||||
primitiveObjectMap.put("integer", "Integer");
|
||||
primitiveObjectMap.put("Integer", "Integer");
|
||||
primitiveObjectMap.put("java.lang.Integer", "Integer");
|
||||
primitiveObjectMap.put("boolean", "Boolean");
|
||||
primitiveObjectMap.put("Boolean", "Boolean");
|
||||
primitiveObjectMap.put("java.lang.Boolean", "Boolean");
|
||||
primitiveObjectMap.put("long", "Long");
|
||||
primitiveObjectMap.put("Long", "Long");
|
||||
primitiveObjectMap.put("java.lang.Long", "Long");
|
||||
primitiveObjectMap.put("float", "Float");
|
||||
primitiveObjectMap.put("Float", "Float");
|
||||
primitiveObjectMap.put("java.lang.Float", "Float");
|
||||
primitiveObjectMap.put("Date", "Date");
|
||||
primitiveObjectMap.put("date", "Date");
|
||||
primitiveObjectMap.put("java.util.Date", "Date");
|
||||
}
|
||||
|
||||
private NamingPolicyProvider nameGenerator = new CamelCaseNamingPolicyProvider();
|
||||
|
||||
public boolean isPrimitiveType(String type) {
|
||||
if(type.equalsIgnoreCase("String") || type.equalsIgnoreCase("int") || type.equalsIgnoreCase("integer") ||
|
||||
type.equalsIgnoreCase("boolean") || type.equalsIgnoreCase("float")|| type.equalsIgnoreCase("long") ){
|
||||
if(primitiveObjectMap.containsKey(type)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -17,17 +17,12 @@
|
||||
package com.wordnik.swagger.codegen.config.java;
|
||||
|
||||
import com.wordnik.swagger.codegen.LibraryCodeGenerator;
|
||||
import com.wordnik.swagger.codegen.config.ApiConfiguration;
|
||||
import com.wordnik.swagger.codegen.config.CodeGenRulesProvider;
|
||||
import com.wordnik.swagger.codegen.config.LanguageConfiguration;
|
||||
import com.wordnik.swagger.codegen.config.common.CamelCaseNamingPolicyProvider;
|
||||
import com.wordnik.swagger.codegen.exception.CodeGenerationException;
|
||||
import com.wordnik.swagger.codegen.util.FileUtil;
|
||||
import com.wordnik.swagger.exception.CodeGenerationException;
|
||||
import org.codehaus.jackson.map.DeserializationConfig;
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* User: ramesh
|
||||
@ -40,9 +35,30 @@ public class JavaLibCodeGen extends LibraryCodeGenerator {
|
||||
if(args.length < 1){
|
||||
throw new CodeGenerationException("Invalid number of arguments passed: No command line argument was passed to the program for config json");
|
||||
}
|
||||
String configPath = args[0];
|
||||
JavaLibCodeGen codeGenerator = new JavaLibCodeGen(configPath);
|
||||
codeGenerator.generateCode();
|
||||
if(args.length == 1) {
|
||||
String configPath = args[0];
|
||||
JavaLibCodeGen codeGenerator = new JavaLibCodeGen(configPath);
|
||||
codeGenerator.generateCode();
|
||||
}
|
||||
if(args.length == 6) {
|
||||
String apiServerURL = args[0];
|
||||
String apiKey = args[1];
|
||||
String modelPackageName = args[2];
|
||||
String apiPackageName = args[3];
|
||||
String classOutputDir = args[4];
|
||||
String libraryHome = args[5];
|
||||
JavaLibCodeGen codeGenerator = new JavaLibCodeGen(apiServerURL, apiKey, modelPackageName,
|
||||
apiPackageName, classOutputDir, libraryHome);
|
||||
codeGenerator.generateCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public JavaLibCodeGen(String apiServerURL, String apiKey, String modelPackageName, String apiPackageName,
|
||||
String classOutputDir, String libraryHome){
|
||||
super(apiServerURL, apiKey, modelPackageName, apiPackageName, classOutputDir, libraryHome);
|
||||
this.setDataTypeMappingProvider(new JavaDataTypeMappingProvider());
|
||||
this.setNameGenerator(new CamelCaseNamingPolicyProvider());
|
||||
}
|
||||
|
||||
public JavaLibCodeGen(String configPath){
|
||||
@ -62,10 +78,9 @@ public class JavaLibCodeGen extends LibraryCodeGenerator {
|
||||
//create ouput directories
|
||||
FileUtil.createOutputDirectories(javaConfiguration.getModelClassLocation(), javaConfiguration.getClassFileExtension());
|
||||
FileUtil.createOutputDirectories(javaConfiguration.getResourceClassLocation(), javaConfiguration.getClassFileExtension());
|
||||
FileUtil.clearFolder(javaConfiguration.getLibraryHome() + "/src/main/java/com/wordnik/swagger/common");
|
||||
FileUtil.clearFolder(javaConfiguration.getLibraryHome() + "/src/main/java/com/wordnik/swagger/exception");
|
||||
FileUtil.clearFolder(javaConfiguration.getLibraryHome() + "/src/main/java/com/wordnik/swagger/annotations");
|
||||
FileUtil.copyDirectory(new File(javaConfiguration.getStructureLocation()), new File(javaConfiguration.getLibraryHome()));
|
||||
FileUtil.clearFolder(javaConfiguration.getLibraryHome() + "/src/main/java/com/wordnik/swagger/runtime");
|
||||
FileUtil.createOutputDirectories(javaConfiguration.getLibraryHome() + "/src/main/java/com/wordnik/swagger/runtime", "java");
|
||||
FileUtil.copyDirectory(new File("src/main/java/com/wordnik/swagger/runtime"), new File(javaConfiguration.getLibraryHome()+"/src/main/java/com/wordnik/swagger/runtime"));
|
||||
return javaConfiguration;
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.wordnik.swagger.exception;
|
||||
package com.wordnik.swagger.codegen.exception;
|
||||
|
||||
/**
|
||||
* Exception raised while generating code for java driver.
|
@ -35,6 +35,8 @@ public class EndpointOperation {
|
||||
public static String PARAM_TYPE_PATH = "path";
|
||||
public static String PARAM_TYPE_BODY = "body";
|
||||
public static String PARAM_TYPE_HEADER = "header";
|
||||
public static String POST_PARAM_NAME = "postData";
|
||||
|
||||
private static String AUTH_TOKEN_PARAM_NAME = "auth_token";
|
||||
private static String API_KEY_PARAM_NAME = "api_key";
|
||||
private static String FORMAT_PARAM_NAME = "format";
|
||||
@ -238,7 +240,7 @@ public class EndpointOperation {
|
||||
arguments.add(anArgument);
|
||||
}else if (modelField.getParamType().equalsIgnoreCase(PARAM_TYPE_BODY)) {
|
||||
if(modelField.getName() == null) {
|
||||
modelField.setName("postObject");
|
||||
modelField.setName(POST_PARAM_NAME);
|
||||
}
|
||||
anArgument.setName(modelField.getName());
|
||||
anArgument.setDataType(dataTypeMapper.getClassType(modelField.getDataType(), false));
|
||||
@ -263,7 +265,7 @@ public class EndpointOperation {
|
||||
modelforMethodInput.setName(inputobjectName);
|
||||
List<ModelField> fields = new ArrayList<ModelField>();
|
||||
for(MethodArgument argument: method.getArguments()){
|
||||
if(!argument.getName().equals("postObject") && !argument.getName().equals("authToken")){
|
||||
if(!argument.getName().equals(POST_PARAM_NAME) && !argument.getName().equals("authToken")){
|
||||
ModelField aModelField = new ModelField();
|
||||
aModelField.setAllowedValues(argument.getAllowedValues());
|
||||
aModelField.setDescription(argument.getDescription());
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
package com.wordnik.swagger.codegen.util;
|
||||
|
||||
import com.wordnik.swagger.exception.CodeGenerationException;
|
||||
import com.wordnik.swagger.codegen.exception.CodeGenerationException;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
@ -63,9 +63,11 @@ public class FileUtil {
|
||||
public static void clearFolder(String directoryLocation) {
|
||||
File fDir = new File(directoryLocation);
|
||||
File[] files = fDir.listFiles();
|
||||
for(File aFile : files) {
|
||||
aFile.delete();
|
||||
}
|
||||
if(files != null) {
|
||||
for(File aFile : files) {
|
||||
aFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clears the folder of the files with extension
|
||||
@ -76,9 +78,10 @@ public class FileUtil {
|
||||
return (strName.endsWith(strExt));
|
||||
}
|
||||
});
|
||||
|
||||
for (int i = 0; i < fLogs.length; i++) {
|
||||
deleteFile(fLogs[i].getAbsolutePath());
|
||||
if(fLogs != null){
|
||||
for (int i = 0; i < fLogs.length; i++) {
|
||||
deleteFile(fLogs[i].getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,6 +113,7 @@ public class FileUtil {
|
||||
in.close();
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new CodeGenerationException("Copy directory operation failed");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright 2011 Wordnik, Inc.
|
||||
*
|
||||
* Licensed 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 com.wordnik.swagger.runtime.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
|
||||
/**
|
||||
* Annotation used to provide list of possible values
|
||||
* @author ramesh
|
||||
*
|
||||
*/
|
||||
@Target({ElementType.FIELD,ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AllowableValues {
|
||||
|
||||
String value() default "";
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright 2011 Wordnik, Inc.
|
||||
*
|
||||
* Licensed 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 com.wordnik.swagger.runtime.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
|
||||
@Target({ElementType.FIELD,ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MethodArgumentNames {
|
||||
String value() default "";
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright 2011 Wordnik, Inc.
|
||||
*
|
||||
* Licensed 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 com.wordnik.swagger.runtime.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation used to indicate given property or field is required or not
|
||||
* @author ramesh
|
||||
*
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Required {
|
||||
|
||||
}
|
273
src/main/java/com/wordnik/swagger/runtime/common/APIInvoker.java
Normal file
273
src/main/java/com/wordnik/swagger/runtime/common/APIInvoker.java
Normal file
@ -0,0 +1,273 @@
|
||||
/**
|
||||
* Copyright 2011 Wordnik, Inc.
|
||||
*
|
||||
* Licensed 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 com.wordnik.swagger.runtime.common;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.String;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
||||
import com.wordnik.swagger.runtime.exception.APIException;
|
||||
import com.wordnik.swagger.runtime.exception.APIExceptionCodes;
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.codehaus.jackson.map.DeserializationConfig.Feature;
|
||||
import org.codehaus.jackson.map.SerializationConfig;
|
||||
import org.codehaus.jackson.type.TypeReference;
|
||||
|
||||
import com.sun.jersey.api.client.Client;
|
||||
import com.sun.jersey.api.client.ClientResponse;
|
||||
import com.sun.jersey.api.client.WebResource;
|
||||
import com.sun.jersey.api.client.WebResource.Builder;
|
||||
import com.sun.jersey.api.client.filter.LoggingFilter;
|
||||
|
||||
|
||||
/**
|
||||
* Provides method to initialize the api server settings and also handles the logic related to invoking the API server
|
||||
* along with serealizing and deserializing input and output responses.
|
||||
*
|
||||
* This is also a Base class for all API classes
|
||||
*
|
||||
* @author ramesh
|
||||
*
|
||||
*/
|
||||
public class APIInvoker {
|
||||
|
||||
private static String apiServer = "http://api.wordnik.com/v4";
|
||||
private static SecurityHandler securityHandler = null;
|
||||
private static boolean loggingEnabled;
|
||||
private static Logger logger = null;
|
||||
|
||||
protected static String POST = "POST";
|
||||
protected static String GET = "GET";
|
||||
protected static String PUT = "PUT";
|
||||
protected static String DELETE = "DELETE";
|
||||
public static ObjectMapper mapper = new ObjectMapper();
|
||||
static{
|
||||
mapper.getDeserializationConfig().set(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
mapper.getSerializationConfig().set(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
|
||||
mapper.configure(SerializationConfig.Feature.WRITE_NULL_PROPERTIES, false);
|
||||
mapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the API communication with required inputs.
|
||||
* @param securityHandler security handler responsible for populating necessary security invocation while making API server calls
|
||||
* @param apiServer Sets the URL for the API server. It is defaulted to the server
|
||||
* used while building the driver. This value should be provided while testing the APIs against
|
||||
* test servers or if there is any changes in production server URLs.
|
||||
* @param enableLogging This will enable the logging using Jersey logging filter. Refer the following documentation
|
||||
* for more details. {@link com.sun.jersey.api.client.filter.LoggingFilter}. Default output is sent to system.out.
|
||||
* Create a logger ({@link java.util.logging.Logger} class and set using setLogger method.
|
||||
*/
|
||||
public static void initialize(SecurityHandler securityHandler, String apiServer, boolean enableLogging) {
|
||||
setSecurityHandler(securityHandler);
|
||||
if(apiServer != null && apiServer.length() > 0) {
|
||||
if(apiServer.substring(apiServer.length()-1).equals("/")){
|
||||
apiServer = apiServer.substring(0, apiServer.length()-1);
|
||||
}
|
||||
setApiServer(apiServer);
|
||||
}
|
||||
loggingEnabled = enableLogging;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the logger instance used for Jersey logging.
|
||||
* @param aLogger
|
||||
*/
|
||||
public static void setLogger(Logger aLogger) {
|
||||
logger = aLogger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the API key used for server communication.
|
||||
* This value is set using initialize method.
|
||||
* @return
|
||||
*/
|
||||
public static SecurityHandler setSecurityHandler() {
|
||||
return securityHandler;
|
||||
}
|
||||
|
||||
private static void setSecurityHandler(SecurityHandler aSecurityHandler) {
|
||||
securityHandler = aSecurityHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the URL for the API server. It is defaulted to the server used while building the driver.
|
||||
* @return
|
||||
*/
|
||||
private static String getApiServer() {
|
||||
return apiServer;
|
||||
}
|
||||
|
||||
public static void setApiServer(String server) {
|
||||
apiServer = server;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Invokes the API and returns the response as json string.
|
||||
*
|
||||
* This is an internal method called by individual APIs for communication. It sets the required security information
|
||||
* based ons ecuroty handler
|
||||
*
|
||||
* @param resourceURL - URL for the rest resource
|
||||
* @param method - Method we should use for communicating to the back end.
|
||||
* @param postData - if the method is POST, provide the object that should be sent as part of post request.
|
||||
* @return JSON response of the API call.
|
||||
* @throws com.wordnik.swagger.runtime.exception.APIException if the call to API server fails.
|
||||
*/
|
||||
public static String invokeAPI(String resourceURL, String method, Map<String,
|
||||
String> queryParams, Object postData) throws APIException {
|
||||
|
||||
|
||||
Client apiClient = Client.create();
|
||||
|
||||
//check for app server values
|
||||
if(getApiServer() == null || getApiServer().length() == 0) {
|
||||
String[] args = {getApiServer()};
|
||||
throw new APIException(APIExceptionCodes.API_SERVER_NOT_VALID, args);
|
||||
}
|
||||
|
||||
//initialize the logger if needed
|
||||
if(loggingEnabled) {
|
||||
if(logger == null) {
|
||||
apiClient.addFilter(new LoggingFilter());
|
||||
}else{
|
||||
apiClient.addFilter(new LoggingFilter(logger));
|
||||
}
|
||||
}
|
||||
|
||||
//make the communication
|
||||
resourceURL = getApiServer() + resourceURL;
|
||||
if(queryParams.keySet().size() > 0){
|
||||
int i=0;
|
||||
for(String paramName : queryParams.keySet()){
|
||||
String symbol = "&";
|
||||
if(i==0){
|
||||
symbol = "?";
|
||||
}
|
||||
resourceURL = resourceURL + symbol + paramName + "=" + queryParams.get(paramName);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
Map<String, String> headerMap = new HashMap<String, String>();
|
||||
if(securityHandler != null){
|
||||
securityHandler.populateSecurityInfo(resourceURL, headerMap);
|
||||
}
|
||||
WebResource aResource = apiClient.resource(resourceURL);
|
||||
|
||||
|
||||
//set the required HTTP headers
|
||||
Builder builder = aResource.type("application/json");
|
||||
for(String key : headerMap.keySet()){
|
||||
builder.header(key, headerMap.get(key));
|
||||
}
|
||||
|
||||
ClientResponse clientResponse = null;
|
||||
if(method.equals(GET)) {
|
||||
clientResponse = builder.get(ClientResponse.class);
|
||||
}else if (method.equals(POST)) {
|
||||
clientResponse = builder.post(ClientResponse.class, serialize(postData));
|
||||
}else if (method.equals(PUT)) {
|
||||
clientResponse = builder.put(ClientResponse.class, serialize(postData));
|
||||
}else if (method.equals(DELETE)) {
|
||||
clientResponse = builder.delete(ClientResponse.class);
|
||||
}
|
||||
|
||||
//process the response
|
||||
if(clientResponse.getClientResponseStatus() == ClientResponse.Status.OK) {
|
||||
String response = clientResponse.getEntity(String.class);
|
||||
return response;
|
||||
}else{
|
||||
int responseCode = clientResponse.getClientResponseStatus().getStatusCode() ;
|
||||
throw new APIException(responseCode, clientResponse.getEntity(String.class));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* De-serialize the object from String to object of type input class name.
|
||||
* @param response
|
||||
* @param inputClassName
|
||||
* @return
|
||||
*/
|
||||
public static Object deserialize(String response, Class inputClassName) throws APIException {
|
||||
try {
|
||||
System.out.println("response: " + response + " , class name:" + inputClassName);
|
||||
Object responseObject = mapper.readValue(response, inputClassName);
|
||||
return responseObject;
|
||||
} catch (IOException ioe) {
|
||||
String[] args = new String[]{response, inputClassName.toString()};
|
||||
throw new APIException(APIExceptionCodes.ERROR_CONVERTING_JSON_TO_JAVA, args, "Error in coversting response json value to java object : " + ioe.getMessage(), ioe);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* serialize the object from String to input object.
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static String serialize(Object input) throws APIException {
|
||||
try {
|
||||
if(input != null) {
|
||||
return mapper.writeValueAsString(input);
|
||||
}else{
|
||||
return "";
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new APIException(APIExceptionCodes.ERROR_CONVERTING_JAVA_TO_JSON, "Error in coverting input java to json : " + ioe.getMessage(), ioe);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overloaded method for returning the path value
|
||||
* For a string value an empty value is returned if the value is null
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static String toPathValue(String value) {
|
||||
return value == null ? "" : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloaded method for returning a path value
|
||||
* For a list of objects a comma separated string is returned
|
||||
* @param objects
|
||||
* @return
|
||||
*/
|
||||
public static String toPathValue(List objects) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
for(Object o: objects){
|
||||
out.append(o.toString());
|
||||
out.append(",");
|
||||
}
|
||||
if(out.indexOf(",") != -1) {
|
||||
return out.substring(0, out.lastIndexOf(",") );
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
public static boolean isLoggingEnable() {
|
||||
return loggingEnabled;
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright 2011 Wordnik, Inc.
|
||||
*
|
||||
* Licensed 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 com.wordnik.swagger.runtime.common;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* User: ramesh
|
||||
* Date: 8/4/11
|
||||
* Time: 6:39 PM
|
||||
*/
|
||||
public class ApiKeyAuthTokenBasedSecurityHandler implements SecurityHandler {
|
||||
|
||||
private String apiKey = "";
|
||||
private String authToken = "";
|
||||
|
||||
public ApiKeyAuthTokenBasedSecurityHandler(String apiKey, String authToken) {
|
||||
this.apiKey = apiKey;
|
||||
this.authToken = authToken;
|
||||
}
|
||||
|
||||
public String getAuthToken() {
|
||||
return authToken;
|
||||
}
|
||||
|
||||
public void setAuthToken(String authToken) {
|
||||
this.authToken = authToken;
|
||||
}
|
||||
|
||||
public String getApiKey() {
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
public void setApiKey(String apiKey) {
|
||||
this.apiKey = apiKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the security infomration in http headers map and/or reqsource URL.
|
||||
*
|
||||
* Value spopulated in the http headers map will be set as http headers while making the server communication.
|
||||
*
|
||||
* Depending on the usecase requried information can be added to either of them or both.
|
||||
*
|
||||
* @param resourceURL
|
||||
* @param headers
|
||||
*/
|
||||
public void populateSecurityInfo(String resourceURL, Map<String, String> httpHeaders) {
|
||||
resourceURL = resourceURL + "api_key="+apiKey;
|
||||
httpHeaders.put("api_key", apiKey);
|
||||
httpHeaders.put("auth_token", authToken);
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright 2011 Wordnik, Inc.
|
||||
*
|
||||
* Licensed 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 com.wordnik.swagger.runtime.common;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Provide methods that are responsible for handling security aspect while communicating with the backend server.
|
||||
*
|
||||
* Example: For some cases API key may need to be passed in the headers for all server communication and some times
|
||||
* user authentication token may need to be passed along with api key.
|
||||
*
|
||||
* Implementers of this class are responsible for handling storing information related to secutiry and sending it
|
||||
* along with all API calls
|
||||
*
|
||||
* User: ramesh
|
||||
* Date: 4/12/11
|
||||
* Time: 5:46 PM
|
||||
*/
|
||||
public interface SecurityHandler {
|
||||
|
||||
/**
|
||||
* Populate the security infomration in http headers map and/or reqsource URL.
|
||||
*
|
||||
* Value spopulated in the http headers map will be set as http headers while making the server communication.
|
||||
*
|
||||
* Depending on the usecase requried information can be added to either of them or both.
|
||||
*
|
||||
* @param resourceURL
|
||||
* @param headers
|
||||
*/
|
||||
public void populateSecurityInfo(String resourceURL, Map<String, String> httpHeaders);
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright 2011 Wordnik, Inc.
|
||||
*
|
||||
* Licensed 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 com.wordnik.swagger.runtime.exception;
|
||||
|
||||
import com.sun.jersey.api.client.ClientResponse;
|
||||
import org.codehaus.jackson.annotate.JsonAutoDetect;
|
||||
import org.codehaus.jackson.annotate.JsonCreator;
|
||||
import org.codehaus.jackson.annotate.JsonMethod;
|
||||
import org.codehaus.jackson.annotate.JsonProperty;
|
||||
|
||||
/**
|
||||
* Exception that is thrown if there are any issues in invoking Wordnik API.
|
||||
*
|
||||
* Each exception carries a code and message. Code can be either HTTP error response code {@link com.sun.jersey.api.client.ClientResponse.Status}
|
||||
* or The list of possible Wordnik exception code that are listed in the interface {@link APIExceptionCodes}.
|
||||
* User: ramesh
|
||||
* Date: 3/31/11
|
||||
* Time: 9:27 AM
|
||||
*/
|
||||
public class APIException extends Exception {
|
||||
|
||||
private String message;
|
||||
|
||||
private int code;
|
||||
|
||||
private String[] args;
|
||||
|
||||
@JsonCreator
|
||||
public APIException() {
|
||||
}
|
||||
|
||||
public APIException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public APIException(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public APIException(int code, String message, Throwable t) {
|
||||
super(message, t);
|
||||
this.message = message;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public APIException(int code, String[] args, String message, Throwable t) {
|
||||
super(message, t);
|
||||
this.message = message;
|
||||
this.code = code;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public APIException(int code, String message) {
|
||||
super(message);
|
||||
this.message = message;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public APIException(int code, String[] args, String message) {
|
||||
super(message);
|
||||
this.message = message;
|
||||
this.code = code;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public APIException(int code, String[] args) {
|
||||
this.code = code;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright 2011 Wordnik, Inc.
|
||||
*
|
||||
* Licensed 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 com.wordnik.swagger.runtime.exception;
|
||||
|
||||
/**
|
||||
* Lists all the possible exception codes
|
||||
* @author ramesh
|
||||
*
|
||||
*/
|
||||
public interface APIExceptionCodes {
|
||||
|
||||
/**
|
||||
* System exception.
|
||||
*/
|
||||
public static final int SYSTEM_EXCEPTION = 0;
|
||||
|
||||
/**
|
||||
* With Arguments as current key.
|
||||
*/
|
||||
public static final int API_KEY_NOT_VALID = 1000;
|
||||
/**
|
||||
* With arguments as current token value
|
||||
*/
|
||||
public static final int AUTH_TOKEN_NOT_VALID = 1001;
|
||||
/**
|
||||
* With arguments as input JSON and output class anme
|
||||
*/
|
||||
public static final int ERROR_CONVERTING_JSON_TO_JAVA = 1002;
|
||||
/**
|
||||
* With arguments as JAVA class name
|
||||
*/
|
||||
public static final int ERROR_CONVERTING_JAVA_TO_JSON = 1003;
|
||||
|
||||
public static final int ERROR_FROM_WEBSERVICE_CALL = 1004;
|
||||
/**
|
||||
* With arguments as current API server name
|
||||
*/
|
||||
public static final int API_SERVER_NOT_VALID = 1005;
|
||||
|
||||
}
|
@ -0,0 +1,545 @@
|
||||
package com.wordnik.swagger.testframework;
|
||||
|
||||
import com.wordnik.swagger.codegen.config.common.CamelCaseNamingPolicyProvider;
|
||||
import com.wordnik.swagger.runtime.common.APIInvoker;
|
||||
import com.wordnik.swagger.runtime.common.ApiKeyAuthTokenBasedSecurityHandler;
|
||||
import com.wordnik.swagger.runtime.common.SecurityHandler;
|
||||
import com.wordnik.swagger.runtime.exception.APIException;
|
||||
import org.apache.commons.beanutils.MethodUtils;
|
||||
import org.apache.commons.beanutils.PropertyUtils;
|
||||
import org.codehaus.jackson.map.DeserializationConfig.Feature;
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.codehaus.jackson.map.SerializationConfig;
|
||||
import org.codehaus.jackson.map.type.TypeFactory;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Instance of this class is used to run the tests and assert the results based on
|
||||
* JSON based test script.
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: ramesh
|
||||
* Date: 3/30/11
|
||||
* Time: 6:27 PM
|
||||
*/
|
||||
public class APITestRunner {
|
||||
|
||||
private static String INPUT_DATA_EXPRESSION_PREFIX = "${input.";
|
||||
private static String OUTPUT_DATA_EXPRESSION_PREFIX = "${output";
|
||||
public static String POST_PARAM_NAME = "postData";
|
||||
|
||||
private static String CONDITION_EQUAL = "==";
|
||||
private static String CONDITION_NOT_EQUAL = "!=";
|
||||
private static String CONDITION_GREATER = ">";
|
||||
private static String CONDITION_LESSER = "<";
|
||||
private static String CONDITION_GREATER_EQUAL = ">=";
|
||||
private static String CONDITION_LESSER_EQUAL = "<=";
|
||||
|
||||
private TestOutput testCaseOutput = new TestOutput();
|
||||
private TestStatus testStatus = new TestStatus();
|
||||
private Object testData = null;
|
||||
private TestPackage aPackage = null;
|
||||
|
||||
private static String JAVA = "JAVA";
|
||||
private static String SCALA = "SCALA";
|
||||
private static String PYTHON = "PYTHON";
|
||||
private static String RUBY = "RUBY";
|
||||
private static String ANDROID = "ANDROID";
|
||||
private static String OBJECTIVE_C = "OBJECTIVE_C";
|
||||
private static String AS3 = "AS3";
|
||||
private static String NET = "NET";
|
||||
private static String PHP = "PHP";
|
||||
private static String HASKEL = "HASKEL";
|
||||
private static String CLOJURE = "CLOJURE";
|
||||
|
||||
private static ObjectMapper mapper = new ObjectMapper();
|
||||
static{
|
||||
mapper.getDeserializationConfig().set(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
mapper.configure(SerializationConfig.Feature.WRITE_NULL_PROPERTIES, false);
|
||||
mapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
|
||||
}
|
||||
|
||||
private CamelCaseNamingPolicyProvider namingPolicyProvider = new CamelCaseNamingPolicyProvider();
|
||||
|
||||
/**
|
||||
* Follow the following argument pattern
|
||||
*
|
||||
* Arg[0] --> api server URL
|
||||
* Arg[1] --> api key
|
||||
* Arg[2] --> test script file path
|
||||
* Arg[3] --> test data file path
|
||||
* Arg[4] --> test data class name (class to which test data file will be deserialized)
|
||||
* Arg[5] --> package where API classes are available
|
||||
* Arg[6] --> Language to execute test cases
|
||||
* Arg[7] --> Optional test cases id. provide this if you need to execute only one test case
|
||||
*
|
||||
* @param args
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
String apiServer = args[0];
|
||||
String apiKey = args[1];
|
||||
String testScriptLocation = args[2];
|
||||
String testDataLocation = args[3];
|
||||
String testDataClass = args[4];
|
||||
String apiPackageName = args[5];
|
||||
String language = args[6];
|
||||
String suiteId = "0";
|
||||
if(args.length > 7){
|
||||
suiteId = args[7];
|
||||
}
|
||||
|
||||
ApiKeyAuthTokenBasedSecurityHandler securityHandler = new ApiKeyAuthTokenBasedSecurityHandler(apiKey, "");
|
||||
APIInvoker.initialize(securityHandler, apiServer, true);
|
||||
APITestRunner runner = new APITestRunner();
|
||||
runner.initialize(testScriptLocation, testDataLocation, testDataClass);
|
||||
runner.runTests(apiServer, apiPackageName, runner.getTestPackage(), language, new Integer(suiteId), apiPackageName, securityHandler);
|
||||
}
|
||||
|
||||
public void initialize(String testScriptLocation, String testDataLocation, String testDataClass) throws Exception {
|
||||
//load test script
|
||||
File aFile = new File(testScriptLocation);
|
||||
BufferedReader reader = new BufferedReader(new FileReader(aFile));
|
||||
StringBuilder builder = new StringBuilder();
|
||||
while(true){
|
||||
String line = reader.readLine();
|
||||
if(line == null){
|
||||
break;
|
||||
}else{
|
||||
builder.append(line);
|
||||
}
|
||||
}
|
||||
mapper.getDeserializationConfig().set(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
aPackage = (TestPackage) mapper.readValue(builder.toString(), TestPackage.class);
|
||||
|
||||
//load test data
|
||||
aFile = new File(testDataLocation);
|
||||
reader = new BufferedReader(new FileReader(aFile));
|
||||
builder = new StringBuilder();
|
||||
while(true){
|
||||
String line = reader.readLine();
|
||||
if(line == null){
|
||||
break;
|
||||
}else{
|
||||
builder.append(line);
|
||||
}
|
||||
}
|
||||
testData = mapper.readValue(builder.toString(), Class.forName(testDataClass));
|
||||
reader.close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the package that is initialized for testing
|
||||
* @return
|
||||
*/
|
||||
public TestPackage getTestPackage() {
|
||||
return aPackage;
|
||||
}
|
||||
|
||||
/***
|
||||
* Runs individual test cases in all test suites and stored the result in output object
|
||||
* @param testPackage
|
||||
*/
|
||||
private void runTests(String apiServer, String apiPackageName, TestPackage testPackage, String language, int suiteId,
|
||||
String libraryPackageName, ApiKeyAuthTokenBasedSecurityHandler securityHandler) throws Exception {
|
||||
/**
|
||||
* Logic:
|
||||
*
|
||||
* 1. Get each test case
|
||||
*
|
||||
* 2. based on the patch arrive at the method that needs to be executed
|
||||
*
|
||||
* 3. From the method get list of input parameters
|
||||
*
|
||||
* 4. Read input parameters based on input structure
|
||||
*
|
||||
* 5 Execute method by calling system command
|
||||
*
|
||||
* 6. Get the output
|
||||
*
|
||||
* 7. Store output in output object
|
||||
*
|
||||
* 8. execute assertions
|
||||
*
|
||||
* 9. Continue with next test case
|
||||
*/
|
||||
|
||||
Map<Integer, TestResource> resourceMap = new HashMap<Integer, TestResource>();
|
||||
for(TestResource resource: testPackage.getResources()){
|
||||
resourceMap.put(resource.getId(), resource);
|
||||
}
|
||||
|
||||
for(TestSuite suite : testPackage.getTestSuites()) {
|
||||
if(suiteId != 0 && suiteId != suite.getId()){
|
||||
continue;
|
||||
}
|
||||
int testSuiteId = suite.getId();
|
||||
//1
|
||||
for(TestCase testCase : suite.getTestCases()){
|
||||
String testCasePath = testCasePath(testSuiteId , testCase.getId());
|
||||
|
||||
//2
|
||||
TestResource resource = resourceMap.get(testCase.getResourceId());
|
||||
String path = resource.getPath();
|
||||
String className = namingPolicyProvider.getServiceName(path);
|
||||
String methodName = resource.getSuggestedMethodName();
|
||||
|
||||
//3
|
||||
Class apiClass = Class.forName(libraryPackageName +"." + className);
|
||||
Method[] methods = apiClass.getMethods();
|
||||
Method methodToExecute = null;
|
||||
for(Method method : methods){
|
||||
if(method.getName().equals(methodName)){
|
||||
methodToExecute = method;
|
||||
break;
|
||||
}
|
||||
}
|
||||
try {
|
||||
if(methodToExecute != null) {
|
||||
//4
|
||||
Map<String, Object> arguments = getArgumentsForMethodCall(methodToExecute, testCase);
|
||||
|
||||
String authToken = "\"\"";
|
||||
String postData = "\"\"";
|
||||
StringBuilder queryPathParameters = new StringBuilder();
|
||||
for(String argName : arguments.keySet()){
|
||||
Object value = arguments.get(argName);
|
||||
if(argName.equals("authToken")){
|
||||
authToken = value.toString();
|
||||
}else if (argName.equals(POST_PARAM_NAME)){
|
||||
postData = convertObjectToJSONString(value);
|
||||
}else{
|
||||
if(queryPathParameters.toString().length()> 0){
|
||||
queryPathParameters.append("~");
|
||||
}
|
||||
queryPathParameters.append(argName+"="+value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
//get eternal command
|
||||
String[] externalCommand = constructExternalCommand(apiServer, apiPackageName,
|
||||
securityHandler.getApiKey(), authToken,
|
||||
resource.getPath(), resource.getHttpMethod(), resource.getSuggestedMethodName(),
|
||||
queryPathParameters.toString(), postData, language);
|
||||
//print the command
|
||||
System.out.println("Test Case :" + testCasePath);
|
||||
for(String arg : externalCommand){
|
||||
System.out.print(arg + " ");
|
||||
}
|
||||
System.out.println("");
|
||||
//execute and get data
|
||||
String outputString = executeExternalTestCaseAndGetResult(externalCommand);
|
||||
Object output = null;
|
||||
if(outputString != null && outputString.length() > 0) {
|
||||
output = convertJSONStringToObject(outputString, methodToExecute.getReturnType());
|
||||
}
|
||||
//6
|
||||
Class returnType = methodToExecute.getReturnType();
|
||||
if(!returnType.getName().equalsIgnoreCase("void")){
|
||||
//7
|
||||
testCaseOutput.getData().put(testCasePath, output);
|
||||
}
|
||||
//8
|
||||
//log it as passed, if there is any failures in assertions, assertions will update the status
|
||||
//to failed
|
||||
testStatus.logStatus(testCase, testCasePath, true);
|
||||
executeAssertions(testCasePath, testCase);
|
||||
}
|
||||
}catch(Exception e){
|
||||
boolean asserted = false;
|
||||
if(testCase.getAssertions() != null) {
|
||||
for(Assertion assertion : testCase.getAssertions()){
|
||||
if(assertion.getExpectedOutput().equalsIgnoreCase("Exception")){
|
||||
testStatus.logStatus(testCase, testCasePath, true);
|
||||
asserted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!asserted){
|
||||
testStatus.logStatus(testCase, testCasePath, false, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(testStatus.printTestStatus());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Populate necessayr argument values tat needs ot be populated before calling the method
|
||||
* @return
|
||||
*/
|
||||
protected Map<String, Object> getArgumentsForMethodCall(Method methodToExecute, TestCase testCase) throws Exception {
|
||||
|
||||
Map<String, Object> queryPathParameters = new HashMap<String, Object>();
|
||||
if(testCase.getInput() != null) {
|
||||
for(String inputParamName: testCase.getInput().keySet()){
|
||||
Object value = getParamValue(testCase.getInput().get(inputParamName));
|
||||
queryPathParameters.put(inputParamName, value);
|
||||
}
|
||||
}
|
||||
return queryPathParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all assertions in the test case. If there are nay failures test case will be amrked as failed
|
||||
* and logged into test status object.
|
||||
* @param testCase
|
||||
*/
|
||||
private void executeAssertions(String testCasePath, TestCase testCase) {
|
||||
List<Assertion> assertions = testCase.getAssertions();
|
||||
if(assertions != null) {
|
||||
for(Assertion assertion: assertions){
|
||||
try{
|
||||
Object actualOutPut = getParamValue(assertion.getActualOutput());
|
||||
Object expectedValue = getParamValue(assertion.getExpectedOutput());
|
||||
boolean failed = false;
|
||||
if(assertion.getCondition().equals(CONDITION_EQUAL)){
|
||||
if(expectedValue.toString().equalsIgnoreCase("NULL") && actualOutPut == null){
|
||||
failed = false;
|
||||
}else{
|
||||
if(expectedValue.getClass().isAssignableFrom(String.class)){
|
||||
actualOutPut = actualOutPut.toString();
|
||||
}
|
||||
if(!actualOutPut.equals(expectedValue)){
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
}else if(assertion.getCondition().equals(CONDITION_NOT_EQUAL)){
|
||||
if(expectedValue.toString().equalsIgnoreCase("EXCEPTION")){
|
||||
//this means user is not expecting any exception, output can be null, if we have reached
|
||||
// here means there are no exceptions hence we can call the assertion is passed.
|
||||
failed = false;
|
||||
}
|
||||
else if(actualOutPut == null || actualOutPut.equals(expectedValue)){
|
||||
failed = true;
|
||||
}
|
||||
}else{
|
||||
float actual = new Float(actualOutPut.toString());
|
||||
float expected = new Float(expectedValue.toString());
|
||||
if(assertion.getCondition().equals(CONDITION_GREATER)){
|
||||
if(!(actual > expected)){
|
||||
failed = true;
|
||||
}
|
||||
}else if(assertion.getCondition().equals(CONDITION_LESSER)){
|
||||
if(!(actual < expected)){
|
||||
failed = true;
|
||||
}
|
||||
}else if(assertion.getCondition().equals(CONDITION_LESSER_EQUAL)){
|
||||
if(!(actual <= expected)){
|
||||
failed = true;
|
||||
}
|
||||
}else if(assertion.getCondition().equals(CONDITION_GREATER_EQUAL)){
|
||||
if(!(actual >= expected)){
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(failed) {
|
||||
if(actualOutPut == null) {
|
||||
testStatus.logAssertionStatus(testCasePath, false, expectedValue.toString(), null, assertion.getCondition());
|
||||
}else{
|
||||
testStatus.logAssertionStatus(testCasePath, false, expectedValue.toString(), actualOutPut.toString(), assertion.getCondition());
|
||||
}
|
||||
} else{
|
||||
if(actualOutPut == null) {
|
||||
testStatus.logAssertionStatus(testCasePath, true, expectedValue.toString(), "null", assertion.getCondition());
|
||||
}else{
|
||||
testStatus.logAssertionStatus(testCasePath, true, expectedValue.toString(), actualOutPut.toString(), assertion.getCondition());
|
||||
}
|
||||
}
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
testStatus.logAssertionStatus(testCasePath, false, assertion.getExpectedOutput(), assertion.getActualOutput(), assertion.getCondition(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* creates the test case unique path
|
||||
* @param suiteId
|
||||
* @param caseId
|
||||
* @return
|
||||
*/
|
||||
private String testCasePath(int suiteId, int caseId) {
|
||||
return suiteId + "." + caseId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the values based on expression.
|
||||
* The expression can refer the value in input data structure or outputs generated from executing the current or previous
|
||||
* test cases or direct input. The Test script follow the syntax of ${output if it is referring output data,
|
||||
* ${input if it is referring input data.
|
||||
* @param name
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private Object getParamValue(String name) throws Exception {
|
||||
//this means we should use the input form previous steps or data file.
|
||||
if(name.startsWith("$")){
|
||||
//sample:"${input.userList[0].username}"
|
||||
if(name.startsWith(INPUT_DATA_EXPRESSION_PREFIX)){
|
||||
String expression = name.substring(INPUT_DATA_EXPRESSION_PREFIX.length(), name.length()-1);
|
||||
boolean hasSize = false;
|
||||
if(expression.endsWith("size")){
|
||||
expression = expression.substring(0, expression.length()-5);
|
||||
hasSize = true;
|
||||
}
|
||||
Object value = PropertyUtils.getProperty(testData, expression);
|
||||
if(hasSize){
|
||||
return MethodUtils.invokeMethod(value, "size", null);
|
||||
}
|
||||
|
||||
return value;
|
||||
}else if(name.startsWith(OUTPUT_DATA_EXPRESSION_PREFIX)) {
|
||||
//sample: ${output(1.1.1).token}
|
||||
String expression = name.substring(OUTPUT_DATA_EXPRESSION_PREFIX.length(), name.length()-1);
|
||||
expression = "data"+expression;
|
||||
boolean hasSize = false;
|
||||
if(expression.endsWith("size")){
|
||||
expression = expression.substring(0, expression.length()-5);
|
||||
hasSize = true;
|
||||
}
|
||||
Object value = PropertyUtils.getProperty(testCaseOutput, expression);
|
||||
if(hasSize){
|
||||
return MethodUtils.invokeMethod(value, "size", null);
|
||||
}
|
||||
return value;
|
||||
}else{
|
||||
throw new RuntimeException("Input expression for parameter " + name + "is not as per valid syntax ");
|
||||
}
|
||||
}else{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts JSON string to object.
|
||||
*/
|
||||
public static Object convertJSONStringToObject(String inputJSON, Class objectType) throws Exception {
|
||||
boolean isArray = false;
|
||||
boolean isList = false;
|
||||
Class className = objectType;
|
||||
String ObjectTypeName = objectType.getName();
|
||||
|
||||
//identify if the input is a array
|
||||
if(ObjectTypeName.startsWith("[")){
|
||||
isArray = true;
|
||||
className = objectType.getComponentType();
|
||||
}
|
||||
|
||||
//identify if the input is a list
|
||||
if(List.class.isAssignableFrom(objectType)){
|
||||
isList = true;
|
||||
}
|
||||
|
||||
if(isArray || isList){
|
||||
Object responseObject = mapper.readValue(inputJSON, TypeFactory.type(objectType));
|
||||
return responseObject;
|
||||
}else{
|
||||
return APIInvoker.deserialize(inputJSON, className);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts JSON string to object.
|
||||
*/
|
||||
public static String convertObjectToJSONString(Object input) throws Exception {
|
||||
return APIInvoker.serialize(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the test case results from standard out, converts that into java object and stores the value
|
||||
* in test case output data so that the same can be used in subsequent test case execution
|
||||
*
|
||||
* First line fo response should be a status line with possible values as SUCCESS, ERROR
|
||||
*/
|
||||
private String executeExternalTestCaseAndGetResult(String[] command) throws Exception {
|
||||
|
||||
Process p = Runtime.getRuntime().exec(command);
|
||||
|
||||
BufferedReader stdInput = new BufferedReader(new
|
||||
InputStreamReader(p.getInputStream()));
|
||||
StringBuilder output = new StringBuilder();
|
||||
String s = null;
|
||||
boolean isStatusLine = true;
|
||||
String status = "";
|
||||
while ((s = stdInput.readLine()) != null) {
|
||||
System.out.println(s);
|
||||
if(isStatusLine){
|
||||
status = s;
|
||||
if(status.equalsIgnoreCase("SUCCESS")||status.equalsIgnoreCase("OK") ) {
|
||||
isStatusLine = false;
|
||||
}
|
||||
}else{
|
||||
output.append(s);
|
||||
}
|
||||
}
|
||||
if(status.equalsIgnoreCase("SUCCESS")||status.equalsIgnoreCase("OK") ) {
|
||||
return output.toString();
|
||||
}else{
|
||||
APIException exception = (APIException)convertJSONStringToObject(output.toString(),
|
||||
APIException.class);
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the java command line that needs to be executed for runnign a test case
|
||||
*/
|
||||
private String[] constructExternalCommand(String apiServer, String apiPackageName, String apiKey, String authToken,
|
||||
String resource, String httpMethod, String suggestedMethodName, String queryAndPathParams,
|
||||
String postData, String language) {
|
||||
List<String> command = new ArrayList<String>();
|
||||
if(language.equals(JAVA)){
|
||||
command.add("./bin/runjava.sh");
|
||||
command.add("com.wordnik.swagger.testframework.JavaTestCaseExecutor");
|
||||
}else if (language.equals(PYTHON)){
|
||||
command.add("../python/runtest.py ");
|
||||
}else if (language.equals(ANDROID)){
|
||||
command.add("../android/driver-test/bin/runandroid.sh");
|
||||
command.add("com.wordnik.swagger.testframework.JavaTestCaseExecutor");
|
||||
}
|
||||
|
||||
command.addAll(getCommandInputs(apiServer, apiPackageName, apiKey, authToken, resource, httpMethod,
|
||||
suggestedMethodName, queryAndPathParams, postData,
|
||||
language));
|
||||
String[] commandArray = new String[command.size()];
|
||||
command.toArray(commandArray);
|
||||
return commandArray;
|
||||
}
|
||||
|
||||
private List<String> getCommandInputs(String apiServer, String apiPackageName, String apiKey, String authToken, String resource, String httpMethod,
|
||||
String suggestedMethodName, String queryAndPathParams, String postData,
|
||||
String language) {
|
||||
List<String> inputs = new ArrayList<String>();
|
||||
inputs.add(apiServer);
|
||||
inputs.add(apiPackageName);
|
||||
inputs.add(apiKey);
|
||||
inputs.add(authToken);
|
||||
inputs.add(resource);
|
||||
inputs.add(httpMethod);
|
||||
inputs.add(suggestedMethodName);
|
||||
inputs.add(queryAndPathParams);
|
||||
if(postData.equals("\"\"")){
|
||||
inputs.add(postData);
|
||||
}else{
|
||||
inputs.add(postData);
|
||||
}
|
||||
return inputs;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.wordnik.swagger.testframework;
|
||||
|
||||
public class Assertion {
|
||||
|
||||
private String expectedOutput;
|
||||
|
||||
private String actualOutputWithOutputWrapper;
|
||||
|
||||
private String condition;
|
||||
|
||||
private String actualOutput;
|
||||
|
||||
public String getExpectedOutput() {
|
||||
return expectedOutput;
|
||||
}
|
||||
|
||||
public void setExpectedOutput(String expression) {
|
||||
this.expectedOutput = expression;
|
||||
}
|
||||
|
||||
public String getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
public void setCondition(String condition) {
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
public String getActualOutput() {
|
||||
return actualOutput;
|
||||
}
|
||||
|
||||
public void setActualOutput(String value) {
|
||||
this.actualOutput = value;
|
||||
}
|
||||
|
||||
public String getActualOutputWithOutputWrapper() {
|
||||
return actualOutputWithOutputWrapper;
|
||||
}
|
||||
|
||||
public void setActualOutputWithOutputWrapper(String actualOutputWithOutputWrapper) {
|
||||
this.actualOutputWithOutputWrapper = actualOutputWithOutputWrapper;
|
||||
}
|
||||
}
|
@ -0,0 +1,192 @@
|
||||
package com.wordnik.swagger.testframework;
|
||||
|
||||
import com.wordnik.swagger.codegen.config.java.JavaDataTypeMappingProvider;
|
||||
import com.wordnik.swagger.runtime.annotations.MethodArgumentNames;
|
||||
import com.wordnik.swagger.codegen.config.common.CamelCaseNamingPolicyProvider;
|
||||
import com.wordnik.swagger.runtime.common.APIInvoker;
|
||||
import com.wordnik.swagger.runtime.common.ApiKeyAuthTokenBasedSecurityHandler;
|
||||
import com.wordnik.swagger.runtime.exception.APIException;
|
||||
import com.wordnik.swagger.runtime.exception.APIExceptionCodes;
|
||||
import org.apache.commons.beanutils.BeanUtils;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Instance of this class runs single test case
|
||||
* User: ramesh
|
||||
* Date: 4/22/11
|
||||
* Time: 7:32 AM
|
||||
*/
|
||||
public class JavaTestCaseExecutor {
|
||||
|
||||
private CamelCaseNamingPolicyProvider namingPolicyProvider = new CamelCaseNamingPolicyProvider();
|
||||
private JavaDataTypeMappingProvider datatypeMppingProvider = new JavaDataTypeMappingProvider();
|
||||
|
||||
/**
|
||||
* Follow the following argument pattern
|
||||
* Arguments in calling this method:
|
||||
* ApiServerURL
|
||||
*
|
||||
* @param args
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
|
||||
JavaTestCaseExecutor runner = new JavaTestCaseExecutor();
|
||||
String apiServer = args[0];
|
||||
String servicePackageName = args[1];
|
||||
String apiKey = args[2];
|
||||
String authToken = args[3];
|
||||
String resource = args[4];
|
||||
String httpMethod = args[5];
|
||||
String suggestedMethodName = args[6];
|
||||
Map<String, String> queryAndPathParameters = new HashMap<String, String>();
|
||||
String postData = null;
|
||||
if(args.length > 7 && args[7].length() > 0){
|
||||
String[] qpTuple = args[7].split("~");
|
||||
for(String tuple: qpTuple){
|
||||
String[] nameValue = tuple.split("=");
|
||||
queryAndPathParameters.put(nameValue[0], nameValue[1]);
|
||||
}
|
||||
}
|
||||
if(args.length > 8 ){
|
||||
postData = args[8];
|
||||
}
|
||||
queryAndPathParameters.put("authToken", authToken);
|
||||
|
||||
ApiKeyAuthTokenBasedSecurityHandler securityHandler = new ApiKeyAuthTokenBasedSecurityHandler(apiKey, authToken);
|
||||
APIInvoker.initialize(securityHandler, apiServer, true);
|
||||
|
||||
runner.executeTestCase(resource, servicePackageName, suggestedMethodName, queryAndPathParameters, postData);
|
||||
|
||||
}
|
||||
|
||||
private void executeTestCase(String resourceName, String servicePackageName, String suggestedName,
|
||||
Map<String, String> queryAndPathParameters, String postData) {
|
||||
|
||||
String className = namingPolicyProvider.getServiceName(resourceName);
|
||||
String methodName = suggestedName;
|
||||
//3
|
||||
try {
|
||||
Class apiClass = Class.forName(servicePackageName + "." + className);
|
||||
Method[] methods = apiClass.getMethods();
|
||||
Method methodToExecute = null;
|
||||
for(Method method : methods){
|
||||
if(method.getName().equals(methodName)){
|
||||
methodToExecute = method;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(methodToExecute != null) {
|
||||
//4
|
||||
Object[] arguments = populateArgumentsForTestCaseExecution(methodToExecute, queryAndPathParameters,
|
||||
postData, className, resourceName);
|
||||
Object output = null;
|
||||
if(arguments != null && arguments.length > 0){
|
||||
//5
|
||||
output = methodToExecute.invoke(null, arguments);
|
||||
}else{
|
||||
//5
|
||||
output = methodToExecute.invoke(null);
|
||||
}
|
||||
//6
|
||||
System.out.println("SUCCESS");
|
||||
System.out.println(APITestRunner.convertObjectToJSONString(output));
|
||||
|
||||
}
|
||||
}catch(APIException e){
|
||||
StringWriter sWriter = new StringWriter();
|
||||
PrintWriter writer = new PrintWriter(sWriter);
|
||||
e.printStackTrace(writer);
|
||||
System.out.println(sWriter.getBuffer().toString());
|
||||
System.out.println(e.getMessage());
|
||||
System.out.println("ERROR");
|
||||
try{
|
||||
System.out.println(APITestRunner.convertObjectToJSONString(e));
|
||||
}catch(Exception ex){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
} catch(Exception e){
|
||||
StringWriter sWriter = new StringWriter();
|
||||
PrintWriter writer = new PrintWriter(sWriter);
|
||||
e.printStackTrace(writer);
|
||||
System.out.println(sWriter.getBuffer().toString());
|
||||
e.printStackTrace();
|
||||
System.out.println("ERROR");
|
||||
try{
|
||||
APIException apiException = new APIException(APIExceptionCodes.SYSTEM_EXCEPTION,
|
||||
e.getMessage());
|
||||
System.out.println(APITestRunner.convertObjectToJSONString(apiException));
|
||||
}catch(Exception ex){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of input query and path parameters and post data vlues and covenrt them to arguments that
|
||||
* can be used for calling the method. This logic will be different in each driver language depends on how method
|
||||
* input arguments are created.
|
||||
*/
|
||||
private Object[] populateArgumentsForTestCaseExecution(Method methodToExecute, Map<String, String> queryAndPathParameters,
|
||||
String postData, String serviceName, String resourcePath) throws Exception {
|
||||
MethodArgumentNames argNames = methodToExecute.getAnnotation(MethodArgumentNames.class);
|
||||
String[] argNamesArray = null;
|
||||
if(argNames != null && argNames.value().length() > 0) {
|
||||
argNamesArray = argNames.value().split(",");
|
||||
}
|
||||
Class[] argTypesArray = methodToExecute.getParameterTypes();
|
||||
Object output = null;
|
||||
String inputClassName = namingPolicyProvider.getInputObjectName(serviceName, resourcePath);
|
||||
|
||||
if(argNamesArray != null && argNamesArray.length > 0){
|
||||
Object[] arguments = new Object[argNamesArray.length];
|
||||
|
||||
for(int i=0; i < argNamesArray.length; i++){
|
||||
Object argument = null;
|
||||
//if the method takes input model instead of individual arguments, convert individual arguments into input model object
|
||||
if(argTypesArray[i].getName().equalsIgnoreCase(inputClassName)){
|
||||
argument = populateInputModelObject(argTypesArray[i], queryAndPathParameters);
|
||||
}else if(datatypeMppingProvider.isPrimitiveType(argTypesArray[i].getName())){
|
||||
argument = queryAndPathParameters.get(argNamesArray[i].trim());
|
||||
}else if (argNamesArray[i].trim().equals(APITestRunner.POST_PARAM_NAME)){
|
||||
argument = APITestRunner.convertJSONStringToObject(postData, argTypesArray[i]);
|
||||
}else{
|
||||
argument = APITestRunner.convertJSONStringToObject(queryAndPathParameters.get(argNamesArray[i].trim()), argTypesArray[i]);
|
||||
}
|
||||
arguments[i] = argument;
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the swagger input model object.
|
||||
*
|
||||
* Input model is created when number of inputs to a method exceed certain limit.
|
||||
* @param inputDefinitions
|
||||
* @return
|
||||
*/
|
||||
private Object populateInputModelObject(Class swaggerInputClass, Map<String, String> inputDefinitions) throws Exception {
|
||||
Object object = swaggerInputClass.getConstructor().newInstance();
|
||||
Method[] methods = swaggerInputClass.getMethods();
|
||||
for(Method method : methods){
|
||||
if(method.getName().startsWith("get")){
|
||||
String methodName = method.getName();
|
||||
String fieldName = methodName.substring(3);
|
||||
fieldName = namingPolicyProvider.applyMethodNamingPolicy(fieldName);
|
||||
Object value = inputDefinitions.get(fieldName);
|
||||
BeanUtils.setProperty(object, fieldName, value);
|
||||
}
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package com.wordnik.swagger.testframework;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Test case executes individual test case. A given test suite has one or many test cases.
|
||||
* @author ramesh
|
||||
*
|
||||
*/
|
||||
public class TestCase {
|
||||
|
||||
private String name;
|
||||
|
||||
private int id;
|
||||
|
||||
private int resourceId;
|
||||
|
||||
private Map<String, String> input;
|
||||
|
||||
private String referenceInput;
|
||||
|
||||
private List<Assertion> assertions;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getResourceId() {
|
||||
return resourceId;
|
||||
}
|
||||
|
||||
public void setResourceId(int resourceId) {
|
||||
this.resourceId = resourceId;
|
||||
}
|
||||
|
||||
public Map<String, String> getInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
public void setInput(Map<String, String> input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public String getReferenceInput() {
|
||||
return referenceInput;
|
||||
}
|
||||
|
||||
public void setReferenceInput(String referenceInput) {
|
||||
this.referenceInput = referenceInput;
|
||||
}
|
||||
|
||||
public List<Assertion> getAssertions() {
|
||||
return assertions;
|
||||
}
|
||||
|
||||
public void setAssertions(List<Assertion> assertions) {
|
||||
this.assertions = assertions;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.wordnik.swagger.testframework;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class TestOutput {
|
||||
|
||||
Map<String, Object> data = new HashMap<String, Object>();
|
||||
|
||||
public Map<String, Object> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(Map<String, Object> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.wordnik.swagger.testframework;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TestPackage {
|
||||
|
||||
private List<TestResource> resources;
|
||||
|
||||
private List<TestSuite> testSuites;
|
||||
|
||||
|
||||
public List<TestResource> getResources() {
|
||||
return resources;
|
||||
}
|
||||
|
||||
public void setResources(List<TestResource> resources) {
|
||||
this.resources = resources;
|
||||
}
|
||||
|
||||
public List<TestSuite> getTestSuites() {
|
||||
return testSuites;
|
||||
}
|
||||
|
||||
public void setTestSuites(List<TestSuite> testSuites) {
|
||||
this.testSuites = testSuites;
|
||||
}
|
||||
|
||||
public TestCase getTestCaseById(int suiteId, int caseId) {
|
||||
TestSuite aSuite = null;
|
||||
TestCase aTestCase = null;
|
||||
if(this.getTestSuites() != null){
|
||||
for(TestSuite suite : getTestSuites()){
|
||||
if(suite.getId() == suiteId){
|
||||
aSuite = suite;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(aSuite != null){
|
||||
for(TestCase testCase : aSuite.getTestCases()){
|
||||
if(testCase.getId() == caseId){
|
||||
aTestCase = testCase;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return aTestCase;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.wordnik.swagger.testframework;
|
||||
|
||||
public class TestResource {
|
||||
|
||||
private int id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String httpMethod;
|
||||
|
||||
private String path;
|
||||
|
||||
private String suggestedMethodName;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getHttpMethod() {
|
||||
return httpMethod;
|
||||
}
|
||||
|
||||
public void setHttpMethod(String method) {
|
||||
this.httpMethod = method;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getSuggestedMethodName() {
|
||||
return suggestedMethodName;
|
||||
}
|
||||
|
||||
public void setSuggestedMethodName(String suggestedMethodName) {
|
||||
this.suggestedMethodName = suggestedMethodName;
|
||||
}
|
||||
|
||||
}
|
165
src/main/java/com/wordnik/swagger/testframework/TestStatus.java
Normal file
165
src/main/java/com/wordnik/swagger/testframework/TestStatus.java
Normal file
@ -0,0 +1,165 @@
|
||||
package com.wordnik.swagger.testframework;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Stores the status of the tests executed.
|
||||
* @author ramesh
|
||||
*
|
||||
*/
|
||||
public class TestStatus {
|
||||
|
||||
private int totalTestCaseCount;
|
||||
|
||||
private int failedTestCaseCount;
|
||||
|
||||
private List<TestCaseStatus> testCaseStatuses = new ArrayList<TestCaseStatus>();
|
||||
private Map<String, TestCaseStatus> testCaseStatusMap = new HashMap<String, TestCaseStatus>();
|
||||
|
||||
public void logStatus(TestCase testCase, String testCasePath, boolean passed){
|
||||
logStatus(testCase, testCasePath, passed, null, null);
|
||||
}
|
||||
|
||||
public void logStatus(TestCase testCase, String testCasePath, boolean passed, String failureDescription){
|
||||
logStatus(testCase, testCasePath, passed, failureDescription, null);
|
||||
}
|
||||
|
||||
public void logStatus(TestCase testCase, String testCasePath, boolean passed, String failureDescription, Throwable exception){
|
||||
TestCaseStatus status = new TestCaseStatus(testCase, testCasePath, passed, failureDescription, exception);
|
||||
testCaseStatuses.add(status);
|
||||
testCaseStatusMap.put(testCasePath, status);
|
||||
totalTestCaseCount++;
|
||||
if(!passed){
|
||||
failedTestCaseCount++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void logAssertionStatus(String path, boolean passed, String expectedValue, String actualValue, String condition) {
|
||||
logAssertionStatus(path, passed, expectedValue, actualValue, condition, null);
|
||||
}
|
||||
|
||||
public void logAssertionStatus(String path, boolean passed, String expectedValue, String actualValue, String condition, Throwable stack) {
|
||||
TestCaseStatus status = testCaseStatusMap.get(path);
|
||||
if(!passed && status.passed) {
|
||||
status.passed = false;
|
||||
failedTestCaseCount++;
|
||||
}
|
||||
status.addAssertionStatus(passed, expectedValue, actualValue, condition, stack);
|
||||
}
|
||||
|
||||
public String printTestStatus() {
|
||||
StringBuilder output = new StringBuilder();
|
||||
output.append("Summary --> Total Test Cases: " + totalTestCaseCount + " Failed Test Cases: " + failedTestCaseCount);
|
||||
output.append("\nDetails: \n");
|
||||
for(TestCaseStatus status : testCaseStatuses) {
|
||||
output.append(status.getStatusDescription() + "\n");
|
||||
}
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if there are any failured in executing the test cases.
|
||||
* @return
|
||||
*/
|
||||
public boolean hasFailures() {
|
||||
return (failedTestCaseCount > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class Stores the details on individual test cases.
|
||||
* @author ramesh
|
||||
*
|
||||
*/
|
||||
private class TestCaseStatus {
|
||||
|
||||
String testCasePath;
|
||||
|
||||
boolean passed;
|
||||
|
||||
String failureDescription;
|
||||
|
||||
Throwable exceptionStack;
|
||||
|
||||
TestCase testCase;
|
||||
|
||||
List<AssertionStatus> assertionStatuses = new ArrayList<AssertionStatus>();
|
||||
|
||||
public TestCaseStatus(TestCase testCase, String testCasePath, boolean passed, String failureDescription,
|
||||
Throwable exceptionStack) {
|
||||
this.exceptionStack = exceptionStack;
|
||||
this.testCase = testCase;
|
||||
this.passed = passed;
|
||||
this.failureDescription = failureDescription;
|
||||
this.testCasePath = testCasePath;
|
||||
}
|
||||
|
||||
public void addAssertionStatus(boolean passed, String expectedValue, String actualValue, String condition, Throwable stack) {
|
||||
String assertionDesc = expectedValue + " " + condition + " " + actualValue;
|
||||
AssertionStatus status = new AssertionStatus(assertionDesc, passed, stack);
|
||||
assertionStatuses.add(status);
|
||||
if(!passed){
|
||||
this.passed = false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getStatusDescription(){
|
||||
StringBuilder output = new StringBuilder();
|
||||
if(passed){
|
||||
output.append(testCasePath);
|
||||
output.append(" : ");
|
||||
output.append(testCase.getName());
|
||||
output.append(" : ");
|
||||
output.append(" passed ");
|
||||
output.append(" \n ");
|
||||
}else{
|
||||
output.append(testCasePath);
|
||||
output.append(" : ");
|
||||
output.append(testCase.getName());
|
||||
output.append(" : ");
|
||||
output.append(" failed ");
|
||||
output.append(" \n ");
|
||||
if ( failureDescription != null) {
|
||||
output.append(" failure message : ");
|
||||
output.append(failureDescription + "\n");
|
||||
}
|
||||
if(exceptionStack != null){
|
||||
StringWriter out = new StringWriter();
|
||||
PrintWriter writer = new PrintWriter(out);
|
||||
exceptionStack.printStackTrace(writer);
|
||||
output.append(out.toString());
|
||||
}
|
||||
for(AssertionStatus status:assertionStatuses){
|
||||
if(!status.passed) {
|
||||
output.append(status.getAssertionDescription()+"\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
return output.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private class AssertionStatus {
|
||||
|
||||
String assertionDescription;
|
||||
|
||||
boolean passed;
|
||||
|
||||
Throwable exceptionStack;
|
||||
|
||||
public AssertionStatus(String description, boolean passed, Throwable stack){
|
||||
this.assertionDescription = description;
|
||||
this.passed = passed;
|
||||
this.exceptionStack = stack;
|
||||
}
|
||||
|
||||
public String getAssertionDescription() {
|
||||
return assertionDescription + " : " + (passed ? "Passed " : " Failed ") + ((exceptionStack !=null) ? exceptionStack.getMessage() : "" );
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package com.wordnik.swagger.testframework;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Test suite contains collection of test cases.
|
||||
*
|
||||
* As a best practice write one test suite for each resource
|
||||
* @author ramesh
|
||||
*
|
||||
*/
|
||||
public class TestSuite {
|
||||
|
||||
private String name ;
|
||||
|
||||
private int id;
|
||||
|
||||
private List<TestCase> testCases;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public List<TestCase> getTestCases() {
|
||||
return testCases;
|
||||
}
|
||||
|
||||
public void setTestCases(List<TestCase> testCases) {
|
||||
this.testCases = testCases;
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user