Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ jobs:
strategy:
fail-fast: false
matrix:
version: ["1.31.20", "1.32.17", "1.33.5", "1.34.0", "1.35.2"]
version: ["1.32.17", "1.33.5", "1.34.0", "1.35.2", "1.36.0"]
uses: ./.github/workflows/test-on-weaviate-version.yml
secrets: inherit
with:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -486,3 +486,4 @@ $RECYCLE.BIN/
*.swp

.serena
memory/
62 changes: 58 additions & 4 deletions ci/compose.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,30 @@ function exec_dc {
}

function compose_up {
exec_dc up -d --quiet-pull
echo "Pulling Weaviate image ${WEAVIATE_VERSION:-latest}..."
echo "Images to be pulled:"
exec_dc config --images
echo ""

if ! exec_dc pull; then
echo "ERROR: Failed to pull Docker images"
echo "Image pull failed for version ${WEAVIATE_VERSION}"
return 1
fi

echo "Successfully pulled images. Starting containers..."
if ! exec_dc up -d; then
echo "ERROR: Failed to start containers"
echo "Container status:"
docker ps -a
echo ""
echo "Container logs:"
exec_dc logs
return 1
fi

echo "Containers started successfully"
return 0
}

function compose_down {
Expand All @@ -47,6 +70,25 @@ function wait(){
while true; do
# first check if weaviate already responds
if ! curl -s "$1" > /dev/null; then
echo "Weaviate port not responding yet. (waited for ${ALREADY_WAITING}s)"
if [ $ALREADY_WAITING -gt $MAX_WAIT_SECONDS ]; then
echo "======================================"
echo "ERROR: Weaviate did not start up in $MAX_WAIT_SECONDS seconds"
echo "======================================"
echo ""
echo "Docker container status:"
docker ps -a --filter "name=weaviate"
echo ""
echo "Docker compose logs (last 50 lines):"
exec_dc logs --tail=50
echo ""
echo "Checking port accessibility:"
nc -zv localhost 8080 || echo "Port 8080 not accessible"
echo "======================================"
exit 1
fi
sleep 2
(( ALREADY_WAITING+=2 )) || true
continue
fi

Expand All @@ -56,9 +98,21 @@ function wait(){
if [ "$HTTP_STATUS" -eq 200 ]; then
break
else
echo "Weaviate is not up yet. (waited for ${ALREADY_WAITING}s)"
echo "Weaviate responding but not ready yet. HTTP $HTTP_STATUS (waited for ${ALREADY_WAITING}s)"
if [ $ALREADY_WAITING -gt $MAX_WAIT_SECONDS ]; then
echo "Weaviate did not start up in $MAX_WAIT_SECONDS."
echo "======================================"
echo "ERROR: Weaviate did not become ready in $MAX_WAIT_SECONDS seconds"
echo "======================================"
echo ""
echo "Docker container status:"
docker ps -a --filter "name=weaviate"
echo ""
echo "Docker compose logs (last 50 lines):"
exec_dc logs --tail=50
echo ""
echo "Weaviate ready endpoint response:"
curl -v "$1/v1/.well-known/ready" || true
echo "======================================"
exit 1
else
sleep 2
Expand All @@ -68,4 +122,4 @@ function wait(){
done

echo "Weaviate is up and running!"
}
}
6 changes: 3 additions & 3 deletions ci/docker-compose-cluster.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
services:
weaviate-node-1:
image: semitechnologies/weaviate:${WEAVIATE_VERSION}
image: cr.weaviate.io/semitechnologies/weaviate:${WEAVIATE_VERSION}
restart: on-failure:0
ports:
- "8087:8080"
Expand Down Expand Up @@ -32,7 +32,7 @@ services:
- '8080'
- --scheme
- http
image: semitechnologies/weaviate:${WEAVIATE_VERSION}
image: cr.weaviate.io/semitechnologies/weaviate:${WEAVIATE_VERSION}
ports:
- 8088:8080
- "50059:50051"
Expand Down Expand Up @@ -66,7 +66,7 @@ services:
- '8080'
- --scheme
- http
image: semitechnologies/weaviate:${WEAVIATE_VERSION}
image: cr.weaviate.io/semitechnologies/weaviate:${WEAVIATE_VERSION}
ports:
- 8089:8080
- "50060:50051"
Expand Down
2 changes: 1 addition & 1 deletion ci/docker-compose-okta-cc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ services:
- --scheme
- http
- --write-timeout=600s
image: semitechnologies/weaviate:${WEAVIATE_VERSION}
image: cr.weaviate.io/semitechnologies/weaviate:${WEAVIATE_VERSION}
ports:
- 8082:8082
restart: on-failure:0
Expand Down
2 changes: 1 addition & 1 deletion ci/docker-compose-okta-users.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ services:
- --scheme
- http
- --write-timeout=600s
image: semitechnologies/weaviate:${WEAVIATE_VERSION}
image: cr.weaviate.io/semitechnologies/weaviate:${WEAVIATE_VERSION}
ports:
- 8083:8083
restart: on-failure:0
Expand Down
2 changes: 1 addition & 1 deletion ci/docker-compose-rbac.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ services:
- --scheme
- http
- --write-timeout=600s
image: semitechnologies/weaviate:${WEAVIATE_VERSION}
image: cr.weaviate.io/semitechnologies/weaviate:${WEAVIATE_VERSION}
ports:
- 8092:8085
- 50063:50051
Expand Down
1 change: 1 addition & 0 deletions ci/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ services:
AUTOSCHEMA_ENABLED: 'false'
DISABLE_TELEMETRY: 'true'
DISABLE_LAZY_LOAD_SHARDS: 'true'
OBJECTS_TTL_DELETE_SCHEDULE: "@every 1m"
GRPC_MAX_MESSAGE_SIZE: 100000000 # 100mb
#ASYNC_INDEXING: 'true'
TRANSFORMERS_INFERENCE_API: http://transformers:8080
Expand Down
12 changes: 11 additions & 1 deletion ci/start_weaviate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,17 @@ compose_down
rm -rf weaviate-data || true

echo "Run Docker compose (Weaviate $WEAVIATE_VERSION)"
compose_up
if ! compose_up; then
echo "======================================"
echo "ERROR: Failed to start Weaviate with Docker Compose"
echo "Version: $WEAVIATE_VERSION"
echo "======================================"
exit 1
fi

echo "Checking Docker container status after compose up:"
docker ps -a --filter "name=weaviate"
echo ""

echo "Wait until all containers are up"

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
using Xunit;
using VerifyCS = Microsoft.CodeAnalysis.CSharp.Testing.XUnit.AnalyzerVerifier<Weaviate.Client.Analyzers.RequiresVersionEnsureCallAnalyzer>;

namespace Weaviate.Client.Analyzers.Tests;

/// <summary>
/// Tests for WEAVIATE008 — methods decorated with [RequiresWeaviateVersion] must call EnsureVersion&lt;T&gt;().
/// </summary>
public class RequiresVersionEnsureCallAnalyzerTests
{
/// <summary>
/// Minimal stubs that reproduce the real types the analyzer looks for.
/// </summary>
private const string Stubs =
@"
using System;
using System.Threading.Tasks;

[AttributeUsage(AttributeTargets.Method)]
public sealed class RequiresWeaviateVersionAttribute : Attribute
{
public RequiresWeaviateVersionAttribute(int major, int minor, int patch = 0) { }
}

public class WeaviateClient
{
public Task EnsureVersion<T>(string operationName = """") => Task.CompletedTask;
}
";

/// <summary>
/// A method with the attribute that correctly calls EnsureVersion produces no diagnostic.
/// </summary>
[Fact]
public async Task WithAttributeAndEnsureVersionCall_NoDiagnostic()
{
var testCode =
Stubs
+ @"
public class CollectionConfigClient
{
private WeaviateClient _client = new WeaviateClient();

[RequiresWeaviateVersion(1, 36, 0)]
public async Task DeletePropertyIndex()
{
await _client.EnsureVersion<CollectionConfigClient>();
}
}";

await VerifyCS.VerifyAnalyzerAsync(testCode);
}

/// <summary>
/// A method with the attribute but no EnsureVersion call produces a diagnostic.
/// </summary>
[Fact]
public async Task WithAttributeButMissingEnsureVersionCall_ReportsDiagnostic()
{
var testCode =
Stubs
+ @"
public class CollectionConfigClient
{
[RequiresWeaviateVersion(1, 36, 0)]
public async Task {|#0:DeletePropertyIndex|}()
{
await Task.CompletedTask;
}
}";

var expected = VerifyCS
.Diagnostic(RequiresVersionEnsureCallAnalyzer.DiagnosticId)
.WithLocation(0)
.WithArguments("DeletePropertyIndex", "CollectionConfigClient");

await VerifyCS.VerifyAnalyzerAsync(testCode, expected);
}

/// <summary>
/// A method without the attribute does not need to call EnsureVersion.
/// </summary>
[Fact]
public async Task WithoutAttribute_NoDiagnostic()
{
var testCode =
Stubs
+ @"
public class CollectionConfigClient
{
public async Task SomeRegularMethod()
{
await Task.CompletedTask;
}
}";

await VerifyCS.VerifyAnalyzerAsync(testCode);
}

/// <summary>
/// A method using the full attribute type name (RequiresWeaviateVersionAttribute) is also caught.
/// </summary>
[Fact]
public async Task FullAttributeName_WithoutEnsureVersionCall_ReportsDiagnostic()
{
var testCode =
Stubs
+ @"
public class SomeClient
{
[RequiresWeaviateVersionAttribute(1, 35, 0)]
public async Task {|#0:VersionedMethod|}()
{
await Task.CompletedTask;
}
}";

var expected = VerifyCS
.Diagnostic(RequiresVersionEnsureCallAnalyzer.DiagnosticId)
.WithLocation(0)
.WithArguments("VersionedMethod", "SomeClient");

await VerifyCS.VerifyAnalyzerAsync(testCode, expected);
}

/// <summary>
/// An EnsureVersion call anywhere in the method body (not just the first statement) satisfies the rule.
/// </summary>
[Fact]
public async Task EnsureVersionCallInMiddleOfBody_NoDiagnostic()
{
var testCode =
Stubs
+ @"
public class SomeClient
{
private WeaviateClient _client = new WeaviateClient();

[RequiresWeaviateVersion(1, 36, 0)]
public async Task VersionedMethod(bool condition)
{
if (condition)
{
await _client.EnsureVersion<SomeClient>();
}
await Task.CompletedTask;
}
}";

await VerifyCS.VerifyAnalyzerAsync(testCode);
}

/// <summary>
/// Two methods in the same class: one decorated correctly, one missing the call.
/// Only the offending method should produce a diagnostic.
/// </summary>
[Fact]
public async Task TwoMethods_OnlyDecoratedAndMissingCallReportsDiagnostic()
{
var testCode =
Stubs
+ @"
public class SomeClient
{
private WeaviateClient _client = new WeaviateClient();

[RequiresWeaviateVersion(1, 36, 0)]
public async Task GoodMethod()
{
await _client.EnsureVersion<SomeClient>();
}

[RequiresWeaviateVersion(1, 36, 0)]
public async Task {|#0:BadMethod|}()
{
await Task.CompletedTask;
}
}";

var expected = VerifyCS
.Diagnostic(RequiresVersionEnsureCallAnalyzer.DiagnosticId)
.WithLocation(0)
.WithArguments("BadMethod", "SomeClient");

await VerifyCS.VerifyAnalyzerAsync(testCode, expected);
}
}
5 changes: 3 additions & 2 deletions src/Weaviate.Client.Analyzers/AnalyzerReleases.Unshipped.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

### New Rules

Rule ID | Category | Severity | Notes
------------|----------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------
Rule ID | Category | Severity | Notes
------------|-------------|----------|-----------------------------------------------------------------
WEAVIATE008 | Correctness | Error | Methods decorated with [RequiresWeaviateVersion] must call EnsureVersion to enforce the minimum server version at runtime.
Loading
Loading