Skip to content

Commit a0441c5

Browse files
committed
test: add more tests
1 parent f23d2ee commit a0441c5

File tree

6 files changed

+681
-6
lines changed

6 files changed

+681
-6
lines changed

drivers/spanner-ado-net/spanner-ado-net-tests/AbstractMockServerTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
using System;
1615
using Google.Cloud.SpannerLib.MockServer;
1716

1817
namespace Google.Cloud.Spanner.DataProvider.Tests;

drivers/spanner-ado-net/spanner-ado-net-tests/BasicTests.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
1-
using System;
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
215
using System.Data.Common;
3-
using System.Linq;
416
using System.Text.Json;
517
using Google.Cloud.Spanner.V1;
618
using Google.Cloud.SpannerLib.MockServer;
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System.Data;
16+
17+
namespace Google.Cloud.Spanner.DataProvider.Tests;
18+
19+
public class ConnectionStringBuilderTests
20+
{
21+
[Test]
22+
public void Basic()
23+
{
24+
var builder = new SpannerConnectionStringBuilder();
25+
Assert.That(builder.Keys, Is.Empty);
26+
Assert.That(builder.Count, Is.EqualTo(0));
27+
Assert.False(builder.ContainsKey("host"));
28+
builder.Host = "myhost";
29+
Assert.That(builder["host"], Is.EqualTo("myhost"));
30+
Assert.That(builder.Count, Is.EqualTo(1));
31+
Assert.That(builder.ConnectionString, Is.EqualTo("Host=myhost"));
32+
builder.Remove("HOST");
33+
Assert.That(builder["host"], Is.EqualTo(""));
34+
Assert.That(builder.Count, Is.EqualTo(0));
35+
}
36+
37+
[Test]
38+
public void TryGetValue()
39+
{
40+
var builder = new SpannerConnectionStringBuilder
41+
{
42+
ConnectionString = "Host=myhost"
43+
};
44+
Assert.That(builder.TryGetValue("Host", out var value), Is.True);
45+
Assert.That(value, Is.EqualTo("myhost"));
46+
Assert.That(builder.TryGetValue("SomethingUnknown", out value), Is.False);
47+
}
48+
49+
[Test]
50+
public void Remove()
51+
{
52+
var builder = new SpannerConnectionStringBuilder
53+
{
54+
UsePlainText = true
55+
};
56+
Assert.That(builder["Use plain text"], Is.True);
57+
builder.Remove("UsePlainText");
58+
Assert.That(builder.ConnectionString, Is.EqualTo(""));
59+
}
60+
61+
[Test]
62+
public void Clear()
63+
{
64+
var builder = new SpannerConnectionStringBuilder { Host = "myhost" };
65+
builder.Clear();
66+
Assert.That(builder.Count, Is.EqualTo(0));
67+
Assert.That(builder["host"], Is.EqualTo(""));
68+
Assert.That(builder.Host, Is.Empty);
69+
}
70+
71+
[Test]
72+
public void RemovingResetsToDefault()
73+
{
74+
var builder = new SpannerConnectionStringBuilder();
75+
Assert.That(builder.Port, Is.EqualTo(SpannerConnectionStringOption.Port.DefaultValue));
76+
builder.Port = 8;
77+
builder.Remove("Port");
78+
Assert.That(builder.Port, Is.EqualTo(SpannerConnectionStringOption.Port.DefaultValue));
79+
}
80+
81+
[Test]
82+
public void SettingToNullResetsToDefault()
83+
{
84+
var builder = new SpannerConnectionStringBuilder();
85+
Assert.That(builder.Port, Is.EqualTo(SpannerConnectionStringOption.Port.DefaultValue));
86+
builder.Port = 8;
87+
builder["Port"] = null;
88+
Assert.That(builder.Port, Is.EqualTo(SpannerConnectionStringOption.Port.DefaultValue));
89+
}
90+
91+
[Test]
92+
public void Enum()
93+
{
94+
var builder = new SpannerConnectionStringBuilder
95+
{
96+
ConnectionString = "DefaultIsolationLevel=Serializable"
97+
};
98+
Assert.That(builder.DefaultIsolationLevel, Is.EqualTo(IsolationLevel.Serializable));
99+
Assert.That(builder.Count, Is.EqualTo(1));
100+
}
101+
102+
[Test]
103+
public void EnumCaseInsensitive()
104+
{
105+
var builder = new SpannerConnectionStringBuilder
106+
{
107+
ConnectionString = "defaultisolationlevel=repeatable read"
108+
};
109+
Assert.That(builder.DefaultIsolationLevel, Is.EqualTo(IsolationLevel.RepeatableRead));
110+
Assert.That(builder.Count, Is.EqualTo(1));
111+
}
112+
113+
[Test]
114+
public void Clone()
115+
{
116+
var builder = new SpannerConnectionStringBuilder
117+
{
118+
Host = "myhost"
119+
};
120+
var builder2 = builder.Clone();
121+
Assert.That(builder2.Host, Is.EqualTo("myhost"));
122+
Assert.That(builder2["Host"], Is.EqualTo("myhost"));
123+
Assert.That(builder.Port, Is.EqualTo(SpannerConnectionStringOption.Port.DefaultValue));
124+
}
125+
126+
[Test]
127+
public void ConversionErrorThrows()
128+
{
129+
// ReSharper disable once CollectionNeverQueried.Local
130+
var builder = new SpannerConnectionStringBuilder();
131+
Assert.That(() => builder["Port"] = "hello",
132+
Throws.Exception.TypeOf<ArgumentException>().With.Message.Contains("Port"));
133+
}
134+
135+
[Test]
136+
public void InvalidConnectionStringThrows()
137+
{
138+
var builder = new SpannerConnectionStringBuilder();
139+
Assert.That(() => builder.ConnectionString = "Server=127.0.0.1;User Id=npgsql_tests;Pooling:false",
140+
Throws.Exception.TypeOf<ArgumentException>());
141+
}
142+
143+
[Test]
144+
public void ConnectionStringToProperties()
145+
{
146+
var builder = new SpannerConnectionStringBuilder
147+
{
148+
ConnectionString = "Host=localhost;Port=80;UsePlainText=true;DefaultIsolationLevel=Repeatable read",
149+
};
150+
Assert.That(builder.Host, Is.EqualTo("localhost"));
151+
Assert.That(builder.Port, Is.EqualTo(80));
152+
Assert.That(builder.UsePlainText, Is.True);
153+
Assert.That(builder.DefaultIsolationLevel, Is.EqualTo(IsolationLevel.RepeatableRead));
154+
}
155+
156+
[Test]
157+
public void PropertiesToConnectionString()
158+
{
159+
var builder = new SpannerConnectionStringBuilder
160+
{
161+
Host = "localhost",
162+
Port = 80,
163+
UsePlainText = true,
164+
DefaultIsolationLevel = IsolationLevel.RepeatableRead,
165+
DataSource = "projects/project1/instances/instance1/databases/database1"
166+
};
167+
Assert.That(builder.ConnectionString, Is.EqualTo("Data Source=projects/project1/instances/instance1/databases/database1;Host=localhost;Port=80;UsePlainText=True;DefaultIsolationLevel=RepeatableRead"));
168+
Assert.That(builder.SpannerLibConnectionString, Is.EqualTo("localhost:80/projects/project1/instances/instance1/databases/database1;UsePlainText=True;DefaultIsolationLevel=RepeatableRead"));
169+
}
170+
171+
}

