import test from "blue-tape";
import { Cookie } from "express-session";
import { Redis } from "ioredis";
import { promisify } from "node:util";
import { createClient } from "redis";
import RedisStore from "./";
import * as redisSrv from "./testdata/server";
test("setup", async () => {
    await redisSrv.connect();
});
test("defaults", async (t) => {
    let client = createClient({ url: `redis://localhost:${redisSrv.port}` });
    await client.connect();
    let store = new RedisStore({ client });
    t.ok(store.client, "stores client");
    t.equal(store.prefix, "sess:", "defaults to sess:");
    t.equal(store.ttl, 86400, "defaults to one day");
    t.equal(store.scanCount, 100, "defaults SCAN count to 100");
    t.equal(store.serializer, JSON, "defaults to JSON serialization");
    t.equal(store.disableTouch, false, "defaults to having `touch` enabled");
    t.equal(store.disableTTL, false, "defaults to having `ttl` enabled");
    await client.disconnect();
});
test("redis", async (t) => {
    let client = createClient({ url: `redis://localhost:${redisSrv.port}` });
    await client.connect();
    let store = new RedisStore({ client });
    await lifecycleTest(store, client, t);
    await client.disconnect();
});
test("ioredis", async (t) => {
    let client = new Redis(`redis://localhost:${redisSrv.port}`);
    let store = new RedisStore({ client });
    await lifecycleTest(store, client, t);
    client.disconnect();
});
test("teardown", redisSrv.disconnect);
async function lifecycleTest(store, client, t) {
    const P = (f) => promisify(f).bind(store);
    let res = await P(store.clear)();
    let sess = { foo: "bar" };
    await P(store.set)("123", sess);
    res = await P(store.get)("123");
    t.same(res, sess, "store.get");
    let ttl = await client.ttl("sess:123");
    t.ok(ttl >= 86399, "check one day ttl");
    ttl = 60;
    let expires = new Date(Date.now() + ttl * 1000).toISOString();
    await P(store.set)("456", { cookie: { expires } });
    ttl = await client.ttl("sess:456");
    t.ok(ttl <= 60, "check expires ttl");
    ttl = 90;
    let expires2 = new Date(Date.now() + ttl * 1000).toISOString();
    await P(store.touch)("456", { cookie: { expires: expires2 } });
    ttl = await client.ttl("sess:456");
    t.ok(ttl > 60, "check expires ttl touch");
    res = await P(store.length)();
    t.equal(res, 2, "stored two keys length");
    res = await P(store.ids)();
    res.sort();
    t.same(res, ["123", "456"], "stored two keys ids");
    res = await P(store.all)();
    res.sort((a, b) => (a.id > b.id ? 1 : -1));
    t.same(res, [
        { id: "123", foo: "bar" },
        { id: "456", cookie: { expires } },
    ], "stored two keys data");
    await P(store.destroy)("456");
    res = await P(store.length)();
    t.equal(res, 1, "one key remains");
    res = await P(store.clear)();
    res = await P(store.length)();
    t.equal(res, 0, "no keys remain");
    let count = 1000;
    await load(store, count);
    res = await P(store.length)();
    t.equal(res, count, "bulk count");
    await P(store.clear)();
    res = await P(store.length)();
    t.equal(res, 0, "bulk clear");
    expires = new Date(Date.now() + ttl * 1000).toISOString(); // expires in the future
    res = await P(store.set)("789", { cookie: { expires } });
    res = await P(store.length)();
    t.equal(res, 1, "one key exists (session 789)");
    expires = new Date(Date.now() - ttl * 1000).toISOString(); // expires in the past
    await P(store.set)("789", { cookie: { expires } });
    res = await P(store.length)();
    t.equal(res, 0, "no key remains and that includes session 789");
}
async function load(store, count) {
    let cookie = new Cookie();
    for (let sid = 0; sid < count; sid++) {
        cookie.expires = new Date(Date.now() + 1000);
        await store.set("s" + sid, { cookie });
    }
}
