summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAhila <ahila.pandaram@wipro.com>2022-08-04 16:14:16 +0530
committerAhila <ahila.pandaram@wipro.com>2022-08-05 11:52:15 +0530
commit7bd19d7fecb5c455c3e63e18f2aee4356d8531cd (patch)
treeef52e6d8ba93bf68ae323b4d799b6e07da55ff21
parent015b7529adc61181862c84a20ed7140a96e479dc (diff)
KPI-Computation-MS Code coverage improvement
Issue-ID: DCAEGEN2-3162 Signed-off-by: Ahila <ahila.pandaram@wipro.com> Change-Id: I26ec8c7cd591c059395c0cedd471643e3e87c114
-rw-r--r--components/kpi-computation-ms/Changelog.md4
-rw-r--r--components/kpi-computation-ms/lombok.config2
-rw-r--r--components/kpi-computation-ms/pom.xml3
-rw-r--r--components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/computation/KpiComputationTest.java57
-rw-r--r--components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/controller/HealthCheckTest.java41
-rw-r--r--components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/models/ConfigPolicyTest.java41
-rw-r--r--components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/models/ConfigurationTest.java36
-rw-r--r--components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/utils/BeanUtilTest.java39
-rw-r--r--components/kpi-computation-ms/src/test/resources/kpi/cbs_config4.json36
-rw-r--r--components/kpi-computation-ms/src/test/resources/kpi/ves_message_missing_field.json82
-rw-r--r--components/kpi-computation-ms/version.properties2
11 files changed, 326 insertions, 17 deletions
diff --git a/components/kpi-computation-ms/Changelog.md b/components/kpi-computation-ms/Changelog.md
index 5c9c4f0b..9c1beccd 100644
--- a/components/kpi-computation-ms/Changelog.md
+++ b/components/kpi-computation-ms/Changelog.md
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
+## [1.0.6]
+### Changed
+* CodeCoverage improvement for dcaegen2-services-kpi-computation-ms (DCAEGEN2-3162)
+
## [1.0.5]
### Changed
* Enhancements to KPI Computation MS for Kohn Release (DCAEGEN2-3193)
diff --git a/components/kpi-computation-ms/lombok.config b/components/kpi-computation-ms/lombok.config
new file mode 100644
index 00000000..df71bb6a
--- /dev/null
+++ b/components/kpi-computation-ms/lombok.config
@@ -0,0 +1,2 @@
+config.stopBubbling = true
+lombok.addLombokGeneratedAnnotation = true
diff --git a/components/kpi-computation-ms/pom.xml b/components/kpi-computation-ms/pom.xml
index 1defef1f..c71b9189 100644
--- a/components/kpi-computation-ms/pom.xml
+++ b/components/kpi-computation-ms/pom.xml
@@ -29,7 +29,7 @@
<groupId>org.onap.dcaegen2.services.components</groupId>
<artifactId>kpi-ms</artifactId>
- <version>1.0.5-SNAPSHOT</version>
+ <version>1.0.6-SNAPSHOT</version>
<name>dcaegen2-services-kpi-computation-ms</name>
<description>Kpi ms</description>
<packaging>jar</packaging>
@@ -345,7 +345,6 @@
<directory>${project.basedir}</directory>
</resource>
</resources>
-
<runs>
<!-- Maven is loosing file permissions during artifacts copy -->
<run>export trustpass=`cat /opt/app/kpims/etc/cert/trust.pass`</run>
diff --git a/components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/computation/KpiComputationTest.java b/components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/computation/KpiComputationTest.java
index 4320981b..dc1becb3 100644
--- a/components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/computation/KpiComputationTest.java
+++ b/components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/computation/KpiComputationTest.java
@@ -26,12 +26,21 @@ import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+import org.mockito.Spy;
import org.onap.dcaegen2.kpi.computation.KpiComputation;
+import org.onap.dcaegen2.kpi.exception.KpiComputationException;
import org.onap.dcaegen2.kpi.models.Configuration;
+import org.onap.dcaegen2.kpi.models.KpiOperand;
+import org.onap.dcaegen2.kpi.models.MeasDataCollection;
import org.onap.dcaegen2.kpi.models.VesEvent;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.reflect.Whitebox;
import java.math.BigDecimal;
import java.math.RoundingMode;
@@ -47,7 +56,9 @@ public class KpiComputationTest {
private static final String VES_MESSAGE_NULL_FILE = "kpi/ves_message_null.json";
private static final String VES_MESSAGE_SLICING_FILE = "kpi/ves_message_slicing.json";
private static final String VES_MESSAGE_EVENTNAME_FILE = "kpi/ves_message_eventname.json";
-
+ private static final String VES_MESSAGE_FIELD_MISSING ="kpi/ves_message_missing_field.json";
+
+
@Test
public void testKpiComputation() {
@@ -88,7 +99,7 @@ public class KpiComputationTest {
assertEquals(vesEvent.getEvent().getPerf3gppFields().getMeasDataCollection().getMeasInfoList().get(0)
.getMeasValuesList().get(0).getMeasResults().get(0).getSvalue(), "158");
}
-
+
@Test
public void testKpiComputationSumRatio() {
@@ -134,5 +145,47 @@ public class KpiComputationTest {
List<VesEvent> vesList = new KpiComputation().checkAndDoComputation(vesMessage, config);
assertEquals(null, vesList);
}
+
+ @Test
+ public void testKpiComputationException() {
+ String strKpiConfigSumRatio = FileUtils.getFileContents(KPI_CONFIG_SUMRATIO_FILE);
+ String vesMessage = FileUtils.getFileContents(VES_MESSAGE_FIELD_MISSING);
+ Configuration config = mock(Configuration.class);
+ when(config.getKpiConfig()).thenReturn(strKpiConfigSumRatio);
+ KpiComputationException kpiException = Assertions.assertThrows(KpiComputationException.class, () -> {
+ List<VesEvent> vesList = new KpiComputation().checkAndDoComputation(vesMessage, config);
+ });
+ Assertions.assertEquals("Required Field: EventName not present", kpiException.getMessage());
+ }
+ @Test
+ public void testNullOperands() throws Exception {
+ Map<String, List<KpiOperand>> operands = null;
+ operands = Whitebox.invokeMethod(new KpiComputation(), "getOperands", new MeasDataCollection(), null);
+ Assertions.assertNull(operands);
+ }
+ @Test
+ public void testEmptyOperands() throws Exception {
+ Map<String, List<KpiOperand>> operands = null;
+ List<String> inputOperands = new ArrayList<String>();
+ operands = Whitebox.invokeMethod(new KpiComputation(), "getOperands", new MeasDataCollection(), inputOperands);
+ Assertions.assertNull(operands);
+ }
+ @Test
+ public void testNullVESMessage() {
+ String strKpiConfigSumRatio = FileUtils.getFileContents(KPI_CONFIG_FILE);
+ Configuration config = mock(Configuration.class);
+ when(config.getKpiConfig()).thenReturn(strKpiConfigSumRatio);
+ List<VesEvent> vesList = new KpiComputation().checkAndDoComputation(null, config);
+ Assertions.assertNull(vesList);
+ }
+ @Test
+ public void testEmptyVESMessage() {
+ String strKpiConfigSumRatio = FileUtils.getFileContents(KPI_CONFIG_FILE);
+ Configuration config = mock(Configuration.class);
+ when(config.getKpiConfig()).thenReturn(strKpiConfigSumRatio);
+ String vesMessage = "{}";
+ List<VesEvent> vesList = new KpiComputation().checkAndDoComputation(vesMessage, config);
+ Assertions.assertNull(vesList);
+ }
}
diff --git a/components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/controller/HealthCheckTest.java b/components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/controller/HealthCheckTest.java
new file mode 100644
index 00000000..b0f2c0ef
--- /dev/null
+++ b/components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/controller/HealthCheckTest.java
@@ -0,0 +1,41 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022 Wipro Limited.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.kpi.controller;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Spy;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+public class HealthCheckTest {
+ @Spy
+ HealthCheck healthCheck;
+ @Test
+ public void testHealthCheck(){
+ ResponseEntity<HttpStatus> status = healthCheck.healthCheck();
+ assertEquals(HttpStatus.OK, status.getStatusCode());
+ }
+}
diff --git a/components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/models/ConfigPolicyTest.java b/components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/models/ConfigPolicyTest.java
new file mode 100644
index 00000000..0d9bea09
--- /dev/null
+++ b/components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/models/ConfigPolicyTest.java
@@ -0,0 +1,41 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022 Wipro Limited.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.dcaegen2.kpi.models;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+import org.mockito.Spy;
+public class ConfigPolicyTest {
+ @Spy
+ ConfigPolicy configPolicy;
+ @Test
+ public void testGetInstance() {
+ ConfigPolicy instance = ConfigPolicy.getInstance();
+ assertNotNull(instance);
+ }
+ @Test
+ public void testGetInstanceIfNull() {
+ ConfigPolicy instance = ConfigPolicy.getInstance();
+ instance = null;
+ ConfigPolicy instanceNew = ConfigPolicy.getInstance();
+ assertNotNull(instanceNew);
+ }
+}
diff --git a/components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/models/ConfigurationTest.java b/components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/models/ConfigurationTest.java
index efe84983..cc22ef13 100644
--- a/components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/models/ConfigurationTest.java
+++ b/components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/models/ConfigurationTest.java
@@ -1,8 +1,9 @@
/*******************************************************************************
* ============LICENSE_START=======================================================
- * slice-analysis-ms
+ * kpi-computation-ms
* ================================================================================
* Copyright (C) 2020 Wipro Limited.
+ * Copyright (C) 2022 Wipro Limited.
* ==============================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +24,7 @@
package org.onap.dcaegen2.kpi.models;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import java.util.ArrayList;
import java.util.HashMap;
@@ -32,10 +34,14 @@ import java.util.Map;
import org.junit.Test;
import org.onap.dcaegen2.kpi.computation.FileUtils;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
public class ConfigurationTest {
Configuration configuration = Configuration.getInstance();
private static final String KPI_CONFIG_FILE = "kpi/kpi_config.json";
+ private static final String CBS_CONFIG_FILE = "kpi/cbs_config4.json";
@Test
public void configurationTest() {
@@ -43,7 +49,6 @@ public class ConfigurationTest {
List<String> list = new ArrayList<String>();
list.add("server");
Map<String, Object> subscribes = new HashMap<>();
-
configuration.setStreamsSubscribes(subscribes);
configuration.setStreamsPublishes(subscribes);
configuration.setDmaapServers(list);
@@ -61,7 +66,6 @@ public class ConfigurationTest {
configuration.setEnablessl(true);
configuration.setCbsPollingInterval(10);
configuration.setKpiConfig("kpi config");
-
assertEquals("cg", configuration.getCg());
assertEquals("cid", configuration.getCid());
assertEquals("user", configuration.getAafUsername());
@@ -72,17 +76,25 @@ public class ConfigurationTest {
assertEquals("192.168.1.1", configuration.getHost());
assertEquals(21, configuration.getPort());
assertEquals("user", configuration.getUsername());
- assertEquals("password", configuration.getPassword());
- assertEquals("database", configuration.getDatabasename());
- assertEquals(true, configuration.isEnablessl());
- assertEquals("kpi config", configuration.getKpiConfig());
- assertEquals(10, configuration.getCbsPollingInterval());
+ assertEquals("password", configuration.getPassword());
+ assertEquals("database", configuration.getDatabasename());
+ assertEquals(true, configuration.isEnablessl());
+ assertEquals("kpi config", configuration.getKpiConfig());
+ assertEquals(10, configuration.getCbsPollingInterval());
}
-
@Test
public void updateConfigFromPolicyTest() {
- String strKpiConfig = FileUtils.getFileContents(KPI_CONFIG_FILE);
- configuration.setKpiConfig(strKpiConfig);
- assertEquals(strKpiConfig, configuration.getKpiConfig());
+ String strKpiConfig = FileUtils.getFileContents(KPI_CONFIG_FILE);
+ configuration.setKpiConfig(strKpiConfig);
+ assertEquals(strKpiConfig, configuration.getKpiConfig());
+ }
+ @Test
+ public void testNullFields() {
+ String strCbsConfig = FileUtils.getFileContents(CBS_CONFIG_FILE);
+ JsonObject jsonObject = new JsonParser().parse(strCbsConfig).getAsJsonObject().getAsJsonObject("config");
+ Configuration config = new Configuration();
+ config.updateConfigurationFromJsonObject(jsonObject);
+ assertNull(config.getAafUsername());
+ assertNull(config.getAafPassword());
}
}
diff --git a/components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/utils/BeanUtilTest.java b/components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/utils/BeanUtilTest.java
new file mode 100644
index 00000000..681091a2
--- /dev/null
+++ b/components/kpi-computation-ms/src/test/java/org/onap/dcaegen2/kpi/utils/BeanUtilTest.java
@@ -0,0 +1,39 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022 Wipro Limited.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.kpi.utils;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.context.ApplicationContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.AnnotationConfigContextLoader;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes=BeanUtil.class, loader=AnnotationConfigContextLoader.class)
+public class BeanUtilTest {
+ @Test
+ public void testBeanUtils() {
+ assertNotNull(ApplicationContext.class);
+ }
+}
diff --git a/components/kpi-computation-ms/src/test/resources/kpi/cbs_config4.json b/components/kpi-computation-ms/src/test/resources/kpi/cbs_config4.json
new file mode 100644
index 00000000..b2649ec3
--- /dev/null
+++ b/components/kpi-computation-ms/src/test/resources/kpi/cbs_config4.json
@@ -0,0 +1,36 @@
+{
+ "config": {
+ "pollingInterval": 20,
+ "cbsPollingInterval": 60,
+ "mongo.host": "192.168.225.61",
+ "cid": "kpi-cid",
+ "trust_store_pass_path": "/opt/app/kpims/etc/cert/trust.pass",
+ "cg": "kpi-cg",
+ "mongo.port": 27017,
+ "mongo.databasename": "datalake",
+ "streams_subscribes": {
+ "performance_management_topic": {
+ "aaf_password": "demo123456!",
+ "type": "message-router",
+ "dmaap_info": {
+ "topic_url": "https://message-router.onap.svc.cluster.local:3905/events/org.onap.dmaap.mr.PERFORMANCE_MEASUREMENTS"
+ },
+ "aaf_username": "dcae@dcae.onap.org"
+ }
+ },
+ "trust_store_path": "/opt/app/kpims/etc/cert/trust.jks",
+ "pollingTimeout": 60,
+ "streams_publishes": {
+ "kpi_topic": {
+ "aaf_password": "demo123456!",
+ "type": "message-router",
+ "dmaap_info": {
+ "topic_url": "https://message-router.onap.svc.cluster.local:3905/events/unauthenticated.DCAE_KPI_OUTPUT"
+ },
+ "aaf_username": "dcae@dcae.onap.org"
+ }
+ },
+ "kpi.policy": "{\"domain\":\"measurementsForKpi\",\"methodForKpi\":[{\"eventName\":\"perf3gpp_CORE-AMF_pmMeasResult\",\"controlLoopSchemaType\":\"SLICE\",\"policyScope\":\"resource=networkSlice;type=configuration\",\"policyName\":\"configuration.dcae.microservice.pm-mapper.xml\",\"policyVersion\":\"v0.0.1\",\"kpis\":[{\"measType\":\"AMFRegNbr\",\"operation\":\"SUM\",\"operands\":[\"RM.RegisteredSubNbrMean\"]}]},{\"eventName\":\"perf3gpp_AcmeNode-Acme_pmMeasResult\",\"controlLoopSchemaType\":\"SLICE\",\"policyScope\":\"resource=networkSlice;type=configuration\",\"policyName\":\"configuration.dcae.microservice.pm-mapper.xml\",\"policyVersion\":\"v0.0.1\",\"kpis\":[{\"measType\":\"UpstreamThr\",\"operation\":\"SUMRATIO\",\"operands\":[\"GTP.InDataOctN3UPF\",\"GTP.OutDataOctN3UPF\"]},{\"measType\":\"DownstreamThr\",\"operation\":\"SUMRATIO\",\"operands\":[\"GTP.InDataOctN3UPF\",\"GTP.OutDataOctN3UPF\"]}]}]}",
+ "dmaap.server": ["message-router"]
+ }
+}
diff --git a/components/kpi-computation-ms/src/test/resources/kpi/ves_message_missing_field.json b/components/kpi-computation-ms/src/test/resources/kpi/ves_message_missing_field.json
new file mode 100644
index 00000000..9e8a56fb
--- /dev/null
+++ b/components/kpi-computation-ms/src/test/resources/kpi/ves_message_missing_field.json
@@ -0,0 +1,82 @@
+{
+ "event":{
+ "commonEventHeader":{
+ "domain":"perf3gpp",
+ "eventId":"14618daf-c0ce-4ccc-9169-9e1ac79971f2",
+ "sequence":0,
+ "sourceName":"oteNB5309",
+ "reportingEntityName":"",
+ "priority":"Normal",
+ "startEpochMicrosec":1591099200000,
+ "lastEpochMicrosec":1591100100000,
+ "version":"4.0",
+ "vesEventListenerVersion":"7.1",
+ "timeZoneOffset":"UTC+05:00"
+ },
+ "perf3gppFields":{
+ "perf3gppFieldsVersion":"1.0",
+ "measDataCollection":{
+ "granularityPeriod":1591100100000,
+ "measuredEntityUserName":"",
+ "measuredEntityDn":"UPFMeasurement",
+ "measuredEntitySoftwareVersion":"r0.1",
+ "measInfoList":[
+ {
+ "measInfoId":{
+ "sMeasInfoId":"UPFFunction0"
+ },
+ "measTypes":{
+ "sMeasTypesList":[
+ "GTP.InDataOctN3UPF.08_010101",
+ "GTP.OutDataOctN3UPF.08_010101"
+ ]
+ },
+ "measValuesList":[
+ {
+ "measObjInstId":"some measObjLdn",
+ "suspectFlag":"false",
+ "measResults":[
+ {
+ "p":1,
+ "sValue":"10"
+ },
+ {
+ "p":2,
+ "sValue":"20"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "measInfoId":{
+ "sMeasInfoId":"UPFFunction1"
+ },
+ "measTypes":{
+ "sMeasTypesList":[
+ "GTP.InDataOctN3UPF.08_010101",
+ "GTP.OutDataOctN3UPF.08_010101"
+ ]
+ },
+ "measValuesList":[
+ {
+ "measObjInstId":"some measObjLdn",
+ "suspectFlag":"false",
+ "measResults":[
+ {
+ "p":1,
+ "sValue":"30"
+ },
+ {
+ "p":2,
+ "sValue":"40"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/components/kpi-computation-ms/version.properties b/components/kpi-computation-ms/version.properties
index be3c3ddd..7cecbb45 100644
--- a/components/kpi-computation-ms/version.properties
+++ b/components/kpi-computation-ms/version.properties
@@ -21,7 +21,7 @@
###############################################################################
major=1
minor=0
-patch=5
+patch=6
base_version=${major}.${minor}.${patch}
release_version=${base_version}
snapshot_version=${base_version}-SNAPSHOT