diff --git a/.github/workflows/smoketest.yml b/.github/workflows/smoketest.yml new file mode 100644 index 0000000000..a7f67da2b8 --- /dev/null +++ b/.github/workflows/smoketest.yml @@ -0,0 +1,92 @@ +on: + push: + branches: + - main +name: SmokeTest +concurrency: + group: ${{ github.ref }}-smoketest + cancel-in-progress: true +jobs: + smoke-test-upgrade-path: + name: Smoke Test Upgrade Path + if: github.event_name != 'pull_request' || github.event.action == 'enqueued' || contains( github.event.pull_request.labels.*.name, 'run-all') + runs-on: ubuntu-latest + steps: + - name: Checkout the repository with full history + uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref }} + fetch-depth: 0 + fetch-tags: true + - name: Get last tagged release + run: | + latest_release=$(git tag --sort=-v:refname | grep -v v1 | head -n 1) + echo "Latest release: $latest_release" + echo "LATEST_VERSION=${latest_release#v}" >> "$GITHUB_ENV" + - name: Check out the last tagged release + uses: actions/checkout@v4 + with: + ref: v${{ env.LATEST_VERSION }} + fetch-depth: 1 + fetch-tags: true + # The following grabs the current smoke test and deployment Justfile from the HEAD. This + # is to solve the chicken-and-egg. Once it's in the tagged release, skip this. + - name: Check out the current smoke test + uses: actions/checkout@v4 + with: + clean: false + repository: TBD54566975/ftl.git + path: tmpsmoketest + ref: ${{ github.head_ref }} + fetch-depth: 0 + sparse-checkout: | + smoketest + deployment + sparse-checkout-cone-mode: false + # When we remove the above step to fetch the current smoke tests and deployment Justfile + # into tmpsmoketest, remove the overwrite step as well. + - name: Replace the tagged release smoketest with the current smoketest + run: | + set -euo pipefail + echo "Replacing tagged release smoketest with current smoketest" + rm -r ./smoketest && mv ./tmpsmoketest/smoketest ./smoketest + echo "Replacing deployment Justfile with current Justfile" + cp ./tmpsmoketest/deployment/Justfile ./deployment/Justfile + echo "Removing tmpsmoketest" + rm -r ./tmpsmoketest + - name: Init Hermit + uses: cashapp/activate-hermit@v1 + with: + cache: true + - name: Build Cache + uses: ./.github/actions/build-cache + - name: Download Go Modules + run: go mod download + - name: Set up a kube cluster with the tagged release dockerhub image + run: | + set -euo pipefail + echo "Deploying the tagged release to the cluster" + cd deployment && just deploy-version ${{ env.LATEST_VERSION }} && cd .. + # We skip this since it requires an integration test change to skip the full kube deploy. + # Re-enable this step when the tagged release has the integration test change. + # - name: Smoke test the tagged release images + # run: | + # set -euo pipefail + # echo "Running smoke test on the tagged release images" + # USE_DB_CONFIG=true SKIP_KUBE_FULL_DEPLOY=true go test -v -tags smoketest -run '^Test' ./smoketest + - name: Check out HEAD of the current branch + uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref }} + fetch-depth: 1 + - name: Smoke test HEAD with a full deploy to test upgrade path + run: | + set -euo pipefail + echo "Running smoke test on the HEAD images" + USE_DB_CONFIG=true go test -v -timeout 15m -tags smoketest -run '^Test' ./smoketest + - name: Archive Report + uses: actions/upload-artifact@v4 + if: always() + with: + name: kube-report-smoke-test-upgrade + path: /tmp/ftl-kube-report/ diff --git a/deployment/Justfile b/deployment/Justfile index fcfac310d9..7c8f9a0ba0 100755 --- a/deployment/Justfile +++ b/deployment/Justfile @@ -72,8 +72,9 @@ apply: kubectl delete job --ignore-not-found=true ftl-dbmig-latest helm upgrade --install ftl ../charts/ftl -f values.yaml -deploy-version version: setup-cluster +deploy-version version: setup-cluster install-istio helm repo add ftl https://tbd54566975.github.io/ftl-charts --force-update + helm upgrade --install ftl ftl/ftl --version={{version}} -f values-release.yaml || sleep 5 # wait for CRDs to be created, the initial apply will usually fail helm upgrade --install ftl ftl/ftl --version={{version}} -f values-release.yaml delete: diff --git a/internal/integration/actions.go b/internal/integration/actions.go index b2b6a0227c..909f4b8662 100644 --- a/internal/integration/actions.go +++ b/internal/integration/actions.go @@ -1,4 +1,4 @@ -//go:build integration || infrastructure +//go:build integration || infrastructure || smoketest package integration diff --git a/internal/integration/harness.go b/internal/integration/harness.go index ffc07fa688..6dd30c0176 100644 --- a/internal/integration/harness.go +++ b/internal/integration/harness.go @@ -1,4 +1,4 @@ -//go:build integration || infrastructure +//go:build integration || infrastructure || smoketest package integration diff --git a/smoketest/echo/echo.go b/smoketest/echo/echo.go new file mode 100644 index 0000000000..6ce84c47b6 --- /dev/null +++ b/smoketest/echo/echo.go @@ -0,0 +1,14 @@ +// This is the echo module. +package echo + +import ( + "context" + "fmt" +) + +// Echo returns a greeting with the current time. +// +//ftl:verb export +func Echo(ctx context.Context, req string) (string, error) { + return fmt.Sprintf("Hello, %s!!!", req), nil +} diff --git a/smoketest/echo/ftl.toml b/smoketest/echo/ftl.toml new file mode 100644 index 0000000000..72ce292aa2 --- /dev/null +++ b/smoketest/echo/ftl.toml @@ -0,0 +1,2 @@ +module = "echo" +language = "go" diff --git a/smoketest/echo/go.mod b/smoketest/echo/go.mod new file mode 100644 index 0000000000..7a9cff947f --- /dev/null +++ b/smoketest/echo/go.mod @@ -0,0 +1,18 @@ +module ftl/echo + +go 1.23.0 + +replace github.com/TBD54566975/ftl => ../.. + +require github.com/TBD54566975/ftl v0.0.0-00010101000000-000000000000 + +require ( + github.com/alecthomas/participle/v2 v2.1.1 // indirect + github.com/alecthomas/types v0.16.0 // indirect + github.com/deckarep/golang-set/v2 v2.6.0 // indirect + github.com/hashicorp/cronexpr v1.1.2 // indirect + github.com/swaggest/jsonschema-go v0.3.72 // indirect + github.com/swaggest/refl v1.3.0 // indirect + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect + google.golang.org/protobuf v1.35.1 // indirect +) diff --git a/smoketest/echo/go.sum b/smoketest/echo/go.sum new file mode 100644 index 0000000000..c74b6955ee --- /dev/null +++ b/smoketest/echo/go.sum @@ -0,0 +1,206 @@ +al.essio.dev/pkg/shellescape v1.5.1 h1:86HrALUujYS/h+GtqoB26SBEdkWfmMI6FubjXlsXyho= +al.essio.dev/pkg/shellescape v1.5.1/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890= +connectrpc.com/connect v1.16.2 h1:ybd6y+ls7GOlb7Bh5C8+ghA6SvCBajHwxssO2CGFjqE= +connectrpc.com/connect v1.16.2/go.mod h1:n2kgwskMHXC+lVqb18wngEpF95ldBHXjZYJussz5FRc= +connectrpc.com/grpcreflect v1.2.0 h1:Q6og1S7HinmtbEuBvARLNwYmTbhEGRpHDhqrPNlmK+U= +connectrpc.com/grpcreflect v1.2.0/go.mod h1:nwSOKmE8nU5u/CidgHtPYk1PFI3U9ignz7iDMxOYkSY= +connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY= +connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= +github.com/TBD54566975/scaffolder v1.2.0 h1:7NqCC+iTDgk2awkOgk2Pj95Nz3GonhdIhwHQgQxug9k= +github.com/TBD54566975/scaffolder v1.2.0/go.mod h1:oHLiKFPkkSMHP4ALVZ91T2V/xyx4MvPpRSpQttJxY7g= +github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= +github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= +github.com/alecthomas/concurrency v0.0.2 h1:Q3kGPtLbleMbH9lHX5OBFvJygfyFw29bXZKBg+IEVuo= +github.com/alecthomas/concurrency v0.0.2/go.mod h1:GmuQb/iHX7mbNtPlC/WDzEFxDMB0HYFer2Qda9QTs7w= +github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8= +github.com/alecthomas/participle/v2 v2.1.1/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= +github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= +github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/alecthomas/types v0.16.0 h1:o9+JSwCRB6DDaWDeR/Mg7v/zh3R+MlknM6DrnDyY7U0= +github.com/alecthomas/types v0.16.0/go.mod h1:Tswm0qQpjpVq8rn70OquRsUtFxbQKub/8TMyYYGI0+k= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/bool64/dev v0.2.35 h1:M17TLsO/pV2J7PYI/gpe3Ua26ETkzZGb+dC06eoMqlk= +github.com/bool64/dev v0.2.35/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= +github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= +github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs= +github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0= +github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= +github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc= +github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= +github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= +github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4= +github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7o2xQ= +github.com/swaggest/assertjson v1.9.0/go.mod h1:b+ZKX2VRiUjxfUIal0HDN85W0nHPAYUbYH5WkkSsFsU= +github.com/swaggest/jsonschema-go v0.3.72 h1:IHaGlR1bdBUBPfhe4tfacN2TGAPKENEGiNyNzvnVHv4= +github.com/swaggest/jsonschema-go v0.3.72/go.mod h1:OrGyEoVqpfSFJ4Am4V/FQcQ3mlEC1vVeleA+5ggbVW4= +github.com/swaggest/refl v1.3.0 h1:PEUWIku+ZznYfsoyheF97ypSduvMApYyGkYF3nabS0I= +github.com/swaggest/refl v1.3.0/go.mod h1:3Ujvbmh1pfSbDYjC6JGG7nMgPvpG0ehQL4iNonnLNbg= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/zalando/go-keyring v0.2.6 h1:r7Yc3+H+Ux0+M72zacZoItR3UDxeWfKTcabvkI8ua9s= +github.com/zalando/go-keyring v0.2.6/go.mod h1:2TCrxYrbUNYfNS/Kgy/LSrkSQzZ5UPVH85RwfczwvcI= +go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= +go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 h1:T6rh4haD3GVYsgEfWExoCZA2o2FmbNyKpTuAxbEFPTg= +google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:wp2WsuBYj6j8wUdo3ToZsdxxixbvQNAHqVJrTgi5E5M= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +istio.io/api v1.23.3 h1:+CP0AHz8/+WJ7ZKJLbilHEiqBCi5KLe1Yil9bJI39ow= +istio.io/api v1.23.3/go.mod h1:QPSTGXuIQdnZFEm3myf9NZ5uBMwCdJWUvfj9ZZ+2oBM= +istio.io/client-go v1.23.3 h1:rs+mO4A+NaXVcZgDO0RRZE7KRAlDooq2PSkxl7tevig= +istio.io/client-go v1.23.3/go.mod h1:Lfa3anzx7/kCOpcAciR+JiRMj/SYuzDcbXQDjkThnLg= +k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= +k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= +k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= +k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= +k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= +modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= +modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= +modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= +modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/sqlite v1.33.1 h1:trb6Z3YYoeM9eDL1O8do81kP+0ejv+YzgyFo+Gwy0nM= +modernc.org/sqlite v1.33.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/smoketest/echo/types.ftl.go b/smoketest/echo/types.ftl.go new file mode 100644 index 0000000000..c32e18f9a2 --- /dev/null +++ b/smoketest/echo/types.ftl.go @@ -0,0 +1,17 @@ +// Code generated by FTL. DO NOT EDIT. +package echo + +import ( + "context" + "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" +) + +type EchoClient func(context.Context, string) (string, error) + +func init() { + reflection.Register( + reflection.ProvideResourcesForVerb( + Echo, + ), + ) +} diff --git a/smoketest/smoketest_integration_test.go b/smoketest/exemplar_integration_test.go similarity index 75% rename from smoketest/smoketest_integration_test.go rename to smoketest/exemplar_integration_test.go index a24956e730..8233acef79 100644 --- a/smoketest/smoketest_integration_test.go +++ b/smoketest/exemplar_integration_test.go @@ -15,7 +15,7 @@ import ( in "github.com/TBD54566975/ftl/internal/integration" ) -func TestSmokeTest(t *testing.T) { +func TestExemplarIntegration(t *testing.T) { tmpDir := t.TempDir() logFilePath := filepath.Join(tmpDir, "smoketest.log") @@ -33,7 +33,7 @@ func TestSmokeTest(t *testing.T) { in.CopyModule("origin"), in.CopyModule("relay"), in.CopyModule("pulse"), - in.CreateDBAction("relay", "exemplardb", false), + // in.CreateDBAction("relay", "exemplardb", false), in.ExecWithOutput("ftl", []string{"config", "set", "origin.nonce", "--inline", nonce}, func(output string) { fmt.Println(output) @@ -47,19 +47,21 @@ func TestSmokeTest(t *testing.T) { in.Deploy("relay"), in.Deploy("pulse"), - in.ExecWithOutput("curl", []string{"-s", "-X", "POST", "http://127.0.0.1:8891/http/agent", "-H", "Content-Type: application/json", "-d", fmt.Sprintf(`{"id": %v, "alias": "james", "license_to_kill": true, "hired_at": "2023-10-23T23:20:45.00Z"}`, successAgentId)}, func(output string) { + in.ExecWithOutput("curl", []string{"-s", "-X", "POST", "http://127.0.0.1:8891/ingress/agent", "-H", "Content-Type: application/json", "-d", fmt.Sprintf(`{"id": %v, "alias": "james", "license_to_kill": true, "hired_at": "2023-10-23T23:20:45.00Z"}`, successAgentId)}, func(output string) { + fmt.Printf("output: %s\n", output) err := json.Unmarshal([]byte(output), &postResult) assert.NoError(t, err) assert.Equal(t, successAgentId, postResult.ID) }), - in.ExecWithOutput("curl", []string{"-s", "-X", "POST", "http://127.0.0.1:8891/http/agent", "-H", "Content-Type: application/json", "-d", fmt.Sprintf(`{"id": %v, "alias": "bill", "license_to_kill": false, "hired_at": "2024-08-12T21:10:37.00Z"}`, failedAgentId)}, func(output string) { + in.ExecWithOutput("curl", []string{"-s", "-X", "POST", "http://127.0.0.1:8891/ingress/agent", "-H", "Content-Type: application/json", "-d", fmt.Sprintf(`{"id": %v, "alias": "bill", "license_to_kill": false, "hired_at": "2024-08-12T21:10:37.00Z"}`, failedAgentId)}, func(output string) { + fmt.Printf("output: %s\n", output) err := json.Unmarshal([]byte(output), &postResult) assert.NoError(t, err) assert.Equal(t, failedAgentId, postResult.ID) }), - in.Sleep(2*time.Second), + in.Sleep(5*time.Second), in.ExecWithOutput("ftl", []string{"call", "relay.missionResult", fmt.Sprintf(`{"agentId": %v, "successful": true}`, successAgentId)}, func(output string) { fmt.Println(output) @@ -71,6 +73,10 @@ func TestSmokeTest(t *testing.T) { in.Sleep(2*time.Second), + // in.Call("relay", "fetchLogs", in.Obj{}, func(t testing.TB, resp in.Obj) { + // fmt.Printf("fetchLogs: %v\n", resp) + // }), + in.FileContains(logFilePath, fmt.Sprintf("deployed %d", successAgentId)), in.FileContains(logFilePath, fmt.Sprintf("deployed %d", failedAgentId)), in.FileContains(logFilePath, fmt.Sprintf("succeeded %d", successAgentId)), diff --git a/smoketest/exemplar_smoke_test.go b/smoketest/exemplar_smoke_test.go new file mode 100644 index 0000000000..53466b678f --- /dev/null +++ b/smoketest/exemplar_smoke_test.go @@ -0,0 +1,90 @@ +//go:build smoketest + +package smoketest + +import ( + "encoding/json" + "fmt" + "math/rand" + "path/filepath" + "testing" + "time" + + "github.com/alecthomas/assert/v2" + + in "github.com/TBD54566975/ftl/internal/integration" +) + +func TestExemplarSmoke(t *testing.T) { + tmpDir := "/tmp" + logFilePath := filepath.Join(tmpDir, "smoketest.log") + + var postResult struct { + ID int `json:"id"` + } + var successAgentId int = 7 + var failedAgentId int = 99 + nonce := randomString(4) + + in.Run(t, + in.WithKubernetes(), + in.WithJavaBuild(), + in.WithFTLConfig("../../../ftl-project.toml"), + in.WithTestDataDir("."), + in.CopyModule("origin"), + in.CopyModule("relay"), + in.CopyModule("pulse"), + + in.ExecWithOutput("ftl", []string{"config", "set", "origin.nonce", "--db", nonce}, func(output string) { + fmt.Println(output) + }), + + in.ExecWithOutput("ftl", []string{"config", "set", "relay.log_file", "--db", logFilePath}, func(output string) { + fmt.Println(output) + }), + + in.Deploy("origin"), + in.Deploy("relay"), + in.Deploy("pulse"), + + in.ExecWithOutput("curl", []string{"-s", "-X", "POST", "http://127.0.0.1:8891/ingress/agent", "-H", "Content-Type: application/json", "-d", fmt.Sprintf(`{"id": %v, "alias": "james", "license_to_kill": true, "hired_at": "2023-10-23T23:20:45.00Z"}`, successAgentId)}, func(output string) { + fmt.Printf("output: %s\n", output) + err := json.Unmarshal([]byte(output), &postResult) + assert.NoError(t, err) + assert.Equal(t, successAgentId, postResult.ID) + }), + + in.ExecWithOutput("curl", []string{"-s", "-X", "POST", "http://127.0.0.1:8891/ingress/agent", "-H", "Content-Type: application/json", "-d", fmt.Sprintf(`{"id": %v, "alias": "bill", "license_to_kill": false, "hired_at": "2024-08-12T21:10:37.00Z"}`, failedAgentId)}, func(output string) { + fmt.Printf("output: %s\n", output) + err := json.Unmarshal([]byte(output), &postResult) + assert.NoError(t, err) + assert.Equal(t, failedAgentId, postResult.ID) + }), + + in.Sleep(5*time.Second), + + in.ExecWithOutput("ftl", []string{"call", "relay.missionResult", fmt.Sprintf(`{"agentId": %v, "successful": true}`, successAgentId)}, func(output string) { + fmt.Println(output) + }), + + in.ExecWithOutput("ftl", []string{"call", "relay.missionResult", fmt.Sprintf(`{"agentId": %v, "successful": false}`, failedAgentId)}, func(output string) { + fmt.Println(output) + }), + + in.Sleep(2*time.Second), + + in.Call("relay", "fetchLogs", in.Obj{}, func(t testing.TB, resp in.Obj) { + fmt.Printf("fetchLogs: %v\n", resp) + }), + ) +} + +const charset = "abcdefghijklmnopqrstuvwxyz" + +func randomString(length int) string { + b := make([]byte, length) + for i := range b { + b[i] = charset[rand.Intn(len(charset))] + } + return string(b) +} diff --git a/smoketest/jecho/ftl.toml b/smoketest/jecho/ftl.toml new file mode 100644 index 0000000000..795fff84b5 --- /dev/null +++ b/smoketest/jecho/ftl.toml @@ -0,0 +1,2 @@ +module = "jecho" +language = "java" diff --git a/smoketest/jecho/pom.xml b/smoketest/jecho/pom.xml new file mode 100644 index 0000000000..aaae86efe4 --- /dev/null +++ b/smoketest/jecho/pom.xml @@ -0,0 +1,14 @@ + + + 4.0.0 + ftl.com.example + jecho + 1.0-SNAPSHOT + + + xyz.block.ftl + ftl-build-parent-java + 1.0-SNAPSHOT + + + diff --git a/smoketest/jecho/src/main/java/com/example/EchoVerb.java b/smoketest/jecho/src/main/java/com/example/EchoVerb.java new file mode 100644 index 0000000000..7cd2af1422 --- /dev/null +++ b/smoketest/jecho/src/main/java/com/example/EchoVerb.java @@ -0,0 +1,13 @@ +package com.example; + +import xyz.block.ftl.Export; +import xyz.block.ftl.Verb; + +public class EchoVerb { + + @Export + @Verb + public String echo(String request) { + return "Hello, " + request + "!"; + } +} diff --git a/smoketest/origin/origin.go b/smoketest/origin/origin.go index 9aa2ed7892..97693299ea 100644 --- a/smoketest/origin/origin.go +++ b/smoketest/origin/origin.go @@ -15,11 +15,10 @@ var nonce = ftl.Config[string]("nonce") var AgentBroadcast = ftl.Topic[Agent]("agentBroadcast") type Agent struct { - ID int `json:"id"` - Alias string `json:"alias"` - LicenseToKill bool `json:"license_to_kill"` - HiredAt time.Time `json:"hired_at"` - BriefedAt ftl.Option[time.Time] `json:"briefed_at"` + ID int `json:"id"` + Alias string `json:"alias"` + LicenseToKill bool `json:"license_to_kill"` + HiredAt time.Time `json:"hired_at"` } type PostAgentResponse struct { @@ -28,7 +27,7 @@ type PostAgentResponse struct { type PostAgentErrorResponse string -//ftl:ingress POST /http/agent +//ftl:ingress POST /ingress/agent func PostAgent(ctx context.Context, req builtin.HttpRequest[Agent, ftl.Unit, ftl.Unit]) (builtin.HttpResponse[PostAgentResponse, PostAgentErrorResponse], error) { agent := Agent{ ID: req.Body.ID, @@ -36,7 +35,13 @@ func PostAgent(ctx context.Context, req builtin.HttpRequest[Agent, ftl.Unit, ftl LicenseToKill: req.Body.LicenseToKill, HiredAt: req.Body.HiredAt, } - AgentBroadcast.Publish(ctx, agent) + err := AgentBroadcast.Publish(ctx, agent) + if err != nil { + return builtin.HttpResponse[PostAgentResponse, PostAgentErrorResponse]{ + Status: 500, + Body: ftl.None[PostAgentResponse](), + }, err + } return builtin.HttpResponse[PostAgentResponse, PostAgentErrorResponse]{ Status: 201, Body: ftl.Some(PostAgentResponse{ID: agent.ID}), diff --git a/smoketest/pulse/src/main/java/com/example/Pulse.java b/smoketest/pulse/src/main/java/com/example/Pulse.java index d3880c31ab..ea2808e1b8 100644 --- a/smoketest/pulse/src/main/java/com/example/Pulse.java +++ b/smoketest/pulse/src/main/java/com/example/Pulse.java @@ -6,28 +6,19 @@ import ftl.origin.GetNonceClient; import ftl.origin.GetNonceRequest; import ftl.origin.GetNonceResponse; -import ftl.relay.GetLogFileClient; -import ftl.relay.GetLogFileRequest; -import ftl.relay.GetLogFileResponse; +import ftl.relay.AppendLogClient; +import ftl.relay.AppendLogRequest; +import ftl.relay.AppendLogResponse; import io.quarkus.logging.Log; import xyz.block.ftl.Cron; public class Pulse { @Cron("1s") - public void cron10s(GetNonceClient nonceClient, GetLogFileClient logClient) throws Exception { - GetNonceResponse nr = nonceClient.getNonce(new GetNonceRequest()); - GetLogFileResponse lfr = logClient.getLogFile(new GetLogFileRequest()); - Log.infof("Cron job triggered, nonce %s, log file: %s", nr.getNonce(), lfr.getPath()); - appendLog(lfr.getPath(), "cron %s", nr.getNonce()); - } - - public static void appendLog(String path, String msg, Object... args) { - try (FileWriter writer = new FileWriter(path, true)) { - writer.write(String.format(msg + "%n", args)); - } catch (IOException e) { - throw new RuntimeException("Error writing to log file", e); - } + public void cron10s(GetNonceClient getNonceClient, AppendLogClient appendLogClient) throws Exception { + GetNonceResponse nr = getNonceClient.getNonce(new GetNonceRequest()); + Log.infof("Cron job triggered, nonce %s", nr.getNonce()); + appendLogClient.appendLog(new AppendLogRequest(String.format("cron %s", nr.getNonce()))); } } diff --git a/smoketest/relay/relay.go b/smoketest/relay/relay.go index b32f4ea8ca..30011acad9 100644 --- a/smoketest/relay/relay.go +++ b/smoketest/relay/relay.go @@ -12,7 +12,8 @@ import ( ) var logFile = ftl.Config[string]("log_file") -var db = ftl.PostgresDatabase("exemplardb") + +// var db = ftl.PostgresDatabase("exemplardb") // PubSub @@ -41,9 +42,7 @@ type AgentTerminated struct { //ftl:verb func Briefed(ctx context.Context, agent origin.Agent, deployed DeployedClient) error { - briefedAt := time.Now() - ftl.LoggerFromContext(ctx).Infof("Briefed agent %v at %s", agent.Id, briefedAt) - agent.BriefedAt = ftl.Some(briefedAt) + ftl.LoggerFromContext(ctx).Infof("Briefed agent %v", agent.Id) d := AgentDeployment{ Agent: agent, Target: "villain", @@ -88,7 +87,7 @@ func MissionResult(ctx context.Context, req MissionResultRequest, success Succee AgentID: int(agentID), SuccessAt: time.Now(), } - err := success(ctx, event.(MissionSuccess)) + err := success(ctx, event.(MissionSuccess)) //nolint:forcetypeassert if err != nil { return MissionResultResponse{}, err } @@ -97,7 +96,7 @@ func MissionResult(ctx context.Context, req MissionResultRequest, success Succee AgentID: int(agentID), TerminatedAt: time.Now(), } - err := failure(ctx, event.(AgentTerminated)) + err := failure(ctx, event.(AgentTerminated)) //nolint:forcetypeassert if err != nil { return MissionResultResponse{}, err } @@ -106,14 +105,45 @@ func MissionResult(ctx context.Context, req MissionResultRequest, success Succee return MissionResultResponse{}, nil } -type GetLogFileRequest struct{} -type GetLogFileResponse struct { - Path string +// Logging + +type AppendLogRequest struct { + Message string `json:"message"` +} + +type FetchLogsRequest struct{} + +type FetchLogsResponse struct { + Messages []string `json:"messages"` +} + +//ftl:verb export +func AppendLog(ctx context.Context, req AppendLogRequest) error { + ftl.LoggerFromContext(ctx).Infof("Appending message: %s", req.Message) + return appendLog(ctx, req.Message) } //ftl:verb export -func GetLogFile(ctx context.Context, req GetLogFileRequest) (GetLogFileResponse, error) { - return GetLogFileResponse{Path: logFile.Get(ctx)}, nil +func FetchLogs(ctx context.Context, req FetchLogsRequest) (FetchLogsResponse, error) { + path := logFile.Get(ctx) + if path == "" { + return FetchLogsResponse{}, fmt.Errorf("log_file config not set") + } + r, err := os.Open(path) + if err != nil { + return FetchLogsResponse{}, fmt.Errorf("failed to open log file %q: %w", path, err) + } + defer r.Close() + var messages []string + for { + var msg string + _, err := fmt.Fscanln(r, &msg) + if err != nil { + break + } + messages = append(messages, msg) + } + return FetchLogsResponse{Messages: messages}, nil } // Helpers