Skip to content

Commit c60eb3b

Browse files
authored
Merge pull request #356 from weaviate/ci/weaviate-1.38-matrix
ci: refresh test matrix to latest patches, add 1.38.4, fix 1.38 DTO staleness
2 parents 64fb14c + 87e3abb commit c60eb3b

12 files changed

Lines changed: 1797 additions & 35 deletions

File tree

.github/workflows/main.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ jobs:
136136
strategy:
137137
fail-fast: false
138138
matrix:
139-
version: ["1.32.27", "1.33.18", "1.34.20", "1.35.16", "1.36.10", "1.37.5-e0fe0d5.amd64"]
139+
version: ["1.32.27", "1.33.18", "1.34.20", "1.35.23", "1.36.21", "1.37.12", "1.38.4"]
140140
uses: ./.github/workflows/test-on-weaviate-version.yml
141141
secrets: inherit
142142
with:

src/Weaviate.Client.Tests/Integration/TestCollections.cs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,13 @@ public async Task Test_Collections_Export_Cases(string key)
126126

127127
var expected = CollectionConfig.FromCollectionCreate(c);
128128

129+
if (ServerVersionIsInRange("1.38.0") && expected.ReplicationConfig is not null)
130+
{
131+
// Weaviate 1.38 removed the per-collection asyncEnabled setting: the server
132+
// derives it as `factor > 1` and ignores the value sent at creation.
133+
expected.ReplicationConfig.AsyncEnabled = expected.ReplicationConfig.Factor > 1;
134+
}
135+
129136
Assert.Equal(expected, export);
130137
}
131138
#endif
@@ -404,7 +411,16 @@ public async Task Test_Collections_Export_NonDefaultValues_Sharding()
404411

405412
// ReplicationConfig validation
406413
Assert.NotNull(export.ReplicationConfig);
407-
Assert.True(export.ReplicationConfig.AsyncEnabled);
414+
if (ServerVersionIsInRange("1.38.0"))
415+
{
416+
// Weaviate 1.38 removed the per-collection asyncEnabled setting: the server
417+
// derives it as `factor > 1` (factor is 1 here) and ignores the value sent.
418+
Assert.False(export.ReplicationConfig.AsyncEnabled);
419+
}
420+
else
421+
{
422+
Assert.True(export.ReplicationConfig.AsyncEnabled);
423+
}
408424
Assert.True(
409425
new[]
410426
{
@@ -561,7 +577,16 @@ public async Task Test_Collections_Export_NonDefaultValues_MultiTenacy()
561577

562578
// ReplicationConfig validation
563579
Assert.NotNull(export.ReplicationConfig);
564-
Assert.True(export.ReplicationConfig.AsyncEnabled);
580+
if (ServerVersionIsInRange("1.38.0"))
581+
{
582+
// Weaviate 1.38 removed the per-collection asyncEnabled setting: the server
583+
// derives it as `factor > 1` (factor is 1 here) and ignores the value sent.
584+
Assert.False(export.ReplicationConfig.AsyncEnabled);
585+
}
586+
else
587+
{
588+
Assert.True(export.ReplicationConfig.AsyncEnabled);
589+
}
565590
Assert.True(
566591
new[]
567592
{

src/Weaviate.Client.Tests/Integration/TestRbacRoles.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,4 +574,44 @@ public async Task CreateRoleWithMcpPermission()
574574
await _weaviate.Roles.Delete(roleName, TestContext.Current.CancellationToken);
575575
}
576576
}
577+
578+
/// <summary>
579+
/// Tests that create role with namespaces permission round trips (Weaviate 1.38+)
580+
/// </summary>
581+
[Fact]
582+
public async Task CreateRoleWithNamespacesPermission()
583+
{
584+
RequireVersion("1.38.0");
585+
var roleName = MakeRoleName("namespaces");
586+
try
587+
{
588+
await _weaviate.Roles.Delete(roleName, TestContext.Current.CancellationToken);
589+
var created = await _weaviate.Roles.Create(
590+
roleName,
591+
[new Permissions.Namespaces("*") { Manage = true }],
592+
TestContext.Current.CancellationToken
593+
);
594+
Assert.NotNull(created);
595+
Assert.Equal(roleName, created.Name);
596+
Assert.Single(created.Permissions);
597+
var scope = Assert.IsType<Permissions.Namespaces>(created.Permissions.Single());
598+
Assert.True(scope.Manage);
599+
Assert.Equal("*", scope.Resource.Namespace);
600+
601+
var fetched = await _weaviate.Roles.Get(
602+
roleName,
603+
TestContext.Current.CancellationToken
604+
);
605+
Assert.NotNull(fetched);
606+
Assert.Equal(roleName, fetched!.Name);
607+
Assert.Single(fetched.Permissions);
608+
var fetchedScope = Assert.IsType<Permissions.Namespaces>(fetched.Permissions.Single());
609+
Assert.True(fetchedScope.Manage);
610+
Assert.Equal("*", fetchedScope.Resource.Namespace);
611+
}
612+
finally
613+
{
614+
await _weaviate.Roles.Delete(roleName, TestContext.Current.CancellationToken);
615+
}
616+
}
577617
}

src/Weaviate.Client.Tests/Unit/PermissionsScopeTests.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,54 @@ public void Backups_Aggregates_ManageBackupsOnly()
389389
Assert.True(backups[0].Manage);
390390
}
391391

