Skip to content

Commit 53ce3a9

Browse files
authored
adjust comments and add some more tests for the data.Providers (#28)
1 parent 54eddd2 commit 53ce3a9

File tree

8 files changed

+206
-67
lines changed

8 files changed

+206
-67
lines changed

engines/extism/evaluator/evaluator.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,8 @@ func (be *Evaluator) Eval(ctx context.Context) (platform.EvaluatorResponse, erro
208208
return result, nil
209209
}
210210

211-
// AddDataToContext implements the data.Setter interface for Extism WebAssembly modules.
212-
// It enriches the provided context with data for script evaluation, using the
213-
// ExecutableUnit's DataProvider to store the data.
211+
// AddDataToContext implements the data.Setter interface which stores and prepares runtime data
212+
// which can be eventually passed to the Eval method.
214213
func (be *Evaluator) AddDataToContext(
215214
ctx context.Context,
216215
d ...map[string]any,

engines/extism/new.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ func FromExtismLoader(
3434
}
3535

3636
// FromExtismLoaderWithData creates an Extism evaluator with both static and dynamic data capabilities.
37-
// To add runtime data, use the `AddDataToContext` method on the evaluator to add data to the context.
3837
//
3938
// Input parameters:
4039
// - l: loader implementation for loading the WASM content

engines/risor/evaluator/evaluator.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,8 @@ func (be *Evaluator) Eval(ctx context.Context) (platform.EvaluatorResponse, erro
155155
return result, nil
156156
}
157157

158-
// AddDataToContext implements the data.Setter interface for Risor scripts.
159-
// It enriches the provided context with data for script evaluation, using the
160-
// ExecutableUnit's DataProvider to store the data.
158+
// AddDataToContext implements the data.Setter interface which stores and prepares runtime data
159+
// which can be eventually passed to the Eval method.
161160
func (be *Evaluator) AddDataToContext(
162161
ctx context.Context,
163162
d ...map[string]any,

engines/risor/new.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ func FromRisorLoader(
3131
}
3232

3333
// FromRisorLoaderWithData creates a Risor evaluator with both static and dynamic data capabilities.
34-
// To add runtime data, use the `AddDataToContext` method on the evaluator to add data to the context.
3534
//
3635
// Input parameters:
3736
// - logHandler: logger handler for logging

engines/starlark/evaluator/evaluator.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,8 @@ func (be *Evaluator) Eval(ctx context.Context) (platform.EvaluatorResponse, erro
222222
return result, nil
223223
}
224224

225-
// AddDataToContext implements the data.Setter interface for Starlark scripts.
226-
// It enriches the provided context with data for script evaluation, using the
227-
// ExecutableUnit's DataProvider to store the data.
225+
// AddDataToContext implements the data.Setter interface which stores and prepares runtime data
226+
// which can be eventually passed to the Eval method.
228227
func (be *Evaluator) AddDataToContext(
229228
ctx context.Context,
230229
d ...map[string]any,

engines/starlark/new.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ func FromStarlarkLoader(
3131
}
3232

3333
// FromStarlarkLoaderWithData creates a Starlark evaluator with both static and dynamic data capabilities.
34-
// To add runtime data, use the `AddDataToContext` method on the evaluator to add data to the context.
3534
//
3635
// Input parameters:
3736
// - logHandler: logger handler for logging

platform/data/compositeProvider_test.go

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,154 @@ func TestCompositeProvider_GetData(t *testing.T) {
253253
func TestCompositeProvider_AddDataToContext(t *testing.T) {
254254
t.Parallel()
255255

256+
t.Run("multiple ContextProviders with same key", func(t *testing.T) {
257+
// Create multiple context providers with the same key
258+
contextProvider1 := NewContextProvider(constants.EvalData)
259+
contextProvider2 := NewContextProvider(constants.EvalData)
260+
261+
// Composite provider with both context providers
262+
provider := NewCompositeProvider(contextProvider1, contextProvider2)
263+
264+
// Start with empty context
265+
ctx := context.Background()
266+
267+
// Add data with first call (should use the first provider)
268+
data1 := map[string]any{
269+
"user": map[string]any{
270+
"name": "Alice",
271+
"settings": map[string]any{
272+
"theme": "dark",
273+
},
274+
},
275+
"shared": "first",
276+
}
277+
ctx1, err1 := provider.AddDataToContext(ctx, data1)
278+
require.NoError(t, err1)
279+
280+
// Add more data with second call (should use first provider again, since its earlier in the chain)
281+
data2 := map[string]any{
282+
"user": map[string]any{
283+
"age": 30,
284+
"settings": map[string]any{
285+
"notifications": true,
286+
},
287+
},
288+
"shared": "second", // This should override "first"
289+
}
290+
ctx2, err2 := provider.AddDataToContext(ctx1, data2)
291+
require.NoError(t, err2)
292+
293+
// Verify the data was merged correctly
294+
result, err := provider.GetData(ctx2)
295+
require.NoError(t, err)
296+
297+
// Check that both data sets were merged
298+
userMap, ok := result["user"].(map[string]any)
299+
assert.True(t, ok, "User should be a map")
300+
assert.Equal(t, "Alice", userMap["name"], "Name should be preserved")
301+
assert.Equal(t, 30, userMap["age"], "Age should be added")
302+
303+
settings, ok := userMap["settings"].(map[string]any)
304+
assert.True(t, ok, "Settings should be a map")
305+
assert.Equal(t, "dark", settings["theme"], "Theme should be preserved")
306+
assert.Equal(t, true, settings["notifications"], "Notifications should be added")
307+
308+
// Check that shared value was overridden
309+
assert.Equal(t, "second", result["shared"], "Shared value should be overridden")
310+
})
311+
312+
t.Run("complex interaction between multiple ContextProviders", func(t *testing.T) {
313+
// Create three context providers with the same key
314+
provider1 := NewContextProvider(constants.EvalData)
315+
provider2 := NewContextProvider(constants.EvalData)
316+
provider3 := NewContextProvider(constants.EvalData)
317+
318+
// Create composite provider with a specific order
319+
composite := NewCompositeProvider(provider1, provider2, provider3)
320+
321+
// Setup initial context with data in each provider's storage
322+
ctx := context.Background()
323+
324+
// Setup data for first provider (this should be accessible by all providers)
325+
initialData := map[string]any{
326+
"config": map[string]any{
327+
"mode": "production",
328+
"features": map[string]any{
329+
"feature1": true,
330+
"feature2": false,
331+
},
332+
},
333+
"counter": 1,
334+
}
335+
ctx = context.WithValue(ctx, constants.EvalData, initialData)
336+
337+
// First AddDataToContext call (uses provider1)
338+
data1 := map[string]any{
339+
"config": map[string]any{
340+
"features": map[string]any{
341+
"feature2": true, // Override feature2
342+
"feature3": true, // Add feature3
343+
},
344+
"timeout": 30, // Add timeout
345+
},
346+
"counter": 2, // Override counter
347+
}
348+
ctx, err := composite.AddDataToContext(ctx, data1)
349+
require.NoError(t, err)
350+
351+
// Second AddDataToContext call (uses provider1 again)
352+
data2 := map[string]any{
353+
"config": map[string]any{
354+
"mode": "development", // Override mode
355+
"features": map[string]any{
356+
"feature1": false, // Override feature1
357+
},
358+
},
359+
"counter": 3, // Override counter again
360+
"user": "admin", // Add new field
361+
}
362+
ctx, err = composite.AddDataToContext(ctx, data2)
363+
require.NoError(t, err)
364+
365+
// Verify the final state
366+
result, err := composite.GetData(ctx)
367+
require.NoError(t, err)
368+
369+
// Check counter (simplest case - should be last value)
370+
assert.Equal(t, 3, result["counter"])
371+
372+
// Check user (added in second call)
373+
assert.Equal(t, "admin", result["user"])
374+
375+
// Check config (complex nested structure with multiple updates)
376+
config, ok := result["config"].(map[string]any)
377+
require.True(t, ok)
378+
379+
// Check mode (updated in second call)
380+
assert.Equal(t, "development", config["mode"])
381+
382+
// Check timeout (added in first call, not touched in second)
383+
assert.Equal(t, 30, config["timeout"])
384+
385+
// Check features (updated across multiple calls)
386+
features, ok := config["features"].(map[string]any)
387+
require.True(t, ok)
388+
389+
assert.Equal(
390+
t,
391+
false,
392+
features["feature1"],
393+
"feature1 should be false (updated in second call)",
394+
)
395+
assert.Equal(
396+
t,
397+
true,
398+
features["feature2"],
399+
"feature2 should be true (updated in first call)",
400+
)
401+
assert.Equal(t, true, features["feature3"], "feature3 should be true (added in first call)")
402+
})
403+
256404
t.Run("empty providers list", func(t *testing.T) {
257405
provider := NewCompositeProvider()
258406
require.NotNil(t, provider)
@@ -396,6 +544,48 @@ func TestCompositeProvider_NestedStructures(t *testing.T) {
396544
setupContext func() context.Context
397545
expectedResult map[string]any
398546
}{
547+
{
548+
name: "multiple ContextProviders with same context key",
549+
setupProviders: func() *CompositeProvider {
550+
// Create multiple context providers with the same key
551+
contextProvider1 := NewContextProvider(constants.EvalData)
552+
contextProvider2 := NewContextProvider(constants.EvalData)
553+
contextProvider3 := NewContextProvider(constants.EvalData)
554+
555+
// Composite provider with all three context providers
556+
return NewCompositeProvider(contextProvider1, contextProvider2, contextProvider3)
557+
},
558+
setupContext: func() context.Context {
559+
// Create a context with data for each provider to access/modify
560+
ctx := context.Background()
561+
562+
// First provider data
563+
ctx = context.WithValue(ctx, constants.EvalData, map[string]any{
564+
"user": map[string]any{
565+
"name": "Alice",
566+
"role": "admin",
567+
"settings": map[string]any{
568+
"theme": "dark",
569+
},
570+
},
571+
"version": "1.0",
572+
"shared": "first",
573+
})
574+
575+
return ctx
576+
},
577+
expectedResult: map[string]any{
578+
"user": map[string]any{
579+
"name": "Alice",
580+
"role": "admin",
581+
"settings": map[string]any{
582+
"theme": "dark",
583+
},
584+
},
585+
"version": "1.0",
586+
"shared": "first",
587+
},
588+
},
399589
{
400590
name: "nested composite providers with static data",
401591
setupProviders: func() *CompositeProvider {

0 commit comments

Comments
 (0)