[GRIFFIN-244] get metrics by instance

This is just a squashed version of #491

Author: Rodion Gorkovenko <rodiongork@github.com>
Author: rodion <dershov@griddynamics.com>

Closes #492 from RodionGork/griffin-244-squashed.
diff --git a/griffin-doc/service/api-guide.md b/griffin-doc/service/api-guide.md
index 95113af..17bca5b 100644
--- a/griffin-doc/service/api-guide.md
+++ b/griffin-doc/service/api-guide.md
@@ -42,12 +42,14 @@
     - [Get Job Instances](#34)
     - [Get Job Healthy Statistics](#35)
     - [Download Sample Records](#36)
+    - [Get Job Instance by Id](#38)
 
 - [Metrics](#4)
     - [Get Metrics](#41)
     - [Add Metric Value](#42)
     - [Get Metric Value](#43)
     - [Remove Metric Value](#44)
+    - [Get Metric Value by Job Instance Id](#45)
 
 - [Hive MetaStore](#5)
     - [Get Table Metadata](#51)
@@ -747,6 +749,17 @@
 ```
 If successful, this method returns missing records in the response body, maximum record count is 100.
 
+<div id = "38"></div>
+
+### Get Job Instance by Id
+`GET /api/v1/jobs/instances/{jobInstanceId}`
+
+#### API Example
+```
+curl -k -G -X GET http://127.0.0.1:8080/api/v1/jobs/instances/1
+```
+If successful, this method returns job instance description for the given job instance id. If there is no instance with given id found, returns Griffin Exception.
+
 <h2 id = "4"></h2>
 
 ## Metrics
@@ -927,6 +940,32 @@
 }
 ```
 
+<div id = "45"></div>
+
+### Get Metric Value by Job Instance Id
+`GET http://127.0.0.1:8080/api/v1/metrics/values/:jobInstanceId`
+#### API Example
+```
+curl -k -G -X GET http://127.0.0.1:8080/api/v1/metrics/values/{304}
+{
+    "name": "some_job",
+    "tmst": 1553526960000,
+    "value": {
+        "total": 74,
+        "miss": 31,
+        "matched": 43,
+        "matchedFraction": 0.581081081081081
+    },
+    "metadata": {
+        "applicationId": "\"application_1549876136110_0237\"",
+    }
+}
+```
+
+
+
+
+
 <h2 id = "5"></h2>
 
 ### Hive MetaStore
diff --git a/griffin-doc/service/postman/griffin.json b/griffin-doc/service/postman/griffin.json
index e789121..55d7bac 100644
--- a/griffin-doc/service/postman/griffin.json
+++ b/griffin-doc/service/postman/griffin.json
@@ -1406,7 +1406,7 @@
 								"health"
 							]
 						},
-						"description": "`GET /api/v1/jobs/health`\n\n#### Response Body Sample\n```\n{\n  \"healthyJobCount\": 1,\n  \"jobCount\": 2\n}\n```"
+						"description": "`GET /api/v1/jobs/health`\n\n#### Response Body Sample\n```\n{\n  \"job instance info\"\n}\n```"
 					},
 					"response": [
 						{
@@ -1430,7 +1430,7 @@
 										"health"
 									]
 								},
-								"description": "`GET /api/v1/jobs/health`\n\n#### Response Body Sample\n```\n{\n  \"healthyJobCount\": 1,\n  \"jobCount\": 2\n}\n```"
+								"description": "`GET /api/v1/jobs/health`\n\n#### Response Body Sample\n```\n{\n  \"job instance info\"\n}\n```"
 							},
 							"status": "OK",
 							"code": 200,
@@ -1838,6 +1838,75 @@
 							"body": ""
 						}
 					]
+				},
+				{
+					"name": "Get Job Instance by Id",
+					"request": {
+						"method": "GET",
+						"header": [],
+						"body": {
+							"mode": "raw",
+							"raw": ""
+						},
+						"url": {
+							"raw": "{{BASE_PATH}}/api/v1/jobs/instances/:id",
+							"host": [
+								"{{BASE_PATH}}"
+							],
+							"path": [
+								"api",
+								"v1",
+								"jobs",
+								"instances",
+								":id"
+							],
+							"variable": [
+								{
+									"key": "id",
+									"value": "2"
+								}
+							]
+						},
+						"description": "`GET /api/v1/jobs/instances/{id}`\n\n#### Response Body Sample\n```\n{\n  \"job instance info\"\n}\n```"
+					},
+					"response": [
+						{
+							"name": "Get Job Instance by Id",
+							"originalRequest": {
+								"method": "GET",
+								"header": [],
+								"body": {
+									"mode": "raw",
+									"raw": ""
+								},
+								"url": {
+									"raw": "{{BASE_PATH}}/api/v1/jobs/instances/:id",
+									"host": [
+										"{{BASE_PATH}}"
+									],
+									"path": [
+										"api",
+										"v1",
+										"jobs",
+										"instances",
+										":id"
+									],
+									"variable": [
+										{
+											"key": "id",
+											"value": "2"
+										}
+									]
+								},
+								"description": "`GET /api/v1/jobs/instances/{id}`\n\n#### Response Body Sample\n```\n{\n  \"job instance info\"\n}\n```"
+							},
+							"status": "OK",
+							"code": 200,
+							"_postman_previewlanguage": "json",
+							"cookie": [],
+							"body": "{\n    \"healthyJobCount\": 1,\n    \"jobCount\": 2\n}"
+						}
+					]
 				}
 			]
 		},
@@ -2080,7 +2149,7 @@
 						],
 						"body": {
 							"mode": "raw",
-							"raw": "[\n\t{\n\t\t\"name\" : \"metricName\",\n\t\t\"tmst\" : 1509599811123,\n\t\t\"value\" : {\n\t\t\t\"__tmst\" : 1509599811123,\n\t\t\t\"miss\" : 11,\n\t\t\t\"total\" : 125000,\n\t\t\t\"matched\" : 124989\n\t\t}\n   }\n]"
+							"raw": "[\n\t{\n\t\t\"name\" : \"metricName\",\n\t\t\"tmst\" : 1509599811123,\n\t\t\"applicationId\" : \"app_1\",\n\t\t\"value\" : {\n\t\t\t\"__tmst\" : 1509599811123,\n\t\t\t\"miss\" : 11,\n\t\t\t\"total\" : 125000,\n\t\t\t\"matched\" : 124989\n\t\t}\n   }\n]"
 						},
 						"url": {
 							"raw": "{{BASE_PATH}}/api/v1/metrics/values",
@@ -2109,7 +2178,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "[\n\t{\n\t\t\"name\" : \"metricName\",\n\t\t\"tmst\" : 1509599811123,\n\t\t\"value\" : {\n\t\t\t\"__tmst\" : 1509599811123,\n\t\t\t\"miss\" : 11,\n\t\t\t\"total\" : 125000,\n\t\t\t\"matched\" : 124989\n\t\t}\n   }\n]"
+									"raw": "[\n\t{\n\t\t\"name\" : \"metricName\",\n\t\t\"tmst\" : 1509599811123,\n\t\t\"applicationId\" : \"app_1\",\n\t\t\"value\" : {\n\t\t\t\"__tmst\" : 1509599811123,\n\t\t\t\"miss\" : 11,\n\t\t\t\"total\" : 125000,\n\t\t\t\"matched\" : 124989\n\t\t}\n   }\n]"
 								},
 								"url": {
 									"raw": "{{BASE_PATH}}/api/v1/metrics/values",
@@ -2307,6 +2376,75 @@
 							"body": "{\"took\":363,\"timed_out\":false,\"total\":5,\"deleted\":5,\"batches\":1,\"version_conflicts\":0,\"noops\":0,\"retries\":{\"bulk\":0,\"search\":0},\"throttled_millis\":0,\"requests_per_second\":-1.0,\"throttled_until_millis\":0,\"failures\":[]}"
 						}
 					]
+				},
+				{
+					"name": "Get Metrics Value by Job Instance Id",
+					"request": {
+						"method": "GET",
+						"header": [],
+						"body": {
+							"mode": "raw",
+							"raw": ""
+						},
+						"url": {
+							"raw": "{{BASE_PATH}}/api/v1/metrics/values/:jobInstanceId",
+							"host": [
+								"{{BASE_PATH}}"
+							],
+							"path": [
+								"api",
+								"v1",
+								"metrics",
+								"values",
+								":jobInstanceId"
+							],
+							"variable": [
+								{
+									"key": "jobInstanceId",
+									"value": "304"
+								}
+							]
+						},
+						"description": "`GET /api/v1/metrics/values/{jobInstanceId}`\n\n#### Response Body Sample\n```\n{\n  \"metric value\"\n}\n```"
+					},
+					"response": [
+						{
+							"name": "Get Metrics Value by Job Instance Id",
+							"originalRequest": {
+								"method": "GET",
+								"header": [],
+								"body": {
+									"mode": "raw",
+									"raw": ""
+								},
+								"url": {
+									"raw": "{{BASE_PATH}}/api/v1/metrics/values/:jobInstanceId",
+									"host": [
+										"{{BASE_PATH}}"
+									],
+									"path": [
+										"api",
+										"v1",
+										"metrics",
+										"values",
+										":jobInstanceId"
+									],
+									"variable": [
+										{
+											"key": "jobInstanceId",
+											"value": "304"
+										}
+									]
+								},
+								"description": "`GET /api/v1/metrics/values/{jobInstanceId}`\n\n#### Response Body Sample\n```\n{\n  \"metric value\"\n}\n```"
+							},
+							"status": "OK",
+							"code": 200,
+							"_postman_previewlanguage": "json",
+							"cookie": [],
+							"body": "{\n    \"name\": some_job,\n    \"tmst\": 1553526960000\n    \"applicationId\": application_1549876136110_0237\n    \"value\": {\n    \"total\": 74}}"
+						}
+					]
 				}
 			]
 		},
