Skip to content

Commit

Permalink
WIP - trying to get integration tests to work
Browse files Browse the repository at this point in the history
  • Loading branch information
tippmar-nr committed Dec 4, 2024
1 parent 96d40aa commit 5b7ef78
Show file tree
Hide file tree
Showing 13 changed files with 162 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public override string ToString()
string partition = string.IsNullOrEmpty(Partition) ? "[Missing]" : Partition;
string region = string.IsNullOrEmpty(Region) ? "[Missing]" : Region;
string idPresent = string.IsNullOrEmpty(AccountId) ? "[Missing]" : "[Present]";

return $"Partition: {partition}, Region: {region}, AccountId: {idPresent}";
}

Expand All @@ -155,6 +155,5 @@ private string ConstructArn(string partition, string service, string region, str
}
return "arn:" + partition + ":" + service + ":" + region + ":" + accountId + ":" + resource;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,20 @@ public static string GetAccountId(string awsAccessKeyId)
/// <summary>
/// Performs a Base-32 decode of the specified input string.
/// Allowed character range is a-z and 2-7. 'a' being 0 and '7' is 31.
///
/// public to allow for unit testing
/// </summary>
/// <param name="src">The string to be decoded. Must be at least 10 characters.</param>
/// <returns>A long containing first 6 bytes of the base 32 decoded data.</returns>
/// <exception cref="ArgumentException">If src has less than 10 characters.</exception>
/// <exception cref="ArgumentOutOfRangeException">If src contains invalid characters for Base-32</exception>
private static long Base32Decode(string src)
public static long Base32Decode(string src)
{
if (string.IsNullOrEmpty(src))
{
throw new ArgumentNullException(nameof(src), "The input string cannot be null or empty.");
}

if (src.Length < 10)
{
throw new ArgumentException("The input string must be at least 10 characters long.", nameof(src));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ public AfterWrappedMethodDelegate BeforeWrappedMethod(InstrumentedMethodCall ins

// convert the access key to an account id
AwsAccountId = AwsAccountIdDecoder.GetAccountId(accessKey);

// TODO: TESTING ONLY
agent.Logger.Info($"Successfully parsed AWS AccountId: {AwsAccountId}");

Check failure

Code scanning / CodeQL

Clear text storage of sensitive information High

This stores sensitive data returned by
call to method GetAccountId : String
as clear text.
}
catch (Exception e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,13 @@ private ArnBuilder CreateArnBuilder(IAgent agent, dynamic requestContext)
try
{
accountId = GetAccountId(agent);
var clientconfig = requestContext.ClientConfig;
var regionEndpoint = clientconfig.RegionEndpoint;
systemName = regionEndpoint.SystemName;
partition = regionEndpoint.PartitionName;
var clientConfig = requestContext.ClientConfig;
if (clientConfig.RegionEndpoint != null)
{
var regionEndpoint = clientConfig.RegionEndpoint;
systemName = regionEndpoint.SystemName;
partition = regionEndpoint.PartitionName;
}
}
catch (Exception e)
{
Expand All @@ -46,8 +49,10 @@ private ArnBuilder CreateArnBuilder(IAgent agent, dynamic requestContext)
_reportBadArnBuilder = false;
}
}

return new ArnBuilder(partition, systemName, accountId);
agent.Logger.Debug($"AwsSdkPipelineWrapper: Creating ArnBuilder with partition: {partition}, systemName: {systemName}, accountId: {accountId}");

Check failure

Code scanning / CodeQL

Clear text storage of sensitive information High

This stores sensitive data returned by
access to field accountIdField : String
as clear text.
This stores sensitive data returned by
access to field _awsAccountId : String
as clear text.
This stores sensitive data returned by
call to method EnvironmentOverrides : String
as clear text.
This stores sensitive data returned by
access to field _awsAccountId : String
as clear text.
This stores sensitive data returned by
call to method GetAccountId : String
as clear text.
This stores sensitive data returned by
call to method GetAccountId : String
as clear text.
This stores sensitive data returned by
access to local variable accountId : String
as clear text.
This stores sensitive data returned by
access to local variable accountId : String
as clear text.
This stores sensitive data returned by
access to local variable accountId : String
as clear text.
This stores sensitive data returned by
access to local variable accountId : String
as clear text.
This stores sensitive data returned by
access to local variable accountId : String
as clear text.
This stores sensitive data returned by
access to local variable accountId : String
as clear text.
var arnBuilder = new ArnBuilder(partition, systemName, accountId);
agent.Logger.Debug($"AwsSdkPipelineWrapper: ArnBuilder created: {arnBuilder}");
return arnBuilder;
}

private string GetAccountId(IAgent agent)
Expand All @@ -66,6 +71,8 @@ private string GetAccountId(IAgent agent)
}
}

