feat(profiles): first-class profile switching — phase 0 baseline port (#820)
* feat(profiles): make profile switching actually scope the app (issue #781 follow-up) * fix(profiles): inherit connection token when switching to same-dashboard profile (issue #781 follow-up) * fix(chat): reset open session on profile switch + prefill login profile (desktop parity) * fix(ws): inject profile into profile-scoped RPC params so chat follows the selected profile * test(chat): de-poison SlashCommandDispatchRpcTest (drop static Dispatchers mock) mockkStatic(Dispatchers::class) + a stubbed Dispatchers.IO bleeds JVM-wide and breaks later classes in suite order (CI 2026-08-06: COMMAND_DISPATCH captures cross-wired → ComparisonFailure on lower stack PRs). ChatViewModel gains an injected ioDispatcher (38 sites); the slash test constructs the VM with the test dispatcher so the IO stub is unnecessary. --------- Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
1 parent
e56d4c9bfa
commit
75ac0c4790
14 files changed
+579
-56
No files matched your search
@@ -79,14 +79,31 @@ class ProfileScopeInterceptorTest {
|
||||
|
||||
@Test
|
||||
fun nonScopedEndpoint_untouched() {
|
||||
// Pairing is machine-global (not profile-scoped on the backend).
|
||||
every { AuthManager.getSelectedProfileId() } returns "work"
|
||||
val client = OkHttpClient.Builder().addInterceptor(ProfileScopeInterceptor).build()
|
||||
server.enqueue(MockResponse().setResponseCode(200).setBody("{}"))
|
||||
val req = Request.Builder().url(server.url("api/cron/jobs")).build()
|
||||
val req = Request.Builder().url(server.url("api/pairing")).build()
|
||||
client.newCall(req).execute().close()
|
||||
val url = server.takeRequest().requestUrl!!
|
||||
assertNull(url.queryParameter("profile"))
|
||||
assertEquals("/api/cron/jobs", url.encodedPath)
|
||||
assertEquals("/api/pairing", url.encodedPath)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cronSessionsPluginsEndpoints_areScoped() {
|
||||
// Issue #781 follow-up: cron, sessions and plugin REST are all
|
||||
// profile-scoped on the backend — switching profiles must switch
|
||||
// what these screens show, so the interceptor rewrites them too.
|
||||
val client = clientFor("work")
|
||||
for (path in listOf("api/cron/jobs", "api/sessions", "api/plugins/hermes-achievements/achievements")) {
|
||||
server.enqueue(MockResponse().setResponseCode(200).setBody("{}"))
|
||||
val req = Request.Builder().url(server.url(path)).build()
|
||||
client.newCall(req).execute().close()
|
||||
val url = server.takeRequest().requestUrl!!
|
||||
assertEquals("work", url.queryParameter("profile"))
|
||||
assertEquals("/$path", url.encodedPath)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in new issue
Block a user