diff --git a/measure/src/main/scala/org/apache/griffin/measure/context/MetricWrapper.scala b/measure/src/main/scala/org/apache/griffin/measure/context/MetricWrapper.scala
index df162a7..484797a 100644
--- a/measure/src/main/scala/org/apache/griffin/measure/context/MetricWrapper.scala
+++ b/measure/src/main/scala/org/apache/griffin/measure/context/MetricWrapper.scala
@@ -28,7 +28,7 @@
   val _Name = "name"
   val _Timestamp = "tmst"
   val _Value = "value"
-  val _ApplicationId = "applicationId"
+  val _Metadata = "metadata"
 
   val metrics: MutableMap[Long, Map[String, Any]] = MutableMap()
 
@@ -47,7 +47,7 @@
         (_Name -> name),
         (_Timestamp -> timestamp),
         (_Value -> value),
-        (_ApplicationId -> applicationId)
+        (_Metadata -> Map("applicationId" -> applicationId))
       ))
     }
   }
diff --git a/measure/src/test/scala/org/apache/griffin/measure/context/MetricWrapperTest.scala b/measure/src/test/scala/org/apache/griffin/measure/context/MetricWrapperTest.scala
index 8ad7d5d..4a49c75 100644
--- a/measure/src/test/scala/org/apache/griffin/measure/context/MetricWrapperTest.scala
+++ b/measure/src/test/scala/org/apache/griffin/measure/context/MetricWrapperTest.scala
@@ -35,8 +35,9 @@
     metricWrapper.insertMetric(2, Map("miss" -> 4))
     metricWrapper.flush should be (Map(
       1L -> Map("name" -> "test", "tmst" -> 1, "value" -> Map("total" -> 10, "miss"-> 2, "match" -> 8),
-        "applicationId" -> "appId"),
-      2L -> Map("name" -> "test", "tmst" -> 2, "value" -> Map("total" -> 20, "miss"-> 4), "applicationId" -> "appId")
+        "metadata" -> Map("applicationId" -> "appId")),
+      2L -> Map("name" -> "test", "tmst" -> 2, "value" -> Map("total" -> 20, "miss"-> 4),
+        "metadata" -> Map("applicationId" -> "appId"))
     ))
   }
 
