microsoft/teams.net

Public

mirrored from https://github.com/microsoft/teams.netAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
cg/integration-test-caching

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

core/test/Microsoft.Teams.Apps.UnitTests/State/TurnStateLoaderTests.cs

185lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4using Microsoft.Extensions.Caching.Distributed;
5using Microsoft.Extensions.Logging.Abstractions;
6using Microsoft.Extensions.Options;
7using Microsoft.Teams.Apps.State;
8using Moq;
9
10namespace Microsoft.Teams.Apps.UnitTests.State;
11
12public class TurnStateLoaderTests
13{
14 private readonly Mock<IDistributedCache> _cacheMock = new();
15 private readonly TurnStateOptions _options = new();
16
17 private TurnStateLoader CreateLoader() =>
18 new(_cacheMock.Object, Options.Create(_options), NullLogger<TurnStateLoader>.Instance);
19
20 // ── Load behavior ─────────────────────────────────────────────────
21
22 [Fact]
23 public async Task LoadAsync_ReturnsConversationAndUserState()
24 {
25 TurnStateLoader loader = CreateLoader();
26
27 TurnStateContainer container = await loader.LoadAsync("conv1", "user1", CancellationToken.None);
28
29 Assert.NotNull(container.ConversationState);
30 Assert.NotNull(container.UserState);
31 }
32
33 [Fact]
34 public async Task LoadAsync_NullUserId_ReturnsNullUserState()
35 {
36 TurnStateLoader loader = CreateLoader();
37
38 TurnStateContainer container = await loader.LoadAsync("conv1", null, CancellationToken.None);
39
40 Assert.NotNull(container.ConversationState);
41 Assert.Null(container.UserState);
42 }
43
44 [Fact]
45 public async Task LoadAsync_EmptyUserId_ReturnsNullUserState()
46 {
47 TurnStateLoader loader = CreateLoader();
48
49 TurnStateContainer container = await loader.LoadAsync("conv1", "", CancellationToken.None);
50
51 Assert.NotNull(container.ConversationState);
52 Assert.Null(container.UserState);
53 }
54
55 [Fact]
56 public async Task LoadAsync_ExistingConversationState_IsLoaded()
57 {
58 TurnState existing = new();
59 existing.Set("shared", "hello");
60
61 _cacheMock.Setup(c => c.GetAsync("ts:conv:conv1", It.IsAny<CancellationToken>()))
62 .ReturnsAsync(existing.ToJsonBytes());
63
64 TurnStateLoader loader = CreateLoader();
65 TurnStateContainer container = await loader.LoadAsync("conv1", "user1", CancellationToken.None);
66
67 Assert.Equal("hello", container.ConversationState.Get<string>("shared"));
68 }
69
70 [Fact]
71 public async Task LoadAsync_ExistingUserState_IsLoaded()
72 {
73 TurnState existing = new();
74 existing.Set("private", "world");
75
76 _cacheMock.Setup(c => c.GetAsync("ts:user:conv1:user1", It.IsAny<CancellationToken>()))
77 .ReturnsAsync(existing.ToJsonBytes());
78
79 TurnStateLoader loader = CreateLoader();
80 TurnStateContainer container = await loader.LoadAsync("conv1", "user1", CancellationToken.None);
81
82 Assert.Equal("world", container.UserState!.Get<string>("private"));
83 }
84
85 // ── Save behavior ─────────────────────────────────────────────────
86
87 [Fact]
88 public async Task SaveAsync_DirtyConversationState_IsSaved()
89 {
90 TurnStateLoader loader = CreateLoader();
91 TurnStateContainer container = await loader.LoadAsync("conv1", "user1", CancellationToken.None);
92
93 container.ConversationState.Set("key", "value");
94
95 await loader.SaveAsync(container, "conv1", "user1", CancellationToken.None);
96
97 _cacheMock.Verify(c => c.SetAsync(
98 "ts:conv:conv1",
99 It.IsAny<byte[]>(),
100 It.IsAny<DistributedCacheEntryOptions>(),
101 It.IsAny<CancellationToken>()), Times.Once);
102 }
103
104 [Fact]
105 public async Task SaveAsync_DirtyUserState_IsSaved()
106 {
107 TurnStateLoader loader = CreateLoader();
108 TurnStateContainer container = await loader.LoadAsync("conv1", "user1", CancellationToken.None);
109
110 container.UserState!.Set("key", "value");
111
112 await loader.SaveAsync(container, "conv1", "user1", CancellationToken.None);
113
114 _cacheMock.Verify(c => c.SetAsync(
115 "ts:user:conv1:user1",
116 It.IsAny<byte[]>(),
117 It.IsAny<DistributedCacheEntryOptions>(),
118 It.IsAny<CancellationToken>()), Times.Once);
119 }
120
121 [Fact]
122 public async Task SaveAsync_NonDirtyState_IsNotSaved()
123 {
124 TurnStateLoader loader = CreateLoader();
125 TurnStateContainer container = await loader.LoadAsync("conv1", "user1", CancellationToken.None);
126
127 await loader.SaveAsync(container, "conv1", "user1", CancellationToken.None);
128
129 _cacheMock.Verify(c => c.SetAsync(
130 It.IsAny<string>(),
131 It.IsAny<byte[]>(),
132 It.IsAny<DistributedCacheEntryOptions>(),
133 It.IsAny<CancellationToken>()), Times.Never);
134 }
135
136 // ── Key format ────────────────────────────────────────────────────
137
138 [Fact]
139 public async Task KeysUseCorrectFormat()
140 {
141 TurnStateLoader loader = CreateLoader();
142 TurnStateContainer container = await loader.LoadAsync("myConv", "myUser", CancellationToken.None);
143
144 container.ConversationState.Set("x", 1);
145 container.UserState!.Set("y", 2);
146
147 await loader.SaveAsync(container, "myConv", "myUser", CancellationToken.None);
148
149 _cacheMock.Verify(c => c.SetAsync(
150 "ts:conv:myConv",
151 It.IsAny<byte[]>(),
152 It.IsAny<DistributedCacheEntryOptions>(),
153 It.IsAny<CancellationToken>()), Times.Once);
154
155 _cacheMock.Verify(c => c.SetAsync(
156 "ts:user:myConv:myUser",
157 It.IsAny<byte[]>(),
158 It.IsAny<DistributedCacheEntryOptions>(),
159 It.IsAny<CancellationToken>()), Times.Once);
160 }
161
162 // ── Delete behavior ────────────────────────────────────────────────
163
164 [Fact]
165 public async Task DeleteAsync_RemovesConversationAndUserKeys()
166 {
167 TurnStateLoader loader = CreateLoader();
168
169 await loader.DeleteAsync("conv1", "user1", CancellationToken.None);
170
171 _cacheMock.Verify(c => c.RemoveAsync("ts:conv:conv1", It.IsAny<CancellationToken>()), Times.Once);
172 _cacheMock.Verify(c => c.RemoveAsync("ts:user:conv1:user1", It.IsAny<CancellationToken>()), Times.Once);
173 }
174
175 [Fact]
176 public async Task DeleteAsync_NullUserId_RemovesOnlyConversationKey()
177 {
178 TurnStateLoader loader = CreateLoader();
179
180 await loader.DeleteAsync("conv1", null, CancellationToken.None);
181
182 _cacheMock.Verify(c => c.RemoveAsync("ts:conv:conv1", It.IsAny<CancellationToken>()), Times.Once);
183 _cacheMock.Verify(c => c.RemoveAsync(It.Is<string>(k => k.StartsWith("ts:user:")), It.IsAny<CancellationToken>()), Times.Never);
184 }
185}
186