Skip to content

Commit

Permalink
feature/appcheck/unit-test
Browse files Browse the repository at this point in the history
  • Loading branch information
pavlo committed Jan 25, 2024
1 parent bc8360f commit e2fabac
Show file tree
Hide file tree
Showing 24 changed files with 1,159 additions and 105 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<LangVersion>latest</LangVersion>
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Expand Down Expand Up @@ -30,4 +30,4 @@
</None>
</ItemGroup>

</Project>
</Project>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<CodeAnalysisRuleSet>../../stylecop_test.ruleset</CodeAnalysisRuleSet>
Expand Down
211 changes: 211 additions & 0 deletions FirebaseAdmin/FirebaseAdmin.Tests/AppCheck/AppCheckApiClientTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FirebaseAdmin.Check;
using Google.Apis.Auth.OAuth2;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Moq;
using Xunit;

namespace FirebaseAdmin.Tests.AppCheck
{
public class AppCheckApiClientTest
{
private readonly string appId = "1:1234:android:1234";
private readonly string testTokenToExchange = "signed-custom-token";
private readonly string noProjectId = "Failed to determine project ID.Initialize the SDK with service "
+ "account credentials or set project ID as an app option. Alternatively, set the "
+ "GOOGLE_CLOUD_PROJECT environment variable.";

[Fact]
public void CreateInvalidApp()
{
Assert.Throws<ArgumentException>(() => new AppCheckApiClient(null));
}

[Fact]
public async Task ExchangeTokenNoProjectId()
{
var appCheckApiClient = new Mock<IAppCheckApiClient>();

appCheckApiClient.Setup(service => service.ExchangeTokenAsync(It.IsAny<string>(), It.IsAny<string>()))
.Throws(new ArgumentException(this.noProjectId));
var result = await Assert.ThrowsAsync<ArgumentException>(() => appCheckApiClient.Object.ExchangeTokenAsync(this.testTokenToExchange, this.appId));
Assert.Equal(this.noProjectId, result.Message);
}

[Fact]
public async Task ExchangeTokenInvalidAppId()
{
var appCheckApiClient = new Mock<IAppCheckApiClient>();

appCheckApiClient.Setup(service => service.ExchangeTokenAsync(It.IsAny<string>(), It.IsAny<string>()))
.Throws(new ArgumentException(this.noProjectId));

await Assert.ThrowsAsync<ArgumentException>(() => appCheckApiClient.Object.ExchangeTokenAsync(this.testTokenToExchange, string.Empty));
await Assert.ThrowsAsync<ArgumentException>(() => appCheckApiClient.Object.ExchangeTokenAsync(this.testTokenToExchange, null));
}

[Fact]
public async Task ExchangeTokenInvalidCustomTokenAsync()
{
var appCheckApiClient = new Mock<IAppCheckApiClient>();

appCheckApiClient.Setup(service => service.ExchangeTokenAsync(It.IsAny<string>(), It.IsAny<string>()))
.Throws(new ArgumentException(this.noProjectId));

await Assert.ThrowsAsync<ArgumentException>(() => appCheckApiClient.Object.ExchangeTokenAsync(string.Empty, this.appId));
await Assert.ThrowsAsync<ArgumentException>(() => appCheckApiClient.Object.ExchangeTokenAsync(null, this.appId));
}

[Fact]
public async Task ExchangeTokenFullErrorResponseAsync()
{
var appCheckApiClient = new Mock<IAppCheckApiClient>();

appCheckApiClient.Setup(service => service.ExchangeTokenAsync(It.IsAny<string>(), It.IsAny<string>()))
.Throws(new ArgumentException("not-found", "Requested entity not found"));

await Assert.ThrowsAsync<ArgumentException>(() => appCheckApiClient.Object.ExchangeTokenAsync(this.testTokenToExchange, this.appId));
}

[Fact]
public async Task ExchangeTokenErrorCodeAsync()
{
var appCheckApiClient = new Mock<IAppCheckApiClient>();

appCheckApiClient.Setup(service => service.ExchangeTokenAsync(It.IsAny<string>(), It.IsAny<string>()))
.Throws(new ArgumentException("unknown-error", "Unknown server error: {}"));

await Assert.ThrowsAsync<ArgumentException>(() => appCheckApiClient.Object.ExchangeTokenAsync(this.testTokenToExchange, this.appId));
}

[Fact]
public async Task ExchangeTokenFullNonJsonAsync()
{
var appCheckApiClient = new Mock<IAppCheckApiClient>();

appCheckApiClient.Setup(service => service.ExchangeTokenAsync(It.IsAny<string>(), It.IsAny<string>()))
.Throws(new ArgumentException("unknown-error", "Unexpected response with status: 404 and body: not json"));

await Assert.ThrowsAsync<ArgumentException>(() => appCheckApiClient.Object.ExchangeTokenAsync(this.testTokenToExchange, this.appId));
}

[Fact]
public async Task ExchangeTokenAppErrorAsync()
{
var appCheckApiClient = new Mock<IAppCheckApiClient>();

appCheckApiClient.Setup(service => service.ExchangeTokenAsync(It.IsAny<string>(), It.IsAny<string>()))
.Throws(new ArgumentException("network-error", "socket hang up"));

await Assert.ThrowsAsync<ArgumentException>(() => appCheckApiClient.Object.ExchangeTokenAsync(string.Empty, this.appId));
}

[Fact]
public async Task ExchangeTokenOnSuccessAsync()
{
var appCheckApiClient = new Mock<IAppCheckApiClient>();

appCheckApiClient.Setup(service => service.ExchangeTokenAsync(It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(new AppCheckToken("token", 3000));

var result = await appCheckApiClient.Object.ExchangeTokenAsync(this.testTokenToExchange, this.appId).ConfigureAwait(false);
Assert.NotNull(result);
Assert.Equal("token", result.Token);
Assert.Equal(3000, result.TtlMillis);
}

[Fact]
public async Task VerifyReplayNoProjectIdAsync()
{
var appCheckApiClient = new Mock<IAppCheckApiClient>();

appCheckApiClient.Setup(service => service.VerifyReplayProtection(It.IsAny<string>()))
.Throws(new ArgumentException(this.noProjectId));

await Assert.ThrowsAsync<ArgumentException>(() => appCheckApiClient.Object.VerifyReplayProtection(this.testTokenToExchange));
}

[Fact]
public async Task VerifyReplayInvaildTokenAsync()
{
var appCheckApiClient = new Mock<IAppCheckApiClient>();

appCheckApiClient.Setup(service => service.VerifyReplayProtection(It.IsAny<string>()))
.Throws(new ArgumentException(this.noProjectId));

await Assert.ThrowsAsync<ArgumentException>(() => appCheckApiClient.Object.VerifyReplayProtection(string.Empty));
}

[Fact]
public async Task VerifyReplayFullErrorAsync()
{
var appCheckApiClient = new Mock<IAppCheckApiClient>();

appCheckApiClient.Setup(service => service.VerifyReplayProtection(It.IsAny<string>()))
.Throws(new ArgumentException("not-found", "Requested entity not found"));

await Assert.ThrowsAsync<ArgumentException>(() => appCheckApiClient.Object.VerifyReplayProtection(this.testTokenToExchange));
}

[Fact]
public async Task VerifyReplayErrorCodeAsync()
{
var appCheckApiClient = new Mock<IAppCheckApiClient>();

appCheckApiClient.Setup(service => service.VerifyReplayProtection(It.IsAny<string>()))
.Throws(new ArgumentException("unknown-error", "Unknown server error: {}"));

await Assert.ThrowsAsync<ArgumentException>(() => appCheckApiClient.Object.VerifyReplayProtection(this.testTokenToExchange));
}

[Fact]
public async Task VerifyReplayNonJsonAsync()
{
var appCheckApiClient = new Mock<IAppCheckApiClient>();

appCheckApiClient.Setup(service => service.VerifyReplayProtection(It.IsAny<string>()))
.Throws(new ArgumentException("unknown-error", "Unexpected response with status: 404 and body: not json"));

await Assert.ThrowsAsync<ArgumentException>(() => appCheckApiClient.Object.VerifyReplayProtection(this.testTokenToExchange));
}

[Fact]
public async Task VerifyReplayFirebaseAppErrorAsync()
{
var appCheckApiClient = new Mock<IAppCheckApiClient>();

appCheckApiClient.Setup(service => service.VerifyReplayProtection(It.IsAny<string>()))
.Throws(new ArgumentException("network-error", "socket hang up"));

await Assert.ThrowsAsync<ArgumentException>(() => appCheckApiClient.Object.VerifyReplayProtection(this.testTokenToExchange));
}

[Fact]
public async Task VerifyReplayAlreadyTrueAsync()
{
var appCheckApiClient = new Mock<IAppCheckApiClient>();

appCheckApiClient.Setup(service => service.VerifyReplayProtection(It.IsAny<string>()))
.ReturnsAsync(true);

bool res = await appCheckApiClient.Object.VerifyReplayProtection(this.testTokenToExchange).ConfigureAwait(false);
Assert.True(res);
}

[Fact]
public async Task VerifyReplayAlreadyFlaseAsync()
{
var appCheckApiClient = new Mock<IAppCheckApiClient>();

appCheckApiClient.Setup(service => service.VerifyReplayProtection(It.IsAny<string>()))
.ReturnsAsync(true);

bool res = await appCheckApiClient.Object.VerifyReplayProtection(this.testTokenToExchange).ConfigureAwait(false);
Assert.True(res);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using FirebaseAdmin.Auth.Jwt;
using FirebaseAdmin.Check;
using Google.Apis.Auth.OAuth2;
using Moq;
using Newtonsoft.Json.Linq;
using Xunit;

namespace FirebaseAdmin.Tests.AppCheck
{
public class AppCheckTokenGeneratorTest
{
public static readonly IEnumerable<object[]> InvalidStrings = new List<object[]>
{
new object[] { null },
new object[] { string.Empty },
};

private const int ThirtyMinInMs = 1800000;
private const int SevenDaysInMs = 604800000;
private static readonly GoogleCredential MockCredential =
GoogleCredential.FromAccessToken("test-token");

private readonly string appId = "test-app-id";

[Fact]
public void ProjectIdFromOptions()
{
var app = FirebaseApp.Create(new AppOptions()
{
Credential = MockCredential,
ProjectId = "explicit-project-id1",
});
var verifier = AppCheckTokenVerify.Create(app);
Assert.Equal("explicit-project-id1", verifier.ProjectId);
}

[Fact]
public void ProjectIdFromServiceAccount()
{
var app = FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.FromFile("./resources/service_account.json"),
});
var verifier = AppCheckTokenVerify.Create(app);
Assert.Equal("test-project", verifier.ProjectId);
}

[Fact]
public async Task InvalidAppId()
{
var options = new AppOptions()
{
Credential = GoogleCredential.FromAccessToken("token"),
};
var app = FirebaseApp.Create(options, "123");

AppCheckTokenGenerator tokenGenerator = AppCheckTokenGenerator.Create(app);
await Assert.ThrowsAsync<ArgumentException>(() => tokenGenerator.CreateCustomTokenAsync(string.Empty));
await Assert.ThrowsAsync<ArgumentException>(() => tokenGenerator.CreateCustomTokenAsync(null));
}

[Fact]
public async Task InvalidOptions()
{
var options = new AppOptions()
{
Credential = GoogleCredential.FromAccessToken("token"),
};
var app = FirebaseApp.Create(options, "1234");
var tokenGernerator = AppCheckTokenGenerator.Create(app);
int[] ttls = new int[] { -100, -1, 0, 10, 1799999, 604800001, 1209600000 };
foreach (var ttl in ttls)
{
var option = new AppCheckTokenOptions(ttl);

var result = await Assert.ThrowsAsync<ArgumentException>(() =>
tokenGernerator.CreateCustomTokenAsync(this.appId, option));
}
}

[Fact]
public void ValidOptions()
{
var options = new AppOptions()
{
Credential = GoogleCredential.FromAccessToken("token"),
};
var app = FirebaseApp.Create(options, "12356");
var tokenGernerator = AppCheckTokenGenerator.Create(app);
int[] ttls = new int[] { ThirtyMinInMs, ThirtyMinInMs + 1, SevenDaysInMs / 2, SevenDaysInMs - 1, SevenDaysInMs };
foreach (var ttl in ttls)
{
var option = new AppCheckTokenOptions(ttl);

var result = tokenGernerator.CreateCustomTokenAsync(this.appId, option);
Assert.NotNull(result);
}
}

[Fact]
public void Dispose()
{
FirebaseApp.DeleteAll();
}
}
}
Loading

0 comments on commit e2fabac

Please sign in to comment.