diff --git a/service/src/main/java/org/apache/griffin/core/exception/GriffinExceptionMessage.java b/service/src/main/java/org/apache/griffin/core/exception/GriffinExceptionMessage.java
index 6a9b9da..4f65248 100644
--- a/service/src/main/java/org/apache/griffin/core/exception/GriffinExceptionMessage.java
+++ b/service/src/main/java/org/apache/griffin/core/exception/GriffinExceptionMessage.java
@@ -76,6 +76,8 @@
 
     INSTANCE_ID_DOES_NOT_EXIST(40409, "Instance id does not exist"),
 
+    JOB_INSTANCE_NOT_FOUND(40410, "No job instances with given job instance id found"),
+
     //409, "Conflict"
     MEASURE_NAME_ALREADY_EXIST(40901, "Measure name already exists"),
 
diff --git a/service/src/main/java/org/apache/griffin/core/job/entity/JobInstanceBean.java b/service/src/main/java/org/apache/griffin/core/job/entity/JobInstanceBean.java
index 6fc5cf2..c3b0f1c 100644
--- a/service/src/main/java/org/apache/griffin/core/job/entity/JobInstanceBean.java
+++ b/service/src/main/java/org/apache/griffin/core/job/entity/JobInstanceBean.java
@@ -186,6 +186,13 @@
     public JobInstanceBean() {
     }
 
