Skip to content
This repository was archived by the owner on Jun 2, 2024. It is now read-only.

Commit

Permalink
#1 Add application perspective API incl tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
gessnerfl committed Apr 5, 2019
1 parent c5adb25 commit 7449029
Show file tree
Hide file tree
Showing 2 changed files with 296 additions and 0 deletions.
146 changes: 146 additions & 0 deletions instana/restapi/application-perspective-api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package restapi

import "errors"

//MatchExpressionType type for MatchExpression discriminator type
type MatchExpressionType string

const (
//BinaryOperatorExpressionType discriminator type for binary operations
BinaryOperatorExpressionType MatchExpressionType = "BINARY_OP"
//LeafExpressionType discriminator type for leaf operations
LeafExpressionType MatchExpressionType = "LEAF"
)

//ApplicationConfigResource represents the REST resource of application perspective configuration at Instana
type ApplicationConfigResource interface {
GetOne(id string) (ApplicationConfig, error)
Upsert(rule ApplicationConfig) (ApplicationConfig, error)
Delete(rule ApplicationConfig) error
DeleteByID(applicationID string) error
}

//MatchExpression is the interface definition of a match expression in Instana
type MatchExpression interface {
GetType() MatchExpressionType
Validate() error
}

//NewBinaryOperator creates and new binary operator MatchExpression
func NewBinaryOperator(left MatchExpression, conjunction string, right MatchExpression) MatchExpression {
return binaryOperator{
Dtype: BinaryOperatorExpressionType,
Left: left,
Right: right,
Conjunction: conjunction,
}
}

//BinaryOperator is the representation of a binary operator expression in Instana
type binaryOperator struct {
Dtype MatchExpressionType `json:"type"`
Left MatchExpression `json:"left"`
Right MatchExpression `json:"right"`
Conjunction string `json:"conjunction"`
}

//NewTagMatcherExpression creates and new tag matcher MatchExpression
func NewTagMatcherExpression(key string, operator string, value string) MatchExpression {
return tagMatcherExpression{
Dtype: LeafExpressionType,
Key: key,
Operator: operator,
Value: value,
}
}

//TagMatcherExpression is the representation of a tag matcher expression in Instana
type tagMatcherExpression struct {
Dtype MatchExpressionType `json:"type"`
Key string `json:"key"`
Operator string `json:"operator"`
Value string `json:"value"`
}

//ApplicationConfig is the representation of a application perspective configuration in Instana
type ApplicationConfig struct {
ID string `json:"id"`
Label string `json:"label"`
MatchSpecification MatchExpression `json:"matchSpecification"`
Scope string `json:"scope"`
}

//GetID implemention of the interface InstanaDataObject
func (a ApplicationConfig) GetID() string {
return a.ID
}

//Validate implemention of the interface InstanaDataObject for ApplicationConfig
func (a ApplicationConfig) Validate() error {
if len(a.ID) == 0 {
return errors.New("ID is missing")
}
if len(a.Label) == 0 {
return errors.New("Label is missing")
}
if a.MatchSpecification == nil {
return errors.New("MatchSpecification is missing")
}

if err := a.MatchSpecification.Validate(); err != nil {
return err
}

if len(a.Scope) == 0 {
return errors.New("Scope is missing")
}
return nil
}

//GetType implemention of the interface MatchExpression for binaryOperator
func (b binaryOperator) GetType() MatchExpressionType {
return b.Dtype
}

//Validate implemention of the interface MatchExpression for binaryOperator
func (b binaryOperator) Validate() error {
if b.Left == nil {
return errors.New("Left expression is missing")
}
if err := b.Left.Validate(); err != nil {
return err
}

if len(b.Conjunction) == 0 {
return errors.New("Conjunction of expressions is missing")
}

if b.Right == nil {
return errors.New("Right expression is missing")
}
if err := b.Right.Validate(); err != nil {
return err
}
return nil
}

//GetType implemention of the interface MatchExpression for tagMatcherExpression
func (t tagMatcherExpression) GetType() MatchExpressionType {
return t.Dtype
}

//Validate implemention of the interface MatchExpression for tagMatcherExpression
func (t tagMatcherExpression) Validate() error {
if len(t.Key) == 0 {
return errors.New("Key of tag expression is missing")
}
if len(t.Operator) == 0 {
return errors.New("Operator of tag expression is missing")
}
if t.Operator != "NOT_EMPTY" {
if len(t.Value) == 0 {
return errors.New("Value of tag expression is missing")
}
}
return nil
}
150 changes: 150 additions & 0 deletions instana/restapi/application-perspective-api_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package restapi_test

import (
"strings"
"testing"

. "github.com/gessnerfl/terraform-provider-instana/instana/restapi"
)

func TestShouldSuccussullyValididateConsistentApplicationConfig(t *testing.T) {
config := ApplicationConfig{
ID: "id",
Label: "label",
MatchSpecification: NewTagMatcherExpression("key", "EQUALS", "value"),
Scope: "scope",
}

if err := config.Validate(); err != nil {
t.Fatalf("Expected no error but got, %s", err)
}
}

