service test complete
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java
index 1d1dab6..ad84fd0 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java
@@ -19,7 +19,6 @@
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.dubbo.admin.model.domain.MethodMetadata;
-import org.apache.dubbo.admin.model.dto.MethodDTO;
 import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
 import org.apache.dubbo.metadata.definition.model.MethodDefinition;
 import org.apache.dubbo.metadata.definition.model.ServiceDefinition;
@@ -34,10 +33,16 @@
     private static Pattern COLLECTION_PATTERN = Pattern.compile("^java\\.util\\..*(Set|List|Queue|Collection|Deque)(<.*>)*$");
     private static Pattern MAP_PATTERN = Pattern.compile("^java\\.util\\..*Map.*(<.*>)*$");
 
-    public static boolean sameMethod(MethodDefinition m, MethodDTO methodDTO) {
-        return (m.getName().equals(methodDTO.getName())
-                && m.getReturnType().equals(methodDTO.getReturnType())
-                && m.getParameterTypes().equals(methodDTO.getParameterTypes().toArray()));
+    public static boolean sameMethod(MethodDefinition m, String methodSig) {
+        String name = m.getName();
+        String[] parameters = m.getParameterTypes();
+        StringBuilder sb = new StringBuilder();
+        sb.append(name).append("~");
+        for (String parameter : parameters) {
+            sb.append(parameter).append(";");
+        }
+        String sig = StringUtils.removeEnd(sb.toString(), ";");
+        return sig.equals(methodSig);
     }
 
     public static MethodMetadata generateMethodMeta(FullServiceDefinition serviceDefinition, MethodDefinition methodDefinition) {
@@ -85,7 +90,7 @@
     private static void generateComplexType(ServiceDefinition sd, TypeDefinition td, Map holder) {
         for (Map.Entry<String, TypeDefinition> entry : td.getProperties().entrySet()) {
             if (isPrimitiveType(td)) {
-                holder.put(entry.getKey(), td.getType());
+                holder.put(entry.getKey(), generatePrimitiveType(td));
             } else {
                 generateEnclosedType(holder, entry.getKey(), sd, entry.getValue());
             }
@@ -201,7 +206,7 @@
     }
 
     private static void generateEnclosedType(Map<String, Object> holder, String key, ServiceDefinition sd, TypeDefinition td) {
-        if (td.getProperties() == null || td.getProperties().size() == 0) {
+        if (td.getProperties() == null || td.getProperties().size() == 0 || isPrimitiveType(td)) {
             holder.put(key, generateType(sd, td));
         } else {
             Map<String, Object> enclosedMap = new HashMap<>();
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
index 2944d64..9233f2a 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
@@ -128,6 +128,8 @@
         }
         serviceDetailDTO.setConsumers(consumers);
         serviceDetailDTO.setProviders(providers);
+        serviceDetailDTO.setService(service);
+        serviceDetailDTO.setApplication(application);
         return serviceDetailDTO;
     }
 }
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceTestController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceTestController.java
index 6b7207c..bf0497b 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceTestController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceTestController.java
@@ -4,23 +4,18 @@
 import org.apache.dubbo.admin.common.util.ConvertUtil;
 import org.apache.dubbo.admin.common.util.ServiceTestUtil;
 import org.apache.dubbo.admin.model.domain.MethodMetadata;
-import org.apache.dubbo.admin.model.dto.MethodDTO;
 import org.apache.dubbo.admin.model.dto.ServiceTestDTO;
 import org.apache.dubbo.admin.service.ProviderService;
 import org.apache.dubbo.admin.service.impl.GenericServiceImpl;
 import org.apache.dubbo.common.Constants;
 import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
 import org.apache.dubbo.metadata.definition.model.MethodDefinition;
-import org.apache.dubbo.metadata.definition.model.TypeDefinition;
 import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
 
 @RestController
 @RequestMapping("/api/{env}/test")
@@ -34,14 +29,13 @@
 
     @RequestMapping(method = RequestMethod.POST)
     public Object test(@PathVariable String env, @RequestBody ServiceTestDTO serviceTestDTO) {
-        return genericService.invoke(serviceTestDTO.getService(), serviceTestDTO.getMethod(), serviceTestDTO.getTypes(), serviceTestDTO.getParams());
+        return genericService.invoke(serviceTestDTO.getService(), serviceTestDTO.getMethod(), serviceTestDTO.getParamaterTypes(), serviceTestDTO.getParams());
 //        return null;
     }
 
     @RequestMapping(value = "/method", method = RequestMethod.GET)
-    public MethodMetadata methodDetail(@PathVariable String env, @RequestBody MethodDTO methodDTO) {
-        String service = methodDTO.getService();
-        String application = methodDTO.getApplication();
+    public MethodMetadata methodDetail(@PathVariable String env, @RequestParam String application, @RequestParam String service,
+                                       @RequestParam String method) {
         Map<String, String> info = ConvertUtil.serviceName2Map(service);
         MetadataIdentifier identifier = new MetadataIdentifier(info.get(Constants.INTERFACE_KEY),
                 info.get(Constants.VERSION_KEY),
@@ -54,7 +48,7 @@
             List<MethodDefinition> methods = serviceDefinition.getMethods();
             if (methods != null) {
                 for (MethodDefinition m : methods) {
-                    if (ServiceTestUtil.sameMethod(m, methodDTO)) {
+                    if (ServiceTestUtil.sameMethod(m, method)) {
                         methodMetadata = ServiceTestUtil.generateMethodMeta(serviceDefinition, m);
                         break;
                     }
@@ -63,10 +57,4 @@
         }
         return methodMetadata;
     }
-
-    public static void main(String[] args) {
-        String[] types = new String[]{"java.lang.String", "java.lang.Map", "com.taobao.alibaba.Demo"};
-        String signature = Arrays.stream(types).collect(Collectors.joining(";"));
-        System.out.println(signature);
-    }
 }
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDetailDTO.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDetailDTO.java
index 2a738f5..1ef4beb 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDetailDTO.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDetailDTO.java
@@ -27,9 +27,26 @@
 
     List<Provider> providers;
     List<Consumer> consumers;
+    private String service;
+    private String application;
 
     FullServiceDefinition metadata;
 
+    public String getService() {
+        return service;
+    }
+
+    public void setService(String service) {
+        this.service = service;
+    }
+
+    public String getApplication() {
+        return application;
+    }
+
+    public void setApplication(String application) {
+        this.application = application;
+    }
 
     public List<Provider> getProviders() {
         return providers;
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceTestDTO.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceTestDTO.java
index 3979e78..7a398f7 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceTestDTO.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceTestDTO.java
@@ -3,7 +3,7 @@
 public class ServiceTestDTO {
     private String service;
     private String method;
-    private String[] types;
+    private String[] paramaterTypes;
     private Object[] params;
 
     public String getService() {
@@ -22,12 +22,12 @@
         this.method = method;
     }
 
-    public String[] getTypes() {
-        return types;
+    public String[] getParamaterTypes() {
+        return paramaterTypes;
     }
 
-    public void setTypes(String[] types) {
-        this.types = types;
+    public void setParamaterTypes(String[] paramaterTypes) {
+        this.paramaterTypes = paramaterTypes;
     }
 
     public Object[] getParams() {
diff --git a/dubbo-admin-frontend/src/components/test/ServiceTest.vue b/dubbo-admin-frontend/src/components/test/ServiceTest.vue
index 5289a4c..a9568ad 100644
--- a/dubbo-admin-frontend/src/components/test/ServiceTest.vue
+++ b/dubbo-admin-frontend/src/components/test/ServiceTest.vue
@@ -31,11 +31,12 @@
             <td><v-chip label>{{ props.item.returnType }}</v-chip></td>
             <td class="text-xs-right">
               <v-tooltip bottom>
-                <v-icon small
-                        class="mr-2"
-                        color="blue"
-                        slot="activator"
-                        @click="toTest(props.item)">input</v-icon>
+                <v-btn
+                  fab dark small color="blue" slot="activator"
+                  :href="getHref(props.item.application, props.item.service, props.item.signature)"
+                >
+                  <v-icon>edit</v-icon>
+                </v-btn>
                 <span>Try it</span>
               </v-tooltip>
             </td>
@@ -109,7 +110,7 @@
         modal: {
           method: null,
           enable: false,
-          types: null,
+          paramaterTypes: null,
           json: []
         }
       }
@@ -129,7 +130,26 @@
         this.$axios.get('/service/' + this.filter).then(response => {
           this.service = response.data
           if (this.service.hasOwnProperty('metadata')) {
-            this.methods = this.service.metadata.methods
+            let data = this.service.metadata.methods
+            for (let i = 0; i < data.length; i++) {
+              let method = {}
+              let sig = data[i].name + '~'
+              let parameters = data[i].parameterTypes
+              let length = parameters.length
+              for (let j = 0; j < length; j++) {
+                sig = sig + parameters[j]
+                if (j !== length - 1) {
+                  sig = sig + ';'
+                }
+              }
+              method.signature = sig
+              method.name = data[i].name
+              method.parameterTypes = data[i].parameterTypes
+              method.returnType = data[i].returnType
+              method.service = response.data.service
+              method.application = response.data.application
+              this.methods.push(method)
+            }
           }
         }).catch(error => {
           this.showSnackbar('error', error.response.data.message)
@@ -141,16 +161,21 @@
           method: item.name
         })
         this.modal.json = []
-        this.modal.types = item.parameterTypes
+        this.modal.paramaterTypes = item.parameterTypes
         item.parameterTypes.forEach((i, index) => {
           this.modal.json.push(this.getType(i))
         })
       },
+      getHref (application, service, method) {
+        let base = '/#/testMethod?'
+        let query = 'application=' + application + '&service=' + service + '&method=' + method
+        return base + query
+      },
       test () {
         this.$axios.post('/test', {
           service: this.service.metadata.canonicalName,
           method: this.modal.method,
-          types: this.modal.types,
+          paramaterTypes: this.modal.paramaterTypes,
           params: this.modal.json
         }).then(response => {
           console.log(response)
diff --git a/dubbo-admin-frontend/src/components/test/TestMethod.vue b/dubbo-admin-frontend/src/components/test/TestMethod.vue
index 5c511a0..d3b3b9d 100644
--- a/dubbo-admin-frontend/src/components/test/TestMethod.vue
+++ b/dubbo-admin-frontend/src/components/test/TestMethod.vue
@@ -19,33 +19,27 @@
   <v-container grid-list-xl fluid>
     <v-layout row wrap>
       <v-flex lg12>
-        <v-data-table
-          :items="basic"
-          class="elevation-1"
-          hide-actions
-          hide-headers >
-          <template slot="items" slot-scope="props">
-            <td><h4>{{props.item.name}}</h4></td>
-            <td>{{props.item.value}}</td>
-          </template>
-        </v-data-table>
       </v-flex>
       <v-flex lg12>
         <v-card>
-          <v-toolbar flat color="transparent" class="elevation-0">
-            <v-toolbar-title><h3>Please fill in parameters</h3></v-toolbar-title>
-          </v-toolbar>
-          <v-layout row wrap>
-            <v-flex lg10>
-              <json-editor id="test"/>
-            </v-flex>
-            <v-toolbar flat color="transparent" class="elevation-0">
-              <v-toolbar-title><h3>Test Result</h3></v-toolbar-title>
-            </v-toolbar>
-            <v-flex lg10>
-              <json-editor id="result" v-if="method.showResult"/>
-            </v-flex>
-          </v-layout>
+          <v-flex lg8>
+            <v-card-title>
+              <span>Service: {{service}}<br> Method: {{method.name}}</span>
+            </v-card-title>
+            <v-card-text>
+              <json-editor id="test" v-model="method.json"/>
+            </v-card-text>
+            <v-card-actions>
+              <v-spacer></v-spacer>
+              <v-btn id="execute" mt-0 color="blue" @click="executeMethod()">EXECUTE</v-btn>
+            </v-card-actions>
+          </v-flex>
+          <v-flex lg8>
+            <v-card-text>
+              <h2>Test Result</h2>
+              <json-editor id="result" v-model="result" v-if="showResult"></json-editor>
+            </v-card-text>
+          </v-flex>
         </v-card>
       </v-flex>
 
@@ -61,38 +55,67 @@
     data () {
       return {
         basic: [],
+        service: null,
+        application: null,
         method: {
           name: null,
-          types: [],
-          json: [],
-          showResult: false
-        }
+          parameterTypes: [],
+          json: []
+        },
+        showResult: false,
+        result: {}
+      }
+    },
+
+    methods: {
+      executeMethod: function () {
+        let serviceTestDTO = {}
+        serviceTestDTO.service = this.service
+        serviceTestDTO.method = this.method.name
+        serviceTestDTO.parameterType = this.method.parameterTypes
+        serviceTestDTO.params = this.method.json
+        this.$axios.post('/test', serviceTestDTO)
+          .then(response => {
+            if (response.status === 200) {
+              this.result = response.data
+              this.showResult = true
+            }
+          })
       }
     },
 
     mounted: function () {
       let query = this.$route.query
       let vm = this
+      let method = null
       Object.keys(query).forEach(function (key) {
         if (key === 'service') {
           let item = {}
           item.name = 'service'
           item.value = query[key]
           vm.basic.push(item)
+          vm.service = query[key]
         }
         if (key === 'method') {
           let item = {}
           item.name = 'method'
           item.value = query[key]
           vm.method.name = query[key].split('~')[0]
-          let sig = query[key].split('~')[1]
-          vm.types = sig.split(';')
-          vm.types.forEach(function (item) {
-            vm.json.push(item)
-          })
-
+          method = query[key]
           vm.basic.push(item)
         }
+        if (key === 'application') {
+          vm.application = query[key]
+        }
+      })
+      this.$axios.get('/test/method', {
+        params: {
+          application: vm.application,
+          service: vm.service,
+          method: method
+        }
+      }).then(response => {
+        this.method.json = response.data.parameterTypes
       })
     },
     components: {
@@ -103,5 +126,4 @@
 </script>
 
 <style scoped>
-
 </style>