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
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
<ItemGroup>
<PackageVersion Include="BenchmarkDotNet" Version="0.15.8" />
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
<PackageVersion Include="FsCheck.Xunit" Version="3.3.2" />
<PackageVersion Include="GitHubActionsTestLogger" Version="3.0.1" />
<PackageVersion Include="Grpc.AspNetCore" Version="2.67.0" />
<PackageVersion Include="Grpc.AspNetCore.Server" Version="2.67.0" />
Expand Down
1 change: 1 addition & 0 deletions OpenTelemetry.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@
<Project Path="test/OpenTelemetry.Api.ProviderBuilderExtensions.Tests/OpenTelemetry.Api.ProviderBuilderExtensions.Tests.csproj" />
<Project Path="test/OpenTelemetry.Api.Tests/OpenTelemetry.Api.Tests.csproj" />
<Project Path="test/OpenTelemetry.Exporter.Console.Tests/OpenTelemetry.Exporter.Console.Tests.csproj" />
<Project Path="test/OpenTelemetry.Exporter.OpenTelemetryProtocol.FuzzTests/OpenTelemetry.Exporter.OpenTelemetryProtocol.FuzzTests.csproj" />
<Project Path="test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj" />
<Project Path="test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests.csproj" />
<Project Path="test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests.csproj" />
Expand Down
2 changes: 1 addition & 1 deletion build/Common.nonprod.props
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<DefaultTargetFrameworkForExampleApps>net10.0</DefaultTargetFrameworkForExampleApps>
</PropertyGroup>

<PropertyGroup Condition="$(MSBuildProjectName.EndsWith('.Tests'))">
<PropertyGroup Condition="$(MSBuildProjectName.EndsWith('.Tests')) OR $(MSBuildProjectName.EndsWith('.FuzzTests'))">
<IsTestProject>true</IsTestProject>
</PropertyGroup>

Expand Down
1 change: 1 addition & 0 deletions src/OpenTelemetry.Api/OpenTelemetry.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<InternalsVisibleTo Include="OpenTelemetry.Exporter.Console" PublicKey="$(StrongNamePublicKey)" />
<InternalsVisibleTo Include="OpenTelemetry.Exporter.InMemory" PublicKey="$(StrongNamePublicKey)" />
<InternalsVisibleTo Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" PublicKey="$(StrongNamePublicKey)" />
<InternalsVisibleTo Include="OpenTelemetry.Exporter.OpenTelemetryProtocol.FuzzTests" PublicKey="$(StrongNamePublicKey)" />
<InternalsVisibleTo Include="OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests" PublicKey="$(StrongNamePublicKey)" />
<InternalsVisibleTo Include="OpenTelemetry.Extensions.Hosting" PublicKey="$(StrongNamePublicKey)" />
<InternalsVisibleTo Include="OpenTelemetry.Extensions.Hosting.Tests" PublicKey="$(StrongNamePublicKey)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
<ItemGroup>
<InternalsVisibleTo Include="Benchmarks" PublicKey="$(StrongNamePublicKey)" />
<InternalsVisibleTo Include="MockOpenTelemetryCollector" PublicKey="$(StrongNamePublicKey)" />
<InternalsVisibleTo Include="OpenTelemetry.Exporter.OpenTelemetryProtocol.FuzzTests" PublicKey="$(StrongNamePublicKey)" />
<InternalsVisibleTo Include="OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests" PublicKey="$(StrongNamePublicKey)" />
</ItemGroup>

Expand Down
1 change: 1 addition & 0 deletions src/OpenTelemetry/OpenTelemetry.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<InternalsVisibleTo Include="OpenTelemetry.Exporter.Console" PublicKey="$(StrongNamePublicKey)" />
<InternalsVisibleTo Include="OpenTelemetry.Exporter.InMemory" PublicKey="$(StrongNamePublicKey)" />
<InternalsVisibleTo Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" PublicKey="$(StrongNamePublicKey)" />
<InternalsVisibleTo Include="OpenTelemetry.Exporter.OpenTelemetryProtocol.FuzzTests" PublicKey="$(StrongNamePublicKey)" />
<InternalsVisibleTo Include="OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests" PublicKey="$(StrongNamePublicKey)" />
<InternalsVisibleTo Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" PublicKey="$(StrongNamePublicKey)" />
<InternalsVisibleTo Include="OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests" PublicKey="$(StrongNamePublicKey)" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