func TestShouldFailToValidateApplicationConfigWhenIDIsMissing(t *testing.T) {
config :=
ApplicationConfig{
Label: "label",
MatchSpecification: NewTagMatcherExpression("key", "EQUALS", "value"),
Scope: "scope",
}

if err := config.Validate(); err == nil || !strings.Contains(err.Error(), "ID") {
t.Fatal("Expected invalid application config because of missing ID")
}
}

func TestShouldFailToValidateApplicationConfigWhenLabelIsMissing(t *testing.T) {
config :=
ApplicationConfig{
ID: "id",
MatchSpecification: NewTagMatcherExpression("key", "EQUALS", "value"),
Scope: "scope",
}

if err := config.Validate(); err == nil || !strings.Contains(err.Error(), "Label") {
t.Fatal("Expected invalid application config because of missing Label")
}
}

func TestShouldFailToValidateApplicationConfigWhenMatchSpecificationIsMissing(t *testing.T) {
config :=
ApplicationConfig{
ID: "id",
Label: "label",
Scope: "scope",
}

if err := config.Validate(); err == nil || !strings.Contains(err.Error(), "MatchSpecification") {
t.Fatal("Expected invalid application config because of missing MatchSpecification")
}
}

func TestShouldFailToValidateApplicationConfigWhenMatchSpecificationIsNotValid(t *testing.T) {
config := ApplicationConfig{
ID: "id",
Label: "label",
MatchSpecification: NewTagMatcherExpression("", "EQUALS", "value"),
Scope: "scope",
}

if err := config.Validate(); err == nil || !strings.Contains(err.Error(), "Key") {
t.Fatal("Expected invalid application config because of invalid match specification")
}
}

func TestShouldFailToValidateApplicationConfigWhenScopeIsMissing(t *testing.T) {
config :=
ApplicationConfig{
ID: "id",
Label: "label",
MatchSpecification: NewTagMatcherExpression("key", "EQUALS", "value"),
}

if err := config.Validate(); err == nil || !strings.Contains(err.Error(), "Scope") {
t.Fatal("Expected invalid application config because of missing Scope")
}
}

func TestShouldSuccessfullyValidateConsistentBinaryExpression(t *testing.T) {
left := NewTagMatcherExpression("keyLeft", "EQUALS", "valueLeft")
right := NewTagMatcherExpression("keyRight", "EQUALS", "valueRight")

exp := NewBinaryOperator(left, "AND", right)

if err := exp.Validate(); err != nil {
t.Fatalf("Expected no error but got, %s", err)
}
}

func TestShouldFailToValidateBinaryExpressionWhenLeftOperatorIsMissing(t *testing.T) {
right := NewTagMatcherExpression("keyRight", "EQUALS", "valueRight")

exp := NewBinaryOperator(nil, "AND", right)

if err := exp.Validate(); err == nil || !strings.Contains(err.Error(), "Left") {
t.Fatal("Expected invalid application config because of missing Left operator")
}
}

func TestShouldFailToValidateBinaryExpressionWhenLeftOperatorIsNotValid(t *testing.T) {
left := NewTagMatcherExpression("", "EQUALS", "valueLeft")
right := NewTagMatcherExpression("keyRight", "EQUALS", "valueRight")

exp := NewBinaryOperator(left, "AND", right)

if err := exp.Validate(); err == nil || !strings.Contains(err.Error(), "Key") {
t.Fatal("Expected invalid application config because of invalid Left operator")
}
}

func TestShouldFailToValidateBinaryExpressionWhenRightOperatorIsMissing(t *testing.T) {
left := NewTagMatcherExpression("keyLeft", "EQUALS", "valueLeft")

exp := NewBinaryOperator(left, "AND", nil)

if err := exp.Validate(); err == nil || !strings.Contains(err.Error(), "Right") {
t.Fatal("Expected invalid application config because of missing right operator")
}
}

func TestShouldFailToValidateBinaryExpressionWhenRightOperatorIsNotValid(t *testing.T) {
left := NewTagMatcherExpression("keyLeft", "EQUALS", "valueLeft")
right := NewTagMatcherExpression("", "EQUALS", "valueRight")

exp := NewBinaryOperator(left, "AND", right)

if err := exp.Validate(); err == nil || !strings.Contains(err.Error(), "Key") {
t.Fatal("Expected invalid application config because of invalid right operator")
}
}

func TestShouldFailToValidateBinaryExpressionWhenConjunctionIsMissing(t *testing.T) {
left := NewTagMatcherExpression("keyLeft", "EQUALS", "valueLeft")
right := NewTagMatcherExpression("keyRight", "EQUALS", "valueRight")

exp := NewBinaryOperator(left, "", right)

if err := exp.Validate(); err == nil || !strings.Contains(err.Error(), "Conjunction") {
t.Fatal("Expected invalid application config because of missing conjunction")
}
}

0 comments on commit 7449029

Please sign in to comment.