mirror of https://github.com/dapr/cli.git
Add E2E for Run template (#1170)
* refactor run into functions Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com> * renamed Apps struct as App Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com> * redirect logs to files. set informational logs. set command dirs Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com> * fix linter errors Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com> * fix e2e test on non-existent resources-path Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com> * more fixes Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com> * fix merge conflict Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com> * set default ports for zero values Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com> * fix linter errors Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com> * add more details in error, fix logs in run -f Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com> * address review comments Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com> * address review comments Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com> * add more fixes in template run based on e2e tests Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com> * add basic happy path e2e for dapr run -f Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com> * add positive and negative e2e tests for run template Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com> * address review comments Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com> Signed-off-by: Mukundan Sundararajan <65565396+mukundansundar@users.noreply.github.com>
This commit is contained in:
parent
14c04f9a87
commit
17dbe5bb13
|
@ -24,6 +24,8 @@ cli
|
|||
|
||||
# CLI's auto-generated components directory
|
||||
**/components
|
||||
# Auto generated logs dir inside .dapr directory
|
||||
**/.dapr/logs
|
||||
|
||||
test_output.json
|
||||
|
||||
|
|
9
Makefile
9
Makefile
|
@ -153,7 +153,7 @@ test: test-deps
|
|||
################################################################################
|
||||
.PHONY: test-e2e-k8s
|
||||
test-e2e-k8s: test-deps
|
||||
gotestsum --jsonfile $(TEST_OUTPUT_FILE) --format standard-verbose -- -timeout 20m -count=1 -tags=e2e ./tests/e2e/kubernetes/...
|
||||
gotestsum --jsonfile $(TEST_OUTPUT_FILE) --format standard-verbose -- -timeout 20m -count=1 -tags=e2e ./tests/e2e/kubernetes/...
|
||||
|
||||
################################################################################
|
||||
# Build, E2E Tests for Kubernetes #
|
||||
|
@ -175,6 +175,13 @@ test-e2e-upgrade: test-deps
|
|||
e2e-build-run-upgrade: build test-e2e-upgrade
|
||||
|
||||
|
||||
################################################################################
|
||||
# E2E Tests for Self-Hosted Template exec #
|
||||
################################################################################
|
||||
.PHONY: test-e2e-sh-template
|
||||
test-e2e-sh-template: test-deps
|
||||
gotestsum --jsonfile $(TEST_OUTPUT_FILE) --format standard-verbose -- -timeout $(E2E_SH_TEST_TIMEOUT) -count=1 -tags=template ./tests/e2e/standalone/...
|
||||
|
||||
################################################################################
|
||||
# E2E Tests for Self-Hosted #
|
||||
################################################################################
|
||||
|
|
16
cmd/run.go
16
cmd/run.go
|
@ -474,7 +474,7 @@ func executeRun(runFilePath string, apps []runfileconfig.App) (bool, error) {
|
|||
runConfig := app.RunConfig
|
||||
err = app.CreateDaprdLogFile()
|
||||
if err != nil {
|
||||
print.StatusEvent(os.Stderr, print.LogFailure, "Error getting log file for app %q present in %s: %s", runConfig.AppID, runFilePath, err.Error())
|
||||
print.StatusEvent(os.Stderr, print.LogFailure, "Error getting daprd log file for app %q present in %s: %s", runConfig.AppID, runFilePath, err.Error())
|
||||
exitWithError = true
|
||||
break
|
||||
}
|
||||
|
@ -490,7 +490,7 @@ func executeRun(runFilePath string, apps []runfileconfig.App) (bool, error) {
|
|||
} else {
|
||||
err = app.CreateAppLogFile()
|
||||
if err != nil {
|
||||
print.StatusEvent(os.Stderr, print.LogFailure, "Error getting log file for app %q present in %s: %s", runConfig.AppID, runFilePath, err.Error())
|
||||
print.StatusEvent(os.Stderr, print.LogFailure, "Error getting app log file for app %q present in %s: %s", runConfig.AppID, runFilePath, err.Error())
|
||||
exitWithError = true
|
||||
break
|
||||
}
|
||||
|
@ -531,7 +531,7 @@ func executeRun(runFilePath string, apps []runfileconfig.App) (bool, error) {
|
|||
}
|
||||
|
||||
// Stop daprd and app processes for each runState.
|
||||
_, closeError := gracefullyShutdownAppsAndCloseResources(runStates, apps)
|
||||
closeError := gracefullyShutdownAppsAndCloseResources(runStates, apps)
|
||||
|
||||
for _, app := range apps {
|
||||
runConfig := app.RunConfig
|
||||
|
@ -551,13 +551,9 @@ func logInformationalStatusToStdout(app runfileconfig.App) {
|
|||
print.InfoStatusEvent(os.Stdout, "Writing log files to directory : %s", app.GetLogsDir())
|
||||
}
|
||||
|
||||
func gracefullyShutdownAppsAndCloseResources(runState []*runExec.RunExec, apps []runfileconfig.App) (bool, error) {
|
||||
exitWithError := false
|
||||
func gracefullyShutdownAppsAndCloseResources(runState []*runExec.RunExec, apps []runfileconfig.App) error {
|
||||
for _, s := range runState {
|
||||
hasErr := stopDaprdAndAppProcesses(s)
|
||||
if !exitWithError && hasErr {
|
||||
exitWithError = true
|
||||
}
|
||||
stopDaprdAndAppProcesses(s)
|
||||
}
|
||||
var err error
|
||||
// close log file resources.
|
||||
|
@ -571,7 +567,7 @@ func gracefullyShutdownAppsAndCloseResources(runState []*runExec.RunExec, apps [
|
|||
err = hasErr
|
||||
}
|
||||
}
|
||||
return exitWithError, err
|
||||
return err
|
||||
}
|
||||
|
||||
func executeRunWithAppsConfigFile(runFilePath string) {
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
Copyright 2023 The Dapr Authors
|
||||
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 main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Metrics struct {
|
||||
MetricsID int `json:"metricsID"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
var host string
|
||||
var port string
|
||||
client := http.Client{}
|
||||
if val, ok := os.LookupEnv("DAPR_HTTP_PORT"); !ok {
|
||||
log.Fatalf("DAPR_HTTP_PORT not automatically injected")
|
||||
} else {
|
||||
log.Println("DAPR_HTTP_PORT set to", val)
|
||||
port = val
|
||||
}
|
||||
// DAPR_HOST_ADD needs to be an env set in dapr.yaml file
|
||||
if val, ok := os.LookupEnv("DAPR_HOST_ADD"); !ok {
|
||||
log.Fatalf("DAPR_HOST_ADD not set")
|
||||
} else {
|
||||
log.Println("DAPR_HOST_ADD set to", val)
|
||||
host = val
|
||||
}
|
||||
finalURL := "http://" + host + ":" + port + "/metrics"
|
||||
log.Println("Sending metrics to ", finalURL)
|
||||
for i := 0; i < 2000; i++ {
|
||||
time.Sleep(1 * time.Second)
|
||||
metrics := Metrics{
|
||||
MetricsID: i,
|
||||
}
|
||||
b, err := json.Marshal(metrics)
|
||||
if err != nil {
|
||||
log.Println("Got error while marshalling metrics ", err)
|
||||
continue
|
||||
}
|
||||
// Send metrics to Dapr
|
||||
req, _ := http.NewRequest(http.MethodPost, finalURL, bytes.NewBuffer(b))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("dapr-app-id", "processor")
|
||||
r, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Println("Got error while sending a request to 'processor' app ", err)
|
||||
continue
|
||||
}
|
||||
defer r.Body.Close()
|
||||
if r.StatusCode != http.StatusOK {
|
||||
log.Printf("Error sending metrics with %d to 'processor' app got status code %d\n", i, r.StatusCode)
|
||||
log.Printf("Status %s \n", r.Status)
|
||||
continue
|
||||
}
|
||||
log.Printf("Metrics with ID %d sent \n", i)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
module emit-metrics
|
||||
|
||||
go 1.19
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
Copyright 2023 The Dapr Authors
|
||||
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 main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
type handler struct{}
|
||||
|
||||
type Metrics struct {
|
||||
MetricsID int `json:"metricsID"`
|
||||
}
|
||||
|
||||
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Println("Received request: ", r.Method)
|
||||
defer r.Body.Close()
|
||||
var metrics Metrics
|
||||
err := json.NewDecoder(r.Body).Decode(&metrics)
|
||||
if err != nil {
|
||||
fmt.Println("Error decoding body: ", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
fmt.Println("Received metrics: ", metrics)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("Starting server in port 9081...")
|
||||
StartServer(9081, &handler{})
|
||||
}
|
||||
|
||||
// StartServer starts a HTTP or HTTP2 server
|
||||
func StartServer(port int, handler http.Handler) {
|
||||
// Create a listener
|
||||
addr := fmt.Sprintf(":%d", port)
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create listener: %v", err)
|
||||
}
|
||||
//nolint:gosec
|
||||
server := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: handler,
|
||||
}
|
||||
|
||||
// Stop the server when we get a termination signal
|
||||
stopCh := make(chan os.Signal, 1)
|
||||
signal.Notify(stopCh, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGINT) //nolint:staticcheck
|
||||
go func() {
|
||||
// Wait for cancelation signal
|
||||
<-stopCh
|
||||
log.Println("Shutdown signal received")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||
defer cancel()
|
||||
server.Shutdown(ctx)
|
||||
}()
|
||||
|
||||
err = server.Serve(ln)
|
||||
|
||||
if err != http.ErrServerClosed {
|
||||
log.Fatalf("Failed to run server: %v", err)
|
||||
}
|
||||
|
||||
log.Println("Server shut down")
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
module processor
|
||||
|
||||
go 1.19
|
|
@ -15,8 +15,12 @@ package spawn
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CommandWithContext runs a command with its arguments in background.
|
||||
|
@ -72,3 +76,39 @@ func Command(command string, arguments ...string) (string, error) {
|
|||
|
||||
return string(outBytes), err
|
||||
}
|
||||
|
||||
// CommandExecWithContext runs a command with its arguments, kills the command after context is done
|
||||
// and returns the combined stdout, stderr or the error.
|
||||
func CommandExecWithContext(ctx context.Context, command string, arguments ...string) (string, error) {
|
||||
cmd := exec.Command(command, arguments...)
|
||||
var b bytes.Buffer
|
||||
cmd.Stdout = &b
|
||||
cmd.Stderr = &b
|
||||
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error starting command : %w", err)
|
||||
}
|
||||
|
||||
waitErrChan := make(chan error, 1)
|
||||
go func(errChan chan error) {
|
||||
waitErr := cmd.Wait()
|
||||
if waitErr != nil {
|
||||
fmt.Printf("error waiting for command : %s\n", waitErr)
|
||||
}
|
||||
waitErrChan <- waitErr
|
||||
}(waitErrChan)
|
||||
<-ctx.Done()
|
||||
if cmd.ProcessState == nil || !cmd.ProcessState.Exited() {
|
||||
cmd.Process.Signal(syscall.SIGTERM)
|
||||
time.Sleep(10 * time.Second)
|
||||
if cmd.ProcessState == nil || !cmd.ProcessState.Exited() {
|
||||
err = cmd.Process.Kill()
|
||||
if err != nil {
|
||||
return b.String(), fmt.Errorf("error killing command : %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return b.String(), <-waitErrChan
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//go:build e2e
|
||||
// +build e2e
|
||||
//go:build e2e || template
|
||||
// +build e2e template
|
||||
|
||||
/*
|
||||
Copyright 2022 The Dapr Authors
|
||||
|
@ -119,6 +119,18 @@ func cmdRun(unixDomainSocket string, args ...string) (string, error) {
|
|||
return spawn.Command(common.GetDaprPath(), runArgs...)
|
||||
}
|
||||
|
||||
// cmdRun runs a Dapr instance and returns the command output and error.
|
||||
func cmdRunWithContext(ctx context.Context, unixDomainSocket string, args ...string) (string, error) {
|
||||
runArgs := []string{"run"}
|
||||
|
||||
if unixDomainSocket != "" {
|
||||
runArgs = append(runArgs, "--unix-domain-socket", unixDomainSocket)
|
||||
}
|
||||
|
||||
runArgs = append(runArgs, args...)
|
||||
return spawn.CommandExecWithContext(ctx, common.GetDaprPath(), runArgs...)
|
||||
}
|
||||
|
||||
// cmdStop stops the specified app and returns the command output and error.
|
||||
func cmdStop(appId string, args ...string) (string, error) {
|
||||
stopArgs := append([]string{"stop", "--log-as-json", "--app-id", appId}, args...)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//go:build e2e
|
||||
// +build e2e
|
||||
//go:build e2e && !template
|
||||
// +build e2e,!template
|
||||
|
||||
/*
|
||||
Copyright 2022 The Dapr Authors
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//go:build e2e
|
||||
// +build e2e
|
||||
//go:build e2e && !template
|
||||
// +build e2e,!template
|
||||
|
||||
/*
|
||||
Copyright 2022 The Dapr Authors
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//go:build e2e
|
||||
// +build e2e
|
||||
//go:build e2e && !template
|
||||
// +build e2e,!template
|
||||
|
||||
/*
|
||||
Copyright 2022 The Dapr Authors
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//go:build e2e
|
||||
// +build e2e
|
||||
//go:build e2e && !template
|
||||
// +build e2e,!template
|
||||
|
||||
/*
|
||||
Copyright 2022 The Dapr Authors
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//go:build e2e
|
||||
// +build e2e
|
||||
//go:build e2e && !template
|
||||
// +build e2e,!template
|
||||
|
||||
/*
|
||||
Copyright 2022 The Dapr Authors
|
||||
|
|
|
@ -0,0 +1,365 @@
|
|||
//go:build e2e || template
|
||||
// +build e2e template
|
||||
|
||||
/*
|
||||
Copyright 2023 The Dapr Authors
|
||||
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 standalone_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type AppTestOutput struct {
|
||||
appID string
|
||||
appLogContents []string
|
||||
daprdLogContent []string
|
||||
baseLogDirPath string
|
||||
appLogDoesNotExist bool
|
||||
}
|
||||
|
||||
func TestRunWithTemplateFile(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Skipping test on Windows")
|
||||
}
|
||||
ensureDaprInstallation(t)
|
||||
t.Cleanup(func() {
|
||||
// remove dapr installation after all tests in this function.
|
||||
must(t, cmdUninstall, "failed to uninstall Dapr")
|
||||
})
|
||||
// These tests are dependent on run template files in ../testdata/run-template-files folder.
|
||||
|
||||
t.Run("invalid template file wrong emit metrics app run", func(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
// assumption in the test is that there is only one set of app and daprd logs in the logs directory.
|
||||
os.RemoveAll("../../apps/emit-metrics/.dapr/logs")
|
||||
os.RemoveAll("../../apps/processor/.dapr/logs")
|
||||
})
|
||||
args := []string{
|
||||
"-f", "../testdata/run-template-files/wrong_emit_metrics_app_dapr.yaml",
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
output, err := cmdRunWithContext(ctx, "", args...)
|
||||
t.Logf(output)
|
||||
require.NoError(t, err, "run failed")
|
||||
// Deterministic output for template file, so we can assert line by line
|
||||
lines := strings.Split(output, "\n")
|
||||
assert.GreaterOrEqual(t, len(lines), 4, "expected at least 4 lines in output of starting two apps")
|
||||
assert.Contains(t, lines[1], "Started Dapr with app id \"processor\". HTTP Port: 3510.")
|
||||
assert.Contains(t, lines[2], "Writing log files to directory")
|
||||
assert.Contains(t, lines[2], "tests/apps/processor/.dapr/logs")
|
||||
assert.Contains(t, lines[4], "Started Dapr with app id \"emit-metrics\". HTTP Port: 3511.")
|
||||
assert.Contains(t, lines[5], "Writing log files to directory")
|
||||
assert.Contains(t, lines[5], "tests/apps/emit-metrics/.dapr/logs")
|
||||
assert.Contains(t, output, "Received signal to stop Dapr and app processes. Shutting down Dapr and app processes.")
|
||||
appTestOutput := AppTestOutput{
|
||||
appID: "processor",
|
||||
baseLogDirPath: "../../apps/processor/.dapr/logs",
|
||||
daprdLogContent: []string{
|
||||
"http server is running on port 3510",
|
||||
"You're up and running! Dapr logs will appear here.",
|
||||
},
|
||||
}
|
||||
assertLogOutputForRunTemplateExec(t, appTestOutput)
|
||||
appTestOutput = AppTestOutput{
|
||||
appID: "emit-metrics",
|
||||
baseLogDirPath: "../../apps/emit-metrics/.dapr/logs",
|
||||
appLogContents: []string{
|
||||
"stat wrongappname.go: no such file or directory",
|
||||
"The App process exited with error code: exit status 1",
|
||||
},
|
||||
daprdLogContent: []string{
|
||||
"termination signal received: shutting down",
|
||||
"Exited Dapr successfully",
|
||||
},
|
||||
}
|
||||
assertLogOutputForRunTemplateExec(t, appTestOutput)
|
||||
})
|
||||
|
||||
t.Run("valid template file", func(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
// assumption in the test is that there is only one set of app and daprd logs in the logs directory.
|
||||
os.RemoveAll("../../apps/emit-metrics/.dapr/logs")
|
||||
os.RemoveAll("../../apps/processor/.dapr/logs")
|
||||
})
|
||||
args := []string{
|
||||
"-f", "../testdata/run-template-files/dapr.yaml",
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
output, err := cmdRunWithContext(ctx, "", args...)
|
||||
t.Logf(output)
|
||||
require.NoError(t, err, "run failed")
|
||||
// Deterministic output for template file, so we can assert line by line
|
||||
lines := strings.Split(output, "\n")
|
||||
assert.GreaterOrEqual(t, len(lines), 6, "expected at least 6 lines in output of starting two apps")
|
||||
assert.Contains(t, lines[0], "Validating config and starting app \"processor\"")
|
||||
assert.Contains(t, lines[1], "Started Dapr with app id \"processor\". HTTP Port: 3510.")
|
||||
assert.Contains(t, lines[2], "Writing log files to directory")
|
||||
assert.Contains(t, lines[2], "tests/apps/processor/.dapr/logs")
|
||||
assert.Contains(t, lines[3], "Validating config and starting app \"emit-metrics\"")
|
||||
assert.Contains(t, lines[4], "Started Dapr with app id \"emit-metrics\". HTTP Port: 3511.")
|
||||
assert.Contains(t, lines[5], "Writing log files to directory")
|
||||
assert.Contains(t, lines[5], "tests/apps/emit-metrics/.dapr/logs")
|
||||
assert.Contains(t, output, "Received signal to stop Dapr and app processes. Shutting down Dapr and app processes.")
|
||||
appTestOutput := AppTestOutput{
|
||||
appID: "processor",
|
||||
baseLogDirPath: "../../apps/processor/.dapr/logs",
|
||||
appLogContents: []string{
|
||||
"Received metrics: {3}",
|
||||
},
|
||||
daprdLogContent: []string{
|
||||
"http server is running on port 3510",
|
||||
"You're up and running! Dapr logs will appear here.",
|
||||
},
|
||||
}
|
||||
assertLogOutputForRunTemplateExec(t, appTestOutput)
|
||||
appTestOutput = AppTestOutput{
|
||||
appID: "emit-metrics",
|
||||
baseLogDirPath: "../../apps/emit-metrics/.dapr/logs",
|
||||
appLogContents: []string{
|
||||
"DAPR_HTTP_PORT set to 3511",
|
||||
"DAPR_HOST_ADD set to localhost",
|
||||
"Metrics with ID 3 sent",
|
||||
},
|
||||
daprdLogContent: []string{
|
||||
"termination signal received: shutting down",
|
||||
"Exited Dapr successfully",
|
||||
"Exited App successfully",
|
||||
},
|
||||
}
|
||||
assertLogOutputForRunTemplateExec(t, appTestOutput)
|
||||
})
|
||||
|
||||
t.Run("invalid template file env var not set", func(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
// assumption in the test is that there is only one set of app and daprd logs in the logs directory.
|
||||
os.RemoveAll("../../apps/emit-metrics/.dapr/logs")
|
||||
os.RemoveAll("../../apps/processor/.dapr/logs")
|
||||
})
|
||||
args := []string{
|
||||
"-f", "../testdata/run-template-files/env_var_not_set_dapr.yaml",
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
output, err := cmdRunWithContext(ctx, "", args...)
|
||||
t.Logf(output)
|
||||
require.NoError(t, err, "run failed")
|
||||
// Deterministic output for template file, so we can assert line by line
|
||||
lines := strings.Split(output, "\n")
|
||||
assert.GreaterOrEqual(t, len(lines), 6, "expected at least 6 lines in output of starting two apps")
|
||||
assert.Contains(t, lines[1], "Started Dapr with app id \"processor\". HTTP Port: 3510.")
|
||||
assert.Contains(t, lines[2], "Writing log files to directory")
|
||||
assert.Contains(t, lines[2], "tests/apps/processor/.dapr/logs")
|
||||
assert.Contains(t, lines[4], "Started Dapr with app id \"emit-metrics\". HTTP Port: 3511.")
|
||||
assert.Contains(t, lines[5], "Writing log files to directory")
|
||||
assert.Contains(t, lines[5], "tests/apps/emit-metrics/.dapr/logs")
|
||||
assert.Contains(t, output, "Received signal to stop Dapr and app processes. Shutting down Dapr and app processes.")
|
||||
appTestOutput := AppTestOutput{
|
||||
appID: "processor",
|
||||
baseLogDirPath: "../../apps/processor/.dapr/logs",
|
||||
daprdLogContent: []string{
|
||||
"http server is running on port 3510",
|
||||
"You're up and running! Dapr logs will appear here.",
|
||||
},
|
||||
}
|
||||
assertLogOutputForRunTemplateExec(t, appTestOutput)
|
||||
appTestOutput = AppTestOutput{
|
||||
appID: "emit-metrics",
|
||||
baseLogDirPath: "../../apps/emit-metrics/.dapr/logs",
|
||||
appLogContents: []string{
|
||||
"DAPR_HTTP_PORT set to 3511",
|
||||
"exit status 1",
|
||||
"Error exiting App: exit status 1",
|
||||
},
|
||||
daprdLogContent: []string{
|
||||
"termination signal received: shutting down",
|
||||
"Exited Dapr successfully",
|
||||
},
|
||||
}
|
||||
assertLogOutputForRunTemplateExec(t, appTestOutput)
|
||||
})
|
||||
|
||||
t.Run("valid template file no app command", func(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
// assumption in the test is that there is only one set of app and daprd logs in the logs directory.
|
||||
os.RemoveAll("../../apps/emit-metrics/.dapr/logs")
|
||||
os.RemoveAll("../../apps/processor/.dapr/logs")
|
||||
})
|
||||
args := []string{
|
||||
"-f", "../testdata/run-template-files/no_app_command.yaml",
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
output, err := cmdRunWithContext(ctx, "", args...)
|
||||
t.Logf(output)
|
||||
require.NoError(t, err, "run failed")
|
||||
// Deterministic output for template file, so we can assert line by line
|
||||
lines := strings.Split(output, "\n")
|
||||
assert.GreaterOrEqual(t, len(lines), 7, "expected at least 7 lines in output of starting two apps with one app not having a command")
|
||||
assert.Contains(t, lines[1], "Started Dapr with app id \"processor\". HTTP Port: 3510.")
|
||||
assert.Contains(t, lines[2], "Writing log files to directory")
|
||||
assert.Contains(t, lines[2], "tests/apps/processor/.dapr/logs")
|
||||
assert.Contains(t, lines[4], "No application command found for app \"emit-metrics\" present in")
|
||||
assert.Contains(t, lines[5], "Started Dapr with app id \"emit-metrics\". HTTP Port: 3511.")
|
||||
assert.Contains(t, lines[6], "Writing log files to directory")
|
||||
assert.Contains(t, lines[6], "tests/apps/emit-metrics/.dapr/logs")
|
||||
assert.Contains(t, output, "Received signal to stop Dapr and app processes. Shutting down Dapr and app processes.")
|
||||
appTestOutput := AppTestOutput{
|
||||
appID: "processor",
|
||||
baseLogDirPath: "../../apps/processor/.dapr/logs",
|
||||
appLogContents: []string{
|
||||
"Starting server in port 9081...",
|
||||
"termination signal received: shutting down",
|
||||
},
|
||||
daprdLogContent: []string{
|
||||
"http server is running on port 3510",
|
||||
"You're up and running! Dapr logs will appear here.",
|
||||
},
|
||||
}
|
||||
assertLogOutputForRunTemplateExec(t, appTestOutput)
|
||||
appTestOutput = AppTestOutput{
|
||||
appID: "emit-metrics",
|
||||
baseLogDirPath: "../../apps/emit-metrics/.dapr/logs",
|
||||
appLogDoesNotExist: true,
|
||||
daprdLogContent: []string{
|
||||
"termination signal received: shutting down",
|
||||
"Exited Dapr successfully",
|
||||
},
|
||||
}
|
||||
assertLogOutputForRunTemplateExec(t, appTestOutput)
|
||||
})
|
||||
|
||||
t.Run("valid template file empty app command", func(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
// assumption in the test is that there is only one set of app and daprd logs in the logs directory.
|
||||
os.RemoveAll("../../apps/emit-metrics/.dapr/logs")
|
||||
os.RemoveAll("../../apps/processor/.dapr/logs")
|
||||
})
|
||||
args := []string{
|
||||
"-f", "../testdata/run-template-files/empty_app_command.yaml",
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
output, err := cmdRunWithContext(ctx, "", args...)
|
||||
t.Logf(output)
|
||||
require.Error(t, err, "run must fail")
|
||||
// Deterministic output for template file, so we can assert line by line
|
||||
lines := strings.Split(output, "\n")
|
||||
assert.GreaterOrEqual(t, len(lines), 5, "expected at least 5 lines in output of starting two apps with last app having an empty command")
|
||||
assert.Contains(t, lines[1], "Started Dapr with app id \"processor\". HTTP Port: 3510.")
|
||||
assert.Contains(t, lines[2], "Writing log files to directory")
|
||||
assert.Contains(t, lines[2], "tests/apps/processor/.dapr/logs")
|
||||
assert.Contains(t, lines[4], "Error starting Dapr and app (\"emit-metrics\"): exec: no command")
|
||||
appTestOutput := AppTestOutput{
|
||||
appID: "processor",
|
||||
baseLogDirPath: "../../apps/processor/.dapr/logs",
|
||||
appLogContents: []string{
|
||||
"Starting server in port 9081...",
|
||||
"termination signal received: shutting down",
|
||||
},
|
||||
daprdLogContent: []string{
|
||||
"http server is running on port 3510",
|
||||
"You're up and running! Dapr logs will appear here.",
|
||||
},
|
||||
}
|
||||
assertLogOutputForRunTemplateExec(t, appTestOutput)
|
||||
appTestOutput = AppTestOutput{
|
||||
appID: "emit-metrics",
|
||||
baseLogDirPath: "../../apps/emit-metrics/.dapr/logs",
|
||||
appLogContents: []string{
|
||||
"Error starting app process: exec: no command",
|
||||
},
|
||||
daprdLogContent: []string{
|
||||
"Error starting Dapr and app (\"emit-metrics\"): exec: no command",
|
||||
},
|
||||
}
|
||||
assertLogOutputForRunTemplateExec(t, appTestOutput)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRunTemplateFileWithoutDaprInit(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Skipping test on Windows")
|
||||
}
|
||||
// remove any dapr installation before this test.
|
||||
must(t, cmdUninstall, "failed to uninstall Dapr")
|
||||
t.Run("valid template file without dapr init", func(t *testing.T) {
|
||||
args := []string{
|
||||
"-f", "../testdata/run-template-files/no_app_command.yaml",
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
output, err := cmdRunWithContext(ctx, "", args...)
|
||||
t.Logf(output)
|
||||
require.Error(t, err, "run must fail")
|
||||
assert.Contains(t, output, " Error starting Dapr and app (\"processor\"): fork/exec")
|
||||
assert.Contains(t, output, "daprd: no such file or directory")
|
||||
})
|
||||
}
|
||||
|
||||
func assertLogOutputForRunTemplateExec(t *testing.T, appTestOutput AppTestOutput) {
|
||||
// assumption in the test is that there is only one set of app and daprd logs in the logs directory.
|
||||
// This is true for the tests in this file.
|
||||
daprdLogFileName, err := lookUpFileFullName(appTestOutput.baseLogDirPath, "daprd")
|
||||
require.NoError(t, err, "failed to find daprd log file")
|
||||
daprdLogPath := filepath.Join(appTestOutput.baseLogDirPath, daprdLogFileName)
|
||||
readAndAssertLogFileContents(t, daprdLogPath, appTestOutput.daprdLogContent)
|
||||
|
||||
if appTestOutput.appLogDoesNotExist {
|
||||
return
|
||||
}
|
||||
appLogFileName, err := lookUpFileFullName(appTestOutput.baseLogDirPath, "app")
|
||||
require.NoError(t, err, "failed to find app log file")
|
||||
appLogPath := filepath.Join(appTestOutput.baseLogDirPath, appLogFileName)
|
||||
readAndAssertLogFileContents(t, appLogPath, appTestOutput.appLogContents)
|
||||
}
|
||||
|
||||
func readAndAssertLogFileContents(t *testing.T, logFilePath string, expectedContent []string) {
|
||||
assert.FileExists(t, logFilePath, "log file %s must exist", logFilePath)
|
||||
fileContents, err := ioutil.ReadFile(logFilePath)
|
||||
assert.NoError(t, err, "failed to read %s log", logFilePath)
|
||||
contentString := string(fileContents)
|
||||
for _, line := range expectedContent {
|
||||
assert.Contains(t, contentString, line, "expected logline to be present")
|
||||
}
|
||||
}
|
||||
|
||||
// lookUpFileFullName looks up the full name of the first file with partial name match in the directory.
|
||||
func lookUpFileFullName(dirPath, partialFilename string) (string, error) {
|
||||
// Look for the file in the current directory
|
||||
files, err := ioutil.ReadDir(dirPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, file := range files {
|
||||
if strings.Contains(file.Name(), partialFilename) {
|
||||
return file.Name(), nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("failed to find file with partial name %s in directory %s", partialFilename, dirPath)
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
//go:build e2e
|
||||
// +build e2e
|
||||
//go:build e2e && !template
|
||||
// +build e2e,!template
|
||||
|
||||
/*
|
||||
Copyright 2022 The Dapr Authors
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//go:build e2e
|
||||
// +build e2e
|
||||
//go:build e2e && !template
|
||||
// +build e2e,!template
|
||||
|
||||
/*
|
||||
Copyright 2022 The Dapr Authors
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//go:build e2e
|
||||
// +build e2e
|
||||
//go:build e2e && !template
|
||||
// +build e2e,!template
|
||||
|
||||
/*
|
||||
Copyright 2022 The Dapr Authors
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//go:build e2e
|
||||
// +build e2e
|
||||
//go:build e2e || template
|
||||
// +build e2e template
|
||||
|
||||
/*
|
||||
Copyright 2022 The Dapr Authors
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//go:build e2e
|
||||
// +build e2e
|
||||
//go:build e2e && !template
|
||||
// +build e2e,!template
|
||||
|
||||
/*
|
||||
Copyright 2022 The Dapr Authors
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: dapr.io/v1alpha1
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: appconfig
|
||||
spec:
|
|
@ -0,0 +1,12 @@
|
|||
version: 1
|
||||
apps:
|
||||
- app_dir_path: ../../../apps/processor/
|
||||
app_port: 9081
|
||||
dapr_http_port: 3510
|
||||
command: ["go","run", "app.go"]
|
||||
- app_id: emit-metrics
|
||||
app_dir_path: ../../../apps/emit-metrics/
|
||||
dapr_http_port: 3511
|
||||
env:
|
||||
DAPR_HOST_ADD: localhost
|
||||
command: ["go","run", "app.go"]
|
|
@ -0,0 +1,12 @@
|
|||
version: 1
|
||||
apps:
|
||||
- app_dir_path: ../../../apps/processor/
|
||||
app_port: 9081
|
||||
dapr_http_port: 3510
|
||||
command: ["go","run", "app.go"]
|
||||
- app_id: emit-metrics
|
||||
app_dir_path: ../../../apps/emit-metrics/
|
||||
dapr_http_port: 3511
|
||||
env:
|
||||
DAPR_HOST_ADD: localhost
|
||||
command: [""]
|
|
@ -0,0 +1,10 @@
|
|||
version: 1
|
||||
apps:
|
||||
- app_dir_path: ../../../apps/processor/
|
||||
app_port: 9081
|
||||
dapr_http_port: 3510
|
||||
command: ["go","run", "app.go"]
|
||||
- app_id: emit-metrics
|
||||
app_dir_path: ../../../apps/emit-metrics/
|
||||
dapr_http_port: 3511 # required env var DAPR_HOST_ADD not set in the yaml file
|
||||
command: ["go","run", "app.go"]
|
|
@ -0,0 +1,17 @@
|
|||
version: 1
|
||||
common:
|
||||
# Unused resources. This is set so that when dapr is not init validation does not fail.
|
||||
# Used in test run template when dapr is not init.
|
||||
resources_path: ../resources
|
||||
config_file_path: appconfig.yaml
|
||||
apps:
|
||||
- app_dir_path: ../../../apps/processor/
|
||||
app_port: 9081
|
||||
dapr_http_port: 3510
|
||||
command: ["go","run", "app.go"]
|
||||
- app_id: emit-metrics
|
||||
app_dir_path: ../../../apps/emit-metrics/
|
||||
dapr_http_port: 3511
|
||||
env:
|
||||
DAPR_HOST_ADD: localhost
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
version: 1
|
||||
apps:
|
||||
- app_dir_path: ../../../apps/processor/
|
||||
app_port: 9081
|
||||
dapr_http_port: 3510
|
||||
command: ["go","run", "app.go"]
|
||||
- app_id: emit-metrics
|
||||
app_dir_path: ../../../apps/emit-metrics/
|
||||
dapr_http_port: 3511
|
||||
env:
|
||||
DAPR_HOST_ADD: localhost
|
||||
# Set wrong app name
|
||||
command: ["go","run", "wrongappname.go"]
|
Loading…
Reference in New Issue