392+
/// <summary>
393+
/// Tests that namespaces aggregates manage namespaces only (Weaviate 1.38+)
394+
/// </summary>
395+
[Fact]
396+
public void Namespaces_Aggregates_ManageNamespacesOnly()
397+
{
398+
var resource = new Rest.Dto.Namespaces { Namespace = "ns-.*" };
399+
var permissions = new List<Rest.Dto.Permission>
400+
{
401+
new()
402+
{
403+
Action = Weaviate.Client.Rest.Dto.PermissionAction.Manage_namespaces,
404+
Namespaces = resource,
405+
},
406+
};
407+
var namespaces = Permissions
408+
.Namespaces.Parse(permissions)
409+
.Cast<Permissions.Namespaces>()
410+
.ToList();
411+
Assert.Single(namespaces);
412+
Assert.True(namespaces[0].Manage);
413+
Assert.Equal("ns-.*", namespaces[0].Resource.Namespace);
414+
}
415+
416+
/// <summary>
417+
/// Tests that namespaces round trips through the dto (Weaviate 1.38+)
418+
/// </summary>
419+
[Fact]
420+
public void Namespaces_ToDto_RoundTrips()
421+
{
422+
var scope = new Permissions.Namespaces("team-a") { Manage = true };
423+
424+
var dtos = scope.ToDto().ToList();
425+
426+
var dto = Assert.Single(dtos);
427+
Assert.Equal(Weaviate.Client.Rest.Dto.PermissionAction.Manage_namespaces, dto.Action);
428+
Assert.NotNull(dto.Namespaces);
429+
Assert.Equal("team-a", dto.Namespaces!.Namespace);
430+
431+
var parsed = Assert.Single(Permissions.Namespaces.Parse(dtos));
432+
var roundTripped = Assert.IsType<Permissions.Namespaces>(parsed);
433+
Assert.True(roundTripped.Manage);
434+
Assert.Equal("team-a", roundTripped.Resource.Namespace);
435+
436+
// No actions set -> no permission entries are emitted.
437+
Assert.Empty(new Permissions.Namespaces("team-a").ToDto());
438+
}
439+
392440
/// <summary>
393441
/// Tests that all permission actions are mentioned
394442
/// </summary>
@@ -411,6 +459,7 @@ public void AllPermissionActions_AreMentioned()
411459
var testedActions = new HashSet<string>
412460
{
413461
"Manage_backups",
462+
"Manage_namespaces",
414463
"Read_cluster",
415464
"Create_data",
416465
"Read_data",

src/Weaviate.Client/Models/PermissionResource.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ public record ReplicateResource(string? Collection = "*", string? Shard = "*");
7070
/// <param name="Alias">Optional alias name (defaults to "*" for all aliases)</param>
7171
public record AliasesResource(string? Collection = "*", string? Alias = "*");
7272

73+
/// <summary>
74+
/// Represents a namespaces resource, optionally scoped to a namespace. Requires Weaviate 1.38 or later.
75+
/// </summary>
76+
/// <param name="Namespace">Optional namespace name or regex pattern (defaults to "*" for all namespaces)</param>
77+
public record NamespacesResource(string? Namespace = "*");
78+
7379
/// <summary>
7480
/// The permission resource extensions class
7581
/// </summary>
@@ -191,6 +197,16 @@ internal static Rest.Dto.Aliases ToDto(this AliasesResource resource)
191197
return new Rest.Dto.Aliases { Collection = resource.Collection, Alias = resource.Alias };
192198
}
193199

