From 689eed6412667db465e96b82cafc19d10454790a Mon Sep 17 00:00:00 2001
From: "David W. Dougherty" <dwdougherty@gmail.com>
Date: Thu, 9 Jan 2025 08:49:12 -0800
Subject: [PATCH 1/2] DOC-4423: add TCEs for various command pages

---
 doctests/cmds-cnxmgmt.js    |  48 ++++++++++++++
 doctests/cmds-hash.js       |  40 ++++++++++-
 doctests/cmds-list.js       | 129 ++++++++++++++++++++++++++++++++++++
 doctests/cmds-servermgmt.js |  45 +++++++++++++
 doctests/cmds-set.js        |  44 ++++++++++++
 5 files changed, 305 insertions(+), 1 deletion(-)
 create mode 100644 doctests/cmds-cnxmgmt.js
 create mode 100644 doctests/cmds-list.js
 create mode 100644 doctests/cmds-servermgmt.js
 create mode 100644 doctests/cmds-set.js

diff --git a/doctests/cmds-cnxmgmt.js b/doctests/cmds-cnxmgmt.js
new file mode 100644
index 00000000000..82fbab625a1
--- /dev/null
+++ b/doctests/cmds-cnxmgmt.js
@@ -0,0 +1,48 @@
+// EXAMPLE: cmds_cnxmgmt
+// REMOVE_START
+import assert from "node:assert";
+// REMOVE_END
+
+// HIDE_START
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect().catch(console.error);
+// HIDE_END
+
+// STEP_START auth1
+// REMOVE_START
+await client.sendCommand(['CONFIG', 'SET', 'requirepass', 'temp_pass']);
+// REMOVE_END
+const res1 = await client.auth({ password: 'temp_pass' });
+console.log(res1); // OK
+
+const res2 = await client.auth({ username: 'default', password: 'temp_pass' });
+console.log(res2); // OK
+
+// REMOVE_START
+assert.equal(res1, "OK");
+assert.equal(res2, "OK");
+await client.sendCommand(['CONFIG', 'SET', 'requirepass', '']);
+// REMOVE_END
+// STEP_END
+
+// STEP_START auth2
+// REMOVE_START
+await client.sendCommand([
+  'ACL', 'SETUSER', 'test-user',
+  'on', '>strong_password', '+acl'
+]);
+// REMOVE_END
+const res3 = await client.auth({ username: 'test-user', password: 'strong_password' });
+console.log(res3); // OK
+
+// REMOVE_START
+assert.equal(res3, "OK");
+await client.sendCommand(['ACL', 'DELUSER', 'test-user']);
+// REMOVE_END
+// STEP_END
+
+// HIDE_START
+await client.quit();
+// HIDE_END
diff --git a/doctests/cmds-hash.js b/doctests/cmds-hash.js
index d47fa1944ae..dd14dc90135 100644
--- a/doctests/cmds-hash.js
+++ b/doctests/cmds-hash.js
@@ -65,7 +65,45 @@ await client.del('myhash')
 // REMOVE_END
 // STEP_END
 
+// STEP_START hgetall
+const res10 = await client.hSet(
+  'myhash',
+  {
+    'field1': 'Hello',
+    'field2': 'World'
+  }
+)
+
+const res11 = await client.hGetAll('myhash')
+console.log(res11) // [Object: null prototype] { field1: 'Hello', field2: 'World' }
+
+// REMOVE_START
+assert.deepEqual(res11, {
+  field1: 'Hello',
+  field2: 'World'
+});
+await client.del('myhash')
+// REMOVE_END
+// STEP_END
+
+// STEP_START hvals
+const res12 = await client.hSet(
+  'myhash',
+  {
+    'field1': 'Hello',
+    'field2': 'World'
+  }
+)
+
+const res13 = await client.hVals('myhash')
+console.log(res13) // [ 'Hello', 'World' ]
+
+// REMOVE_START
+assert.deepEqual(res13, [ 'Hello', 'World' ]);
+await client.del('myhash')
+// REMOVE_END
+// STEP_END
+
 // HIDE_START
 await client.quit();
 // HIDE_END
