From 06540c6fbdbbb37c62c0f0686eec612d8770a1c0 Mon Sep 17 00:00:00 2001 From: Calvin McLean Date: Sat, 17 Aug 2024 17:29:37 -0700 Subject: [PATCH] Improve VCR and move to separate package --- Taskfile.yml | 6 +- garden-app/cmd/root.go | 3 +- garden-app/go.mod | 2 +- garden-app/go.sum | 4 +- garden-app/server/api.go | 16 +- garden-app/server/api_test.go | 52 - garden-app/server/id.go | 1 + .../{ => vcr}/testdata/vcr_server/config.yaml | 0 .../create_and_delete_waterschedule.yaml | 894 ++++++++++++++++++ .../fixtures/create_garden_simple.yaml | 0 .../create_garden_with_light_schedule.yaml | 0 .../fixtures/create_garden_ws_zone.yaml | 0 garden-app/server/{ => vcr}/vcr.go | 17 +- garden-app/server/vcr/vcr_test.go | 50 + 14 files changed, 973 insertions(+), 72 deletions(-) rename garden-app/server/{ => vcr}/testdata/vcr_server/config.yaml (100%) create mode 100644 garden-app/server/vcr/testdata/vcr_server/fixtures/create_and_delete_waterschedule.yaml rename garden-app/server/{ => vcr}/testdata/vcr_server/fixtures/create_garden_simple.yaml (100%) rename garden-app/server/{ => vcr}/testdata/vcr_server/fixtures/create_garden_with_light_schedule.yaml (100%) rename garden-app/server/{ => vcr}/testdata/vcr_server/fixtures/create_garden_ws_zone.yaml (100%) rename garden-app/server/{ => vcr}/vcr.go (66%) create mode 100644 garden-app/server/vcr/vcr_test.go diff --git a/Taskfile.yml b/Taskfile.yml index cf9d3100..d06c7262 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -66,10 +66,12 @@ tasks: desc: Run backend Go app server with VCR enabled aliases: [vcr] dir: ./garden-app + vars: + vcr_base_dir: server/vcr/testdata/vcr_server env: - VCR_CASSETTE: server/testdata/vcr_server/fixtures/{{ .CLI_ARGS }} + VCR_CASSETTE: "{{ .vcr_base_dir }}/fixtures/{{ .CLI_ARGS }}" cmds: - - go run main.go serve --config ./server/testdata/vcr_server/config.yaml + - go run main.go serve --config ./{{ .vcr_base_dir }}/config.yaml run-controller: desc: Run mock controller diff --git a/garden-app/cmd/root.go b/garden-app/cmd/root.go index ca3760f4..63c5c1fe 100644 --- a/garden-app/cmd/root.go +++ b/garden-app/cmd/root.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/calvinmclean/automated-garden/garden-app/server" + "github.com/calvinmclean/automated-garden/garden-app/server/vcr" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -17,7 +18,7 @@ var ( ) func Execute() { - defer server.StopRecorder() + defer vcr.StopRecorder() api := server.NewAPI() command := api.Command() diff --git a/garden-app/go.mod b/garden-app/go.mod index 34507e58..9366b839 100644 --- a/garden-app/go.mod +++ b/garden-app/go.mod @@ -138,6 +138,6 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect ) -replace gopkg.in/dnaeon/go-vcr.v3 => github.com/calvinmclean/go-vcr v0.2.0 +replace gopkg.in/dnaeon/go-vcr.v3 => github.com/calvinmclean/go-vcr v0.3.0 //replace gopkg.in/dnaeon/go-vcr.v3 => ../../go-vcr diff --git a/garden-app/go.sum b/garden-app/go.sum index ccd105e4..a96c1ada 100644 --- a/garden-app/go.sum +++ b/garden-app/go.sum @@ -76,8 +76,8 @@ github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZF github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/calvinmclean/babyapi v0.23.0 h1:rmYnAz80cX6TTDtbjQGt8DzjR7CDZNxkJm0/KvWRQHY= github.com/calvinmclean/babyapi v0.23.0/go.mod h1:zSNiVRsL3DBPOMkXxMJOTFNtzU1ZrPFKD0LFx2JVp4I= -github.com/calvinmclean/go-vcr v0.2.0 h1:foa7hUNJrebZg++/Cg7sNrRWMTa8mqx9PBZXafuI8bA= -github.com/calvinmclean/go-vcr v0.2.0/go.mod h1:Oy/wiaJrF0S8WmwjGRpDSL09yGnb9HXV4qP87dHkfFk= +github.com/calvinmclean/go-vcr v0.3.0 h1:IDcpV3LktoWJjK+p11XdITqU6NOHZ+mCLICW0l7Hf+s= +github.com/calvinmclean/go-vcr v0.3.0/go.mod h1:Oy/wiaJrF0S8WmwjGRpDSL09yGnb9HXV4qP87dHkfFk= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= diff --git a/garden-app/server/api.go b/garden-app/server/api.go index eee0364c..43d2c0a9 100644 --- a/garden-app/server/api.go +++ b/garden-app/server/api.go @@ -6,10 +6,13 @@ import ( "fmt" "log/slog" "net/http" + "os" + "github.com/calvinmclean/automated-garden/garden-app/clock" "github.com/calvinmclean/automated-garden/garden-app/pkg/influxdb" "github.com/calvinmclean/automated-garden/garden-app/pkg/mqtt" "github.com/calvinmclean/automated-garden/garden-app/pkg/storage" + "github.com/calvinmclean/automated-garden/garden-app/server/vcr" "github.com/calvinmclean/automated-garden/garden-app/worker" "github.com/calvinmclean/babyapi" @@ -50,11 +53,22 @@ func NewAPI() *API { AddNestedAPI(api.notificationClients). AddNestedAPI(api.waterSchedules) - api.configureVCR() + cassetteName := os.Getenv("VCR_CASSETTE") + if cassetteName != "" { + EnableMock() + vcr.MustSetupVCR(cassetteName) + } return api } +// EnableMock prepares mock IDs and clock +func EnableMock() { + enableMockIDs = true + mockIDIndex = 0 + _ = clock.MockTime() +} + // Setup will prepare to run by setting up clients and doing any final configurations for the API func (api *API) Setup(cfg Config, validateData bool) error { html.SetFS(templates, "templates/*") diff --git a/garden-app/server/api_test.go b/garden-app/server/api_test.go index 6aa542e1..54a6c9c2 100644 --- a/garden-app/server/api_test.go +++ b/garden-app/server/api_test.go @@ -2,68 +2,16 @@ package server import ( "context" - "os" - "path/filepath" - "strings" "testing" - "github.com/calvinmclean/automated-garden/garden-app/clock" "github.com/calvinmclean/automated-garden/garden-app/pkg" "github.com/calvinmclean/automated-garden/garden-app/pkg/storage" "github.com/calvinmclean/automated-garden/garden-app/pkg/weather" "github.com/calvinmclean/babyapi" - "github.com/spf13/viper" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "gopkg.in/dnaeon/go-vcr.v3/cassette" ) -func TestReplay(t *testing.T) { - // This is currently not in `init` because other tests in this package don't expect mock - _ = clock.MockTime() - enableMockIDs = true - t.Cleanup(func() { - enableMockIDs = false - clock.Reset() - }) - - dir := "testdata/vcr_server/fixtures" - entries, err := os.ReadDir(dir) - require.NoError(t, err) - - for _, entry := range entries { - if entry.IsDir() { - continue - } - - cassetteName := strings.TrimSuffix(entry.Name(), ".yaml") - t.Run(cassetteName, func(t *testing.T) { - api := NewAPI() - mockIDIndex = 0 - - var config Config - t.Run("SetupConfig", func(t *testing.T) { - viper.SetConfigFile("./testdata/vcr_server/config.yaml") - - err := viper.ReadInConfig() - require.NoError(t, err) - - err = viper.Unmarshal(&config) - require.NoError(t, err) - }) - - err := api.Setup(config, true) - require.NoError(t, err) - - r, err := api.Router() - require.NoError(t, err) - - cassette.TestServerReplay(t, filepath.Join(dir, cassetteName), r) - }) - } -} - func TestValidateAllStoredResources(t *testing.T) { tests := []struct { name string diff --git a/garden-app/server/id.go b/garden-app/server/id.go index a33588b6..44bc5ca8 100644 --- a/garden-app/server/id.go +++ b/garden-app/server/id.go @@ -3,6 +3,7 @@ package server import ( "github.com/calvinmclean/automated-garden/garden-app/clock" "github.com/calvinmclean/babyapi" + "github.com/rs/xid" ) diff --git a/garden-app/server/testdata/vcr_server/config.yaml b/garden-app/server/vcr/testdata/vcr_server/config.yaml similarity index 100% rename from garden-app/server/testdata/vcr_server/config.yaml rename to garden-app/server/vcr/testdata/vcr_server/config.yaml diff --git a/garden-app/server/vcr/testdata/vcr_server/fixtures/create_and_delete_waterschedule.yaml b/garden-app/server/vcr/testdata/vcr_server/fixtures/create_and_delete_waterschedule.yaml new file mode 100644 index 00000000..7cd372fe --- /dev/null +++ b/garden-app/server/vcr/testdata/vcr_server/fixtures/create_and_delete_waterschedule.yaml @@ -0,0 +1,894 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: localhost:8080 + remote_addr: '[::1]:57956' + request_uri: / + body: "" + form: {} + headers: + Accept: + - text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + Accept-Encoding: + - gzip, deflate + Accept-Language: + - en-US,en;q=0.9 + Connection: + - keep-alive + Sec-Fetch-Dest: + - document + Sec-Fetch-Mode: + - navigate + Sec-Fetch-Site: + - none + Upgrade-Insecure-Requests: + - "1" + User-Agent: + - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15 + url: http://go-vcr/ + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: |+ + Found. + + headers: + Content-Type: + - text/html; charset=utf-8 + Location: + - /gardens + status: 302 Found + code: 302 + duration: 125ns + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: localhost:8080 + remote_addr: '[::1]:57956' + request_uri: /gardens + body: "" + form: {} + headers: + Accept: + - text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + Accept-Encoding: + - gzip, deflate + Accept-Language: + - en-US,en;q=0.9 + Connection: + - keep-alive + Sec-Fetch-Dest: + - document + Sec-Fetch-Mode: + - navigate + Sec-Fetch-Site: + - none + Upgrade-Insecure-Requests: + - "1" + User-Agent: + - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15 + url: http://go-vcr/gardens + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: "\n\n\n\n\n\n \n \n Garden App\n \n \n \n \n \n\n\n\n\n\n
\n \n \n\n
\n \n
\n\n\n\n\n\n\n" + headers: + Content-Type: + - text/html; charset=utf-8 + status: 200 OK + code: 200 + duration: 292ns + - id: 2 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: localhost:8080 + remote_addr: '[::1]:57956' + request_uri: /favicon.ico + body: "" + form: {} + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Accept-Language: + - en-US,en;q=0.9 + Connection: + - keep-alive + Referer: + - http://localhost:8080/gardens + Sec-Fetch-Dest: + - image + Sec-Fetch-Mode: + - no-cors + Sec-Fetch-Site: + - same-origin + User-Agent: + - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15 + url: http://go-vcr/favicon.ico + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: | + 404 page not found + headers: + Content-Type: + - text/plain; charset=utf-8 + X-Content-Type-Options: + - nosniff + status: 404 Not Found + code: 404 + duration: 83ns + - id: 3 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: localhost:8080 + remote_addr: '[::1]:57959' + request_uri: /apple-touch-icon-precomposed.png + body: "" + form: {} + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Accept-Language: + - en-US,en;q=0.9 + Connection: + - keep-alive + User-Agent: + - Safari/19618.2.12.11.6 CFNetwork/1496.0.7 Darwin/23.5.0 + url: http://go-vcr/apple-touch-icon-precomposed.png + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: | + 404 page not found + headers: + Content-Type: + - text/plain; charset=utf-8 + X-Content-Type-Options: + - nosniff + status: 404 Not Found + code: 404 + duration: 250ns + - id: 4 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: localhost:8080 + remote_addr: '[::1]:57959' + request_uri: /apple-touch-icon.png + body: "" + form: {} + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Accept-Language: + - en-US,en;q=0.9 + Connection: + - keep-alive + User-Agent: + - Safari/19618.2.12.11.6 CFNetwork/1496.0.7 Darwin/23.5.0 + url: http://go-vcr/apple-touch-icon.png + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: | + 404 page not found + headers: + Content-Type: + - text/plain; charset=utf-8 + X-Content-Type-Options: + - nosniff + status: 404 Not Found + code: 404 + duration: 83ns + - id: 5 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: localhost:8080 + remote_addr: '[::1]:57956' + request_uri: /water_schedules?exclude_weather_data=true + body: "" + form: {} + headers: + Accept: + - text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + Accept-Encoding: + - gzip, deflate + Accept-Language: + - en-US,en;q=0.9 + Connection: + - keep-alive + Referer: + - http://localhost:8080/gardens + Sec-Fetch-Dest: + - document + Sec-Fetch-Mode: + - navigate + Sec-Fetch-Site: + - same-origin + Upgrade-Insecure-Requests: + - "1" + User-Agent: + - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15 + url: http://go-vcr/water_schedules?exclude_weather_data=true + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: "\n\n\n\n\n\n \n \n Garden App\n \n \n \n \n \n\n\n\n\n\n
\n \n \n\n
\n \n
\n\n\n\n\n\n\n" + headers: + Content-Type: + - text/html; charset=utf-8 + status: 200 OK + code: 200 + duration: 125ns + - id: 6 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: localhost:8080 + remote_addr: '[::1]:57956' + request_uri: /water_schedules?refresh=true + body: "" + form: {} + headers: + Accept: + - text/html + Accept-Encoding: + - gzip, deflate + Accept-Language: + - en-US,en;q=0.9 + Connection: + - keep-alive + Hx-Current-Url: + - http://localhost:8080/water_schedules?exclude_weather_data=true + Hx-Request: + - "true" + Referer: + - http://localhost:8080/water_schedules?exclude_weather_data=true + Sec-Fetch-Dest: + - empty + Sec-Fetch-Mode: + - cors + Sec-Fetch-Site: + - same-origin + User-Agent: + - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15 + url: http://go-vcr/water_schedules?refresh=true + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: "\n
\n \n
\n" + headers: + Content-Type: + - text/html; charset=utf-8 + status: 200 OK + code: 200 + duration: 84ns + - id: 7 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: localhost:8080 + remote_addr: '[::1]:57956' + request_uri: /water_schedules/components?type=create_modal + body: "" + form: {} + headers: + Accept: + - text/html + Accept-Encoding: + - gzip, deflate + Accept-Language: + - en-US,en;q=0.9 + Connection: + - keep-alive + Hx-Current-Url: + - http://localhost:8080/water_schedules?exclude_weather_data=true + Hx-Request: + - "true" + Hx-Target: + - create-modal-here + Referer: + - http://localhost:8080/water_schedules?exclude_weather_data=true + Sec-Fetch-Dest: + - empty + Sec-Fetch-Mode: + - cors + Sec-Fetch-Site: + - same-origin + User-Agent: + - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15 + url: http://go-vcr/water_schedules/components?type=create_modal + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: "\n\n\n\n\n\n
\n
\n

Create Water Schedule\n

\n\n
\n \n
\n \n
\n
\n \n
\n
\n \n
\n
\n \n
\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n\n \n
\n
\n\n
\n \n
\n
\n \n
\n \n
\n \n \n
\n\n \n\n\n \n \n\n\n
\n
\n
\n" + headers: + Content-Type: + - text/html; charset=utf-8 + status: 200 OK + code: 200 + duration: 333ns + - id: 8 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 241 + transfer_encoding: [] + trailer: {} + host: localhost:8080 + remote_addr: '[::1]:57956' + request_uri: /water_schedules/cqsnecmiuvoqlhrmf2jg + body: ID=cqsnecmiuvoqlhrmf2jg&Name=New%20Water%20Schedule&Description=New&Duration=1h&Interval=72h&StartTime.Hour=5&StartTime.Minute=0&StartTime.TZ=-07%3A00&ActivePeriod.StartMonth=&ActivePeriod.EndMonth=&NotificationClientID=Notification%20Client + form: + ActivePeriod.EndMonth: + - "" + ActivePeriod.StartMonth: + - "" + Description: + - New + Duration: + - 1h + ID: + - cqsnecmiuvoqlhrmf2jg + Interval: + - 72h + Name: + - New Water Schedule + NotificationClientID: + - Notification Client + StartTime.Hour: + - "5" + StartTime.Minute: + - "0" + StartTime.TZ: + - "-07:00" + headers: + Accept: + - text/html + Accept-Encoding: + - gzip, deflate + Accept-Language: + - en-US,en;q=0.9 + Connection: + - keep-alive + Content-Length: + - "241" + Content-Type: + - application/x-www-form-urlencoded + Hx-Current-Url: + - http://localhost:8080/water_schedules?exclude_weather_data=true + Hx-Request: + - "true" + Origin: + - http://localhost:8080 + Referer: + - http://localhost:8080/water_schedules?exclude_weather_data=true + Sec-Fetch-Dest: + - empty + Sec-Fetch-Mode: + - cors + Sec-Fetch-Site: + - same-origin + User-Agent: + - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15 + url: http://go-vcr/water_schedules/cqsnecmiuvoqlhrmf2jg + method: PUT + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: | + {"id":"cqsnecmiuvoqlhrmf2jg","duration":"1h0m0s","interval":"72h0m0s","start_date":"2023-08-23T10:00:00Z","start_time":"05:00:00-07:00","name":"New Water Schedule","description":"New","notification_client_id":"Notification Client","next_water":{"time":"2023-08-23T05:00:00-07:00","duration":"1h0m0s"},"links":[{"rel":"self","href":"/water_schedules/cqsnecmiuvoqlhrmf2jg"}]} + headers: + Content-Type: + - application/json + Hx-Trigger: + - newWaterSchedule + status: 200 OK + code: 200 + duration: 41ns + - id: 9 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: localhost:8080 + remote_addr: '[::1]:57956' + request_uri: /water_schedules?refresh=true + body: "" + form: {} + headers: + Accept: + - text/html + Accept-Encoding: + - gzip, deflate + Accept-Language: + - en-US,en;q=0.9 + Connection: + - keep-alive + Hx-Current-Url: + - http://localhost:8080/water_schedules?exclude_weather_data=true + Hx-Request: + - "true" + Referer: + - http://localhost:8080/water_schedules?exclude_weather_data=true + Sec-Fetch-Dest: + - empty + Sec-Fetch-Mode: + - cors + Sec-Fetch-Site: + - same-origin + User-Agent: + - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15 + url: http://go-vcr/water_schedules?refresh=true + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: "\n
\n \n \n\n\n
\n
\n
\n
\n

\n New Water Schedule\n

\n \n
\n \n \n
\n\n
\n
\n \n \n\n\n
\n Watering for\n 1h\n at 5:00AM\n
\n\n\n\n\n\n \n\n \n
\n

New

\n \n 1h\n \n \n 5:00AM\n \n \n 3 days\n \n \n
\n\n
\n
\n
\n\n \n
\n" + headers: + Content-Type: + - text/html; charset=utf-8 + status: 200 OK + code: 200 + duration: 125ns + - id: 10 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: localhost:8080 + remote_addr: '[::1]:57956' + request_uri: /water_schedules/cqsnecmiuvoqlhrmf2jg/components?type=edit_modal + body: "" + form: {} + headers: + Accept: + - text/html + Accept-Encoding: + - gzip, deflate + Accept-Language: + - en-US,en;q=0.9 + Connection: + - keep-alive + Hx-Current-Url: + - http://localhost:8080/water_schedules?exclude_weather_data=true + Hx-Request: + - "true" + Hx-Target: + - edit-modal-here + Referer: + - http://localhost:8080/water_schedules?exclude_weather_data=true + Sec-Fetch-Dest: + - empty + Sec-Fetch-Mode: + - cors + Sec-Fetch-Site: + - same-origin + User-Agent: + - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15 + url: http://go-vcr/water_schedules/cqsnecmiuvoqlhrmf2jg/components?type=edit_modal + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: "\n\n\n\n
\n
\n

New Water Schedule\n

\n\n
\n \n
\n \n
\n
\n \n
\n
\n \n
\n
\n \n
\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n\n \n
\n
\n\n
\n \n
\n
\n \n
\n \n
\n \n \n
\n\n \n\n\n \n \n\n\n
\n \n
\n \n
\n
\n\n \n \n\n\n
\n
\n
\n" + headers: + Content-Type: + - text/html; charset=utf-8 + status: 200 OK + code: 200 + duration: 167ns + - id: 11 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 251 + transfer_encoding: [] + trailer: {} + host: localhost:8080 + remote_addr: '[::1]:57956' + request_uri: /water_schedules/cqsnecmiuvoqlhrmf2jg + body: ID=cqsnecmiuvoqlhrmf2jg&Name=Old%20Water%20Schedule&Description=New&Duration=1h0m0s&Interval=72h0m0s&StartTime.Hour=05&StartTime.Minute=00&StartTime.TZ=-07%3A00&ActivePeriod.StartMonth=&ActivePeriod.EndMonth=&NotificationClientID=Notification%20Client + form: + ActivePeriod.EndMonth: + - "" + ActivePeriod.StartMonth: + - "" + Description: + - New + Duration: + - 1h0m0s + ID: + - cqsnecmiuvoqlhrmf2jg + Interval: + - 72h0m0s + Name: + - Old Water Schedule + NotificationClientID: + - Notification Client + StartTime.Hour: + - "05" + StartTime.Minute: + - "00" + StartTime.TZ: + - "-07:00" + headers: + Accept: + - text/html + Accept-Encoding: + - gzip, deflate + Accept-Language: + - en-US,en;q=0.9 + Connection: + - keep-alive + Content-Length: + - "251" + Content-Type: + - application/x-www-form-urlencoded + Hx-Current-Url: + - http://localhost:8080/water_schedules?exclude_weather_data=true + Hx-Request: + - "true" + Origin: + - http://localhost:8080 + Referer: + - http://localhost:8080/water_schedules?exclude_weather_data=true + Sec-Fetch-Dest: + - empty + Sec-Fetch-Mode: + - cors + Sec-Fetch-Site: + - same-origin + User-Agent: + - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15 + url: http://go-vcr/water_schedules/cqsnecmiuvoqlhrmf2jg + method: PUT + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: | + {"id":"cqsnecmiuvoqlhrmf2jg","duration":"1h0m0s","interval":"72h0m0s","start_date":"2023-08-23T10:00:00Z","start_time":"05:00:00-07:00","name":"Old Water Schedule","description":"New","notification_client_id":"Notification Client","next_water":{"time":"2023-08-23T05:00:00-07:00","duration":"1h0m0s"},"links":[{"rel":"self","href":"/water_schedules/cqsnecmiuvoqlhrmf2jg"}]} + headers: + Content-Type: + - application/json + Hx-Trigger: + - newWaterSchedule + status: 200 OK + code: 200 + duration: 41ns + - id: 12 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: localhost:8080 + remote_addr: '[::1]:57956' + request_uri: /water_schedules?refresh=true + body: "" + form: {} + headers: + Accept: + - text/html + Accept-Encoding: + - gzip, deflate + Accept-Language: + - en-US,en;q=0.9 + Connection: + - keep-alive + Hx-Current-Url: + - http://localhost:8080/water_schedules?exclude_weather_data=true + Hx-Request: + - "true" + Referer: + - http://localhost:8080/water_schedules?exclude_weather_data=true + Sec-Fetch-Dest: + - empty + Sec-Fetch-Mode: + - cors + Sec-Fetch-Site: + - same-origin + User-Agent: + - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15 + url: http://go-vcr/water_schedules?refresh=true + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: "\n
\n \n \n\n\n
\n
\n
\n
\n

\n Old Water Schedule\n

\n \n
\n \n \n
\n\n
\n
\n \n \n\n\n
\n Watering for\n 1h\n at 5:00AM\n
\n\n\n\n\n\n \n\n \n
\n

New

\n \n 1h\n \n \n 5:00AM\n \n \n 3 days\n \n \n
\n\n
\n
\n
\n\n \n
\n" + headers: + Content-Type: + - text/html; charset=utf-8 + status: 200 OK + code: 200 + duration: 84ns + - id: 13 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: localhost:8080 + remote_addr: '[::1]:57956' + request_uri: /water_schedules/cqsnecmiuvoqlhrmf2jg/components?type=edit_modal + body: "" + form: {} + headers: + Accept: + - text/html + Accept-Encoding: + - gzip, deflate + Accept-Language: + - en-US,en;q=0.9 + Connection: + - keep-alive + Hx-Current-Url: + - http://localhost:8080/water_schedules?exclude_weather_data=true + Hx-Request: + - "true" + Hx-Target: + - edit-modal-here + Referer: + - http://localhost:8080/water_schedules?exclude_weather_data=true + Sec-Fetch-Dest: + - empty + Sec-Fetch-Mode: + - cors + Sec-Fetch-Site: + - same-origin + User-Agent: + - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15 + url: http://go-vcr/water_schedules/cqsnecmiuvoqlhrmf2jg/components?type=edit_modal + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: "\n\n\n\n
\n
\n

Old Water Schedule\n

\n\n
\n \n
\n \n
\n
\n \n
\n
\n \n
\n
\n \n
\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n\n \n
\n
\n\n
\n \n
\n
\n \n
\n \n
\n \n \n
\n\n \n\n\n \n \n\n\n
\n \n
\n \n
\n
\n\n \n \n\n\n
\n
\n
\n" + headers: + Content-Type: + - text/html; charset=utf-8 + status: 200 OK + code: 200 + duration: 125ns + - id: 14 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: localhost:8080 + remote_addr: '[::1]:57956' + request_uri: /gardens + body: "" + form: {} + headers: + Accept: + - text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + Accept-Encoding: + - gzip, deflate + Accept-Language: + - en-US,en;q=0.9 + Connection: + - keep-alive + Referer: + - http://localhost:8080/water_schedules?exclude_weather_data=true + Sec-Fetch-Dest: + - document + Sec-Fetch-Mode: + - navigate + Sec-Fetch-Site: + - same-origin + Upgrade-Insecure-Requests: + - "1" + User-Agent: + - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15 + url: http://go-vcr/gardens + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: "\n\n\n\n\n\n \n \n Garden App\n \n \n \n \n \n\n\n\n\n\n
\n \n \n\n
\n \n
\n\n\n\n\n\n\n" + headers: + Content-Type: + - text/html; charset=utf-8 + status: 200 OK + code: 200 + duration: 84ns + - id: 15 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: localhost:8080 + remote_addr: '[::1]:57956' + request_uri: /gardens/components?type=create_modal + body: "" + form: {} + headers: + Accept: + - text/html + Accept-Encoding: + - gzip, deflate + Accept-Language: + - en-US,en;q=0.9 + Connection: + - keep-alive + Hx-Current-Url: + - http://localhost:8080/gardens + Hx-Request: + - "true" + Hx-Target: + - create-modal-here + Referer: + - http://localhost:8080/gardens + Sec-Fetch-Dest: + - empty + Sec-Fetch-Mode: + - cors + Sec-Fetch-Site: + - same-origin + User-Agent: + - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15 + url: http://go-vcr/gardens/components?type=create_modal + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: "\n
\n
\n

Create Garden

\n\n
\n \n \n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n\n \n
\n \n
\n \n \n
\n\n \n\n\n \n \n\n\n
\n
\n
\n" + headers: + Content-Type: + - text/html; charset=utf-8 + status: 200 OK + code: 200 + duration: 167ns diff --git a/garden-app/server/testdata/vcr_server/fixtures/create_garden_simple.yaml b/garden-app/server/vcr/testdata/vcr_server/fixtures/create_garden_simple.yaml similarity index 100% rename from garden-app/server/testdata/vcr_server/fixtures/create_garden_simple.yaml rename to garden-app/server/vcr/testdata/vcr_server/fixtures/create_garden_simple.yaml diff --git a/garden-app/server/testdata/vcr_server/fixtures/create_garden_with_light_schedule.yaml b/garden-app/server/vcr/testdata/vcr_server/fixtures/create_garden_with_light_schedule.yaml similarity index 100% rename from garden-app/server/testdata/vcr_server/fixtures/create_garden_with_light_schedule.yaml rename to garden-app/server/vcr/testdata/vcr_server/fixtures/create_garden_with_light_schedule.yaml diff --git a/garden-app/server/testdata/vcr_server/fixtures/create_garden_ws_zone.yaml b/garden-app/server/vcr/testdata/vcr_server/fixtures/create_garden_ws_zone.yaml similarity index 100% rename from garden-app/server/testdata/vcr_server/fixtures/create_garden_ws_zone.yaml rename to garden-app/server/vcr/testdata/vcr_server/fixtures/create_garden_ws_zone.yaml diff --git a/garden-app/server/vcr.go b/garden-app/server/vcr/vcr.go similarity index 66% rename from garden-app/server/vcr.go rename to garden-app/server/vcr/vcr.go index d006c554..3ac72bfa 100644 --- a/garden-app/server/vcr.go +++ b/garden-app/server/vcr/vcr.go @@ -1,9 +1,6 @@ -package server +package vcr import ( - "os" - - "github.com/calvinmclean/automated-garden/garden-app/clock" "github.com/calvinmclean/babyapi" "gopkg.in/dnaeon/go-vcr.v3/recorder" @@ -22,15 +19,9 @@ func StopRecorder() { } } -func (api *API) configureVCR() { - cassetteName := os.Getenv("VCR_CASSETTE") - if cassetteName == "" { - return - } - - _ = clock.MockTime() - enableMockIDs = true - +// MustSetupVCR will create a new Recorder and add it to babyapi.DefaultMiddleware. +// Panics if there is an error +func MustSetupVCR(cassetteName string) { var err error rec, err = recorder.NewWithOptions(&recorder.Options{ CassetteName: cassetteName, diff --git a/garden-app/server/vcr/vcr_test.go b/garden-app/server/vcr/vcr_test.go new file mode 100644 index 00000000..02cd72e4 --- /dev/null +++ b/garden-app/server/vcr/vcr_test.go @@ -0,0 +1,50 @@ +package vcr_test + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "github.com/calvinmclean/automated-garden/garden-app/server" + "github.com/spf13/viper" + "github.com/stretchr/testify/require" + "gopkg.in/dnaeon/go-vcr.v3/cassette" +) + +func TestReplay(t *testing.T) { + dir := "testdata/vcr_server/fixtures" + entries, err := os.ReadDir(dir) + require.NoError(t, err) + + for _, entry := range entries { + if entry.IsDir() { + continue + } + + cassetteName := strings.TrimSuffix(entry.Name(), ".yaml") + t.Run(cassetteName, func(t *testing.T) { + api := server.NewAPI() + server.EnableMock() + + var config server.Config + t.Run("SetupConfig", func(t *testing.T) { + viper.SetConfigFile("./testdata/vcr_server/config.yaml") + + err := viper.ReadInConfig() + require.NoError(t, err) + + err = viper.Unmarshal(&config) + require.NoError(t, err) + }) + + err := api.Setup(config, true) + require.NoError(t, err) + + r, err := api.Router() + require.NoError(t, err) + + cassette.TestServerReplay(t, filepath.Join(dir, cassetteName), r) + }) + } +}