200+
/// <summary>
201+
/// Returns the dto using the specified resource
202+
/// </summary>
203+
/// <param name="resource">The resource</param>
204+
/// <returns>The rest dto namespaces</returns>
205+
internal static Rest.Dto.Namespaces ToDto(this NamespacesResource resource)
206+
{
207+
return new Rest.Dto.Namespaces { Namespace = resource.Namespace };
208+
}
209+
194210
/// <summary>
195211
/// Returns the model using the specified resource
196212
/// </summary>
@@ -421,4 +437,26 @@ internal static PermissionScope ToModel(
421437
Delete = actions.Contains(Rest.Dto.PermissionAction.Delete_collections),
422438
};
423439
}
440+
441+
/// <summary>
442+
/// Returns the model using the specified resource
443+
/// </summary>
444+
/// <param name="resource">The resource</param>
445+
/// <param name="permissions">The permissions</param>
446+
/// <returns>The permission scope</returns>
447+
internal static PermissionScope ToModel(
448+
this Rest.Dto.Namespaces resource,
449+
IEnumerable<Rest.Dto.Permission> permissions
450+
)
451+
{
452+
var actions = permissions
453+
.Where(p => p.Namespaces == resource)
454+
.Select(p => p.Action)
455+
.ToHashSet();
456+
457+
return new Permissions.Namespaces(resource.Namespace)
458+
{
459+
Manage = actions.Contains(Rest.Dto.PermissionAction.Manage_namespaces),
460+
};
461+
}
424462
}

src/Weaviate.Client/Models/RbacPermissions.cs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,74 @@ internal static List<PermissionScope> Parse(IEnumerable<Rest.Dto.Permission> inf
267267
}
268268
}
269269

