/*
 * This file is part of Dependency-Track.
 *
 * 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
 * Copyright (c) Steve Springett. All Rights Reserved.
 */
package org.dependencytrack.resources.v1;

import alpine.filters.AuthenticationFilter;
import alpine.util.UuidUtil;
import org.dependencytrack.ResourceTest;
import org.dependencytrack.model.AnalysisState;
import org.dependencytrack.model.Component;
import org.dependencytrack.model.Project;
import org.dependencytrack.model.Severity;
import org.dependencytrack.model.Vulnerability;
import org.dependencytrack.persistence.CweImporter;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.test.DeploymentContext;
import org.glassfish.jersey.test.ServletDeploymentContext;
import org.junit.Assert;
import org.junit.Test;
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.UUID;

public class VulnerabilityResourceTest extends ResourceTest {

    @Override
    protected DeploymentContext configureDeployment() {
        return ServletDeploymentContext.forServlet(new ServletContainer(
                new ResourceConfig(VulnerabilityResource.class)
                        .register(AuthenticationFilter.class)))
                .build();
    }

    @Test
    public void getVulnerabilitiesByComponentUuidTest() throws Exception {
        SampleData sampleData = new SampleData();
        Response response = target(V1_VULNERABILITY + "/component/" + sampleData.c1.getUuid().toString()).request()
                .header(X_API_KEY, apiKey)
                .get(Response.class);
        Assert.assertEquals(200, response.getStatus(), 0);
        Assert.assertEquals(String.valueOf(2), response.getHeaderString(TOTAL_COUNT_HEADER));
        JsonArray json = parseJsonArray(response);
        Assert.assertNotNull(json);
        Assert.assertEquals(2, json.size());
        Assert.assertEquals("INT-1", json.getJsonObject(0).getString("vulnId"));
        Assert.assertEquals("INTERNAL", json.getJsonObject(0).getString("source"));
        Assert.assertEquals("Description 1", json.getJsonObject(0).getString("description"));
        Assert.assertEquals("CRITICAL", json.getJsonObject(0).getString("severity"));
        Assert.assertTrue(UuidUtil.isValidUUID(json.getJsonObject(0).getString("uuid")));
        Assert.assertEquals("INT-2", json.getJsonObject(1).getString("vulnId"));
        Assert.assertEquals("INTERNAL", json.getJsonObject(1).getString("source"));
        Assert.assertEquals("Description 2", json.getJsonObject(1).getString("description"));
        Assert.assertEquals("HIGH", json.getJsonObject(1).getString("severity"));
        Assert.assertTrue(UuidUtil.isValidUUID(json.getJsonObject(1).getString("uuid")));
    }

    @Test
    public void getVulnerabilitiesByComponentMd5Test() throws Exception {
        SampleData sampleData = new SampleData();
        Response response = target(V1_VULNERABILITY + "/component/" + sampleData.c1.getMd5()).request()
                .header(X_API_KEY, apiKey)
                .get(Response.class);
        Assert.assertEquals(200, response.getStatus(), 0);
        Assert.assertEquals(String.valueOf(2), response.getHeaderString(TOTAL_COUNT_HEADER));
        JsonArray json = parseJsonArray(response);
        Assert.assertNotNull(json);
        Assert.assertEquals(2, json.size());
        Assert.assertEquals("INT-1", json.getJsonObject(0).getString("vulnId"));
        Assert.assertEquals("INTERNAL", json.getJsonObject(0).getString("source"));
        Assert.assertEquals("Description 1", json.getJsonObject(0).getString("description"));
        Assert.assertEquals("CRITICAL", json.getJsonObject(0).getString("severity"));
        Assert.assertTrue(UuidUtil.isValidUUID(json.getJsonObject(0).getString("uuid")));
        Assert.assertEquals("INT-2", json.getJsonObject(1).getString("vulnId"));
        Assert.assertEquals("INTERNAL", json.getJsonObject(1).getString("source"));
        Assert.assertEquals("Description 2", json.getJsonObject(1).getString("description"));
        Assert.assertEquals("HIGH", json.getJsonObject(1).getString("severity"));
        Assert.assertTrue(UuidUtil.isValidUUID(json.getJsonObject(1).getString("uuid")));
    }

