// Copyright 2020 The Monogon Project Authors.
//
// SPDX-License-Identifier: Apache-2.0
//
// 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.

package reconciler

import (
	"context"
	"fmt"
	"testing"

	node "k8s.io/api/node/v1beta1"
	policy "k8s.io/api/policy/v1beta1"
	rbac "k8s.io/api/rbac/v1"
	storage "k8s.io/api/storage/v1"
	meta "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// kubernetesMeta unwraps an interface{} that might contain a Kubernetes resource of type that is managed by the
// reconciler. Any time a new Kubernetes type is managed by the reconciler, the following switch should be extended
// to cover that type.
func kubernetesMeta(v interface{}) *meta.ObjectMeta {
	switch v2 := v.(type) {
	case *rbac.ClusterRole:
		return &v2.ObjectMeta
	case *rbac.ClusterRoleBinding:
		return &v2.ObjectMeta
	case *storage.CSIDriver:
		return &v2.ObjectMeta
	case *storage.StorageClass:
		return &v2.ObjectMeta
	case *policy.PodSecurityPolicy:
		return &v2.ObjectMeta
	case *node.RuntimeClass:
		return &v2.ObjectMeta
	}
	return nil
}

// TestExpectedNamedCorrectly ensures that all the Expected objects of all resource types have a correspondence between
// their returned key and inner name. This contract must be met in order for the reconciler to not create runaway
// resources. This assumes all managed resources are Kubernetes resources.
func TestExpectedNamedCorrectly(t *testing.T) {
	for reconciler, r := range allResources(nil) {
		for outer, v := range r.Expected() {
			meta := kubernetesMeta(v)
			if meta == nil {
				t.Errorf("reconciler %q, object %q: could not decode kubernetes metadata", reconciler, outer)
				continue
			}
			if inner := meta.Name; outer != inner {
				t.Errorf("reconciler %q, object %q: inner name mismatch (%q)", reconciler, outer, inner)
				continue
			}
		}
	}
}

// TestExpectedLabeledCorrectly ensures that all the Expected objects of all resource types have a Kubernetes metadata
// label that signifies it's a builtin object, to be retrieved afterwards. This contract must be met in order for the
// reconciler to not keep overwriting objects (and possibly failing), when a newly created object is not then
// retrievable using a selector corresponding to this label. This assumes all managed resources are Kubernetes objects.
func TestExpectedLabeledCorrectly(t *testing.T) {
	for reconciler, r := range allResources(nil) {
		for outer, v := range r.Expected() {
			meta := kubernetesMeta(v)
			if meta == nil {
				t.Errorf("reconciler %q, object %q: could not decode kubernetes metadata", reconciler, outer)
				continue
			}
			if data := meta.Labels[BuiltinLabelKey]; data != BuiltinLabelValue {
				t.Errorf("reconciler %q, object %q: %q=%q, wanted =%q", reconciler, outer, BuiltinLabelKey, data, BuiltinLabelValue)
				continue
			}
		}
	}
}

// testResource is a resource type used for testing. The inner type is a string that is equal to its name (key).
// It simulates a target (ie. k8s apiserver mock) that always acts nominally (all resources are created, deleted as
// requested, and the state is consistent with requests).
type testResource struct {
	// current is the simulated state of resources in the target.
	current map[string]string
	// expected is what this type will report as the Expected() resources.
	expected map[string]string
}

func (r *testResource) List(ctx context.Context) ([]string, error) {
	var keys []string
	for k, _ := range r.current {
		keys = append(keys, k)
	}
	return keys, nil
}

func (r *testResource) Create(ctx context.Context, el interface{}) error {
	r.current[el.(string)] = el.(string)
	return nil
}

func (r *testResource) Delete(ctx context.Context, name string) error {
	delete(r.current, name)
	return nil
}

func (r *testResource) Expected() map[string]interface{} {
	exp := make(map[string]interface{})
	for k, v := range r.expected {
		exp[k] = v
	}
	return exp
}

// newTestResource creates a test resource with a list of expected resource strings.
func newTestResource(want ...string) *testResource {
	expected := make(map[string]string)
	for _, w := range want {
		expected[w] = w
	}
	return &testResource{
		current:  make(map[string]string),
		expected: expected,
	}
}

// currentDiff returns a human-readable string showing the different between the current state and the given resource
// strings. If no difference is present, the returned string is empty.
func (r *testResource) currentDiff(want ...string) string {
	expected := make(map[string]string)
	for _, w := range want {
		if _, ok := r.current[w]; !ok {
			return fmt.Sprintf("%q missing in current", w)
		}
		expected[w] = w
	}
	for _, g := range r.current {
		if _, ok := expected[g]; !ok {
			return fmt.Sprintf("%q spurious in current", g)
		}
	}
	return ""
}

// TestBasicReconciliation ensures that the reconcile function does manipulate a target state based on a set of
// expected resources.
func TestBasicReconciliation(t *testing.T) {
	ctx := context.Background()
	r := newTestResource("foo", "bar", "baz")

	// nothing should have happened yet (testing the test)
	if diff := r.currentDiff(); diff != "" {
		t.Fatalf("wrong state after creation: %s", diff)
	}

	if err := reconcile(ctx, r); err != nil {
		t.Fatalf("reconcile: %v", err)
	}
	// everything requested should have been created
	if diff := r.currentDiff("foo", "bar", "baz"); diff != "" {
		t.Fatalf("wrong state after reconciliation: %s", diff)
	}

	delete(r.expected, "foo")
	if err := reconcile(ctx, r); err != nil {
		t.Fatalf("reconcile: %v", err)
	}
	// foo should not be missing
	if diff := r.currentDiff("bar", "baz"); diff != "" {
		t.Fatalf("wrong state after deleting foo: %s", diff)
	}
}