// TODO: testing only
agent.Logger.Debug($"AwsSdkPipelineWrapper: Using accountId: {accountId}");

Check failure

Code scanning / CodeQL

Clear text storage of sensitive information High

This stores sensitive data returned by
access to field accountIdField : String
as clear text.
This stores sensitive data returned by
access to field _awsAccountId : String
as clear text.
This stores sensitive data returned by
call to method EnvironmentOverrides : String
as clear text.
This stores sensitive data returned by
access to field _awsAccountId : String
as clear text.
This stores sensitive data returned by
call to method GetAccountId : String
as clear text.
This stores sensitive data returned by
access to local variable accountId : String
as clear text.
This stores sensitive data returned by
access to local variable accountId : String
as clear text.
This stores sensitive data returned by
access to local variable accountId : String
as clear text.
This stores sensitive data returned by
access to local variable accountId : String
as clear text.
return accountId;
}

Expand Down Expand Up @@ -104,17 +111,19 @@ public AfterWrappedMethodDelegate BeforeWrappedMethod(InstrumentedMethodCall ins
{
return SQSRequestHandler.HandleSQSRequest(instrumentedMethodCall, agent, transaction, request, isAsync, executionContext);
}
else if (requestType == "Amazon.Lambda.Model.InvokeRequest")

if (requestType == "Amazon.Lambda.Model.InvokeRequest")
{
return LambdaInvokeRequestHandler.HandleInvokeRequest(instrumentedMethodCall, agent, transaction, request, isAsync, builder);
}
else if (requestType.StartsWith("Amazon.DynamoDBv2"))
}

if (requestType.StartsWith("Amazon.DynamoDBv2"))
{
return DynamoDbRequestHandler.HandleDynamoDbRequest(instrumentedMethodCall, agent, transaction, request, isAsync, executionContext, builder);
return DynamoDbRequestHandler.HandleDynamoDbRequest(instrumentedMethodCall, agent, transaction, request, isAsync, builder);
}