+    public JobInstanceBean(State state, Long tms, Long expireTms, String appId) {
+        this.state = state;
+        this.tms = tms;
+        this.expireTms = expireTms;
+        this.appId=appId;
+    }
+
     public JobInstanceBean(State state, Long tms, Long expireTms) {
         this.state = state;
         this.tms = tms;
diff --git a/service/src/main/java/org/apache/griffin/core/metric/MetricController.java b/service/src/main/java/org/apache/griffin/core/metric/MetricController.java
index 4d39ba3..5cd43af 100644
--- a/service/src/main/java/org/apache/griffin/core/metric/MetricController.java
+++ b/service/src/main/java/org/apache/griffin/core/metric/MetricController.java
@@ -27,6 +27,7 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
@@ -71,4 +72,9 @@
                                                         String metricName) {
         return metricService.deleteMetricValues(metricName);
     }
+
+    @RequestMapping(value = "/metrics/values/{instanceId}", method = RequestMethod.GET)
+    public MetricValue getMetric(@PathVariable("instanceId") Long id){
+        return metricService.findMetric(id);
+    }
 }
diff --git a/service/src/main/java/org/apache/griffin/core/metric/MetricService.java b/service/src/main/java/org/apache/griffin/core/metric/MetricService.java
index 039b0cb..75402ff 100644
--- a/service/src/main/java/org/apache/griffin/core/metric/MetricService.java
+++ b/service/src/main/java/org/apache/griffin/core/metric/MetricService.java
@@ -37,4 +37,6 @@
     ResponseEntity addMetricValues(List<MetricValue> values);
 
     ResponseEntity<?> deleteMetricValues(String metricName);
+
+    MetricValue findMetric(Long id);
 }
diff --git a/service/src/main/java/org/apache/griffin/core/metric/MetricServiceImpl.java b/service/src/main/java/org/apache/griffin/core/metric/MetricServiceImpl.java
index f817f65..beca19e 100644
--- a/service/src/main/java/org/apache/griffin/core/metric/MetricServiceImpl.java
+++ b/service/src/main/java/org/apache/griffin/core/metric/MetricServiceImpl.java
@@ -23,6 +23,7 @@
 import static org.apache.griffin.core.exception.GriffinExceptionMessage.INVALID_METRIC_RECORDS_OFFSET;
 import static org.apache.griffin.core.exception.GriffinExceptionMessage.INVALID_METRIC_RECORDS_SIZE;
 import static org.apache.griffin.core.exception.GriffinExceptionMessage.INVALID_METRIC_VALUE_FORMAT;
