Skip to content

Commit

Permalink
feat: add generic resource model (#68)
Browse files Browse the repository at this point in the history
* feat: add generic resource model

Signed-off-by: Luca Stocchi <lstocchi@redhat.com>

* add checks for null values

Signed-off-by: Luca Stocchi <lstocchi@redhat.com>

* fix getName and enhance error messages

Signed-off-by: Luca Stocchi <lstocchi@redhat.com>

* fix tests

Signed-off-by: Luca Stocchi <lstocchi@redhat.com>
  • Loading branch information
lstocchi authored Apr 29, 2021
1 parent 5edad62 commit 65a5bc9
Show file tree
Hide file tree
Showing 15 changed files with 360 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*******************************************************************************
* Copyright (c) 2021 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Red Hat, Inc.
******************************************************************************/
package com.redhat.devtools.intellij.common.model;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

@JsonDeserialize(
using = GenericResourceDeserializer.class
)
public class GenericResource {
private String apiVersion, kind;
private JsonNode metadata, spec;

public GenericResource() {}

public GenericResource(String apiVersion, String kind, JsonNode metadata, JsonNode spec) {
this.apiVersion = apiVersion;
this.kind = kind;
this.metadata = metadata;
this.spec = spec;
}

public String getApiVersion() {
return apiVersion;
}

public void setApiVersion(String apiVersion) {
this.apiVersion = apiVersion;
}

public String getKind() {
return kind;
}

public void setKind(String kind) {
this.kind = kind;
}

public String getName() {
if (metadata.has("name")) {
return metadata.get("name").asText();
}
return metadata.get("generateName").asText();
}

public JsonNode getMetadata() {
return metadata;
}

public void setMetadata(JsonNode metadata) {
this.metadata = metadata;
}

public JsonNode getSpec() {
return spec;
}

public void setSpec(JsonNode spec) {
this.spec = spec;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*******************************************************************************
* Copyright (c) 2021 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Red Hat, Inc.
******************************************************************************/
package com.redhat.devtools.intellij.common.model;

import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdNodeBasedDeserializer;

public class GenericResourceDeserializer extends StdNodeBasedDeserializer<GenericResource> {
public GenericResourceDeserializer() {
super(GenericResource.class);
}

@Override
public GenericResource convert(JsonNode root, DeserializationContext ctxt) throws JsonMappingException {
if (!root.has("apiVersion") || !root.hasNonNull("apiVersion")) {
throw new JsonMappingException(ctxt.getParser(), "Resource configuration not valid. ApiVersion is missing or invalid.");
}
if (!root.has("kind") || !root.hasNonNull("kind")) {
throw new JsonMappingException(ctxt.getParser(), "Resource configuration not valid. Resource kind is missing or invalid.");
}
if (!root.has("metadata") || !root.hasNonNull("metadata")) {
throw new JsonMappingException(ctxt.getParser(), "Resource configuration not valid. Metadata field is missing or invalid.");
}
JsonNode metadata = root.get("metadata");
if ((!metadata.has("name") || !metadata.hasNonNull("name"))
&& (!metadata.has("generateName") || !metadata.hasNonNull("generateName"))) {
throw new JsonMappingException(ctxt.getParser(), "Resource configuration not valid. Resource name is missing or invalid.");
}

if (!root.has("spec") || !root.hasNonNull("spec")) {
throw new JsonMappingException(ctxt.getParser(), "Resource configuration not valid. Spec field is missing or invalid.");
}
return new GenericResource(root.get("apiVersion").asText(), root.get("kind").asText(), metadata, root.get("spec"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,15 @@ public class StringHelper {
public static String beautify(String text) {
return text.length() > 16 ? text.substring(0, 16) + ".." : text;
}

public static String getPlural(String kind) {
kind = kind.toLowerCase();
if (kind.endsWith("s")) {
return kind + "es";
} else if (kind.endsWith("y")) {
return kind.substring(0, kind.length() - 1) + "ies";
} else {
return kind + "s";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*******************************************************************************
* Copyright (c) 2021 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Red Hat, Inc.
******************************************************************************/
package com.redhat.devtools.intellij.common.utils.model;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.redhat.devtools.intellij.common.model.GenericResource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.junit.Before;
import org.junit.Test;


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class GenericResourceDeserializerTest {

private ObjectMapper mapper;

@Before
public void setUp() {
mapper = new ObjectMapper(new YAMLFactory());
}

@Test
public void Convert_ResourceHasNoName_Throws() {
try {
String yaml = load("resource_without_name.yaml");
mapper.readValue(yaml, GenericResource.class);
} catch (IOException e) {
assertTrue(e.getLocalizedMessage().contains("Resource configuration not valid. Resource name is missing or invalid."));
}
}

@Test
public void Convert_ResourceHasNullName_Throws() {
try {
String yaml = load("resource_with_null_name.yaml");
mapper.readValue(yaml, GenericResource.class);
} catch (IOException e) {
assertTrue(e.getLocalizedMessage().contains("Resource configuration not valid. Resource name is missing or invalid."));
}
}

@Test
public void Convert_ResourceHasNoKind_Throws() {
try {
mapper.readValue(load("resource_without_kind.yaml"), GenericResource.class);
} catch (IOException e) {
assertTrue(e.getLocalizedMessage().contains("Resource configuration not valid. Resource kind is missing or invalid."));
}
}

@Test
public void Convert_ResourceHasNullKind_Throws() {
try {
mapper.readValue(load("resource_with_null_kind.yaml"), GenericResource.class);
} catch (IOException e) {
assertTrue(e.getLocalizedMessage().contains("Resource configuration not valid. Resource kind is missing or invalid."));
}
}

@Test
public void Convert_ResourceHasNoApiVersion_Throws() {
try {
mapper.readValue(load("resource_without_apiversion.yaml"), GenericResource.class);
} catch (IOException e) {
assertTrue(e.getLocalizedMessage().contains("Resource configuration not valid. ApiVersion is missing or invalid."));
}
}

@Test
public void Convert_ResourceHasNullApiVersion_Throws() {
try {
mapper.readValue(load("resource_with_null_apiversion.yaml"), GenericResource.class);
} catch (IOException e) {
assertTrue(e.getLocalizedMessage().contains("Resource configuration not valid. ApiVersion is missing or invalid."));
}
}

@Test
public void Convert_ResourceHasNoMetadataSection_Throws() {
try {
mapper.readValue(load("resource_without_metadata.yaml"), GenericResource.class);
} catch (IOException e) {
assertTrue(e.getLocalizedMessage().contains("Resource configuration not valid. Metadata field is missing or invalid."));
}
}

@Test
public void Convert_ResourceHasNullMetadataSection_Throws() {
try {
mapper.readValue(load("resource_with_null_metadata.yaml"), GenericResource.class);
} catch (IOException e) {
assertTrue(e.getLocalizedMessage().contains("Resource configuration not valid. Metadata field is missing or invalid."));
}
}

@Test
public void Convert_ResourceHasNoSpec_Throws() {
try {
mapper.readValue(load("resource_without_spec.yaml"), GenericResource.class);
} catch (IOException e) {
assertTrue(e.getLocalizedMessage().contains("Resource configuration not valid. Spec field is missing or invalid."));
}
}

@Test
public void Convert_ResourceHasNullSpec_Throws() {
try {
mapper.readValue(load("resource_with_null_spec.yaml"), GenericResource.class);
} catch (IOException e) {
assertTrue(e.getLocalizedMessage().contains("Resource configuration not valid. Spec field is missing or invalid."));
}
}

@Test
public void Convert_ResourceIsValid_GenericResource() throws IOException {
GenericResource genericResource = mapper.readValue(load("resource.yaml"), GenericResource.class);
assertEquals(genericResource.getApiVersion(), "tekton.dev/v1beta1");
assertEquals(genericResource.getKind(), "Pipeline");
assertEquals(genericResource.getName(), "foo");
assertTrue(genericResource.getMetadata() != null);
assertTrue(genericResource.getSpec() != null);
}

private String load(String name) throws IOException {
return IOUtils.toString(GenericResourceDeserializerTest.class.getResource("/model/" + name), StandardCharsets.UTF_8);
}
}
10 changes: 10 additions & 0 deletions src/test/resources/model/resource.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: foo
namespace: tekton
spec:
tasks:
- name: step1
taskRef:
name: task1
10 changes: 10 additions & 0 deletions src/test/resources/model/resource_with_null_apiversion.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion:
kind: Pipeline
metadata:
name: foo
namespace: tekton
spec:
tasks:
- name: step1
taskRef:
name: task1
10 changes: 10 additions & 0 deletions src/test/resources/model/resource_with_null_kind.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: tekton.dev/v1beta1
kind:
metadata:
name: foo
namespace: tekton
spec:
tasks:
- name: step1
taskRef:
name: task1
8 changes: 8 additions & 0 deletions src/test/resources/model/resource_with_null_metadata.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
spec:
tasks:
- name: step1
taskRef:
name: task1
10 changes: 10 additions & 0 deletions src/test/resources/model/resource_with_null_name.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name:
namespace: tekton
spec:
tasks:
- name: step1
taskRef:
name: task1
6 changes: 6 additions & 0 deletions src/test/resources/model/resource_with_null_spec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: foo
namespace: tekton
spec:
9 changes: 9 additions & 0 deletions src/test/resources/model/resource_without_apiversion.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
kind: Pipeline
metadata:
name: foo
namespace: tekton
spec:
tasks:
- name: step1
taskRef:
name: task1
9 changes: 9 additions & 0 deletions src/test/resources/model/resource_without_kind.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: tekton.dev/v1beta1
metadata:
name: foo
namespace: tekton
spec:
tasks:
- name: step1
taskRef:
name: task1
7 changes: 7 additions & 0 deletions src/test/resources/model/resource_without_metadata.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: tekton.dev/v1beta1
kind: Pipeline
spec:
tasks:
- name: step1
taskRef:
name: task1
9 changes: 9 additions & 0 deletions src/test/resources/model/resource_without_name.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
namespace: tekton
spec:
tasks:
- name: step1
taskRef:
name: task1
5 changes: 5 additions & 0 deletions src/test/resources/model/resource_without_spec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: foo
namespace: tekton

0 comments on commit 65a5bc9

Please sign in to comment.