-
diff --git a/doctests/cmds-list.js b/doctests/cmds-list.js
new file mode 100644
index 00000000000..65e78d0c8d8
--- /dev/null
+++ b/doctests/cmds-list.js
@@ -0,0 +1,129 @@
+// EXAMPLE: cmds_list
+// HIDE_START
+import assert from 'node:assert';
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect().catch(console.error);
+// HIDE_END
+
+// STEP_START lpush
+const res1 = await client.lPush('mylist', 'world');
+console.log(res1); // 1
+
+const res2 = await client.lPush('mylist', 'hello');
+console.log(res2); // 2
+
+const res3 = await client.lRange('mylist', 0, -1);
+console.log(res3); // [ 'hello', 'world' ]
+
+// REMOVE_START
+assert.deepEqual(res3, [ 'hello', 'world' ]);
+await client.del('mylist');
+// REMOVE_END
+// STEP_END
+
+// STEP_START lrange
+const res4 = await client.rPush('mylist', 'one');
+console.log(res4); // 1
+
+const res5 = await client.rPush('mylist', 'two');
+console.log(res5); // 2
+
+const res6 = await client.rPush('mylist', 'three');
+console.log(res6); // 3
+
+const res7 = await client.lRange('mylist', 0, 0);
+console.log(res7); // [ 'one' ]
+
+const res8 = await client.lRange('mylist', -3, 2);
+console.log(res8); // [ 'one', 'two', 'three' ]
+
+const res9 = await client.lRange('mylist', -100, 100);
+console.log(res9); // [ 'one', 'two', 'three' ]
+
+const res10 = await client.lRange('mylist', 5, 10);
+console.log(res10); // []
+
+// REMOVE_START
+assert.deepEqual(res7, [ 'one' ]);
+assert.deepEqual(res8, [ 'one', 'two', 'three' ]);
+assert.deepEqual(res9, [ 'one', 'two', 'three' ]);
+assert.deepEqual(res10, []);
+await client.del('mylist');
+// REMOVE_END
+// STEP_END
+
+// STEP_START llen
+const res11 = await client.lPush('mylist', 'World');
+console.log(res11); // 1
+
+const res12 = await client.lPush('mylist', 'Hello');
+console.log(res12); // 2
+
+const res13 = await client.lLen('mylist');
+console.log(res13); // 2
+
+// REMOVE_START
+assert.equal(res13, 2);
+await client.del('mylist');
+// REMOVE_END
+// STEP_END
+
+// STEP_START rpush
+const res14 = await client.rPush('mylist', 'hello');
+console.log(res14); // 1
+
+const res15 = await client.rPush('mylist', 'world');
+console.log(res15); // 2
+
+const res16 = await client.lRange('mylist', 0, -1);
+console.log(res16); // [ 'hello', 'world' ]
+
+// REMOVE_START
+assert.deepEqual(res16, [ 'hello', 'world' ]);
+await client.del('mylist');
+// REMOVE_END
+// STEP_END
+
+// STEP_START lpop
+const res17 = await client.rPush('mylist', ["one", "two", "three", "four", "five"]);
+console.log(res17); // 5
+
+const res18 = await client.lPop('mylist');
+console.log(res18); // 'one'
+
+const res19 = await client.lPopCount('mylist', 2);
+console.log(res19); // [ 'two', 'three' ]
+
+const res20 = await client.lRange('mylist', 0, -1);
+console.log(res20); // [ 'four', 'five' ]
+
+// REMOVE_START
+assert.deepEqual(res20, [ 'four', 'five' ]);
+await client.del('mylist');
+// REMOVE_END
+// STEP_END
+
+// STEP_START rpop
+const res21 = await client.rPush('mylist', ["one", "two", "three", "four", "five"]);
+console.log(res21); // 5
+
+const res22 = await client.rPop('mylist');
+console.log(res22); // 'five'
+
+const res23 = await client.rPopCount('mylist', 2);
+console.log(res23); // [ 'four', 'three' ]
+
+const res24 = await client.lRange('mylist', 0, -1);
+console.log(res24); // [ 'one', 'two' ]
+
+// REMOVE_START
+assert.deepEqual(res24, [ 'one', 'two' ]);
+await client.del('mylist');
+// REMOVE_END
+// STEP_END
+
+// HIDE_START
+await client.quit();
+// HIDE_END
diff --git a/doctests/cmds-servermgmt.js b/doctests/cmds-servermgmt.js
new file mode 100644
index 00000000000..5ac6e5909c4
--- /dev/null
+++ b/doctests/cmds-servermgmt.js
@@ -0,0 +1,45 @@
+// EXAMPLE: cmds_servermgmt
+// REMOVE_START
+import assert from 'node:assert';
+// REMOVE_END
+
+// HIDE_START
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect().catch(console.error);
+// HIDE_END
+
+// STEP_START flushall
+// REMOVE_START
+await client.set('foo', '1');
+await client.set('bar', '2');
+await client.set('baz', '3');
+// REMOVE_END
+const res1 = await client.flushAll('SYNC'); // or ASYNC
+console.log(res1); // OK
+
+const res2 = await client.keys('*');
+console.log(res2); // []
+
+// REMOVE_START
+assert.equal(res1, 'OK');
+assert.deepEqual(res2, []);
+// REMOVE_END
+// STEP_END
+
+// STEP_START info
+const res3 = await client.info();
+console.log(res3)
+// # Server
+// redis_version:7.4.0
+// redis_git_sha1:c9d29f6a
+// redis_git_dirty:0
+// redis_build_id:4c367a16e3f9616
+// redis_mode:standalone
+// ...
+// STEP_END
+
+// HIDE_START
+await client.quit();
+// HIDE_END
diff --git a/doctests/cmds-set.js b/doctests/cmds-set.js
new file mode 100644
index 00000000000..80374436a58
--- /dev/null
+++ b/doctests/cmds-set.js
@@ -0,0 +1,44 @@
+// EXAMPLE: cmds_set
+// REMOVE_START
+import assert from 'node:assert';
+// REMOVE_END
+
+// HIDE_START
+import { createClient } from 'redis';
+
+const client = createClient();
+await client.connect().catch(console.error);
+// HIDE_END
+
+// STEP_START sadd
+const res1 = await client.sAdd('myset', ['Hello', 'World']);
+console.log(res1);  // 2
+
+const res2 = await client.sAdd('myset', ['World']);
+console.log(res2);  // 0
+
+const res3 = await client.sMembers('myset')
+console.log(res3);  // ['Hello', 'World']
+
+// REMOVE_START
+assert.deepEqual(res3, ['Hello', 'World']);
+await client.del('myset');
+// REMOVE_END
+// STEP_END
+
+// STEP_START smembers
+const res4 = await client.sAdd('myset', ['Hello', 'World']);
+console.log(res4);  // 2
+
+const res5 = await client.sMembers('myset')
+console.log(res5);  // ['Hello', 'World']
+
+// REMOVE_START
+assert.deepEqual(res5, ['Hello', 'World']);
+await client.del('myset');
+// REMOVE_END
+// STEP_END
+
+// HIDE_START
+await client.quit();
+// HIDE_END