+import static org.apache.griffin.core.exception.GriffinExceptionMessage.JOB_INSTANCE_NOT_FOUND;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -36,6 +37,8 @@
 import org.apache.commons.lang.StringUtils;
 import org.apache.griffin.core.exception.GriffinException;
 import org.apache.griffin.core.job.entity.AbstractJob;
+import org.apache.griffin.core.job.entity.JobInstanceBean;
+import org.apache.griffin.core.job.repo.JobInstanceRepo;
 import org.apache.griffin.core.job.repo.JobRepo;
 import org.apache.griffin.core.measure.entity.Measure;
 import org.apache.griffin.core.measure.repo.MeasureRepo;
@@ -59,6 +62,8 @@
     private JobRepo<AbstractJob> jobRepo;
     @Autowired
     private MetricStore metricStore;
+    @Autowired
+    private JobInstanceRepo jobInstanceRepo;
 
     @Override
     public Map<String, List<Metric>> getAllMetrics() {
@@ -139,6 +144,23 @@
         }
     }
 
+    @Override
+    public MetricValue findMetric(Long id) {
+        JobInstanceBean jobInstanceBean = jobInstanceRepo.findByInstanceId(id);
+        if (jobInstanceBean == null){
+            LOGGER.warn("There are no job instances with id {} ", id);
+            throw new GriffinException
+                    .NotFoundException(JOB_INSTANCE_NOT_FOUND);
+        }
+        String appId = jobInstanceBean.getAppId();
+        try {
+            return metricStore.getMetric(appId);
+        } catch (IOException e) {
+            LOGGER.warn("Failed to get metric for applicationId {} ", appId);
+            throw new GriffinException.ServiceException("Failed to find metric", e);
+        }
+    }
+
     private void checkFormat(MetricValue value) {
         if (StringUtils.isBlank(value.getName()) || value.getTmst() == null
                 || MapUtils.isEmpty(value.getValue())) {
diff --git a/service/src/main/java/org/apache/griffin/core/metric/MetricStore.java b/service/src/main/java/org/apache/griffin/core/metric/MetricStore.java
index a452648..f85c4db 100644
--- a/service/src/main/java/org/apache/griffin/core/metric/MetricStore.java
+++ b/service/src/main/java/org/apache/griffin/core/metric/MetricStore.java
@@ -34,4 +34,6 @@
             throws IOException;
 
     ResponseEntity<?> deleteMetricValues(String metricName) throws IOException;
+
+    MetricValue getMetric(String applicationId) throws IOException;
 }
diff --git a/service/src/main/java/org/apache/griffin/core/metric/MetricStoreImpl.java b/service/src/main/java/org/apache/griffin/core/metric/MetricStoreImpl.java
index 3bff8f5..2d577bb 100644
--- a/service/src/main/java/org/apache/griffin/core/metric/MetricStoreImpl.java
+++ b/service/src/main/java/org/apache/griffin/core/metric/MetricStoreImpl.java
@@ -31,7 +31,9 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.griffin.core.metric.model.MetricValue;
 import org.apache.griffin.core.util.JsonUtil;
 import org.apache.http.Header;
@@ -142,14 +144,16 @@
                 .hasNonNull("hits")) {
             for (JsonNode node : jsonNode.get("hits").get("hits")) {
                 JsonNode sourceNode = node.get("_source");
-                Map<String, Object> value = JsonUtil.toEntity(sourceNode
-                                .get("value").toString(),
-                        new TypeReference<Map<String, Object>>() {
-                        });
-                MetricValue metricValue = new MetricValue(sourceNode
-                        .get("name")
-                        .asText(),
+                Map<String, Object> value = JsonUtil.toEntity(
+                        sourceNode.get("value").toString(),
+                        new TypeReference<Map<String, Object>>() {});
+                Map<String, Object> meta = JsonUtil.toEntity(
+                        Objects.toString(sourceNode.get("metadata"), null),
+                        new TypeReference<Map<String, Object>>() {});
+                MetricValue metricValue = new MetricValue(
+                        sourceNode.get("name").asText(),
                         Long.parseLong(sourceNode.get("tmst").asText()),
+                        meta,
                         value);
                 metricValues.add(metricValue);
             }
@@ -206,4 +210,14 @@
         return String.format("Basic %s", Base64.getEncoder().encodeToString(
                 auth.getBytes()));
     }
+
+    @Override
+    public MetricValue getMetric(String applicationId) throws IOException {
+        Response response = client.performRequest(
+                "GET", urlGet,
+                Collections.singletonMap(
+                        "q", "metadata.applicationId:" + applicationId));
+        List<MetricValue> metricValues = getMetricValuesFromResponse(response);
+        return metricValues.get(0);
+    }
 }