drivers/spanner-ado-net/spanner-ado-net-tests/ConnectionTests.cs

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
using System.Linq;
15+
using System.Data;
1616
using Google.Cloud.Spanner.V1;
1717
using Google.Cloud.SpannerLib;
1818
using Google.Cloud.SpannerLib.MockServer;
19+
using Google.Rpc;
1920
using Grpc.Core;
21+
using Status = Grpc.Core.Status;
2022
using TypeCode = Google.Cloud.Spanner.V1.TypeCode;
2123

2224
namespace Google.Cloud.Spanner.DataProvider.Tests;
@@ -174,4 +176,86 @@ public void TestBatchDml()
174176
Assert.That(affected, Is.EqualTo(new long[] { 2, 3 }));
175177
}
176178

179+
[Test]
180+
public async Task TestBasicLifecycle()
181+
{
182+
await using var conn = new SpannerConnection();
183+
conn.ConnectionString = ConnectionString;
184+
185+
var eventConnecting = false;
186+
var eventOpen = false;
187+
var eventClosed = false;
188+
189+
conn.StateChange += (_, e) =>
190+
{
191+
if (e is { OriginalState: ConnectionState.Closed, CurrentState: ConnectionState.Connecting })
192+
eventConnecting = true;
193+
194+
if (e is { OriginalState: ConnectionState.Connecting, CurrentState: ConnectionState.Open })
195+
eventOpen = true;
196+
197+
if (e is { OriginalState: ConnectionState.Open, CurrentState: ConnectionState.Closed })
198+
eventClosed = true;
199+
};
200+
201+
Assert.That(conn.State, Is.EqualTo(ConnectionState.Closed));
202+
Assert.That(eventConnecting, Is.False);
203+
Assert.That(eventOpen, Is.False);
204+
205+
await conn.OpenAsync();
206+
207+
Assert.That(conn.State, Is.EqualTo(ConnectionState.Open));
208+
Assert.That(eventConnecting, Is.True);
209+
Assert.That(eventOpen, Is.True);
210+
211+
await using (var cmd = new SpannerCommand("SELECT 1", conn))
212+
await using (var reader = await cmd.ExecuteReaderAsync())
213+
{
214+
await reader.ReadAsync();
215+
Assert.That(conn.State, Is.EqualTo(ConnectionState.Open));
216+
}
217+
218+
Assert.That(conn.State, Is.EqualTo(ConnectionState.Open));
219+
220+
await conn.CloseAsync();
221+
222+
Assert.That(conn.State, Is.EqualTo(ConnectionState.Closed));
223+
Assert.That(eventClosed, Is.True);
224+
}
225+
226+
[Test]
227+
[Ignore("SpannerLib should support a connect_timeout property to make this test quicker")]
228+
public async Task TestInvalidHost()
229+
{
230+
await using var conn = new SpannerConnection();
231+
conn.ConnectionString = $"{Fixture.Host}_invalid:{Fixture.Port}/projects/p1/instances/i1/databases/d1;UsePlainText=true";
232+
var exception = Assert.Throws<SpannerException>(() => conn.Open());
233+
Assert.That(exception.Code, Is.EqualTo(Code.DeadlineExceeded));
234+
}
235+
236+
[Test]
237+
public async Task TestInvalidDatabase()
238+
{
239+
// Close all current pools to ensure that we get a fresh pool.
240+
SpannerPool.CloseSpannerLib();
241+
// TODO: Make this a public property in the mock server.
242+
const string detectDialectQuery =
243+
"select option_value from information_schema.database_options where option_name='database_dialect'";
244+
Fixture.SpannerMock.AddOrUpdateStatementResult(detectDialectQuery, StatementResult.CreateException(new RpcException(new Status(StatusCode.NotFound, "Database not found"))));
245+
await using var conn = new SpannerConnection();
246+
conn.ConnectionString = ConnectionString;
247+
var exception = Assert.Throws<SpannerException>(() => conn.Open());
248+
Assert.That(exception.Code, Is.EqualTo(Code.NotFound));
249+
}
250+
251+
[Test]
252+
public async Task TestConnectWithConnectionStringBuilder()
253+
{
254+
var builder = new SpannerConnectionStringBuilder();
255+
builder.DataSource = "projects/my-project/instances/my-instance/databases/my-database";
256+
builder.Host = Fixture.Host;
257+
builder.Port = (uint) Fixture.Port;
258+
builder.UsePlainText = true;
259+
}
260+
177261
}

drivers/spanner-ado-net/spanner-ado-net/SpannerCommand.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ internal SpannerCommand(SpannerConnection connection)
5454
Connection = GaxPreconditions.CheckNotNull(connection, nameof(connection));
5555
}
5656

57+
public SpannerCommand(string commandText, SpannerConnection connection)
58+
{
59+
Connection = GaxPreconditions.CheckNotNull(connection, nameof(connection));
60+
_commandText = GaxPreconditions.CheckNotNull(commandText, nameof(commandText));
61+
}
62+
5763
internal SpannerCommand(SpannerConnection connection, Mutation mutation)
5864
{
5965
Connection = GaxPreconditions.CheckNotNull(connection, nameof(connection));

0 commit comments

Comments
 (0)