Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
46 changes: 34 additions & 12 deletions src/Bugsnag.ConfigurationSection/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ public class Configuration : System.Configuration.ConfigurationSection, IConfigu
{
private static Configuration _configuration = ConfigurationManager.GetSection("bugsnag") as Configuration ?? new Configuration();

private const string HubKeyPrefix = "00000";
private const string HubNotifyUrl = "https://notify.insighthub.smartbear.com";
private const string HubSessionsUrl = "https://sessions.insighthub.smartbear.com";

private static bool IsHubKey(string key) =>
!string.IsNullOrEmpty(key) &&
key.StartsWith(HubKeyPrefix, StringComparison.OrdinalIgnoreCase);

public static Configuration Settings
{
get { return _configuration; }
Expand Down Expand Up @@ -72,15 +80,22 @@ public string AppVersion

private const string endpoint = "endpoint";

[ConfigurationProperty(endpoint, IsRequired = false, DefaultValue = Bugsnag.Configuration.DefaultEndpoint)]
private string InternalEndpoint
{
get { return this[endpoint] as string; }
}
[ConfigurationProperty(endpoint,
IsRequired = false,
DefaultValue = Bugsnag.Configuration.DefaultEndpoint)]
private string InternalEndpoint => this[endpoint] as string;

public Uri Endpoint
{
get { return new Uri(InternalEndpoint); }
get
{
if (IsHubKey(ApiKey) &&
InternalEndpoint == Bugsnag.Configuration.DefaultEndpoint)
{
return new Uri(HubNotifyUrl);
}
return new Uri(InternalEndpoint);
}
}

private const string autoNotify = "autoNotify";
Expand Down Expand Up @@ -382,15 +397,22 @@ public bool AutoCaptureSessions

private const string sessionsEndpoint = "sessionsEndpoint";

[ConfigurationProperty(sessionsEndpoint, IsRequired = false, DefaultValue = Bugsnag.Configuration.DefaultSessionEndpoint)]
private string InternalSessionEndpoint
{
get { return this[sessionsEndpoint] as string; }
}
[ConfigurationProperty(sessionsEndpoint,
IsRequired = false,
DefaultValue = Bugsnag.Configuration.DefaultSessionEndpoint)]
private string InternalSessionEndpoint => this[sessionsEndpoint] as string;

public Uri SessionEndpoint
{
get { return new Uri(InternalSessionEndpoint); }
get
{
if (IsHubKey(ApiKey) &&
InternalSessionEndpoint == Bugsnag.Configuration.DefaultSessionEndpoint)
{
return new Uri(HubSessionsUrl);
}
return new Uri(InternalSessionEndpoint);
}
}

public TimeSpan SessionTrackingInterval
Expand Down
17 changes: 14 additions & 3 deletions src/Bugsnag/Configuration.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Text.RegularExpressions;

namespace Bugsnag
{
Expand All @@ -11,8 +12,11 @@ namespace Bugsnag
public class Configuration : IConfiguration
{
public const string DefaultEndpoint = "https://notify.bugsnag.com";

public const string DefaultSessionEndpoint = "https://sessions.bugsnag.com";
public const string HubEndpoint = "https://notify.insighthub.smartbear.com";
public const string HubSessionEndpoint = "https://sessions.insighthub.smartbear.com";
private const string HubKeyPrefix = "00000";


public Configuration() : this(string.Empty)
{
Expand All @@ -22,9 +26,12 @@ public Configuration() : this(string.Empty)
public Configuration(string apiKey)
{
ApiKey = apiKey;
Endpoint = new Uri(DefaultEndpoint);

bool isHubKey = IsHubKey(apiKey);
Endpoint = new Uri(isHubKey ? HubEndpoint : DefaultEndpoint);
SessionEndpoint = new Uri(isHubKey ? HubSessionEndpoint : DefaultSessionEndpoint);

AutoNotify = true;
SessionEndpoint = new Uri(DefaultSessionEndpoint);
SessionTrackingInterval = TimeSpan.FromSeconds(60);
MetadataFilters = new[] { "password", "Authorization" };
MaximumBreadcrumbs = 25;
Expand Down Expand Up @@ -64,5 +71,9 @@ public Configuration(string apiKey)
public IWebProxy Proxy { get; set; }

public int MaximumBreadcrumbs { get; set; }

private static bool IsHubKey(string key) =>
!string.IsNullOrEmpty(key) &&
key.StartsWith(HubKeyPrefix, StringComparison.OrdinalIgnoreCase);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<ProjectReference Include="..\..\src\Bugsnag.ConfigurationSection\Bugsnag.ConfigurationSection.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="Complete.config">
<None Include="*.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
Expand Down
10 changes: 10 additions & 0 deletions tests/Bugsnag.ConfigurationSection.Tests/ClassicDefault.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="bugsnag"
type="Bugsnag.ConfigurationSection.Configuration, Bugsnag.ConfigurationSection" />
</configSections>

<!-- Classic Bugsnag key, default hosts expected -->
<bugsnag apiKey="abcd1234abcd1234abcd1234abcd1234" />
</configuration>
69 changes: 69 additions & 0 deletions tests/Bugsnag.ConfigurationSection.Tests/EndpointTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System;
using System.Configuration;
using Xunit;

namespace Bugsnag.ConfigurationSection.Tests
{
/// <summary>
/// Verifies that a “Hub”-flavoured API-key (prefix 00000…)
/// automatically switches the notify / sessions hosts to InsightHub,
/// *unless* the user deliberately overrides them in the XML.
/// </summary>
public class HubEndpointTests
{
private static IConfiguration Load(string cfgName)
{
// all .config test files sit next to the binaries
var map = new ExeConfigurationFileMap { ExeConfigFilename = $".\\{cfgName}.config" };
return ConfigurationManager
.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None)
.GetSection("bugsnag") as Configuration;
}

/*─────────────────────────────────────────────────────────
* 1. Hub key, *default* endpoints → InsightHub hosts
*────────────────────────────────────────────────────────*/
[Fact]
public void HubKey_UsesInsightHubHosts_WhenNotOverridden()
{
var cfg = Load("HubDefault"); // see HubDefault.config below

Assert.NotNull(cfg);
Assert.Equal("00000123456789abcdef0123456789", cfg.ApiKey);

Assert.Equal(new Uri("https://notify.insighthub.smartbear.com"), cfg.Endpoint);
Assert.Equal(new Uri("https://sessions.insighthub.smartbear.com"), cfg.SessionEndpoint);
}

/*─────────────────────────────────────────────────────────
* 2. Hub key but custom <endpoint> / <sessionsEndpoint> →
* **user preference wins**
*────────────────────────────────────────────────────────*/
[Fact]
public void HubKey_HonoursCustomEndpoints_WhenPresent()
{
var cfg = Load("HubCustomEndpoint"); // see HubCustomEndpoint.config below

Assert.NotNull(cfg);
Assert.Equal("00000feedfacecafebeefdeadbeef", cfg.ApiKey);

Assert.Equal(new Uri("https://corp.example.com/notify"), cfg.Endpoint);
Assert.Equal(new Uri("https://corp.example.com/sessions"), cfg.SessionEndpoint);
}

/*─────────────────────────────────────────────────────────
* 3. Non-hub key ⇒ still Bugsnag hosts
*────────────────────────────────────────────────────────*/
[Fact]
public void ClassicKey_KeepsBugsnagHosts()
{
var cfg = Load("ClassicDefault"); // see ClassicDefault.config below

Assert.NotNull(cfg);
Assert.Equal("abcd1234abcd1234abcd1234abcd1234", cfg.ApiKey);

Assert.Equal(new Uri(Bugsnag.Configuration.DefaultEndpoint), cfg.Endpoint);
Assert.Equal(new Uri(Bugsnag.Configuration.DefaultSessionEndpoint), cfg.SessionEndpoint);
}
}
}
12 changes: 12 additions & 0 deletions tests/Bugsnag.ConfigurationSection.Tests/HubCustomEndpoint.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="bugsnag"
type="Bugsnag.ConfigurationSection.Configuration, Bugsnag.ConfigurationSection" />
</configSections>

<bugsnag
apiKey="00000feedfacecafebeefdeadbeef"
endpoint="https://corp.example.com/notify"
sessionsEndpoint="https://corp.example.com/sessions" />
</configuration>
10 changes: 10 additions & 0 deletions tests/Bugsnag.ConfigurationSection.Tests/HubDefault.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="bugsnag"
type="Bugsnag.ConfigurationSection.Configuration, Bugsnag.ConfigurationSection" />
</configSections>

<!-- Hub-flavoured key, *no* explicit <endpoint> elements -->
<bugsnag apiKey="00000123456789abcdef0123456789" />
</configuration>
55 changes: 55 additions & 0 deletions tests/Bugsnag.Tests/EndpointTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using Xunit;

using CoreConfiguration = global::Bugsnag.Configuration;

namespace Bugsnag.Tests
{
public class EndpointTests
{
// 5 leading zeroes → Insight Hub
private const string HubKey = "00000aaaaaaaaaaaaaaaaaaaaaaaaaaa";
// Any non-hub key → classic Bugsnag
private const string ClassicKey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

[Fact]
public void ClassicKey_Uses_Bugsnag_Hosts()
{
var cfg = new CoreConfiguration(ClassicKey);

Assert.Equal(new Uri(CoreConfiguration.DefaultEndpoint), cfg.Endpoint);
Assert.Equal(new Uri(CoreConfiguration.DefaultSessionEndpoint), cfg.SessionEndpoint);
}

[Fact]
public void HubKey_Uses_InsightHub_Hosts()
{
var cfg = new CoreConfiguration(HubKey);

Assert.Equal(new Uri(CoreConfiguration.HubEndpoint), cfg.Endpoint);
Assert.Equal(new Uri(CoreConfiguration.HubSessionEndpoint), cfg.SessionEndpoint);
}

[Fact]
public void HubKey_Honours_Custom_Endpoints_When_Provided()
{
var cfg = new CoreConfiguration(HubKey)
{
Endpoint = new Uri("https://notify.example.com"),
SessionEndpoint = new Uri("https://sessions.example.com")
};

Assert.Equal(new Uri("https://notify.example.com"), cfg.Endpoint);
Assert.Equal(new Uri("https://sessions.example.com"), cfg.SessionEndpoint);
}

[Fact]
public void BlankKey_Falls_Back_To_Default_Hosts()
{
var cfg = new CoreConfiguration(string.Empty);

Assert.Equal(new Uri(CoreConfiguration.DefaultEndpoint), cfg.Endpoint);
Assert.Equal(new Uri(CoreConfiguration.DefaultSessionEndpoint), cfg.SessionEndpoint);
}
}
}