func/test/e2e/scenario_extended_flow_test.go

184 lines
6.1 KiB
Go

//go:build e2e
package e2e
import (
"bytes"
"fmt"
"net"
"path/filepath"
"regexp"
"strings"
"syscall"
"testing"
"time"
"gotest.tools/v3/assert"
"knative.dev/func/test/oncluster"
"knative.dev/func/test/testhttp"
common "knative.dev/func/test/common"
)
// TestFunctionExtendedFlow will run a comprehensive path of func commands an end user may perform such as
// > create > build > run > (curl)+invoke > deploy > describe > list > (curl)+invoke > deploy (new revision) > (curl) > delete > list
func TestFunctionExtendedFlow(t *testing.T) {
var funcName = "extended-test"
var funcPath = filepath.Join(t.TempDir(), funcName)
knFunc := common.NewKnFuncShellCli(t)
knFunc.ShouldDumpOnSuccess = false
// ---------------------------
// Func Create Test
// ---------------------------
knFunc.Exec("create", "--language", "node", funcPath)
// From here on, all commands will be executed from the func project path
knFunc.SourceDir = funcPath
// ---------------------------
// Func Build Test
// ---------------------------
knFunc.Exec("build", "--registry", common.GetRegistry())
// ---------------------------
// Func Run Test
// ---------------------------
knFuncTerm1 := common.NewKnFuncShellCli(t)
knFuncTerm1.ShouldDumpOnSuccess = false
knFuncTerm2 := common.NewKnFuncShellCli(t)
knFuncTerm2.ShouldDumpOnSuccess = true
portChannel := make(chan string)
go func() {
t.Log("----Checking for listening port")
// set the function that will be executed while "kn func run" is executed
knFuncTerm1.OnWaitCallback = func(stdout *bytes.Buffer) {
t.Log("-----Executing OnWaitCallback")
funcPort, attempts := "", 0
for funcPort == "" && attempts < 10 {
t.Logf("----Function Output:\n%v\n", stdout.String())
findPort := func(exp string, msg string) (port string) {
matches := regexp.MustCompile(exp).FindStringSubmatch(msg)
if len(matches) > 1 {
port = matches[1]
}
return
}
funcPort = findPort("Running on host port (.*)", stdout.String())
if funcPort == "" {
funcPort = findPort("Function started on port (.*)", stdout.String())
}
attempts++
if funcPort == "" {
time.Sleep(200 * time.Millisecond)
}
}
// can proceed
portChannel <- funcPort
}
knFuncTerm1.Exec("run", "--verbose", "--path", funcPath)
}()
knFuncRunCompleted := false
knFuncRunProcessFinalizer := func() {
if knFuncRunCompleted == false {
knFuncTerm1.ExecCmd.Process.Signal(syscall.SIGTERM)
knFuncRunCompleted = true
}
}
defer knFuncRunProcessFinalizer()
// Get running port (usually 8080) from func output. We can use it for test http.
funcPort := <-portChannel
assert.Assert(t, funcPort != "", "Unable to retrieve local port allocated for function")
// Wait Port to be available
net.DialTimeout("tcp", ":"+funcPort, 3*time.Second)
time.Sleep(time.Second)
// GET Function HTTP Endpoint
_, bodyResp := testhttp.TestGet(t, "http://localhost:"+funcPort+"?message=local")
assert.Assert(t, strings.Contains(bodyResp, `{"message":"local"}`), "function response does not contain expected body.")
// ---------------------------
// Func Invoke Locally Test
// ---------------------------
result := knFuncTerm2.Exec("invoke", "--path", funcPath)
assert.Assert(t, strings.Contains(result.Out, `{"message":"Hello World"}`), "function response does not contain expected body.")
// Stop "kn func run" execution
knFuncRunProcessFinalizer()
time.Sleep(2 * time.Second)
// ---------------------------
// Func Deploy Test
// ---------------------------
knFuncDelete := func(t *testing.T) {
knFunc.Exec("delete", funcName)
listResult := knFunc.Exec("list")
assert.Assert(t, strings.Contains(listResult.Out, funcName) == false, "Function is listed as deployed after delete")
}
result = knFunc.Exec("deploy", "--build=false")
firstRevisionName, functionUrl := common.WaitForFunctionReady(t, funcName)
defer knFuncDelete(t)
wasDeployed := regexp.MustCompile("✅ Function [a-z]* in namespace .* at URL: \n http.*").MatchString(result.Out)
assert.Assert(t, wasDeployed, "Function was not deployed")
urlFromDeploy := ""
matches := regexp.MustCompile("URL: \n (http.*)").FindStringSubmatch(result.Out)
if len(matches) > 1 {
urlFromDeploy = matches[1]
}
assert.Assert(t, urlFromDeploy != "", "URL not returned on deploy output")
// ---------------------------
// Func Describe Test
// ---------------------------
urlFromDescribe := ""
result = knFunc.Exec("describe", "--output", "plain")
matches = regexp.MustCompile("Route (http.*)").FindStringSubmatch(result.Out)
if len(matches) > 1 {
urlFromDescribe = matches[1]
}
assert.Assert(t, urlFromDescribe != "", "URL not returned on info output")
assert.Assert(t, urlFromDescribe == urlFromDeploy, fmt.Sprintf("URL from 'func info' [%s] does not match URL from 'func deploy' [%s]", urlFromDescribe, urlFromDeploy))
assert.Assert(t, urlFromDescribe == functionUrl, "URL does not match knative service URL")
// ---------------------------
// Func List Test
// ---------------------------
result = knFunc.Exec("list")
assert.Assert(t, strings.Contains(result.Out, funcName), "deployed function is not listed")
// ---------------------------
// Invoke Remote Test
// ---------------------------
result = knFunc.Exec("invoke")
assert.Assert(t, strings.Contains(result.Out, `{"message":"Hello World"}`), "function response does not contain expected body.")
// GET Function HTTP Endpoint
_, bodyResp = testhttp.TestGet(t, functionUrl+"?message=remote")
assert.Assert(t, strings.Contains(bodyResp, `{"message":"remote"}`), "function response does not contain expected body.")
// ---------------------------
// Deploy new revision
// ---------------------------
oncluster.WriteNewSimpleIndexJS(t, funcPath, "NEW_REVISION")
knFunc.Exec("deploy")
common.WaitForNewRevisionReady(t, firstRevisionName, funcName)
// ---------------------------
// Call New Revision
// ---------------------------
_, bodyResp = testhttp.TestGet(t, functionUrl)
assert.Assert(t, strings.Contains(bodyResp, "NEW_REVISION"), "function new revision does not contain expected body.")
// Delete Test (on defer)
}