    @Test
    public void getVulnerabilitiesByComponentSha1Test() throws Exception {
        SampleData sampleData = new SampleData();
        Response response = target(V1_VULNERABILITY + "/component/" + sampleData.c1.getSha1()).request()
                .header(X_API_KEY, apiKey)
                .get(Response.class);
        Assert.assertEquals(200, response.getStatus(), 0);
        Assert.assertEquals(String.valueOf(2), response.getHeaderString(TOTAL_COUNT_HEADER));
        JsonArray json = parseJsonArray(response);
        Assert.assertNotNull(json);
        Assert.assertEquals(2, json.size());
        Assert.assertEquals("INT-1", json.getJsonObject(0).getString("vulnId"));
        Assert.assertEquals("INTERNAL", json.getJsonObject(0).getString("source"));
        Assert.assertEquals("Description 1", json.getJsonObject(0).getString("description"));
        Assert.assertEquals("CRITICAL", json.getJsonObject(0).getString("severity"));
        Assert.assertTrue(UuidUtil.isValidUUID(json.getJsonObject(0).getString("uuid")));
        Assert.assertEquals("INT-2", json.getJsonObject(1).getString("vulnId"));
        Assert.assertEquals("INTERNAL", json.getJsonObject(1).getString("source"));
        Assert.assertEquals("Description 2", json.getJsonObject(1).getString("description"));
        Assert.assertEquals("HIGH", json.getJsonObject(1).getString("severity"));
        Assert.assertTrue(UuidUtil.isValidUUID(json.getJsonObject(1).getString("uuid")));
    }

