ai cooking
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Pmiller/directivechangehash (#331)

* wait on deployment

* lost directive completely. get it back and test

---------

Co-authored-by: paul miller <paul.miller>

authored by

Paul Miller
paul miller
and committed by
GitHub
6386adf0 3f77b140

+143
+1
internal/recipes/server.go
··· 793 793 return 794 794 } 795 795 796 + p.Directive = currentUser.Directive 796 797 //if params are already saved redirect and assume someone kicks off genration 797 798 798 799 if err := s.SaveParams(ctx, p); err != nil {
+142
internal/recipes/server_test.go
··· 117 117 } 118 118 } 119 119 120 + func TestHandleRecipes_UsesStoredUserDirectiveInSavedParamsAndHash(t *testing.T) { 121 + cacheStore := cache.NewFileCache(filepath.Join(t.TempDir(), "cache")) 122 + storage := users.NewStorage(cacheStore) 123 + location := &locations.Location{ 124 + ID: "store-1", 125 + Name: "Test Store", 126 + ZipCode: "94105", 127 + } 128 + s := &server{ 129 + recipeio: recipeio{Cache: cacheStore}, 130 + storage: storage, 131 + clerk: auth.DefaultMock(), 132 + generator: mock{}, 133 + locServer: staticLocationLookup{location: location}, 134 + } 135 + t.Cleanup(s.Wait) 136 + 137 + currentUser, err := storage.FindOrCreateFromClerk(t.Context(), "mock-clerk-user-id", auth.DefaultMock()) 138 + if err != nil { 139 + t.Fatalf("failed to seed user: %v", err) 140 + } 141 + currentUser.Directive = "No shellfish. Prefer high-protein dinners." 142 + if err := storage.Update(currentUser); err != nil { 143 + t.Fatalf("failed to save user directive: %v", err) 144 + } 145 + 146 + req := httptest.NewRequest(http.MethodGet, "/recipes?location=store-1&date=2026-03-06&instructions=make+it+vegetarian", nil) 147 + expectedParams, err := s.ParseQueryArgs(t.Context(), req) 148 + if err != nil { 149 + t.Fatalf("failed to build expected params: %v", err) 150 + } 151 + baselineHash := expectedParams.Hash() 152 + expectedParams.Directive = currentUser.Directive 153 + expectedHash := expectedParams.Hash() 154 + if expectedHash == baselineHash { 155 + t.Fatal("expected stored directive to change params hash") 156 + } 157 + 158 + rr := httptest.NewRecorder() 159 + s.handleRecipes(rr, req) 160 + 161 + if rr.Code != http.StatusSeeOther { 162 + t.Fatalf("expected status %d, got %d", http.StatusSeeOther, rr.Code) 163 + } 164 + 165 + locationHeader := rr.Header().Get("Location") 166 + if locationHeader == "" { 167 + t.Fatal("expected redirect location") 168 + } 169 + redirectURL, err := url.Parse(locationHeader) 170 + if err != nil { 171 + t.Fatalf("failed to parse redirect location %q: %v", locationHeader, err) 172 + } 173 + if got := redirectURL.Query().Get("h"); got != expectedHash { 174 + t.Fatalf("expected redirect hash %q, got %q", expectedHash, got) 175 + } 176 + if got := redirectURL.Query().Get("h"); got == baselineHash { 177 + t.Fatalf("expected redirect hash not to use empty-directive hash %q", baselineHash) 178 + } 179 + 180 + savedParams, err := s.ParamsFromCache(t.Context(), expectedHash) 181 + if err != nil { 182 + t.Fatalf("failed to load saved params: %v", err) 183 + } 184 + if got, want := savedParams.Directive, currentUser.Directive; got != want { 185 + t.Fatalf("expected saved directive %q, got %q", want, got) 186 + } 187 + if got, want := savedParams.Hash(), expectedHash; got != want { 188 + t.Fatalf("expected saved params hash %q, got %q", want, got) 189 + } 190 + } 191 + 192 + func TestHandleRecipes_SameRequestDifferentDirectivesProduceDifferentHashes(t *testing.T) { 193 + cacheStore := cache.NewFileCache(filepath.Join(t.TempDir(), "cache")) 194 + storage := users.NewStorage(cacheStore) 195 + location := &locations.Location{ 196 + ID: "store-1", 197 + Name: "Test Store", 198 + ZipCode: "94105", 199 + } 200 + s := &server{ 201 + recipeio: recipeio{Cache: cacheStore}, 202 + storage: storage, 203 + clerk: auth.DefaultMock(), 204 + generator: mock{}, 205 + locServer: staticLocationLookup{location: location}, 206 + } 207 + t.Cleanup(s.Wait) 208 + 209 + currentUser, err := storage.FindOrCreateFromClerk(t.Context(), "mock-clerk-user-id", auth.DefaultMock()) 210 + if err != nil { 211 + t.Fatalf("failed to seed user: %v", err) 212 + } 213 + 214 + req := httptest.NewRequest(http.MethodGet, "/recipes?location=store-1&date=2026-03-06&instructions=make+it+vegetarian", nil) 215 + runRequest := func(t *testing.T, directive string) string { 216 + t.Helper() 217 + 218 + currentUser.Directive = directive 219 + if err := storage.Update(currentUser); err != nil { 220 + t.Fatalf("failed to save user directive %q: %v", directive, err) 221 + } 222 + 223 + rr := httptest.NewRecorder() 224 + s.handleRecipes(rr, req.Clone(t.Context())) 225 + 226 + if rr.Code != http.StatusSeeOther { 227 + t.Fatalf("expected status %d, got %d", http.StatusSeeOther, rr.Code) 228 + } 229 + 230 + locationHeader := rr.Header().Get("Location") 231 + if locationHeader == "" { 232 + t.Fatal("expected redirect location") 233 + } 234 + redirectURL, err := url.Parse(locationHeader) 235 + if err != nil { 236 + t.Fatalf("failed to parse redirect location %q: %v", locationHeader, err) 237 + } 238 + hash := redirectURL.Query().Get("h") 239 + if hash == "" { 240 + t.Fatalf("expected redirect hash in %q", locationHeader) 241 + } 242 + 243 + savedParams, err := s.ParamsFromCache(t.Context(), hash) 244 + if err != nil { 245 + t.Fatalf("failed to load saved params for hash %q: %v", hash, err) 246 + } 247 + if got := savedParams.Directive; got != directive { 248 + t.Fatalf("expected saved directive %q, got %q", directive, got) 249 + } 250 + 251 + return hash 252 + } 253 + 254 + hash1 := runRequest(t, "No shellfish. Prefer high-protein dinners.") 255 + hash2 := runRequest(t, "Vegetarian meals only. Avoid mushrooms.") 256 + 257 + if hash1 == hash2 { 258 + t.Fatalf("expected different hashes for different directives, got %q", hash1) 259 + } 260 + } 261 + 120 262 func TestHandleSingle_NormalizesLegacyOriginHashToCanonicalHash(t *testing.T) { 121 263 cacheStore := cache.NewFileCache(filepath.Join(t.TempDir(), "cache")) 122 264 s := &server{