Skip to content
This repository was archived by the owner on Sep 2, 2024. It is now read-only.

Commit a5ba036

Browse files
committed
added missing cache/pubsub funcs to JS runtime with test close #56
1 parent ae24c78 commit a5ba036

File tree

3 files changed

+217
-7
lines changed

3 files changed

+217
-7
lines changed

cache/dev.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,11 @@ func (d *CacheDev) SetTyped(key string, v any) error {
7474
// Inc increments a value (non-atomic)
7575
func (d *CacheDev) Inc(key string, by int64) (n int64, err error) {
7676
if err = d.GetTyped(key, &n); err != nil {
77-
return
77+
if err.Error() == "key not found in cache" {
78+
n = 0
79+
} else {
80+
return
81+
}
7882
}
7983

8084
n += by

function/runtime.go

Lines changed: 94 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -491,19 +491,19 @@ func (*ExecutionEnvironment) clean(doc map[string]interface{}) error {
491491
}
492492

493493
func (env *ExecutionEnvironment) addVolatileFunctions(vm *goja.Runtime) error {
494-
err := vm.Set("send", func(call goja.FunctionCall) goja.Value {
494+
err := vm.Set("publish", func(call goja.FunctionCall) goja.Value {
495495
if len(call.Arguments) != 3 {
496-
return vm.ToValue(Result{Content: "argument missmatch: you need 3 arguments for send(type, data, channel)"})
496+
return vm.ToValue(Result{Content: "argument missmatch: you need 3 arguments for send(channel, type, data)"})
497497
}
498498

499499
var typ, channel string
500-
if err := vm.ExportTo(call.Argument(0), &typ); err != nil {
500+
if err := vm.ExportTo(call.Argument(0), &channel); err != nil {
501501
return vm.ToValue(Result{Content: "the first argument should be a string"})
502-
} else if err := vm.ExportTo(call.Argument(2), &channel); err != nil {
502+
} else if err := vm.ExportTo(call.Argument(1), &typ); err != nil {
503503
return vm.ToValue(Result{Content: "the third argument should be a string"})
504504
}
505505

506-
b, err := json.Marshal(call.Argument(1).Export())
506+
b, err := json.Marshal(call.Argument(2).Export())
507507
if err != nil {
508508
return vm.ToValue(Result{Content: fmt.Sprintf("error converting your data: %v", err)})
509509
}
@@ -525,7 +525,95 @@ func (env *ExecutionEnvironment) addVolatileFunctions(vm *goja.Runtime) error {
525525
return vm.ToValue(Result{OK: true})
526526
})
527527
if err != nil {
528-
return nil
528+
return err
529+
}
530+
531+
err = vm.Set("cacheGet", func(call goja.FunctionCall) goja.Value {
532+
if len(call.Arguments) != 1 {
533+
return vm.ToValue(Result{Content: "argument missmatch: you need 1 argument for cacheGet(key)"})
534+
}
535+
536+
var key string
537+
if err := vm.ExportTo(call.Argument(0), &key); err != nil {
538+
return vm.ToValue(Result{Content: "the first argument should be a string"})
539+
}
540+
541+
val, _ := env.Volatile.Get(key)
542+
543+
return vm.ToValue(Result{OK: true, Content: val})
544+
})
545+
if err != nil {
546+
return err
547+
}
548+
549+
err = vm.Set("cacheSet", func(call goja.FunctionCall) goja.Value {
550+
if len(call.Arguments) != 2 {
551+
return vm.ToValue(Result{Content: "argument missmatch: you need 2 arguments for cacheSet(key, value)"})
552+
}
553+
554+
var key, value string
555+
if err := vm.ExportTo(call.Argument(0), &key); err != nil {
556+
return vm.ToValue(Result{Content: "the first argument should be a string"})
557+
} else if err := vm.ExportTo(call.Argument(1), &value); err != nil {
558+
return vm.ToValue(Result{Content: "the 2nd argument should be a string"})
559+
}
560+
561+
if err := env.Volatile.Set(key, value); err != nil {
562+
return vm.ToValue(Result{Content: fmt.Sprintf("error while setting cache value: %v", err)})
563+
}
564+
565+
return vm.ToValue(Result{OK: true})
566+
})
567+
if err != nil {
568+
return err
569+
}
570+
571+
err = vm.Set("inc", func(call goja.FunctionCall) goja.Value {
572+
if len(call.Arguments) != 2 {
573+
return vm.ToValue(Result{Content: "argument missmatch: you need 2 arguments for inc(key, n)"})
574+
}
575+
576+
var key string
577+
var n int64
578+
if err := vm.ExportTo(call.Argument(0), &key); err != nil {
579+
return vm.ToValue(Result{Content: "the first argument should be a string"})
580+
} else if err := vm.ExportTo(call.Argument(1), &n); err != nil {
581+
return vm.ToValue(Result{Content: "the 2nd argument should be a number"})
582+
}
583+
584+
total, err := env.Volatile.Inc(key, n)
585+
if err != nil {
586+
return vm.ToValue(Result{Content: fmt.Sprintf("error while incrementing cache value: %v", err)})
587+
}
588+
589+
return vm.ToValue(Result{OK: true, Content: total})
590+
})
591+
if err != nil {
592+
return err
593+
}
594+
595+
err = vm.Set("dec", func(call goja.FunctionCall) goja.Value {
596+
if len(call.Arguments) != 2 {
597+
return vm.ToValue(Result{Content: "argument missmatch: you need 2 arguments for dec(key, n)"})
598+
}
599+
600+
var key string
601+
var n int64
602+
if err := vm.ExportTo(call.Argument(0), &key); err != nil {
603+
return vm.ToValue(Result{Content: "the first argument should be a string"})
604+
} else if err := vm.ExportTo(call.Argument(1), &n); err != nil {
605+
return vm.ToValue(Result{Content: "the 2nd argument should be a number"})
606+
}
607+
608+
total, err := env.Volatile.Dec(key, n)
609+
if err != nil {
610+
return vm.ToValue(Result{Content: fmt.Sprintf("error while decrementing cache value: %v", err)})
611+
}
612+
613+
return vm.ToValue(Result{OK: true, Content: total})
614+
})
615+
if err != nil {
616+
return err
529617
}
530618
return nil
531619
}

functions_test.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"testing"
1010
"time"
1111

12+
"github.com/staticbackendhq/core/backend"
1213
"github.com/staticbackendhq/core/model"
1314
)
1415

@@ -442,3 +443,120 @@ func TestFunctionTriggerByPublishingMsg(t *testing.T) {
442443

443444
time.Sleep(500 * time.Millisecond)
444445
}
446+
447+
func TestFunctionWithVolatilizerHelpers(t *testing.T) {
448+
code := `
449+
function handle(channel, type, body) {
450+
// set some value in the cache
451+
let res = cacheSet("ok-unit-test", "init value");
452+
if (!res.ok) {
453+
log(res.content);
454+
return;
455+
}
456+
457+
res = cacheGet("ok-unit-test");
458+
if (!res.ok) {
459+
log(res.content);
460+
return;
461+
} else if (res.content != "init value") {
462+
log("error, cache value isn't :init value:");
463+
return;
464+
}
465+
466+
cacheSet()
467+
468+
res = inc("some-counter", 10);
469+
if (!res.ok) {
470+
log(res.content);
471+
return;
472+
}
473+
474+
res = dec("some-counter", 2);
475+
if (!res.ok) {
476+
log(res.content);
477+
return;
478+
}
479+
480+
res = publish("test-channel", "some-type", {a: "which data"});
481+
if (!res.ok) {
482+
log(res.content);
483+
return;
484+
}
485+
}
486+
`
487+
488+
data := model.ExecData{
489+
FunctionName: "fn-cache-tests",
490+
Code: code,
491+
TriggerTopic: "trigger-from-unit-test",
492+
}
493+
addResp := dbReq(t, funexec.add, "POST", "/", data, true)
494+
defer addResp.Body.Close()
495+
if addResp.StatusCode != http.StatusOK {
496+
t.Fatal(GetResponseBody(t, addResp))
497+
}
498+
499+
// let's send this message to trigger the function
500+
b, err := json.Marshal(data)
501+
if err != nil {
502+
t.Fatal(err)
503+
}
504+
505+
msg := model.Command{
506+
SID: "unit-test",
507+
Type: "manual-msg",
508+
Data: string(b),
509+
Channel: "trigger-from-unit-test",
510+
Token: adminToken,
511+
Auth: model.Auth{}, // don't need auth for this test
512+
Base: dbName,
513+
}
514+
515+
if err := backend.Cache.Publish(msg); err != nil {
516+
t.Fatal(err)
517+
}
518+
519+
// give sometimes for the event to propagate
520+
time.Sleep(650 * time.Millisecond)
521+
522+
infoResp := dbReq(t, funexec.info, "GET", "/fn/info/fn-cache-tests", nil, true)
523+
defer infoResp.Body.Close()
524+
525+
if infoResp.StatusCode >= 299 {
526+
t.Fatal(GetResponseBody(t, infoResp))
527+
}
528+
529+
var checkFn model.ExecData
530+
if err := parseBody(infoResp.Body, &checkFn); err != nil {
531+
t.Fatal(err)
532+
}
533+
534+
t.Log(checkFn.History)
535+
536+
var errorLines []string
537+
foundError := false
538+
for _, h := range checkFn.History {
539+
for _, line := range h.Output {
540+
if strings.Contains(line, "ERROR") {
541+
errorLines = h.Output
542+
foundError = true
543+
break
544+
}
545+
}
546+
547+
if foundError {
548+
break
549+
}
550+
}
551+
552+
if foundError {
553+
t.Errorf("found error in function exec log: %v", errorLines)
554+
}
555+
556+
var total int64
557+
if err := backend.Cache.GetTyped("some-counter", &total); err != nil {
558+
t.Fatal(err)
559+
} else if total != 8 {
560+
t.Errorf("expected total to be 8 got %d", total)
561+
}
562+
}

0 commit comments

Comments
 (0)