diff --git a/service/src/main/java/org/apache/griffin/core/metric/model/MetricValue.java b/service/src/main/java/org/apache/griffin/core/metric/model/MetricValue.java
index 4839f9f..4c7f386 100644
--- a/service/src/main/java/org/apache/griffin/core/metric/model/MetricValue.java
+++ b/service/src/main/java/org/apache/griffin/core/metric/model/MetricValue.java
@@ -19,7 +19,9 @@
 
 package org.apache.griffin.core.metric.model;
 
+import java.util.Collections;
 import java.util.Map;
+import java.util.Objects;
 
 public class MetricValue {
 
@@ -27,6 +29,8 @@
 
     private Long tmst;
 
+    private Map<String, Object> metadata;
+
     private Map<String, Object> value;
 
     public MetricValue() {
@@ -36,6 +40,15 @@
         this.name = name;
         this.tmst = tmst;
         this.value = value;
+        this.metadata = Collections.emptyMap();
+    }
+
+
+    public MetricValue(String name, Long tmst, Map<String, Object> metadata, Map<String, Object> value) {
+        this.name = name;
+        this.tmst = tmst;
+        this.metadata = metadata;
+        this.value = value;
     }
 
     public String getName() {
@@ -61,4 +74,35 @@
     public void setValue(Map<String, Object> value) {
         this.value = value;
     }
+
+    public Map<String, Object> getMetadata() {
+        return metadata;
+    }
+
+    public void setMetadata(Map<String, Object> metadata) {
+        this.metadata = metadata;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        MetricValue that = (MetricValue) o;
+        return Objects.equals(name, that.name) &&
+                Objects.equals(tmst, that.tmst) &&
+                Objects.equals(metadata, that.metadata) &&
+                Objects.equals(value, that.value);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, tmst, metadata, value);
+    }
+
+    @Override
+    public String toString() {
+        return String.format(
+                "MetricValue{name=%s, ts=%s, meta=%s, value=%s}",
+                name, tmst, metadata, value);
+    }
 }
diff --git a/service/src/test/java/org/apache/griffin/core/job/JobControllerTest.java b/service/src/test/java/org/apache/griffin/core/job/JobControllerTest.java
index d9d5d80..aa10cf2 100644
--- a/service/src/test/java/org/apache/griffin/core/job/JobControllerTest.java
+++ b/service/src/test/java/org/apache/griffin/core/job/JobControllerTest.java
@@ -38,6 +38,7 @@
 
 import org.apache.griffin.core.exception.GriffinException;
 import org.apache.griffin.core.exception.GriffinExceptionHandler;
+import org.apache.griffin.core.exception.GriffinExceptionMessage;
 import org.apache.griffin.core.job.entity.AbstractJob;
 import org.apache.griffin.core.job.entity.JobHealth;
 import org.apache.griffin.core.job.entity.JobInstanceBean;
@@ -186,6 +187,16 @@
     }
 
     @Test