using System.Diagnostics;
using System.Diagnostics.Metrics;
using FsCheck;
using FsCheck.Fluent;
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;

namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.FuzzTests;

internal static class Generators
{
public static readonly ActivitySource TestActivitySource = new("Fuzz.ActivitySource", "1.0.0");

private static readonly Gen<ActivityStatusCode> ActivityStatusCodes = Gen.Elements(
[
ActivityStatusCode.Unset,
ActivityStatusCode.Ok,
ActivityStatusCode.Error,
]);

private static readonly Gen<LogRecordSeverity> LogRecordSeverities = Gen.Elements(
[
LogRecordSeverity.Debug,
LogRecordSeverity.Error,
LogRecordSeverity.Fatal,
LogRecordSeverity.Info,
LogRecordSeverity.Trace,
LogRecordSeverity.Unspecified,
LogRecordSeverity.Warn,
]);

public static Arbitrary<SdkLimitOptions> SdkLimitOptionsArbitrary()
{
var gen = from spanAttributesLimit in Gen.Choose(0, 1000).Select(x => (int?)x)
from spanEventsLimit in Gen.Choose(0, 1000).Select(x => (int?)x)
from spanLinksLimit in Gen.Choose(0, 1000).Select(x => (int?)x)
from spanEventAttributesLimit in Gen.Choose(0, 1000).Select(x => (int?)x)
from spanLinkAttributesLimit in Gen.Choose(0, 1000).Select(x => (int?)x)
from attributeValueLimit in Gen.Choose(0, 10000).Select(x => (int?)x)
from logAttributesLimit in Gen.Choose(0, 1000).Select(x => (int?)x)
select new SdkLimitOptions
{
AttributeValueLengthLimit = attributeValueLimit,
LogRecordAttributeCountLimit = logAttributesLimit,
SpanAttributeCountLimit = spanAttributesLimit,
SpanEventAttributeCountLimit = spanEventAttributesLimit,
SpanEventCountLimit = spanEventsLimit,
SpanLinkAttributeCountLimit = spanLinkAttributesLimit,
SpanLinkCountLimit = spanLinksLimit,
};

return gen.ToArbitrary();
}

public static Arbitrary<Activity> ActivityArbitrary(ActivityStatusCode? status = default)
{
var gen = Gen.Sized(size =>
{
var activity = TestActivitySource.StartActivity($"TestActivity_{Guid.NewGuid():N}");
if (activity == null)
{
return Gen.Constant(new Activity("Fallback"));
}

// Generate tags
var tagCount = Math.Min(size, 50);
for (int i = 0; i < tagCount; i++)
{
activity.SetTag($"tag.{i}", $"value_{i}_{Guid.NewGuid():N}");
}

// Generate events
var eventCount = Math.Min(size / 10, 10);
for (int i = 0; i < eventCount; i++)
{
var eventTags = new ActivityTagsCollection
{
{ $"event.tag.{i}", $"event_value_{i}" },
};
activity.AddEvent(new ActivityEvent($"Event_{i}", DateTimeOffset.UtcNow, eventTags));
}

// Generate links
var linkCount = Math.Min(size / 10, 10);
for (int i = 0; i < linkCount; i++)
{
var linkTags = new ActivityTagsCollection
{
{ $"link.tag.{i}", $"link_value_{i}" },
};

var context = new ActivityContext(
ActivityTraceId.CreateRandom(),
ActivitySpanId.CreateRandom(),
ActivityTraceFlags.Recorded);

activity.AddLink(new ActivityLink(context, linkTags));
}

activity.SetStatus(status ?? ActivityStatusCodes.Sample(size, 1).First());

return Gen.Constant(activity);
});

return gen.ToArbitrary();
}

public static Arbitrary<Resource> ResourceArbitrary()
{
var gen = Gen.Sized(size =>
{
var count = Math.Min(size, 20);
var attributes = new Dictionary<string, object>(count);

for (int i = 0; i < count; i++)
{
attributes[$"resource.attr.{i}"] = $"value_{i}";
}

return Gen.Constant(Resource.Empty.Merge(new Resource(attributes)));
});

return gen.ToArbitrary();
}

/// <summary>
/// Generates valid Metric instances for different metric types.
/// </summary>
public static Arbitrary<Batch<Metric>> BatchMetricArbitrary()
{
var gen = Gen.Sized(size =>
{
var metrics = new List<Metric>();

var builder = Sdk.CreateMeterProviderBuilder()
.AddMeter("FuzzTest.Meter")
.AddInMemoryExporter(metrics);

if (size % 7 == 0)
{
var boundaries = new double[Math.Min(size % 10, 10)];
for (int i = 0; i < boundaries.Length; i++)
{
boundaries[i] = (i * 50.0) + (size % 50);
}

builder.AddView("test.histogram", new ExplicitBucketHistogramConfiguration { Boundaries = boundaries });
}

using (var meterProvider = builder.Build())
{
using var meter = new Meter("FuzzTest.Meter", "1.0.0");

var counter = meter.CreateCounter<long>("test.counter");

for (int i = 0; i < size; i++)
{
counter.Add(100 * i);
}

var gauge = meter.CreateGauge<double>("test.gauge");

for (int i = 0; i < size; i++)
{
gauge.Record(0.1 * i);
}

var histogram = meter.CreateHistogram<int>("test.histogram");

for (int i = 0; i < size; i++)
{
histogram.Record(300 * i);
}

meterProvider.ForceFlush();
}

var batch = new Batch<Metric>([.. metrics], metrics.Count);

return Gen.Constant(batch);
});

return gen.ToArbitrary();
}

/// <summary>
/// Generates valid LogRecord instances.
/// </summary>
public static Arbitrary<LogRecord> LogRecordArbitrary(LogRecordSeverity? severity = default)
{
var gen = Gen.Sized(size =>
{
var logRecord = LogRecordSharedPool.Current.Rent();

logRecord.Severity = severity ?? LogRecordSeverities.Sample(size, 1).First();
logRecord.Timestamp = DateTime.UtcNow;

// Add attributes
var count = Math.Min(size, 50);
var attributes = new List<KeyValuePair<string, object?>>(count);
for (int i = 0; i < count; i++)
{
attributes.Add(new KeyValuePair<string, object?>($"log.attribute.{i}", $"value_{i}"));
}

if (attributes.Count > 0)
{
logRecord.Attributes = attributes;
}

return Gen.Constant(logRecord);
});

return gen.ToArbitrary();
}

public static Arbitrary<Activity[]> ActivityBatchArbitrary()
{
var gen = Gen.Sized(size =>
{
var batchSize = Math.Min(size, 100);
return Gen.ArrayOf(ActivityArbitrary().Generator, batchSize);
});

return gen.ToArbitrary();
}

public static Arbitrary<int> BufferSizeArbitrary() => Gen.Choose(64, 10 * 1024 * 1024).ToArbitrary();

public static Arbitrary<LogRecordSeverity> LogRecordSeverityArbitrary() => LogRecordSeverities.ToArbitrary();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>$(TargetFrameworksForTests)</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FsCheck.Xunit" />
<PackageReference Include="Grpc" />
<PackageReference Include="Grpc.AspNetCore.Server" Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'" />
<PackageReference Include="Grpc.Net.Client" />
<PackageReference Include="Google.Protobuf" />
<PackageReference Include="Grpc.Tools" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Exporter.InMemory\OpenTelemetry.Exporter.InMemory.csproj" />
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Exporter.OpenTelemetryProtocol\OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj" />
</ItemGroup>

<ItemGroup>
<Protobuf Include="$(RepoRoot)\src\Shared\Proto\**\*.proto" Link="Proto\%(RecursiveDir)%(Filename)%(Extension)" Access="internal">
<ProtoRoot>$(RepoRoot)\src\Shared\Proto</ProtoRoot>
</Protobuf>
</ItemGroup>

</Project>
Loading