1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 07:36:14 -05:00

Freshsales integration (#1782)

* Add FreshsalesController

* Add better errors

* Fix formatting issues

* Add comments

* Add Billing.Test to solution files

* Fix unit test

* Format code

* Address PR feedback
This commit is contained in:
Justin Baur
2021-12-22 13:27:52 -05:00
committed by GitHub
parent a14f16b34f
commit bb34de74cb
8 changed files with 465 additions and 0 deletions

View File

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="AutoFixture.Xunit2" Version="4.14.0" />
<PackageReference Include="NSubstitute" Version="4.2.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Billing\Billing.csproj" />
<ProjectReference Include="..\Common\Common.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Bit.Billing.Controllers;
using Bit.Core.Models.Table;
using Bit.Core.Repositories;
using Bit.Core.Settings;
using Bit.Test.Common.AutoFixture.Attributes;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NSubstitute;
using Xunit;
namespace Bit.Billing.Test.Controllers
{
public class FreshsalesControllerTests
{
private const string ApiKey = "TEST_FRESHSALES_APIKEY";
private const string TestLead = "TEST_FRESHSALES_TESTLEAD";
private static (FreshsalesController, IUserRepository, IOrganizationRepository) CreateSut(
string freshsalesApiKey)
{
var userRepository = Substitute.For<IUserRepository>();
var organizationRepository = Substitute.For<IOrganizationRepository>();
var billingSettings = Options.Create(new BillingSettings
{
FreshsalesApiKey = freshsalesApiKey,
});
var globalSettings = new GlobalSettings();
globalSettings.BaseServiceUri.Admin = "https://test.com";
var sut = new FreshsalesController(
userRepository,
organizationRepository,
billingSettings,
Substitute.For<ILogger<FreshsalesController>>(),
globalSettings
);
return (sut, userRepository, organizationRepository);
}
[RequiredEnvironmentTheory(ApiKey, TestLead), EnvironmentData(ApiKey, TestLead)]
public async Task PostWebhook_Success(string freshsalesApiKey, long leadId)
{
// This test is only for development to use:
// `export TEST_FRESHSALES_APIKEY=[apikey]`
// `export TEST_FRESHSALES_TESTLEAD=[lead id]`
// `dotnet test --filter "FullyQualifiedName~FreshsalesControllerTests.PostWebhook_Success"`
var (sut, userRepository, organizationRepository) = CreateSut(freshsalesApiKey);
var user = new User
{
Id = Guid.NewGuid(),
Email = "test@email.com",
Premium = true,
};
userRepository.GetByEmailAsync(user.Email)
.Returns(user);
organizationRepository.GetManyByUserIdAsync(user.Id)
.Returns(new List<Organization>
{
new Organization
{
Id = Guid.NewGuid(),
Name = "Test Org",
}
});
var response = await sut.PostWebhook(freshsalesApiKey, new CustomWebhookRequestModel
{
LeadId = leadId,
}, new CancellationToken(false));
var statusCodeResult = Assert.IsAssignableFrom<StatusCodeResult>(response);
Assert.Equal(StatusCodes.Status204NoContent, statusCodeResult.StatusCode);
}
}
}

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Xunit.Sdk;
namespace Bit.Test.Common.AutoFixture.Attributes
{
/// <summary>
/// Used for collecting data from environment useful for when we want to test an integration with another service and
/// it might require an api key or other piece of sensitive data that we don't want slipping into the wrong hands.
/// </summary>
/// <remarks>
/// It probably should be refactored to support fixtures and other customization so it can more easily be used in conjunction
/// with more parameters. Currently it attempt to match environment variable names to values of the parameter type in that positions.
/// It will start from the first parameter and go for each supplied name.
/// </remarks>
public class EnvironmentDataAttribute : DataAttribute
{
private readonly string[] _environmentVariableNames;
public EnvironmentDataAttribute(params string[] environmentVariableNames)
{
_environmentVariableNames = environmentVariableNames;
}
public override IEnumerable<object[]> GetData(MethodInfo testMethod)
{
var methodParameters = testMethod.GetParameters();
if (methodParameters.Length < _environmentVariableNames.Length)
{
throw new ArgumentException($"The target test method only has {methodParameters.Length} arguments but you supplied {_environmentVariableNames.Length}");
}
var values = new object[_environmentVariableNames.Length];
for (var i = 0; i < _environmentVariableNames.Length; i++)
{
values[i] = Convert.ChangeType(Environment.GetEnvironmentVariable(_environmentVariableNames[i]), methodParameters[i].ParameterType);
}
return new[] { values };
}
}
}

View File

@ -0,0 +1,39 @@
using System;
using Xunit;
namespace Bit.Test.Common.AutoFixture.Attributes
{
/// <summary>
/// Used for requiring certain environment variables exist at the time. Mostly used for more edge unit tests that shouldn't
/// be run during CI builds or should only be ran in CI builds when pieces of information are available.
/// </summary>
public class RequiredEnvironmentTheoryAttribute : TheoryAttribute
{
private readonly string[] _environmentVariableNames;
public RequiredEnvironmentTheoryAttribute(params string[] environmentVariableNames)
{
_environmentVariableNames = environmentVariableNames;
if (!HasRequiredEnvironmentVariables())
{
Skip = $"Missing one or more required environment variables. ({string.Join(", ", _environmentVariableNames)})";
}
}
private bool HasRequiredEnvironmentVariables()
{
foreach (var env in _environmentVariableNames)
{
var value = Environment.GetEnvironmentVariable(env);
if (value == null)
{
return false;
}
}
return true;
}
}
}

View File

@ -11,6 +11,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Api.Test", "Api.Test\Api.Te
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "Common\Common.csproj", "{E94B2922-EE05-435C-9472-FDEFEAD0AA37}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Billing.Test", "Billing.Test\Billing.Test.csproj", "{8CD044FE-3FED-4F29-858C-B06BCE70EAA6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -72,5 +74,17 @@ Global
{E94B2922-EE05-435C-9472-FDEFEAD0AA37}.Release|x64.Build.0 = Release|Any CPU
{E94B2922-EE05-435C-9472-FDEFEAD0AA37}.Release|x86.ActiveCfg = Release|Any CPU
{E94B2922-EE05-435C-9472-FDEFEAD0AA37}.Release|x86.Build.0 = Release|Any CPU
{8CD044FE-3FED-4F29-858C-B06BCE70EAA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8CD044FE-3FED-4F29-858C-B06BCE70EAA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8CD044FE-3FED-4F29-858C-B06BCE70EAA6}.Debug|x64.ActiveCfg = Debug|Any CPU
{8CD044FE-3FED-4F29-858C-B06BCE70EAA6}.Debug|x64.Build.0 = Debug|Any CPU
{8CD044FE-3FED-4F29-858C-B06BCE70EAA6}.Debug|x86.ActiveCfg = Debug|Any CPU
{8CD044FE-3FED-4F29-858C-B06BCE70EAA6}.Debug|x86.Build.0 = Debug|Any CPU
{8CD044FE-3FED-4F29-858C-B06BCE70EAA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8CD044FE-3FED-4F29-858C-B06BCE70EAA6}.Release|Any CPU.Build.0 = Release|Any CPU
{8CD044FE-3FED-4F29-858C-B06BCE70EAA6}.Release|x64.ActiveCfg = Release|Any CPU
{8CD044FE-3FED-4F29-858C-B06BCE70EAA6}.Release|x64.Build.0 = Release|Any CPU
{8CD044FE-3FED-4F29-858C-B06BCE70EAA6}.Release|x86.ActiveCfg = Release|Any CPU
{8CD044FE-3FED-4F29-858C-B06BCE70EAA6}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal