[READ-ONLY] Mirror of https://github.com/FoxxMD/multi-scrobbler. Scrobble plays from multiple sources to multiple clients docs.multi-scrobbler.app
deezer docker jellyfin koito lastfm listenbrainz maloja mopidy mpris music music-assistant plex scrobble self-hosted spotify subsonic tautulli youtube-music
0

Configure Feed

Select the types of activity you want to include in your feed.

test: Add scrobble client caching test

FoxxMD (Sep 11, 2025, 7:14 PM UTC) ffb41b4e d78bc48e

+38 -16
+38 -16
src/backend/tests/cache/cache.test.ts
··· 9 9 import { generatePlay, generatePlayerStateData, generatePlays, normalizePlays } from "../utils/PlayTestUtils.js"; 10 10 import { ListenProgressPositional, ListenProgressTS } from "../../sources/PlayerState/ListenProgress.js"; 11 11 import { isPortReachableConnect } from "../../utils/NetworkUtils.js"; 12 + import { getRoot } from "../../ioc.js"; 13 + import { transientCache } from "../utils/CacheTestUtils.js"; 14 + import { TestScrobbler } from "../scrobbler/TestScrobbler.js"; 15 + import { sleep } from "../../utils.js"; 16 + import {promises} from 'node:fs'; 12 17 13 18 chai.use(asPromised); 14 19 ··· 68 73 expect(time).to.not.be.undefined; 69 74 expect(time instanceof dayjs).is.true; 70 75 expect(now.toJSON()).eq((time as any).toJSON()); 76 + flat.destroy(); 71 77 72 78 }, { unsafeCleanup: true }); 73 79 }); ··· 90 96 expect(cachedProg).to.not.be.undefined; 91 97 expect(cachedProg instanceof ListenProgressTS).is.true; 92 98 expect(cachedProg.timestamp.toJSON()).eq(prog.timestamp.toJSON()); 99 + flat.destroy(); 93 100 94 101 }, { unsafeCleanup: true }); 95 102 }); ··· 140 147 }); 141 148 }); 142 149 150 + describe('#ScrobbleCache', function () { 143 151 152 + afterEach(function () { 153 + const root = getRoot(); 154 + root.upsert({ cache: () => transientCache }); 155 + root.items.cache().init(); 156 + }); 144 157 158 + it('Preserves scrobbles', async function () { 145 159 146 - // it('File backend serializes and deserializes non-primitives', async function() { 147 160 148 - // withLocalTmpDir(async () => { 161 + await withLocalTmpDir(async () => { 149 162 150 - // const cache = new MSCache(loggerTest, {scrobble: {provider: 'file', connection: process.cwd()}}); 151 - // await cache.init(); 163 + const root = getRoot(); 164 + root.upsert({ cache: () => () => new MSCache(loggerTest, { scrobble: { provider: 'file', connection: process.cwd(), persistInterval: 100 } }) }); 165 + root.items.cache().init(); 152 166 153 - // const now = dayjs(); 167 + const test = new TestScrobbler(); 168 + await test.initialize(); 169 + const play = generatePlay(); 170 + test.queueScrobble(play, 'testSource'); 171 + await sleep(101); 172 + const dirContents = await promises.readdir('.'); 173 + const hasCache = dirContents.some(x => x === 'ms-scrobble.cache'); 174 + expect(hasCache).is.true; 154 175 155 - // await cache.cacheScrobble.set('foo', now); 156 - // await cache.cacheScrobble.secondary.store.save(); 157 - // await cache.cacheScrobble.disconnect() 176 + // reinit cache 177 + root.upsert({ cache: () => () => new MSCache(loggerTest, { scrobble: { provider: 'file', connection: process.cwd(), persistInterval: 100 } }) }); 178 + const newCache = root.items.cache(); 179 + expect(newCache.cacheScrobble).to.be.undefined; 180 + newCache.init(); 158 181 159 - // const cleanCache = new MSCache(loggerTest, {scrobble: {provider: 'file', connection: process.cwd()}}); 160 - // await cleanCache.init(); 182 + const newTest = new TestScrobbler(); 183 + await newTest.initialize(); 184 + expect(newTest.queuedScrobbles.length).to.eq(1); 185 + expect(newTest.queuedScrobbles[0].play.data.track).to.eq(play.data.track); 161 186 162 - // const time = await cleanCache.cacheScrobble.get('foo'); 187 + }, { unsafeCleanup: true }); 163 188 164 - // expect(time).to.not.be.undefined; 165 - // expect(time instanceof dayjs).is.true; 166 - // expect(now.toJSON).eq((time as any).toJSON()); 189 + }); 167 190 168 - // }, {unsafeCleanup: true}); 169 - // }); 191 + }); 170 192 171 193 });