Repository: inbucket/inbucket
Pull request #335 (2023-02-14 18:37:30)

delete event: test lua func
- lua: tidy test helpers
- lua: test after_message_deleted func

for #332 


Patch:
diff --git a/pkg/extension/luahost/lua.go b/pkg/extension/luahost/lua.go
index eb74e7b..121a7c3 100644
--- a/pkg/extension/luahost/lua.go
+++ b/pkg/extension/luahost/lua.go
@@ -88,6 +88,7 @@ func (h *Host) CreateChannel(name string) chan lua.LValue {
 	return h.pool.createChannel(name)
 }
 
+const afterMessageDeletedFnName string = "after_message_deleted"
 const afterMessageStoredFnName string = "after_message_stored"
 const beforeMailAcceptedFnName string = "before_mail_accepted"
 
@@ -113,6 +114,9 @@ func (h *Host) wireFunctions(logger zerolog.Logger, ls *lua.LState) {
 	events := h.extHost.Events
 	const listenerName string = "lua"
 
+	if detectFn(afterMessageDeletedFnName) {
+		events.AfterMessageDeleted.AddListener(listenerName, h.handleAfterMessageDeleted)
+	}
 	if detectFn(afterMessageStoredFnName) {
 		events.AfterMessageStored.AddListener(listenerName, h.handleAfterMessageStored)
 	}
@@ -121,6 +125,25 @@ func (h *Host) wireFunctions(logger zerolog.Logger, ls *lua.LState) {
 	}
 }
 
+func (h *Host) handleAfterMessageDeleted(msg event.MessageMetadata) *extension.Void {
+	logger, ls, lfunc, ok := h.prepareFuncCall(afterMessageDeletedFnName)
+	if !ok {
+		return nil
+	}
+	defer h.pool.putState(ls)
+
+	// Call lua function.
+	logger.Debug().Msgf("Calling Lua function with %+v", msg)
+	if err := ls.CallByParam(
+		lua.P{Fn: lfunc, NRet: 0, Protect: true},
+		wrapMessageMetadata(ls, &msg),
+	); err != nil {
+		logger.Error().Err(err).Msg("Failed to call Lua function")
+	}
+
+	return nil
+}
+
 func (h *Host) handleAfterMessageStored(msg event.MessageMetadata) *extension.Void {
 	logger, ls, lfunc, ok := h.prepareFuncCall(afterMessageStoredFnName)
 	if !ok {


Test patch:
diff --git a/pkg/extension/luahost/lua_test.go b/pkg/extension/luahost/lua_test.go
index b0de09d..953c17f 100644
--- a/pkg/extension/luahost/lua_test.go
+++ b/pkg/extension/luahost/lua_test.go
@@ -13,6 +13,45 @@ import (
 	lua "github.com/yuin/gopher-lua"
 )
 
+// LuaInit holds useful test globals.
+const LuaInit = `
+	async = false
+	test_ok = true
+
+	-- Sends marks tests failed instead of erroring when enabled.
+	function assert_async(value, message)
+		if not value then
+			if async then
+				print(message)
+				test_ok = false
+			else
+				error(message)
+			end
+		end
+	end
+
+	-- Tests plain values and list-style tables.
+	function assert_eq(got, want)
+		if type(got) == "table" and type(want) == "table" then
+			assert_async(#got == #want, string.format("got %d elements, wanted %d", #got, #want))
+
+			for i, gotv in ipairs(got) do
+				local wantv = want[i]
+				assert_eq(gotv, wantv, "got[%d] = %q, wanted %q", gotv, wantv)
+			end
+
+			return
+		end
+
+		assert_async(got == want, string.format("got %q, wanted %q", got, want))
+	end
+
+	function assert_contains(got, want)
+		assert_async(string.find(got, want),
+			string.format("got %q, wanted it to contain %q", got, want))
+	end
+`
+
 func TestEmptyScript(t *testing.T) {
 	script := ""
 	extHost := extension.NewHost()
@@ -21,39 +60,51 @@ func TestEmptyScript(t *testing.T) {
 	require.NoError(t, err)
 }
 
-func TestAfterMessageStored(t *testing.T) {
+func TestAfterMessageDeleted(t *testing.T) {
 	// Register lua event listener, setup notify channel.
 	script := `
-		local test_ok = true
-
-		function assert_eq(got, want)
-			if got ~= want then
-				-- Incorrect value, schedule test to fail.
-				print("got '" .. got .. "', wanted '" .. want .. "'")
-				test_ok = false
-			end
-		end
+		async = true
 
-		function after_message_stored(msg)
+		function after_message_deleted(msg)
+			-- Full message bindings tested elsewhere.
 			assert_eq(msg.mailbox, "mb1")
 			assert_eq(msg.id, "id1")
-			assert_eq(msg.subject, "subj1")
-			assert_eq(msg.size, 42)
-
-			assert_eq(msg.from.name, "name1")
-			assert_eq(msg.from.address, "addr1")
+			notify:send(test_ok)
+		end
+	`
+	extHost := extension.NewHost()
+	luaHost, err := luahost.NewFromReader(extHost, strings.NewReader(LuaInit+script), "test.lua")
+	require.NoError(t, err)
+	notify := luaHost.CreateChannel("notify")
 
-			assert_eq(table.getn(msg.to), 1)
-			assert_eq(msg.to[1].name, "name2")
-			assert_eq(msg.to[1].address, "addr2")
+	// Send event, check channel response is true.
+	msg := &event.MessageMetadata{
+		Mailbox: "mb1",
+		ID:      "id1",
+		From:    &mail.Address{Name: "name1", Address: "addr1"},
+		To:      []*mail.Address{{Name: "name2", Address: "addr2"}},
+		Date:    time.Date(2001, time.February, 3, 4, 5, 6, 0, time.UTC),
+		Subject: "subj1",
+		Size:    42,
+	}
+	go extHost.Events.AfterMessageDeleted.Emit(msg)
+	assertNotified(t, notify)
+}
 
-			assert_eq(msg.date, 981173106)
+func TestAfterMessageStored(t *testing.T) {
+	// Register lua event listener, setup notify channel.
+	script := `
+		async = true
 
+		function after_message_stored(msg)
+			-- Full message bindings tested elsewhere.
+			assert_eq(msg.mailbox, "mb1")
+			assert_eq(msg.id, "id1")
 			notify:send(test_ok)
 		end
 	`
 	extHost := extension.NewHost()
-	luaHost, err := luahost.NewFromReader(extHost, strings.NewReader(script), "test.lua")
+	luaHost, err := luahost.NewFromReader(extHost, strings.NewReader(LuaInit+script), "test.lua")
 	require.NoError(t, err)
 	notify := luaHost.CreateChannel("notify")