From c599e46f54a266465b086241202a806ddac6a908 Mon Sep 17 00:00:00 2001
From: Nikolay Karadzhov <nkaradzhov89@gmail.com>
Date: Tue, 22 Apr 2025 15:53:17 +0300
Subject: [PATCH 2/2] fix problematic doctest

from redis docs for ACL DELUSER:
Delete all the specified ACL users and terminate all the connections
 that are authenticated with such users

Nodejs complains: Warning: Detected unsettled top-level await
which in turn gives the error code 13 in the workflow

await client.auth({ username: 'test-user' ...});
// deleting the user that is currently logged in -> bad
await client.sendCommand(['ACL', 'DELUSER', 'test-user']);
await client.quit()

fix: authenticate with the default user before deleting the test-user
---
 doctests/cmds-cnxmgmt.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/doctests/cmds-cnxmgmt.js b/doctests/cmds-cnxmgmt.js
index 82fbab625a1..2f4fc8dc95a 100644
--- a/doctests/cmds-cnxmgmt.js
+++ b/doctests/cmds-cnxmgmt.js
@@ -39,6 +39,7 @@ console.log(res3); // OK
 
 // REMOVE_START
 assert.equal(res3, "OK");
+await client.auth({ username: 'default', password: '' })
 await client.sendCommand(['ACL', 'DELUSER', 'test-user']);
 // REMOVE_END
 // STEP_END