// +build integration

// To enable compilation of this file in Goland, go to "Settings -> Go -> Vendoring & Build Tags -> Custom Tags" and add "knative"

/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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 common

import (
	"bytes"
	"fmt"
	"net/http"
	"testing"

	. "github.com/apache/camel-k/e2e/support"
	"github.com/apache/camel-k/pkg/util/openshift"
	. "github.com/onsi/gomega"
	"github.com/stretchr/testify/assert"
	v1 "k8s.io/api/core/v1"
)

func TestRunREST(t *testing.T) {
	WithNewTestNamespace(t, func(ns string) {
		var profile string
		ocp, err := openshift.IsOpenShift(TestClient())
		assert.Nil(t, err)
		if ocp {
			profile = "OpenShift"
		} else {
			profile = "Kubernetes"
		}

		Expect(Kamel("install", "-n", ns, "--trait-profile", profile).Execute()).Should(BeNil())
		Expect(Kamel("run", "-n", ns, "files/RestConsumer.java").Execute()).Should(BeNil())
		Eventually(IntegrationPodPhase(ns, "rest-consumer"), TestTimeoutMedium).Should(Equal(v1.PodRunning))

		t.Run("Service works", func(t *testing.T) {
			name := "John"
			service := Service(ns, "rest-consumer")
			Eventually(service, TestTimeoutShort).ShouldNot(BeNil())
			Expect(Kamel("run", "-n", ns, "files/RestProducer.groovy", "-p", "serviceName=rest-consumer", "-p", "name="+name).Execute()).Should(BeNil())
			Eventually(IntegrationPodPhase(ns, "rest-producer"), TestTimeoutMedium).Should(Equal(v1.PodRunning))
			Eventually(IntegrationLogs(ns, "rest-consumer"), TestTimeoutShort).Should(ContainSubstring(fmt.Sprintf("get %s", name)))
			Eventually(IntegrationLogs(ns, "rest-producer"), TestTimeoutShort).Should(ContainSubstring(fmt.Sprintf("%s Doe", name)))
		})

		if ocp {
			t.Run("Route works", func(t *testing.T) {
				name := "Peter"
				route := Route(ns, "rest-consumer")
				Eventually(route, TestTimeoutShort).ShouldNot(BeNil())
				response := httpRequest(t, fmt.Sprintf("http://%s/customers/%s", route().Spec.Host, name))
				assert.Equal(t, fmt.Sprintf("%s Doe", name), response)
				Eventually(IntegrationLogs(ns, "rest-consumer"), TestTimeoutShort).Should(ContainSubstring(fmt.Sprintf("get %s", name)))

			})
		}

		// Cleanup
		Expect(Kamel("delete", "--all", "-n", ns).Execute()).Should(BeNil())
	})
}

func httpRequest(t *testing.T, url string) string {
	response, err := http.Get(url)
	defer func() {
		if response != nil {
			_ = response.Body.Close()
		}
	}()

	assert.Nil(t, err)

	buf := new(bytes.Buffer)

	_, err = buf.ReadFrom(response.Body)
	assert.Nil(t, err)

	return buf.String()
}