if (!_unsupportedRequestTypes.Contains(requestType)) // log once per unsupported request type
{
{
agent.Logger.Debug($"AwsSdkPipelineWrapper: Unsupported request type: {requestType}. Returning NoOp delegate.");
_unsupportedRequestTypes.Add(requestType);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal static class DynamoDbRequestHandler

private static readonly ConcurrentDictionary<string, string> _operationNameCache = new();

public static AfterWrappedMethodDelegate HandleDynamoDbRequest(InstrumentedMethodCall instrumentedMethodCall, IAgent agent, ITransaction transaction, dynamic request, bool isAsync, dynamic executionContext, ArnBuilder builder)
public static AfterWrappedMethodDelegate HandleDynamoDbRequest(InstrumentedMethodCall instrumentedMethodCall, IAgent agent, ITransaction transaction, dynamic request, bool isAsync, ArnBuilder builder)
{
var requestType = ((object)request).GetType().Name;

Expand All @@ -29,8 +29,12 @@ public static AfterWrappedMethodDelegate HandleDynamoDbRequest(InstrumentedMetho

// TODO: The entity relationship docs suggest cloud.resource_id should be a span attribute, so maybe we added it to the DataStore segment below instead??
var arn = builder.Build("dynamodb", $"table/{model}");
if (string.IsNullOrEmpty(arn))
if (!string.IsNullOrEmpty(arn))
transaction.AddCloudSdkAttribute("cloud.resource_id", arn);
else
{
agent.Logger.Debug($"Unable to build ARN for DynamoDB request. ArnBuilder reports: {builder}");
}

var segment = transaction.StartDatastoreSegment(instrumentedMethodCall.MethodCall, new ParsedSqlStatement(DatastoreVendor.DynamoDB, model, operation), isLeaf: true);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
using System;
using System.Collections.Generic;
using Amazon.Runtime;
using System.Threading;
using Amazon;

namespace AwsSdkTestApp.AwsSdkExercisers
{
Expand All @@ -25,12 +25,16 @@ public AwsSdkDynamoDBExerciser()
private AmazonDynamoDBClient GetDynamoDBClient()
{

AmazonDynamoDBConfig clientConfig = new AmazonDynamoDBConfig();
// Set the endpoint URL
clientConfig.ServiceURL = "http://dynamodb:8000"; // port must match what is set in docker compose
clientConfig.AuthenticationRegion = "us-west-2";
var creds = new BasicAWSCredentials("xxx", "xxx");
AmazonDynamoDBClient client = new AmazonDynamoDBClient(creds, clientConfig);
AmazonDynamoDBConfig clientConfig = new AmazonDynamoDBConfig
{
// Set the endpoint URL
ServiceURL = "http://dynamodb:8000", // port must match what is set in docker compose
AuthenticationRegion = "us-west-2",
RegionEndpoint = RegionEndpoint.USWest2
};

// use plausible (but fake) access key and fake secret key so account id parsing can be tested
AmazonDynamoDBClient client = new AmazonDynamoDBClient("FOOIHSFODNNAEXAMPLE", "MOREGIBBERISH", clientConfig);

return client;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class AwsSdkContainerSQSTestFixture : AwsSdkContainerTestFixtureBase
{
private const string Dockerfile = "AwsSdkTestApp/Dockerfile";
private const ContainerApplication.Architecture Architecture = ContainerApplication.Architecture.X64;
private const string DistroTag = "jammy";
private const string DistroTag = "noble";

private readonly string BaseUrl;

Expand Down Expand Up @@ -78,7 +78,7 @@ public class AwsSdkContainerDynamoDBTestFixture : AwsSdkContainerTestFixtureBase
{
private const string Dockerfile = "AwsSdkTestApp/Dockerfile";
private const ContainerApplication.Architecture Architecture = ContainerApplication.Architecture.X64;
private const string DistroTag = "jammy";
private const string DistroTag = "noble";

private readonly string BaseUrl;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ protected AwsSdkDynamoDBTestBase(AwsSdkContainerDynamoDBTestFixture fixture, ITe
_fixture = fixture;
_fixture.TestLogger = output;

_fixture.SetAdditionalEnvironmentVariable("AWSSDK_INITCOLLECTIONS", "true");

_fixture.Actions(setupConfiguration: () =>
{
var configModifier = new NewRelicConfigModifier(_fixture.DestinationNewRelicConfigFilePath);
Expand Down Expand Up @@ -54,9 +56,9 @@ protected AwsSdkDynamoDBTestBase(AwsSdkContainerDynamoDBTestFixture fixture, ITe
_fixture.AgentLog.WaitForLogLine(AgentLogBase.MetricDataLogLineRegex, TimeSpan.FromMinutes(2));
_fixture.AgentLog.WaitForLogLine(AgentLogBase.TransactionTransformCompletedLogLineRegex, TimeSpan.FromMinutes(2));

// shut down the container and wait for the agent log to see it
_fixture.ShutdownRemoteApplication();
_fixture.AgentLog.WaitForLogLine(AgentLogBase.ShutdownLogLineRegex, TimeSpan.FromSeconds(10));
//// shut down the container and wait for the agent log to see it
//_fixture.ShutdownRemoteApplication();
//_fixture.AgentLog.WaitForLogLine(AgentLogBase.ShutdownLogLineRegex, TimeSpan.FromSeconds(10));
});

_fixture.Initialize();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ protected AwsSdkSQSTestBase(AwsSdkContainerSQSTestFixture fixture, ITestOutputHe
configModifier.ConfigureFasterMetricsHarvestCycle(15);
configModifier.ConfigureFasterSpanEventsHarvestCycle(15);
configModifier.ConfigureFasterTransactionTracesHarvestCycle(15);
configModifier.LogToConsole();
//configModifier.LogToConsole();

},
exerciseApplication: () =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ public virtual void Initialize()
catch (Exception ex)
{
TestLogger?.WriteLine("Exception occurred in Initialize: " + ex.ToString());
AgentLogExpected = false;
throw;
}
finally
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace NewRelic.Agent.IntegrationTests.Shared
{
public class AwsBedrockConfiguration
public class AwsConfiguration
{
public static string AwsAccessKeyId
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace MultiFunctionApplicationHelpers.NetStandardLibraries.LLM
internal class BedrockModels
{
private static readonly AmazonBedrockRuntimeClient _amazonBedrockRuntimeClient =
new AmazonBedrockRuntimeClient(AwsBedrockConfiguration.AwsAccessKeyId, AwsBedrockConfiguration.AwsSecretAccessKey, AwsBedrockConfiguration.AwsRegion.ToRegionId());
new AmazonBedrockRuntimeClient(AwsConfiguration.AwsAccessKeyId, AwsConfiguration.AwsSecretAccessKey, AwsConfiguration.AwsRegion.ToRegionId());

[MethodImpl(MethodImplOptions.NoInlining)]
public static async Task<string> InvokeAmazonEmbedAsync(string prompt, bool generateError) => await InvokeTitanAsync(prompt, true, generateError);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

using System;
using NewRelic.Agent.Extensions.AwsSdk;
using NUnit.Framework;
using Telerik.JustMock;

namespace Agent.Extensions.Tests.Helpers
{
[TestFixture]
internal class AwsAccountIdDecoderTests
{
[Test]
public void GetAccountId_ValidAwsAccessKeyId_ReturnsExpectedAccountId()
{
// Arrange
string awsAccessKeyId = "AKIAIOSFODNN7EXAMPLE"; // not a real AWS access key!
string expectedAccountId = "581039954779";

// Act
string actualAccountId = AwsAccountIdDecoder.GetAccountId(awsAccessKeyId);

// Assert
Assert.That(expectedAccountId, Is.EqualTo(actualAccountId));
}

[Test]
public void GetAccountId_NullOrEmptyAwsAccessKeyId_ThrowsArgumentNullException()
{
// Arrange
string awsAccessKeyId = null;

// Act & Assert
var ex = Assert.Throws<ArgumentNullException>(() => AwsAccountIdDecoder.GetAccountId(awsAccessKeyId));
Assert.That(ex.ParamName, Is.EqualTo("awsAccessKeyId"));
}

[Test]
public void GetAccountId_ShortAwsAccessKeyId_ThrowsArgumentOutOfRangeException()
{
// Arrange
string awsAccessKeyId = "AKIAIOSFODN";

// Act & Assert
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => AwsAccountIdDecoder.GetAccountId(awsAccessKeyId));
Assert.That(ex.ParamName, Is.EqualTo("awsAccessKeyId"));
}

[Test]
public void Base32Decode_ShortString_ThrowsArgumentException()
{
// Arrange
string shortString = "shortstr";

// Act & Assert
var ex = Assert.Throws<ArgumentException>(() => AwsAccountIdDecoder.Base32Decode(shortString));
Assert.That(ex.ParamName, Is.EqualTo("src"));
}

[Test]
public void Base32Decode_InvalidCharacters_ThrowsArgumentOutOfRangeException()
{
// Arrange
string invalidBase32String = "someBogusbase32string";

// Act & Assert
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => AwsAccountIdDecoder.Base32Decode(invalidBase32String));
Assert.That(ex.ParamName, Is.EqualTo("src"));
}

[Test]
public void Base32Decode_NullOrEmptyString_ThrowsArgumentNullException()
{
// Arrange
string nullString = null;
string emptyString = string.Empty;

// Act & Assert
var exNull = Assert.Throws<ArgumentNullException>(() => AwsAccountIdDecoder.Base32Decode(nullString));
Assert.That(exNull.ParamName, Is.EqualTo("src"));

var exEmpty = Assert.Throws<ArgumentNullException>(() => AwsAccountIdDecoder.Base32Decode(emptyString));
Assert.That(exEmpty.ParamName, Is.EqualTo("src"));
}

[Test]
public void Base32Decode_ValidBase32String_ReturnsDecodedLong()
{
// Arrange
string validBase32String = "iosfodnn7example"; // Example valid Base32 string (10 characters)
long expectedDecodedValue = 74373114211833L;

// Act
long decodedValue = AwsAccountIdDecoder.Base32Decode(validBase32String);

// Assert
Assert.That(decodedValue, Is.EqualTo(expectedDecodedValue)); // Adjust expected value based on actual decoding logic
}

}
}

0 comments on commit 5b7ef78

Please sign in to comment.