270+
/// <summary>
271+
/// The namespaces class. Requires Weaviate 1.38 or later.
272+
/// </summary>
273+
/// <seealso cref="PermissionScope"/>
274+
public class Namespaces : PermissionScope
275+
{
276+
/// <summary>
277+
/// Gets the value of the resource
278+
/// </summary>
279+
public NamespacesResource Resource { get; }
280+
281+
/// <summary>
282+
/// Gets or sets the value of the manage
283+
/// </summary>
284+
public bool Manage { get; set; }
285+
286+
/// <summary>
287+
/// Initializes a new instance of the <see cref="Namespaces"/> class
288+
/// </summary>
289+
/// <param name="namespace">The namespace name or regex pattern</param>
290+
public Namespaces(string? @namespace)
291+
: this(new NamespacesResource(@namespace)) { }
292+
293+
/// <summary>
294+
/// Initializes a new instance of the <see cref="Namespaces"/> class
295+
/// </summary>
296+
/// <param name="resource">The resource</param>
297+
/// <exception cref="ArgumentNullException"></exception>
298+
Namespaces(NamespacesResource resource)
299+
{
300+
Resource = resource ?? throw new ArgumentNullException(nameof(resource));
301+
}
302+
303+
/// <summary>
304+
/// Returns the dto
305+
/// </summary>
306+
/// <returns>An enumerable of rest dto permission</returns>
307+
internal override IEnumerable<Rest.Dto.Permission> ToDto()
308+
{
309+
var permissions = new[]
310+
{
311+
(Action: Rest.Dto.PermissionAction.Manage_namespaces, Allowed: Manage),
312+
};
313+
314+
return permissions
315+
.Where(p => p.Allowed)
316+
.Select(p => new Rest.Dto.Permission
317+
{
318+
Namespaces = Resource.ToDto(),
319+
Action = p.Action,
320+
});
321+
}
322+
323+
/// <summary>
324+
/// Parses the infos
325+
/// </summary>
326+
/// <param name="infos">The infos</param>
327+
/// <returns>A list of permission scope</returns>
328+
internal static List<PermissionScope> Parse(IEnumerable<Rest.Dto.Permission> infos)
329+
{
330+
return infos
331+
.Where(i => i.Namespaces != null)
332+
.GroupBy(i => i.Namespaces!)
333+
.Select(group => group.Key.ToModel(group.AsEnumerable()))
334+
.ToList();
335+
}
336+
}
337+
270338
/// <summary>
271339
/// The mcp class
272340
/// </summary>
@@ -988,6 +1056,7 @@ internal static List<PermissionScope> Parse(IEnumerable<Rest.Dto.Permission> inf
9881056
scopes.AddRange(Alias.Parse(infos));
9891057
scopes.AddRange(Data.Parse(infos));
9901058
scopes.AddRange(Backups.Parse(infos));
1059+
scopes.AddRange(Namespaces.Parse(infos));
9911060
scopes.AddRange(Mcp.Parse(infos));
9921061
scopes.AddRange(Cluster.Parse(infos));
9931062
scopes.AddRange(Nodes.Parse(infos));

src/Weaviate.Client/Models/Replication.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ public enum ReplicationOperationState
5858
/// </summary>
5959
[System.Text.Json.Serialization.JsonStringEnumMemberName("CANCELLED")]
6060
Cancelled,
61+
62+
/// <summary>
63+
/// Replica has finished copying and is being integrated as a queryable member of the
64+
/// shard. Occurs between <see cref="Finalizing"/> and <see cref="Dehydrating"/>.
65+
/// </summary>
66+
[System.Text.Json.Serialization.JsonStringEnumMemberName("INTEGRATING")]
67+
Integrating,
6168
}
6269

6370
/// <summary>

