From d9d877fee72d1c32744716a315cee74fc9027c1d Mon Sep 17 00:00:00 2001
From: Osama Sayegh <asooomaasoooma90@gmail.com>
Date: Wed, 6 Oct 2021 17:42:04 +0300
Subject: [PATCH] DEV: Pass kwargs to the redis gem when calling
 methods/commands that we don't wrap (#14530)

This commit fixes the `eval` and `evalsha` commands/methods and any other methods that don't have a wrapper in `DiscourseRedis` and expect keyword arguments. I noticed this problem in Logster when I was trying to fetch some log messages in JSON format using the rails console and saw the messages were missing the `env` field. Logster uses the `eval` command to fetch messages `env`s:

https://github.com/discourse/logster/blob/dc351fd00f283db212696c940ef3a456efc42ccb/lib/logster/redis_store.rb#L250-L253

and that code was not fetching anything because `DiscourseRedis` didn't pass the `keys` keyword arg to the redis gem.
---
 lib/discourse_redis.rb                  |  2 +-
 spec/components/discourse_redis_spec.rb | 53 +++++++++++++++++++++++++
 2 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/lib/discourse_redis.rb b/lib/discourse_redis.rb
index 341f3d131c5..1ed8fc6a5ed 100644
--- a/lib/discourse_redis.rb
+++ b/lib/discourse_redis.rb
@@ -39,7 +39,7 @@ class DiscourseRedis
   # prefix the key with the namespace
   def method_missing(meth, *args, **kwargs, &block)
     if @redis.respond_to?(meth)
-      DiscourseRedis.ignore_readonly { @redis.public_send(meth, *args, &block) }
+      DiscourseRedis.ignore_readonly { @redis.public_send(meth, *args, **kwargs, &block) }
     else
       super
     end
diff --git a/spec/components/discourse_redis_spec.rb b/spec/components/discourse_redis_spec.rb
index 8156a573ec2..aa8684d1b9a 100644
--- a/spec/components/discourse_redis_spec.rb
+++ b/spec/components/discourse_redis_spec.rb
@@ -78,5 +78,58 @@ describe DiscourseRedis do
         expect(Discourse.recently_readonly?).to eq(true)
       end
     end
+
+    describe "#eval" do
+      it "keys and arvg are passed correcty" do
+        keys = ["key1", "key2"]
+        argv = ["arg1", "arg2"]
+
+        expect(Discourse.redis.eval(
+          "return { KEYS, ARGV };",
+          keys: keys,
+          argv: argv,
+        )).to eq([keys, argv])
+
+        expect(Discourse.redis.eval(
+          "return { KEYS, ARGV };",
+          keys,
+          argv: argv,
+        )).to eq([keys, argv])
+
+        expect(Discourse.redis.eval(
+          "return { KEYS, ARGV };",
+          keys,
+          argv,
+        )).to eq([keys, argv])
+      end
+    end
+
+    describe "#evalsha" do
+      it "keys and arvg are passed correcty" do
+        keys = ["key1", "key2"]
+        argv = ["arg1", "arg2"]
+
+        script = "return { KEYS, ARGV };"
+        Discourse.redis.script(:load, script)
+        sha = Digest::SHA1.hexdigest(script)
+        expect(Discourse.redis.evalsha(
+          sha,
+          keys: keys,
+          argv: argv,
+        )).to eq([keys, argv])
+
+        expect(Discourse.redis.evalsha(
+          sha,
+          keys,
+          argv: argv,
+        )).to eq([keys, argv])
+
+        expect(Discourse.redis.evalsha(
+          sha,
+          keys,
+          argv,
+        )).to eq([keys, argv])
+      end
+    end
   end
 end