+    public void testJobInstanceWithGivenIdNotFound() throws Exception {
+        Long jobInstanceId = 2L;
+        doThrow(new GriffinException.NotFoundException(GriffinExceptionMessage.JOB_INSTANCE_NOT_FOUND))
+                .when(service).findInstance(jobInstanceId);
+
+        mvc.perform(get(URLHelper.API_VERSION_PATH + "/jobs/instances/2"))
+                .andExpect(status().isNotFound());
+    }
+
+    @Test
     public void testGetHealthInfo() throws Exception {
         JobHealth jobHealth = new JobHealth(1, 3);
         given(service.getHealthInfo()).willReturn(jobHealth);
diff --git a/service/src/test/java/org/apache/griffin/core/metric/MetricServiceImplTest.java b/service/src/test/java/org/apache/griffin/core/metric/MetricServiceImplTest.java
index aa55f7a..39837f0 100644
--- a/service/src/test/java/org/apache/griffin/core/metric/MetricServiceImplTest.java
+++ b/service/src/test/java/org/apache/griffin/core/metric/MetricServiceImplTest.java
@@ -33,6 +33,9 @@
 
 import org.apache.griffin.core.exception.GriffinException;
 import org.apache.griffin.core.job.entity.AbstractJob;
+import org.apache.griffin.core.job.entity.JobInstanceBean;
+import org.apache.griffin.core.job.entity.LivySessionStates;
+import org.apache.griffin.core.job.repo.JobInstanceRepo;
 import org.apache.griffin.core.job.repo.JobRepo;
 import org.apache.griffin.core.measure.entity.Measure;
 import org.apache.griffin.core.measure.repo.MeasureRepo;
@@ -63,6 +66,8 @@
     private JobRepo<AbstractJob> jobRepo;
     @Mock
     private MetricStoreImpl metricStore;
+    @Mock
+    private JobInstanceRepo jobInstanceRepo;
 
     @Autowired
     private Environment env;
@@ -204,4 +209,43 @@
 
     }
 
+    @Test
+    public void testFindMetricSuccess() throws IOException {
+        Long id = 1L;
+        String appId = "application";
+        MetricValue expectedMetric = new MetricValue(
+                "name", 1234L, Collections.singletonMap("applicationId", appId), new HashMap<>());
+
+        given(jobInstanceRepo.findByInstanceId(id))
+                .willReturn(new JobInstanceBean(LivySessionStates.State.RUNNING, 12L, 32L, appId));
+        given(metricStore.getMetric(appId))
+                .willReturn(expectedMetric);
+        MetricValue actualMetric = service.findMetric(id);
+
+        assertEquals(expectedMetric, actualMetric);
+    }
+
+    @Test(expected = GriffinException.NotFoundException.class)
+    public void testFailedToFindJobInstance() throws IOException {
+        Long id = 1L;
+        given(jobInstanceRepo.findByInstanceId(id))
+                .willReturn(null);
+        service.findMetric(id);
+
+    }
+
+    @Test(expected = GriffinException.ServiceException.class)
+    public void testFindMetricFailure() throws IOException {
+        Long id = 1L;
+        String appId = "application";
+
+        given(jobInstanceRepo.findByInstanceId(id))
+                .willReturn(new JobInstanceBean(LivySessionStates.State.RUNNING, 12L, 32L, appId));
+        given(metricStore.getMetric(appId))
+                .willThrow(new GriffinException.ServiceException("", new RuntimeException()));
+        service.findMetric(id);
+
+    }
+
+
 }
diff --git a/service/src/test/java/org/apache/griffin/core/metric/MetricStoreImplTest.java b/service/src/test/java/org/apache/griffin/core/metric/MetricStoreImplTest.java
index d3cbfb0..b91f6ba 100644
--- a/service/src/test/java/org/apache/griffin/core/metric/MetricStoreImplTest.java
+++ b/service/src/test/java/org/apache/griffin/core/metric/MetricStoreImplTest.java
@@ -19,15 +19,55 @@
 
 package org.apache.griffin.core.metric;
 