    @Test
    public void getVulnerabilitiesByComponentInvalidTest() throws Exception  {
        new SampleData();
        Response response = target(V1_VULNERABILITY + "/component/" + "jklfdjklfjaklfla").request()
                .header(X_API_KEY, apiKey)
                .get(Response.class);
        Assert.assertEquals(404, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        String body = getPlainTextBody(response);
        Assert.assertEquals("The component could not be found.", body);
    }

    @Test
    public void getVulnerabilitiesByComponentUuidIncludeSuppressedTest() throws Exception {
        SampleData sampleData = new SampleData();
        Response response = target(V1_VULNERABILITY + "/component/" + sampleData.c1.getUuid().toString())
                .queryParam("suppressed", "true")
                .request()
                .header(X_API_KEY, apiKey)
                .get(Response.class);
        Assert.assertEquals(200, response.getStatus(), 0);
        Assert.assertEquals(String.valueOf(3), response.getHeaderString(TOTAL_COUNT_HEADER));
        JsonArray json = parseJsonArray(response);
        Assert.assertNotNull(json);
        Assert.assertEquals(3, json.size());
        Assert.assertEquals("INT-1", json.getJsonObject(0).getString("vulnId"));
        Assert.assertEquals("INTERNAL", json.getJsonObject(0).getString("source"));
        Assert.assertEquals("Description 1", json.getJsonObject(0).getString("description"));
        Assert.assertEquals("CRITICAL", json.getJsonObject(0).getString("severity"));
        Assert.assertTrue(UuidUtil.isValidUUID(json.getJsonObject(0).getString("uuid")));
        Assert.assertEquals("INT-2", json.getJsonObject(1).getString("vulnId"));
        Assert.assertEquals("INTERNAL", json.getJsonObject(1).getString("source"));
        Assert.assertEquals("Description 2", json.getJsonObject(1).getString("description"));
        Assert.assertEquals("HIGH", json.getJsonObject(1).getString("severity"));
        Assert.assertTrue(UuidUtil.isValidUUID(json.getJsonObject(1).getString("uuid")));
        Assert.assertEquals("INT-3", json.getJsonObject(2).getString("vulnId"));
        Assert.assertEquals("INTERNAL", json.getJsonObject(2).getString("source"));
        Assert.assertEquals("Description 3", json.getJsonObject(2).getString("description"));
        Assert.assertEquals("MEDIUM", json.getJsonObject(2).getString("severity"));
        Assert.assertTrue(UuidUtil.isValidUUID(json.getJsonObject(2).getString("uuid")));
    }

    @Test
    public void getVulnerabilitiesByProjectTest() throws Exception {
        SampleData sampleData = new SampleData();
        Response response = target(V1_VULNERABILITY + "/project/" + sampleData.p1.getUuid().toString()).request()
                .header(X_API_KEY, apiKey)
                .get(Response.class);
        Assert.assertEquals(200, response.getStatus(), 0);
        Assert.assertEquals(String.valueOf(4), response.getHeaderString(TOTAL_COUNT_HEADER));
        JsonArray json = parseJsonArray(response);
        Assert.assertNotNull(json);
        Assert.assertEquals(4, json.size());
        Assert.assertEquals("INT-1", json.getJsonObject(0).getString("vulnId"));
        Assert.assertEquals("INTERNAL", json.getJsonObject(0).getString("source"));
        Assert.assertEquals("Description 1", json.getJsonObject(0).getString("description"));
        Assert.assertEquals("CRITICAL", json.getJsonObject(0).getString("severity"));
        Assert.assertTrue(UuidUtil.isValidUUID(json.getJsonObject(0).getString("uuid")));
        Assert.assertEquals("INT-2", json.getJsonObject(1).getString("vulnId"));
        Assert.assertEquals("INTERNAL", json.getJsonObject(1).getString("source"));
        Assert.assertEquals("Description 2", json.getJsonObject(1).getString("description"));
        Assert.assertEquals("HIGH", json.getJsonObject(1).getString("severity"));
        Assert.assertTrue(UuidUtil.isValidUUID(json.getJsonObject(1).getString("uuid")));
        Assert.assertEquals("INT-4", json.getJsonObject(2).getString("vulnId"));
        Assert.assertEquals("INTERNAL", json.getJsonObject(2).getString("source"));
        Assert.assertEquals("Description 4", json.getJsonObject(2).getString("description"));
        Assert.assertEquals("LOW", json.getJsonObject(2).getString("severity"));
        Assert.assertTrue(UuidUtil.isValidUUID(json.getJsonObject(2).getString("uuid")));
        Assert.assertEquals("INT-5", json.getJsonObject(3).getString("vulnId"));
        Assert.assertEquals("INTERNAL", json.getJsonObject(3).getString("source"));
        Assert.assertEquals("Description 5", json.getJsonObject(3).getString("description"));
        Assert.assertEquals("CRITICAL", json.getJsonObject(3).getString("severity"));
        Assert.assertTrue(UuidUtil.isValidUUID(json.getJsonObject(3).getString("uuid")));
    }

    @Test
    public void getVulnerabilitiesByProjectIncludeGlobalSuppressedTest() throws Exception {
        SampleData sampleData = new SampleData();
        Response response = target(V1_VULNERABILITY + "/project/" + sampleData.p1.getUuid().toString())
                .queryParam("suppressed", "true")
                .request()
                .header(X_API_KEY, apiKey)
                .get(Response.class);
        Assert.assertEquals(200, response.getStatus(), 0);
        //Assert.assertEquals(String.valueOf(4), response.getHeaderString(TOTAL_COUNT_HEADER));
        JsonArray json = parseJsonArray(response);
        Assert.assertNotNull(json);
        Assert.assertEquals(5, json.size());
        Assert.assertEquals("INT-1", json.getJsonObject(0).getString("vulnId"));
        Assert.assertEquals("INT-2", json.getJsonObject(1).getString("vulnId"));
        Assert.assertEquals("INT-3", json.getJsonObject(2).getString("vulnId"));
        Assert.assertEquals("INT-4", json.getJsonObject(3).getString("vulnId"));
        Assert.assertEquals("INT-5", json.getJsonObject(4).getString("vulnId"));
    }

    @Test
    public void getVulnerabilitiesByProjectIncludeProjectSuppressedTest() throws Exception {
        SampleData sampleData = new SampleData();
        Response response = target(V1_VULNERABILITY + "/project/" + sampleData.p2.getUuid().toString())
                .queryParam("suppressed", "true")
                .request()
                .header(X_API_KEY, apiKey)
                .get(Response.class);
        Assert.assertEquals(200, response.getStatus(), 0);
        Assert.assertEquals(String.valueOf(2), response.getHeaderString(TOTAL_COUNT_HEADER));
        JsonArray json = parseJsonArray(response);
        Assert.assertNotNull(json);
        Assert.assertEquals(2, json.size());
        Assert.assertEquals("INT-4", json.getJsonObject(0).getString("vulnId"));
        Assert.assertEquals("INT-5", json.getJsonObject(1).getString("vulnId"));
    }

    @Test
    public void getVulnerabilitiesByProjectInvalidTest() throws Exception {
        new SampleData();
        Response response = target(V1_VULNERABILITY + "/project/" + UUID.randomUUID().toString()).request()
                .header(X_API_KEY, apiKey)
                .get(Response.class);
        Assert.assertEquals(404, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        String body = getPlainTextBody(response);
        Assert.assertEquals("The project could not be found.", body);
    }

    @Test
    public void getVulnerabilityByUuidTest() throws Exception {
        SampleData sampleData = new SampleData();
        Response response = target(V1_VULNERABILITY + "/" + sampleData.v1.getUuid().toString()).request()
                .header(X_API_KEY, apiKey)
                .get(Response.class);
        Assert.assertEquals(200, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        JsonObject json = parseJsonObject(response);
        Assert.assertNotNull(json);
        Assert.assertEquals("INT-1", json.getString("vulnId"));
    }

    @Test
    public void getVulnerabilityByUuidInvalidTest() throws Exception {
        new SampleData();
        Response response = target(V1_VULNERABILITY + "/" + UUID.randomUUID().toString()).request()
                .header(X_API_KEY, apiKey)
                .get(Response.class);
        Assert.assertEquals(404, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        String body = getPlainTextBody(response);
        Assert.assertEquals("The vulnerability could not be found.", body);
    }

    @Test
    public void getVulnerabilityByVulnIdTest() throws Exception {
        SampleData sampleData = new SampleData();
        Response response = target(V1_VULNERABILITY + "/source/" + sampleData.v1.getSource() + "/vuln/" + sampleData.v1.getVulnId()).request()
                .header(X_API_KEY, apiKey)
                .get(Response.class);
        Assert.assertEquals(200, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        JsonObject json = parseJsonObject(response);
        Assert.assertNotNull(json);
        Assert.assertEquals("INT-1", json.getString("vulnId"));
    }

    @Test
    public void getVulnerabilityByVulnIdInvalidTest() throws Exception {
        new SampleData();
        Response response = target(V1_VULNERABILITY + "/source/INTERNAL/vuln/blah").request()
                .header(X_API_KEY, apiKey)
                .get(Response.class);
        Assert.assertEquals(404, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        String body = getPlainTextBody(response);
        Assert.assertEquals("The vulnerability could not be found.", body);
    }

    @Test
    public void getAffectedProjectTest() throws Exception {
        SampleData sampleData = new SampleData();
        Response response = target(V1_VULNERABILITY + "/source/" + sampleData.v1.getSource() + "/vuln/" + sampleData.v1.getVulnId() + "/projects").request()
                .header(X_API_KEY, apiKey)
                .get(Response.class);
        Assert.assertEquals(200, response.getStatus(), 0);
        Assert.assertEquals(String.valueOf(1), response.getHeaderString(TOTAL_COUNT_HEADER));
        JsonArray json = parseJsonArray(response);
        Assert.assertNotNull(json);
        Assert.assertEquals("Project 1", json.getJsonObject(0).getString("name"));
        Assert.assertEquals(sampleData.p1.getUuid().toString(), json.getJsonObject(0).getString("uuid"));
    }

    @Test
    public void getAffectedProjectInvalidTest() throws Exception {
        new SampleData();
        Response response = target(V1_VULNERABILITY + "/source/INTERNAL/vuln/blah/projects").request()
                .header(X_API_KEY, apiKey)
                .get(Response.class);
        Assert.assertEquals(404, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        String body = getPlainTextBody(response);
        Assert.assertEquals("The vulnerability could not be found.", body);
    }

    @Test
    public void getAllVulnerabilitiesTest() throws Exception {
        new SampleData();
        Response response = target(V1_VULNERABILITY).request()
                .header(X_API_KEY, apiKey)
                .get(Response.class);
        Assert.assertEquals(200, response.getStatus(), 0);
        Assert.assertEquals(String.valueOf(5), response.getHeaderString(TOTAL_COUNT_HEADER));
        JsonArray json = parseJsonArray(response);
        Assert.assertNotNull(json);
        Assert.assertEquals(5, json.size());
        Assert.assertEquals("INT-1", json.getJsonObject(0).getString("vulnId"));
        Assert.assertEquals("INT-2", json.getJsonObject(1).getString("vulnId"));
        Assert.assertEquals("INT-3", json.getJsonObject(2).getString("vulnId"));
        Assert.assertEquals("INT-4", json.getJsonObject(3).getString("vulnId"));
        Assert.assertEquals("INT-5", json.getJsonObject(4).getString("vulnId"));
    }

    @Test
    public void createVulnerabilityTest() throws Exception {
        new CweImporter().processCweDefinitions();
        JsonObject payload = Json.createObjectBuilder()
                .add("vulnId", "ACME-1")
                .add("description", "Something is vulnerable")
                .add("cwe", Json.createObjectBuilder().add("cweId", 80))
                .add("cvssV2Vector", "(AV:N/AC:M/Au:S/C:P/I:P/A:P)")
                .add("cvssV3Vector", "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L")
                .build();
        Response response = target(V1_VULNERABILITY).request()
                .header(X_API_KEY, apiKey)
                .put(Entity.json(payload.toString()));
        Assert.assertEquals(201, response.getStatus(), 0);
        JsonObject json = parseJsonObject(response);
        Assert.assertNotNull(json);
        Assert.assertEquals("ACME-1", json.getString("vulnId"));
        Assert.assertEquals("INTERNAL", json.getString("source"));
        Assert.assertEquals("Something is vulnerable", json.getString("description"));
        Assert.assertEquals(6.0, json.getJsonNumber("cvssV2BaseScore").doubleValue(), 0);
        Assert.assertEquals(6.4, json.getJsonNumber("cvssV2ImpactSubScore").doubleValue(), 0);
        Assert.assertEquals(6.8, json.getJsonNumber("cvssV2ExploitabilitySubScore").doubleValue(), 0);
        Assert.assertEquals("(AV:N/AC:M/Au:S/C:P/I:P/A:P)", json.getString("cvssV2Vector"));
        Assert.assertEquals(6.3, json.getJsonNumber("cvssV3BaseScore").doubleValue(), 0);
        Assert.assertEquals(3.4, json.getJsonNumber("cvssV3ImpactSubScore").doubleValue(), 0);
        Assert.assertEquals(2.8, json.getJsonNumber("cvssV3ExploitabilitySubScore").doubleValue(), 0);
        Assert.assertEquals("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L", json.getString("cvssV3Vector"));
        Assert.assertEquals("MEDIUM", json.getString("severity"));
        Assert.assertEquals(80, json.getJsonObject("cwe").getInt("cweId"));
        Assert.assertEquals("Improper Neutralization of Script-Related HTML Tags in a Web Page (Basic XSS)", json.getJsonObject("cwe").getString("name"));
        Assert.assertTrue(UuidUtil.isValidUUID(json.getString("uuid")));
    }

    @Test
    public void createVulnerabilityDuplicateTest() {
        Vulnerability vuln = new Vulnerability();
        vuln.setVulnId("ACME-1");
        vuln.setSource(Vulnerability.Source.INTERNAL);
        qm.createVulnerability(vuln, false);
        JsonObject payload = Json.createObjectBuilder()
                .add("vulnId", "ACME-1")
                .add("description", "Something is vulnerable")
                .add("cwe", Json.createObjectBuilder().add("cweId", 80))
                .add("cvssV2Vector", "(AV:N/AC:M/Au:S/C:P/I:P/A:P)")
                .add("cvssV3Vector", "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L")
                .build();
        Response response = target(V1_VULNERABILITY).request()
                .header(X_API_KEY, apiKey)
                .put(Entity.json(payload.toString()));
        Assert.assertEquals(409, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        String body = getPlainTextBody(response);
        Assert.assertEquals("A vulnerability with the specified vulnId already exists.", body);
    }

    @Test
    public void updateVulnerabilityTest() throws Exception {
        new CweImporter().processCweDefinitions();
        Vulnerability vuln = new Vulnerability();
        vuln.setVulnId("ACME-1");
        vuln.setSource(Vulnerability.Source.INTERNAL);
        vuln = qm.createVulnerability(vuln, false);
        JsonObject payload = Json.createObjectBuilder()
                .add("vulnId", "ACME-1")
                .add("source", "INTERNAL")
                .add("description", "Something is vulnerable")
                .add("cwe", Json.createObjectBuilder().add("cweId", 80))
                .add("cvssV2Vector", "(AV:N/AC:M/Au:S/C:P/I:P/A:P)")
                .add("cvssV3Vector", "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L")
                .add("uuid", vuln.getUuid().toString())
                .build();
        Response response = target(V1_VULNERABILITY).request()
                .header(X_API_KEY, apiKey)
                .post(Entity.json(payload.toString()));
        Assert.assertEquals(200, response.getStatus(), 0);
        JsonObject json = parseJsonObject(response);
        Assert.assertNotNull(json);
        Assert.assertEquals("ACME-1", json.getString("vulnId"));
        Assert.assertEquals("INTERNAL", json.getString("source"));
        Assert.assertEquals("Something is vulnerable", json.getString("description"));
        Assert.assertEquals(6.0, json.getJsonNumber("cvssV2BaseScore").doubleValue(), 0);
        Assert.assertEquals(6.4, json.getJsonNumber("cvssV2ImpactSubScore").doubleValue(), 0);
        Assert.assertEquals(6.8, json.getJsonNumber("cvssV2ExploitabilitySubScore").doubleValue(), 0);
        Assert.assertEquals("(AV:N/AC:M/Au:S/C:P/I:P/A:P)", json.getString("cvssV2Vector"));
        Assert.assertEquals(6.3, json.getJsonNumber("cvssV3BaseScore").doubleValue(), 0);
        Assert.assertEquals(3.4, json.getJsonNumber("cvssV3ImpactSubScore").doubleValue(), 0);
        Assert.assertEquals(2.8, json.getJsonNumber("cvssV3ExploitabilitySubScore").doubleValue(), 0);
        Assert.assertEquals("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L", json.getString("cvssV3Vector"));
        Assert.assertEquals("MEDIUM", json.getString("severity"));
        Assert.assertEquals(80, json.getJsonObject("cwe").getInt("cweId"));
        Assert.assertEquals("Improper Neutralization of Script-Related HTML Tags in a Web Page (Basic XSS)", json.getJsonObject("cwe").getString("name"));
        Assert.assertTrue(UuidUtil.isValidUUID(json.getString("uuid")));
    }

    @Test
    public void updateVulnerabilityInvalidTest() {
        JsonObject payload = Json.createObjectBuilder()
                .add("vulnId", "ACME-1")
                .add("description", "Something is vulnerable")
                .add("cwe", Json.createObjectBuilder().add("cweId", 80))
                .add("cvssV2Vector", "(AV:N/AC:M/Au:S/C:P/I:P/A:P)")
                .add("cvssV3Vector", "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L")
                .add("uuid", UUID.randomUUID().toString())
                .build();
        Response response = target(V1_VULNERABILITY).request()
                .header(X_API_KEY, apiKey)
                .post(Entity.json(payload.toString()));
        Assert.assertEquals(404, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        String body = getPlainTextBody(response);
        Assert.assertEquals("The vulnerability could not be found.", body);
    }

    @Test
    public void updateVulnerabilityUnchangableTest() {
        Vulnerability vuln = new Vulnerability();
        vuln.setVulnId("ACME-1");
        vuln.setSource(Vulnerability.Source.INTERNAL);
        qm.createVulnerability(vuln, false);
        JsonObject payload = Json.createObjectBuilder()
                .add("vulnId", "ACME-2")
                .add("description", "Something is vulnerable")
                .add("cwe", Json.createObjectBuilder().add("cweId", 80))
                .add("cvssV2Vector", "(AV:N/AC:M/Au:S/C:P/I:P/A:P)")
                .add("cvssV3Vector", "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L")
                .add("uuid", vuln.getUuid().toString())
                .build();
        Response response = target(V1_VULNERABILITY).request()
                .header(X_API_KEY, apiKey)
                .post(Entity.json(payload.toString()));
        Assert.assertEquals(406, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        String body = getPlainTextBody(response);
        Assert.assertEquals("The vulnId may not be changed.", body);
    }

    @Test
    public void assignVulnerabilityTest() {
        Vulnerability vuln = new Vulnerability();
        vuln.setVulnId("ACME-1");
        vuln.setSource(Vulnerability.Source.INTERNAL);
        qm.createVulnerability(vuln, false);
        Component comp = new Component();
        comp.setName("Test Component");
        comp = qm.createComponent(comp, false);
        Response response = target(V1_VULNERABILITY + "/source/INTERNAL/vuln/ACME-1/component/" + comp.getUuid().toString()).request()
                .header(X_API_KEY, apiKey)
                .post(Entity.entity(null, MediaType.APPLICATION_JSON));
        Assert.assertEquals(200, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
    }

    @Test
    public void assignVulnerabilityInvalidVulnerabilityTest() {
        Component comp = new Component();
        comp.setName("Test Component");
        comp = qm.createComponent(comp, false);
        Response response = target(V1_VULNERABILITY + "/source/INTERNAL/vuln/BLAH/component/" + comp.getUuid().toString()).request()
                .header(X_API_KEY, apiKey)
                .post(Entity.entity(null, MediaType.APPLICATION_JSON));
        Assert.assertEquals(404, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        String body = getPlainTextBody(response);
        Assert.assertEquals("The vulnerability could not be found.", body);
    }

    @Test
    public void assignVulnerabilityInvalidComponentTest() {
        Vulnerability vuln = new Vulnerability();
        vuln.setVulnId("ACME-1");
        vuln.setSource(Vulnerability.Source.INTERNAL);
        qm.createVulnerability(vuln, false);
        Response response = target(V1_VULNERABILITY + "/source/INTERNAL/vuln/ACME-1/component/" + UUID.randomUUID().toString()).request()
                .header(X_API_KEY, apiKey)
                .post(Entity.entity(null, MediaType.APPLICATION_JSON));
        Assert.assertEquals(404, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        String body = getPlainTextBody(response);
        Assert.assertEquals("The component could not be found.", body);
    }

    @Test
    public void assignVulnerabilityByUuidTest() {
        Vulnerability vuln = new Vulnerability();
        vuln.setVulnId("ACME-1");
        vuln.setSource(Vulnerability.Source.INTERNAL);
        vuln = qm.createVulnerability(vuln, false);
        Component comp = new Component();
        comp.setName("Test Component");
        comp = qm.createComponent(comp, false);
        Response response = target(V1_VULNERABILITY + "/" + vuln.getUuid().toString() + "/component/" + comp.getUuid().toString()).request()
                .header(X_API_KEY, apiKey)
                .post(Entity.entity(null, MediaType.APPLICATION_JSON));
        Assert.assertEquals(200, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
    }

    @Test
    public void assignVulnerabilityByUuidInvalidVulnerabilityTest() {
        Component comp = new Component();
        comp.setName("Test Component");
        comp = qm.createComponent(comp, false);
        Response response = target(V1_VULNERABILITY + "/" + UUID.randomUUID().toString() + "/component/" + comp.getUuid().toString()).request()
                .header(X_API_KEY, apiKey)
                .post(Entity.entity(null, MediaType.APPLICATION_JSON));
        Assert.assertEquals(404, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        String body = getPlainTextBody(response);
        Assert.assertEquals("The vulnerability could not be found.", body);
    }

    @Test
    public void assignVulnerabilityByUuidInvalidComponentTest() {
        Vulnerability vuln = new Vulnerability();
        vuln.setVulnId("ACME-1");
        vuln.setSource(Vulnerability.Source.INTERNAL);
        vuln = qm.createVulnerability(vuln, false);
        Response response = target(V1_VULNERABILITY + "/" + vuln.getUuid().toString() + "/component/" + UUID.randomUUID().toString()).request()
                .header(X_API_KEY, apiKey)
                .post(Entity.entity(null, MediaType.APPLICATION_JSON));
        Assert.assertEquals(404, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        String body = getPlainTextBody(response);
        Assert.assertEquals("The component could not be found.", body);
    }

    @Test
    public void unassignVulnerabilityTest() {
        Vulnerability vuln = new Vulnerability();
        vuln.setVulnId("ACME-1");
        vuln.setSource(Vulnerability.Source.INTERNAL);
        qm.createVulnerability(vuln, false);
        Component comp = new Component();
        comp.setName("Test Component");
        comp = qm.createComponent(comp, false);
        Response response = target(V1_VULNERABILITY + "/source/INTERNAL/vuln/ACME-1/component/" + comp.getUuid().toString()).request()
                .header(X_API_KEY, apiKey)
                .delete();
        Assert.assertEquals(200, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
    }

    @Test
    public void unassignVulnerabilityInvalidVulnerabilityTest() {
        Component comp = new Component();
        comp.setName("Test Component");
        comp = qm.createComponent(comp, false);
        Response response = target(V1_VULNERABILITY + "/source/INTERNAL/vuln/BLAH/component/" + comp.getUuid().toString()).request()
                .header(X_API_KEY, apiKey)
                .delete();
        Assert.assertEquals(404, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        String body = getPlainTextBody(response);
        Assert.assertEquals("The vulnerability could not be found.", body);
    }

    @Test
    public void unassignVulnerabilityInvalidComponentTest() {
        Vulnerability vuln = new Vulnerability();
        vuln.setVulnId("ACME-1");
        vuln.setSource(Vulnerability.Source.INTERNAL);
        qm.createVulnerability(vuln, false);
        Response response = target(V1_VULNERABILITY + "/source/INTERNAL/vuln/ACME-1/component/" + UUID.randomUUID().toString()).request()
                .header(X_API_KEY, apiKey)
                .delete();
        Assert.assertEquals(404, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        String body = getPlainTextBody(response);
        Assert.assertEquals("The component could not be found.", body);
    }

    @Test
    public void unassignVulnerabilityByUuidTest() {
        Vulnerability vuln = new Vulnerability();
        vuln.setVulnId("ACME-1");
        vuln.setSource(Vulnerability.Source.INTERNAL);
        vuln = qm.createVulnerability(vuln, false);
        Component comp = new Component();
        comp.setName("Test Component");
        comp = qm.createComponent(comp, false);
        Response response = target(V1_VULNERABILITY + "/" + vuln.getUuid().toString() + "/component/" + comp.getUuid().toString()).request()
                .header(X_API_KEY, apiKey)
                .delete();
        Assert.assertEquals(200, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
    }

    @Test
    public void unassignVulnerabilityByUuidInvalidVulnerabilityTest() {
        Component comp = new Component();
        comp.setName("Test Component");
        comp = qm.createComponent(comp, false);
        Response response = target(V1_VULNERABILITY + "/" + UUID.randomUUID().toString() + "/component/" + comp.getUuid().toString()).request()
                .header(X_API_KEY, apiKey)
                .delete();
        Assert.assertEquals(404, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        String body = getPlainTextBody(response);
        Assert.assertEquals("The vulnerability could not be found.", body);
    }

    @Test
    public void unassignVulnerabilityByUuidInvalidComponentTest() {
        Vulnerability vuln = new Vulnerability();
        vuln.setVulnId("ACME-1");
        vuln.setSource(Vulnerability.Source.INTERNAL);
        vuln = qm.createVulnerability(vuln, false);
        Response response = target(V1_VULNERABILITY + "/" + vuln.getUuid().toString() + "/component/" + UUID.randomUUID().toString()).request()
                .header(X_API_KEY, apiKey)
                .delete();
        Assert.assertEquals(404, response.getStatus(), 0);
        Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
        String body = getPlainTextBody(response);
        Assert.assertEquals("The component could not be found.", body);
    }

    private class SampleData {
        final Project p1;
        final Project p2;
        final Component c1;
        final Component c2;
        final Vulnerability v1;
        final Vulnerability v2;
        final Vulnerability v3;
        final Vulnerability v4;
        final Vulnerability v5;

        SampleData() throws Exception {
            new CweImporter().processCweDefinitions();
            c1 = new Component();
            c1.setName("Component 1");
            c1.setMd5("2AAF520D1F19AECF246A0995D91E93A5");
            c1.setSha1("3D5A54669CF8D4ED55B7DF5751FA18C3F72F0CFB");
            c1.setSha256("47602D7DFE910AD941FEA52E85E6E3F1C175434B0E6E261C31C766FE4C078A25");
            c2 = new Component();
            c2.setName("Component 2");
            c1.setMd5("5EABD62FA03D159A96C77E6EEB6C7027");
            c1.setSha1("108BCF94A1C0E0F915B935C97F6BB9E50FB7C246");
            c1.setSha256("418716B003FE0268B6521EF7ACBED13F5BA491D593896D5DEB2058C42D87002D");
            qm.createComponent(c1, false);
            qm.createComponent(c2, false);

            v1 = new Vulnerability();
            v1.setVulnId("INT-1");
            v1.setSource(Vulnerability.Source.INTERNAL);
            v1.setSeverity(Severity.CRITICAL);
            v1.setDescription("Description 1");

            v2 = new Vulnerability();
            v2.setVulnId("INT-2");
            v2.setSource(Vulnerability.Source.INTERNAL);
            v2.setSeverity(Severity.HIGH);
            v2.setDescription("Description 2");

            v3 = new Vulnerability();
            v3.setVulnId("INT-3");
            v3.setSource(Vulnerability.Source.INTERNAL);
            v3.setSeverity(Severity.MEDIUM);
            v3.setDescription("Description 3");

            v4 = new Vulnerability();
            v4.setVulnId("INT-4");
            v4.setSource(Vulnerability.Source.INTERNAL);
            v4.setSeverity(Severity.LOW);
            v4.setDescription("Description 4");

            v5 = new Vulnerability();
            v5.setVulnId("INT-5");
            v5.setSource(Vulnerability.Source.INTERNAL);
            v5.setSeverity(Severity.CRITICAL);
            v5.setDescription("Description 5");

            qm.createVulnerability(v1, false);
            qm.createVulnerability(v2, false);
            qm.createVulnerability(v3, false);
            qm.createVulnerability(v4, false);
            qm.createVulnerability(v5, false);
            qm.addVulnerability(v1, c1);
            qm.addVulnerability(v2, c1);
            qm.addVulnerability(v3, c1);
            qm.addVulnerability(v4, c2);
            qm.addVulnerability(v5, c2);

            p1 = qm.createProject("Project 1", null, null, null, null, null, true, false);
            p2 = qm.createProject("Project 2", null, null, null, null, null, true, false);

            qm.createDependencyIfNotExist(p1, c1, null, null);
            qm.createDependencyIfNotExist(p1, c2, null, null);
            qm.createDependencyIfNotExist(p2, c2, null, null);

            qm.makeAnalysis(null, c1, v3, AnalysisState.FALSE_POSITIVE, true);
            qm.makeAnalysis(p2, c2, v5, AnalysisState.NOT_AFFECTED, true);
        }
    }
}