add some tests for validating datasource stacks structure
This commit is contained in:
@@ -33,7 +33,7 @@ var StarsResourceInfo = utils.NewResourceInfo(APIGroup, APIVersion,
|
||||
)
|
||||
|
||||
var DatasourceStacksResourceInfo = utils.NewResourceInfo(APIGroup, APIVersion,
|
||||
"datasourcestacks", "datasourcestack", "DataSourceStacks",
|
||||
"datasourcestacks", "datasourcestack", "DataSourceStack",
|
||||
func() runtime.Object { return &DataSourceStack{} },
|
||||
func() runtime.Object { return &DataSourceStackList{} },
|
||||
utils.TableColumns{
|
||||
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* This file was generated by grafana-app-sdk. DO NOT EDIT.
|
||||
*/
|
||||
import { Spec } from './types.spec.gen';
|
||||
|
||||
export interface Metadata {
|
||||
name: string;
|
||||
namespace: string;
|
||||
generateName?: string;
|
||||
selfLink?: string;
|
||||
uid?: string;
|
||||
resourceVersion?: string;
|
||||
generation?: number;
|
||||
creationTimestamp?: string;
|
||||
deletionTimestamp?: string;
|
||||
deletionGracePeriodSeconds?: number;
|
||||
labels?: Record<string, string>;
|
||||
annotations?: Record<string, string>;
|
||||
ownerReferences?: OwnerReference[];
|
||||
finalizers?: string[];
|
||||
managedFields?: ManagedFieldsEntry[];
|
||||
}
|
||||
|
||||
export interface OwnerReference {
|
||||
apiVersion: string;
|
||||
kind: string;
|
||||
name: string;
|
||||
uid: string;
|
||||
controller?: boolean;
|
||||
blockOwnerDeletion?: boolean;
|
||||
}
|
||||
|
||||
export interface ManagedFieldsEntry {
|
||||
manager?: string;
|
||||
operation?: string;
|
||||
apiVersion?: string;
|
||||
time?: string;
|
||||
fieldsType?: string;
|
||||
subresource?: string;
|
||||
}
|
||||
|
||||
export interface Datasources {
|
||||
kind: string;
|
||||
apiVersion: string;
|
||||
metadata: Metadata;
|
||||
spec: Spec;
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
|
||||
// metadata contains embedded CommonMetadata and can be extended with custom string fields
|
||||
// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here
|
||||
// without external reference as using the CommonMetadata reference breaks thema codegen.
|
||||
export interface Metadata {
|
||||
updateTimestamp: string;
|
||||
createdBy: string;
|
||||
uid: string;
|
||||
creationTimestamp: string;
|
||||
deletionTimestamp?: string;
|
||||
finalizers: string[];
|
||||
resourceVersion: string;
|
||||
generation: number;
|
||||
updatedBy: string;
|
||||
labels: Record<string, string>;
|
||||
}
|
||||
|
||||
export const defaultMetadata = (): Metadata => ({
|
||||
updateTimestamp: "",
|
||||
createdBy: "",
|
||||
uid: "",
|
||||
creationTimestamp: "",
|
||||
finalizers: [],
|
||||
resourceVersion: "",
|
||||
generation: 0,
|
||||
updatedBy: "",
|
||||
labels: {},
|
||||
});
|
||||
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
|
||||
export type TemplateSpec = Record<string, DataSourceTemplateSpec>;
|
||||
|
||||
export const defaultTemplateSpec = (): TemplateSpec => ({});
|
||||
|
||||
export interface DataSourceTemplateSpec {
|
||||
// type
|
||||
group: string;
|
||||
// variable name / display name
|
||||
name: string;
|
||||
}
|
||||
|
||||
export const defaultDataSourceTemplateSpec = (): DataSourceTemplateSpec => ({
|
||||
group: "",
|
||||
name: "",
|
||||
});
|
||||
|
||||
export interface Mode {
|
||||
name: string;
|
||||
uid: string;
|
||||
definition: ModeSpec;
|
||||
}
|
||||
|
||||
export const defaultMode = (): Mode => ({
|
||||
name: "",
|
||||
uid: "",
|
||||
definition: defaultModeSpec(),
|
||||
});
|
||||
|
||||
export type ModeSpec = Record<string, DataSourceRef>;
|
||||
|
||||
export const defaultModeSpec = (): ModeSpec => ({});
|
||||
|
||||
export interface DataSourceRef {
|
||||
// grafana data source uid
|
||||
name: string;
|
||||
}
|
||||
|
||||
export const defaultDataSourceRef = (): DataSourceRef => ({
|
||||
name: "",
|
||||
});
|
||||
|
||||
export interface Spec {
|
||||
template: TemplateSpec;
|
||||
modes: Mode[];
|
||||
}
|
||||
|
||||
export const defaultSpec = (): Spec => ({
|
||||
template: defaultTemplateSpec(),
|
||||
modes: [],
|
||||
});
|
||||
|
||||
@@ -18,17 +18,13 @@ func GetDatasourceStacksValidator() builder.APIGroupValidation {
|
||||
}
|
||||
|
||||
func (v *DatasourceStacksValidator) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) {
|
||||
if a.GetKind().Kind != collections.DatasourceStacksResourceInfo.GroupVersionKind().Kind {
|
||||
return nil
|
||||
}
|
||||
|
||||
obj := a.GetObject()
|
||||
if obj == nil {
|
||||
return fmt.Errorf("object is nil (%s %s)", a.GetName(), a.GetKind().GroupVersion().String())
|
||||
}
|
||||
|
||||
operation := a.GetOperation()
|
||||
|
||||
if operation == admission.Connect {
|
||||
return fmt.Errorf("Connect operation is not allowed (%s %s)", a.GetName(), a.GetKind().GroupVersion().String())
|
||||
}
|
||||
|
||||
if operation != admission.Create && operation != admission.Update {
|
||||
return nil
|
||||
}
|
||||
@@ -40,33 +36,28 @@ func (v *DatasourceStacksValidator) Validate(ctx context.Context, a admission.At
|
||||
|
||||
// get the keys from the template
|
||||
template := cast.Spec.Template
|
||||
templateKeys := map[string]bool{}
|
||||
|
||||
// keys must be unique
|
||||
for key := range template {
|
||||
if _, ok := templateKeys[key]; ok {
|
||||
return fmt.Errorf("template keys must be unique. key '%s' already exists (%s %s)", key, a.GetName(), a.GetKind().GroupVersion().String())
|
||||
}
|
||||
templateKeys[key] = true
|
||||
}
|
||||
|
||||
// template names must be unique
|
||||
templateNames := map[string]bool{}
|
||||
for name := range template {
|
||||
if _, ok := templateNames[name]; ok {
|
||||
return fmt.Errorf("template names must be unique. name '%s' already exists (%s %s)", name, a.GetName(), a.GetKind().GroupVersion().String())
|
||||
for _, item := range template {
|
||||
// template items cannot be empty
|
||||
if item.Group == "" || item.Name == "" {
|
||||
return fmt.Errorf("template items cannot be empty (%s %s)", a.GetName(), a.GetKind().GroupVersion().String())
|
||||
}
|
||||
templateNames[name] = true
|
||||
// template names must be unique
|
||||
if _, exists := templateNames[item.Name]; exists {
|
||||
return fmt.Errorf("template item names must be unique. name '%s' already exists (%s %s)", item.Name, a.GetName(), a.GetKind().GroupVersion().String())
|
||||
}
|
||||
templateNames[item.Name] = true
|
||||
}
|
||||
|
||||
// for each mode, check that the keys are in the template
|
||||
modes := cast.Spec.Modes
|
||||
|
||||
// if a key is not in the template, return an error
|
||||
for _, mode := range modes {
|
||||
for key := range mode.Definition {
|
||||
if _, ok := templateKeys[key]; !ok {
|
||||
return fmt.Errorf("key %s is not in the DataSourceStack template. The template keys are %v (%s %s)", key, templateKeys, a.GetName(), a.GetKind().GroupVersion().String())
|
||||
// if a key is not in the template, return an error
|
||||
if _, ok := template[key]; !ok {
|
||||
return fmt.Errorf("key '%s' is not in the DataSourceStack template (%s %s)", key, a.GetName(), a.GetKind().GroupVersion().String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,71 @@ func TestDataSourceValidator_Validate(t *testing.T) {
|
||||
object: &collectionsv1alpha1.Stars{},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "should return error for Connect operation",
|
||||
operation: admission.Connect,
|
||||
object: &collectionsv1alpha1.DataSourceStack{},
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "template items cannot be empty",
|
||||
operation: admission.Create,
|
||||
object: &collectionsv1alpha1.DataSourceStack{
|
||||
Spec: collectionsv1alpha1.DataSourceStackSpec{
|
||||
Template: collectionsv1alpha1.DataSourceStackTemplateSpec{
|
||||
"key1": collectionsv1alpha1.DataSourceStackDataSourceStackTemplateItem{},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectError: true,
|
||||
errorMsg: "template items cannot be empty (test-datasourcestack collections.grafana.app/v1alpha1)",
|
||||
},
|
||||
{
|
||||
name: "template item name keys must be unique",
|
||||
operation: admission.Create,
|
||||
object: &collectionsv1alpha1.DataSourceStack{
|
||||
Spec: collectionsv1alpha1.DataSourceStackSpec{
|
||||
Template: collectionsv1alpha1.DataSourceStackTemplateSpec{
|
||||
"key1": collectionsv1alpha1.DataSourceStackDataSourceStackTemplateItem{
|
||||
Name: "foo",
|
||||
Group: "foo.grafana",
|
||||
},
|
||||
"key2": collectionsv1alpha1.DataSourceStackDataSourceStackTemplateItem{
|
||||
Name: "foo",
|
||||
Group: "foo.grafana",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectError: true,
|
||||
errorMsg: "template item names must be unique. name 'foo' already exists (test-datasourcestack collections.grafana.app/v1alpha1)",
|
||||
},
|
||||
{
|
||||
name: "mode keys must exist in the template",
|
||||
operation: admission.Create,
|
||||
object: &collectionsv1alpha1.DataSourceStack{
|
||||
Spec: collectionsv1alpha1.DataSourceStackSpec{
|
||||
Template: collectionsv1alpha1.DataSourceStackTemplateSpec{
|
||||
"key1": collectionsv1alpha1.DataSourceStackDataSourceStackTemplateItem{
|
||||
Name: "foo",
|
||||
Group: "foo.grafana",
|
||||
},
|
||||
},
|
||||
Modes: []collectionsv1alpha1.DataSourceStackModeSpec{
|
||||
{
|
||||
Name: "prod",
|
||||
Definition: collectionsv1alpha1.DataSourceStackMode{
|
||||
"notintemplate": collectionsv1alpha1.DataSourceStackModeItem{
|
||||
DataSourceRef: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectError: true,
|
||||
errorMsg: "key 'notintemplate' is not in the DataSourceStack template (test-datasourcestack collections.grafana.app/v1alpha1)",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
Reference in New Issue
Block a user