-import static org.junit.Assert.assertTrue;
+import org.apache.griffin.core.metric.model.MetricValue;
+import org.apache.http.HttpEntity;
+import org.elasticsearch.client.Response;
+import org.elasticsearch.client.RestClient;
+import org.elasticsearch.client.RestClientBuilder;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
 
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 
-import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.BDDMockito.*;
 
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({RestClient.class, RestClientBuilder.class})
+@PowerMockIgnore("javax.management.*")
 public class MetricStoreImplTest {
 
+    private static final String INDEX = "griffin";
+    private static final String TYPE = "accuracy";
+
+    private static final String urlBase = String.format("/%s/%s", INDEX, TYPE);
+    private static final String urlGet = urlBase.concat("/_search?filter_path=hits.hits._source");
+
+    private RestClient restClientMock;
+
+    @Before
+    public void setup(){
+        PowerMockito.mockStatic(RestClient.class);
+        restClientMock = PowerMockito.mock(RestClient.class);
+        RestClientBuilder restClientBuilderMock = PowerMockito.mock(RestClientBuilder.class);
+
+        given(RestClient.builder(anyVararg())).willReturn(restClientBuilderMock);
+        given(restClientBuilderMock.build()).willReturn(restClientMock);
+    }
+
     @Test
     public void testBuildBasicAuthString()
             throws NoSuchMethodException, InvocationTargetException,
@@ -40,4 +80,39 @@
         assertTrue(authStr.equals("Basic dXNlcjpwYXNzd29yZA=="));
     }
 
+    @Test
+    public void testMetricGetting() throws IOException, URISyntaxException {
+        //given
+        Response responseMock = PowerMockito.mock(Response.class);
+        HttpEntity httpEntityMock = PowerMockito.mock(HttpEntity.class);
+        InputStream is = Thread.currentThread().getContextClassLoader()
+                .getResourceAsStream("metricvalue.json");
+        Map<String, String> map = new HashMap<>();
+        map.put("q", "metadata.applicationId:application_1549876136110_0018");
+
+        Map<String, Object> value = new HashMap<String, Object>(){{
+            put("total", 74);
+            put("miss", 0);
+            put("matched", 74);
+            put("matchedFraction", 1);
+        }};
+        MetricValue expectedMetric = new MetricValue("de_demo_results_comparision",
+                1549985089648L,
+                Collections.singletonMap("applicationId", "application_1549876136110_0018"),
+                value);
+
+
+        given(restClientMock.performRequest(eq("GET"), eq(urlGet), eq(map), anyVararg())).willReturn(responseMock);
+        given(responseMock.getEntity()).willReturn(httpEntityMock);
+        given(httpEntityMock.getContent()).willReturn(is);
+
+        //when
+        MetricStoreImpl metricStore = new MetricStoreImpl("", 0, "", "", "");
+        MetricValue metric = metricStore.getMetric("application_1549876136110_0018");
+
+        //then
+        PowerMockito.verifyStatic();
+        assertEquals(expectedMetric, metric);
+    }
+
 }
diff --git a/service/src/test/resources/metricvalue.json b/service/src/test/resources/metricvalue.json
new file mode 100644
index 0000000..690c1c4
--- /dev/null
+++ b/service/src/test/resources/metricvalue.json
@@ -0,0 +1,51 @@
+{
+  "took": 47,
+  "timed_out": false,
+  "_shards": {
+    "total": 5,
+    "successful": 5,
+    "skipped": 0,
+    "failed": 0
+  },
+  "hits": {
+    "total": 17,
+    "max_score": 3.226844,
+    "hits": [
+      {
+        "_index": "griffin",
+        "_type": "accuracy",
+        "_id": "RZFP4mgBkZqzqlKSwWtJ",
+        "_score": 3.226844,
+        "_source": {
+          "name": "de_demo_results_comparision",
+          "tmst": 1549985089648,
+          "value": {
+            "total": 74,
+            "miss": 0,
+            "matched": 74,
+            "matchedFraction": 1
+          },
+          "metadata": {
+            "applicationId": "application_1549876136110_0018"
+          }
+        }
+      },
+      {
+        "_index": "griffin",
+        "_type": "accuracy",
+        "_id": "taMpvmgBfOpRJiYFj5Xg",
+        "_score": 2.4107988,
+        "_source": {
+          "name": "de_demo_results_comparision",
+          "tmst": 1549378607658,
+          "value": {
+            "total": 74,
+            "miss": 0,
+            "matched": 74,
+            "matchedFraction": 1
+          }
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file