src/Weaviate.Client/PublicAPI.Unshipped.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#nullable enable
2+
Weaviate.Client.Models.ReplicationOperationState.Integrating = 6 -> Weaviate.Client.Models.ReplicationOperationState
23
*REMOVED*Weaviate.Client.VectorizerFactory.Text2VecAWSBedrock(string! region, string! model, bool? vectorizeCollectionName = null) -> Weaviate.Client.Models.VectorizerConfig!
34
*REMOVED*Weaviate.Client.VectorizerFactory.Text2VecAWSSagemaker(string! region, string! endpoint, string? targetModel = null, string? targetVariant = null, bool? vectorizeCollectionName = null) -> Weaviate.Client.Models.VectorizerConfig!
45
*REMOVED*Weaviate.Client.VectorizerFactory.Text2VecGoogleVertex(string? apiEndpoint = null, string? model = null, string? projectId = null, string? titleProperty = null, int? dimensions = null, string? taskType = null, bool? vectorizeCollectionName = null) -> Weaviate.Client.Models.VectorizerConfig!
@@ -9,3 +10,23 @@ Weaviate.Client.Models.Vectorizer.Text2VecGoogle.Location.set -> void
910
Weaviate.Client.VectorizerFactory.Text2VecAWSBedrock(string! region, string! model, int? dimensions = null, bool? vectorizeCollectionName = null) -> Weaviate.Client.Models.VectorizerConfig!
1011
Weaviate.Client.VectorizerFactory.Text2VecAWSSagemaker(string! region, string! endpoint, string? targetModel = null, string? targetVariant = null, int? dimensions = null, bool? vectorizeCollectionName = null) -> Weaviate.Client.Models.VectorizerConfig!
1112
Weaviate.Client.VectorizerFactory.Text2VecGoogleVertex(string? apiEndpoint = null, string? model = null, string? projectId = null, string? titleProperty = null, int? dimensions = null, string? taskType = null, bool? vectorizeCollectionName = null, string? location = null) -> Weaviate.Client.Models.VectorizerConfig!
13+
override Weaviate.Client.Models.NamespacesResource.Equals(object? obj) -> bool
14+
override Weaviate.Client.Models.NamespacesResource.GetHashCode() -> int
15+
override Weaviate.Client.Models.NamespacesResource.ToString() -> string!
16+
static Weaviate.Client.Models.NamespacesResource.operator !=(Weaviate.Client.Models.NamespacesResource? left, Weaviate.Client.Models.NamespacesResource? right) -> bool
17+
static Weaviate.Client.Models.NamespacesResource.operator ==(Weaviate.Client.Models.NamespacesResource? left, Weaviate.Client.Models.NamespacesResource? right) -> bool
18+
virtual Weaviate.Client.Models.NamespacesResource.<Clone>$() -> Weaviate.Client.Models.NamespacesResource!
19+
virtual Weaviate.Client.Models.NamespacesResource.EqualityContract.get -> System.Type!
20+
virtual Weaviate.Client.Models.NamespacesResource.Equals(Weaviate.Client.Models.NamespacesResource? other) -> bool
21+
virtual Weaviate.Client.Models.NamespacesResource.PrintMembers(System.Text.StringBuilder! builder) -> bool
22+
Weaviate.Client.Models.NamespacesResource
23+
Weaviate.Client.Models.NamespacesResource.Deconstruct(out string? Namespace) -> void
24+
Weaviate.Client.Models.NamespacesResource.Namespace.get -> string?
25+
Weaviate.Client.Models.NamespacesResource.Namespace.init -> void
26+
Weaviate.Client.Models.NamespacesResource.NamespacesResource(string? Namespace = "*") -> void
27+
Weaviate.Client.Models.NamespacesResource.NamespacesResource(Weaviate.Client.Models.NamespacesResource! original) -> void
28+
Weaviate.Client.Models.Permissions.Namespaces
29+
Weaviate.Client.Models.Permissions.Namespaces.Manage.get -> bool
30+
Weaviate.Client.Models.Permissions.Namespaces.Manage.set -> void
31+
Weaviate.Client.Models.Permissions.Namespaces.Namespaces(string? namespace) -> void
32+
Weaviate.Client.Models.Permissions.Namespaces.Resource.get -> Weaviate.Client.Models.NamespacesResource!

src/Weaviate.Client/ReplicationsClient.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ private static ReplicationOperationState ParseState(
183183
ReplicationOperationState.Hydrating,
184184
Rest.Dto.ReplicationReplicateDetailsReplicaStatusState.FINALIZING =>
185185
ReplicationOperationState.Finalizing,
186+
Rest.Dto.ReplicationReplicateDetailsReplicaStatusState.INTEGRATING =>
187+
ReplicationOperationState.Integrating,
186188
Rest.Dto.ReplicationReplicateDetailsReplicaStatusState.DEHYDRATING =>
187189
ReplicationOperationState.Dehydrating,
188190
Rest.Dto.ReplicationReplicateDetailsReplicaStatusState.READY =>

0 commit comments

Comments
 (0)