diff --git a/src/Altinn.Profile/Controllers/UserProfileInternalController.cs b/src/Altinn.Profile/Controllers/UserProfileInternalController.cs
new file mode 100644
index 0000000..2cc92c7
--- /dev/null
+++ b/src/Altinn.Profile/Controllers/UserProfileInternalController.cs
@@ -0,0 +1,71 @@
+using System.Threading.Tasks;
+using Altinn.Platform.Profile.Models;
+using Altinn.Profile.Models;
+using Altinn.Profile.Services.Interfaces;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Altinn.Profile.Controllers
+{
+ ///
+ /// Controller for user profile API endpoints for internal consumption (e.g. Authorization) requiring neither authenticated user token nor access token authorization.
+ ///
+ [Route("profile/api/v1/internal/user")]
+ [ApiExplorerSettings(IgnoreApi = true)]
+ [Consumes("application/json")]
+ [Produces("application/json")]
+ public class UserProfileInternalController : Controller
+ {
+ private readonly IUserProfiles _userProfilesWrapper;
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ /// The users wrapper
+ public UserProfileInternalController(IUserProfiles userProfilesWrapper)
+ {
+ _userProfilesWrapper = userProfilesWrapper;
+ }
+
+ ///
+ /// Gets the user profile for a given user identified by one of the available types of user identifiers:
+ /// UserId (from Altinn 2 Authn UserProfile)
+ /// Username (from Altinn 2 Authn UserProfile)
+ /// SSN/Dnr (from Freg)
+ /// Uuid (from Altinn 2 Party/UserProfile implementation will be added later)
+ ///
+ /// Input model for providing one of the supported lookup parameters
+ /// User profile of the given user
+ [HttpPost]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task> Get([FromBody] UserProfileLookup userProfileLookup)
+ {
+ UserProfile result;
+ if (userProfileLookup != null && userProfileLookup.UserId != 0)
+ {
+ result = await _userProfilesWrapper.GetUser(userProfileLookup.UserId);
+ }
+ else if (!string.IsNullOrWhiteSpace(userProfileLookup?.Username))
+ {
+ result = await _userProfilesWrapper.GetUserByUsername(userProfileLookup.Username);
+ }
+ else if (!string.IsNullOrWhiteSpace(userProfileLookup?.Ssn))
+ {
+ result = await _userProfilesWrapper.GetUser(userProfileLookup.Ssn);
+ }
+ else
+ {
+ return BadRequest();
+ }
+
+ if (result == null)
+ {
+ return NotFound();
+ }
+
+ return Ok(result);
+ }
+ }
+}
diff --git a/src/Altinn.Profile/Models/UserProfileLookup.cs b/src/Altinn.Profile/Models/UserProfileLookup.cs
new file mode 100644
index 0000000..75fab04
--- /dev/null
+++ b/src/Altinn.Profile/Models/UserProfileLookup.cs
@@ -0,0 +1,27 @@
+namespace Altinn.Profile.Models
+{
+ ///
+ /// Input model for internal UserProfile lookup requests, where one of the lookup identifiers available must be set for performing the lookup request:
+ /// UserId (from Altinn 2 Authn UserProfile)
+ /// Username (from Altinn 2 Authn UserProfile)
+ /// SSN/Dnr (from Freg)
+ /// Uuid (from Altinn 2 Party/UserProfile implementation will be added later)
+ ///
+ public class UserProfileLookup
+ {
+ ///
+ /// Gets or sets the users UserId if the lookup is to be performed based on this identifier
+ ///
+ public int UserId { get; set; }
+
+ ///
+ /// Gets or sets the users Username if the lookup is to be performed based on this identifier
+ ///
+ public string Username { get; set; }
+
+ ///
+ /// Gets or sets the users social security number or d-number from Folkeregisteret if the lookup is to be performed based on this identifier
+ ///
+ public string Ssn { get; set; }
+ }
+}
diff --git a/src/Altinn.Profile/Services/Decorators/UserProfileCachingDecorator.cs b/src/Altinn.Profile/Services/Decorators/UserProfileCachingDecorator.cs
index 9a7d809..d900245 100644
--- a/src/Altinn.Profile/Services/Decorators/UserProfileCachingDecorator.cs
+++ b/src/Altinn.Profile/Services/Decorators/UserProfileCachingDecorator.cs
@@ -78,5 +78,25 @@ public async Task GetUser(string ssn)
return user;
}
+
+ ///
+ public async Task GetUserByUsername(string username)
+ {
+ string uniqueCacheKey = "User_Username_" + username;
+
+ if (_memoryCache.TryGetValue(uniqueCacheKey, out UserProfile user))
+ {
+ return user;
+ }
+
+ user = await _decoratedService.GetUserByUsername(username);
+
+ if (user != null)
+ {
+ _memoryCache.Set(uniqueCacheKey, user, _cacheOptions);
+ }
+
+ return user;
+ }
}
}
diff --git a/src/Altinn.Profile/Services/Implementation/UserProfilesWrapper.cs b/src/Altinn.Profile/Services/Implementation/UserProfilesWrapper.cs
index e84af2d..9695b2b 100644
--- a/src/Altinn.Profile/Services/Implementation/UserProfilesWrapper.cs
+++ b/src/Altinn.Profile/Services/Implementation/UserProfilesWrapper.cs
@@ -8,8 +8,6 @@
using Altinn.Platform.Profile.Models;
using Altinn.Profile.Configuration;
using Altinn.Profile.Services.Interfaces;
-
-using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@@ -89,5 +87,26 @@ public async Task GetUser(string ssn)
return user;
}
+
+ ///
+ public async Task GetUserByUsername(string username)
+ {
+ UserProfile user;
+
+ Uri endpointUrl = new Uri($"{_generalSettings.BridgeApiEndpoint}users/?username={username}");
+
+ HttpResponseMessage response = await _client.GetAsync(endpointUrl);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ _logger.LogError("Getting user {username} failed with {statusCode}", username, response.StatusCode);
+ return null;
+ }
+
+ string content = await response.Content.ReadAsStringAsync();
+ user = JsonSerializer.Deserialize(content, _serializerOptions);
+
+ return user;
+ }
}
}
diff --git a/src/Altinn.Profile/Services/Interfaces/IUserProfiles.cs b/src/Altinn.Profile/Services/Interfaces/IUserProfiles.cs
index 5ce5502..420d811 100644
--- a/src/Altinn.Profile/Services/Interfaces/IUserProfiles.cs
+++ b/src/Altinn.Profile/Services/Interfaces/IUserProfiles.cs
@@ -22,5 +22,12 @@ public interface IUserProfiles
/// The user's ssn.
/// User profile connected to given ssn.
Task GetUser(string ssn);
+
+ ///
+ /// Method that fetches a user based on username.
+ ///
+ /// The user's username.
+ /// User profile connected to given username.
+ Task GetUserByUsername(string username);
}
}
diff --git a/test/Altinn.Profile.Tests/IntegrationTests/UserProfileInternalTests.cs b/test/Altinn.Profile.Tests/IntegrationTests/UserProfileInternalTests.cs
new file mode 100644
index 0000000..90b4b26
--- /dev/null
+++ b/test/Altinn.Profile.Tests/IntegrationTests/UserProfileInternalTests.cs
@@ -0,0 +1,391 @@
+using System.Net;
+using System.Net.Http;
+using System.Net.Http.Json;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+using Altinn.Platform.Profile.Models;
+using Altinn.Profile.Configuration;
+using Altinn.Profile.Controllers;
+using Altinn.Profile.Models;
+using Altinn.Profile.Tests.IntegrationTests.Utils;
+using Altinn.Profile.Tests.Mocks;
+using Altinn.Profile.Tests.Testdata;
+
+using Microsoft.AspNetCore.Mvc.Testing;
+
+using Xunit;
+
+namespace Altinn.Profile.Tests.IntegrationTests
+{
+ public class UserProfileInternalTests : IClassFixture>
+ {
+ private readonly WebApplicationFactorySetup _webApplicationFactorySetup;
+
+ private readonly JsonSerializerOptions serializerOptionsCamelCase = new()
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
+ };
+
+ public UserProfileInternalTests(WebApplicationFactory factory)
+ {
+ _webApplicationFactorySetup = new WebApplicationFactorySetup(factory);
+
+ GeneralSettings generalSettings = new() { BridgeApiEndpoint = "http://localhost/" };
+ _webApplicationFactorySetup.GeneralSettingsOptions.Setup(s => s.Value).Returns(generalSettings);
+ }
+
+ [Fact]
+ public async Task GetUserById_SblBridgeFindsProfile_ResponseOk_ReturnsUserProfile()
+ {
+ // Arrange
+ const int UserId = 2516356;
+
+ HttpRequestMessage sblRequest = null;
+ DelegatingHandlerStub messageHandler = new(async (request, token) =>
+ {
+ sblRequest = request;
+
+ UserProfile userProfile = await TestDataLoader.Load(UserId.ToString());
+ return new HttpResponseMessage() { Content = JsonContent.Create(userProfile) };
+ });
+ _webApplicationFactorySetup.SblBridgeHttpMessageHandler = messageHandler;
+
+ HttpRequestMessage httpRequestMessage = CreatePostRequest($"/profile/api/v1/internal/user/", new UserProfileLookup { UserId = UserId });
+
+ HttpClient client = _webApplicationFactorySetup.GetTestServerClient();
+
+ // Act
+ HttpResponseMessage response = await client.SendAsync(httpRequestMessage);
+
+ // Assert
+ Assert.NotNull(sblRequest);
+ Assert.Equal(HttpMethod.Get, sblRequest.Method);
+ Assert.EndsWith($"sblbridge/profile/api/users/{UserId}", sblRequest.RequestUri.ToString());
+
+ string responseContent = await response.Content.ReadAsStringAsync();
+
+ UserProfile actualUser = JsonSerializer.Deserialize(
+ responseContent, serializerOptionsCamelCase);
+
+ // These asserts check that deserializing with camel casing was successful.
+ Assert.Equal(UserId, actualUser.UserId);
+ Assert.Equal("sophie", actualUser.UserName);
+ Assert.Equal("Sophie Salt", actualUser.Party.Name);
+ Assert.Equal("Sophie", actualUser.Party.Person.FirstName);
+ Assert.Equal("nb", actualUser.ProfileSettingPreference.Language);
+ }
+
+ [Fact]
+ public async Task GetUserById_SblBridgeReturnsNotFound_ResponseNotFound()
+ {
+ // Arrange
+ const int UserId = 2222222;
+
+ HttpRequestMessage sblRequest = null;
+ DelegatingHandlerStub messageHandler = new(async (request, token) =>
+ {
+ sblRequest = request;
+
+ return await Task.FromResult(new HttpResponseMessage() { StatusCode = HttpStatusCode.NotFound });
+ });
+ _webApplicationFactorySetup.SblBridgeHttpMessageHandler = messageHandler;
+
+ HttpRequestMessage httpRequestMessage = CreatePostRequest($"/profile/api/v1/internal/user/", new UserProfileLookup { UserId = UserId });
+
+ HttpClient client = _webApplicationFactorySetup.GetTestServerClient();
+
+ // Act
+ HttpResponseMessage response = await client.SendAsync(httpRequestMessage);
+
+ // Assert
+ Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
+
+ Assert.NotNull(sblRequest);
+ Assert.Equal(HttpMethod.Get, sblRequest.Method);
+ Assert.EndsWith($"sblbridge/profile/api/users/{UserId}", sblRequest.RequestUri.ToString());
+ }
+
+ [Fact]
+ public async Task GetUserById_SblBridgeReturnsUnavailable_ResponseNotFound()
+ {
+ // Arrange
+ const int UserId = 2222222;
+
+ HttpRequestMessage sblRequest = null;
+ DelegatingHandlerStub messageHandler = new(async (request, token) =>
+ {
+ sblRequest = request;
+
+ return await Task.FromResult(new HttpResponseMessage() { StatusCode = HttpStatusCode.ServiceUnavailable });
+ });
+ _webApplicationFactorySetup.SblBridgeHttpMessageHandler = messageHandler;
+
+ HttpRequestMessage httpRequestMessage = CreatePostRequest($"/profile/api/v1/internal/user/", new UserProfileLookup { UserId = UserId });
+
+ HttpClient client = _webApplicationFactorySetup.GetTestServerClient();
+
+ // Act
+ HttpResponseMessage response = await client.SendAsync(httpRequestMessage);
+
+ // Assert
+ Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
+
+ Assert.NotNull(sblRequest);
+ Assert.Equal(HttpMethod.Get, sblRequest.Method);
+ Assert.EndsWith($"sblbridge/profile/api/users/{UserId}", sblRequest.RequestUri.ToString());
+ }
+
+ [Fact]
+ public async Task GetUserBySsn_SblBridgeFindsProfile_ReturnsUserProfile()
+ {
+ // Arrange
+ const string Ssn = "01017512345";
+ HttpRequestMessage sblRequest = null;
+ DelegatingHandlerStub messageHandler = new(async (request, token) =>
+ {
+ sblRequest = request;
+
+ UserProfile userProfile = await TestDataLoader.Load("2516356");
+ return new HttpResponseMessage() { Content = JsonContent.Create(userProfile) };
+ });
+ _webApplicationFactorySetup.SblBridgeHttpMessageHandler = messageHandler;
+
+ HttpRequestMessage httpRequestMessage = CreatePostRequest($"/profile/api/v1/internal/user/", new UserProfileLookup { Ssn = Ssn });
+
+ HttpClient client = _webApplicationFactorySetup.GetTestServerClient();
+
+ // Act
+ HttpResponseMessage response = await client.SendAsync(httpRequestMessage);
+
+ // Assert
+ Assert.NotNull(sblRequest);
+ Assert.Equal(HttpMethod.Post, sblRequest.Method);
+ Assert.EndsWith($"sblbridge/profile/api/users", sblRequest.RequestUri.ToString());
+
+ string requestContent = await sblRequest.Content.ReadAsStringAsync();
+
+ Assert.Equal($"\"{Ssn}\"", requestContent);
+
+ string responseContent = await response.Content.ReadAsStringAsync();
+
+ UserProfile actualUser = JsonSerializer.Deserialize(
+ responseContent, serializerOptionsCamelCase);
+
+ // These asserts check that deserializing with camel casing was successful.
+ Assert.Equal(2516356, actualUser.UserId);
+ Assert.Equal("sophie", actualUser.UserName);
+ Assert.Equal("Sophie Salt", actualUser.Party.Name);
+ Assert.Equal("Sophie", actualUser.Party.Person.FirstName);
+ Assert.Equal("nb", actualUser.ProfileSettingPreference.Language);
+ }
+
+ [Fact]
+ public async Task GetUserBySsn_SblBridgeReturnsNotFound_RespondsNotFound()
+ {
+ // Arrange
+ const string Ssn = "01017512345";
+ HttpRequestMessage sblRequest = null;
+ DelegatingHandlerStub messageHandler = new(async (request, token) =>
+ {
+ sblRequest = request;
+
+ return await Task.FromResult(new HttpResponseMessage() { StatusCode = HttpStatusCode.NotFound });
+ });
+ _webApplicationFactorySetup.SblBridgeHttpMessageHandler = messageHandler;
+
+ HttpRequestMessage httpRequestMessage = CreatePostRequest($"/profile/api/v1/internal/user/", new UserProfileLookup { Ssn = Ssn });
+
+ HttpClient client = _webApplicationFactorySetup.GetTestServerClient();
+
+ // Act
+ HttpResponseMessage response = await client.SendAsync(httpRequestMessage);
+
+ // Assert
+ Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
+
+ Assert.NotNull(sblRequest);
+ Assert.Equal(HttpMethod.Post, sblRequest.Method);
+ Assert.EndsWith($"sblbridge/profile/api/users", sblRequest.RequestUri.ToString());
+
+ string requestContent = await sblRequest.Content.ReadAsStringAsync();
+
+ Assert.Equal($"\"{Ssn}\"", requestContent);
+ }
+
+ [Fact]
+ public async Task GetUserBySsn_SblBridgeReturnsUnavailable_RespondsNotFound()
+ {
+ // Arrange
+ const string Ssn = "01017512345";
+ HttpRequestMessage sblRequest = null;
+ DelegatingHandlerStub messageHandler = new(async (request, token) =>
+ {
+ sblRequest = request;
+
+ return await Task.FromResult(new HttpResponseMessage() { StatusCode = HttpStatusCode.ServiceUnavailable });
+ });
+ _webApplicationFactorySetup.SblBridgeHttpMessageHandler = messageHandler;
+
+ HttpRequestMessage httpRequestMessage = CreatePostRequest($"/profile/api/v1/internal/user/", new UserProfileLookup { Ssn = Ssn });
+
+ HttpClient client = _webApplicationFactorySetup.GetTestServerClient();
+
+ // Act
+ HttpResponseMessage response = await client.SendAsync(httpRequestMessage);
+
+ // Assert
+ Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
+
+ Assert.NotNull(sblRequest);
+ Assert.Equal(HttpMethod.Post, sblRequest.Method);
+ Assert.EndsWith($"sblbridge/profile/api/users", sblRequest.RequestUri.ToString());
+
+ string requestContent = await sblRequest.Content.ReadAsStringAsync();
+
+ Assert.Equal($"\"{Ssn}\"", requestContent);
+ }
+
+ [Fact]
+ public async Task GetUserByUsername_SblBridgeFindsProfile_ResponseOk_ReturnsUserProfile()
+ {
+ // Arrange
+ const string Username = "OrstaECUser";
+
+ HttpRequestMessage sblRequest = null;
+ DelegatingHandlerStub messageHandler = new(async (request, token) =>
+ {
+ sblRequest = request;
+
+ UserProfile userProfile = await TestDataLoader.Load(Username);
+ return new HttpResponseMessage() { Content = JsonContent.Create(userProfile) };
+ });
+ _webApplicationFactorySetup.SblBridgeHttpMessageHandler = messageHandler;
+
+ HttpRequestMessage httpRequestMessage = CreatePostRequest($"/profile/api/v1/internal/user/", new UserProfileLookup { Username = Username });
+
+ HttpClient client = _webApplicationFactorySetup.GetTestServerClient();
+
+ // Act
+ HttpResponseMessage response = await client.SendAsync(httpRequestMessage);
+
+ // Assert
+ Assert.NotNull(sblRequest);
+ Assert.Equal(HttpMethod.Get, sblRequest.Method);
+ Assert.EndsWith($"sblbridge/profile/api/users/?username={Username}", sblRequest.RequestUri.ToString());
+
+ string responseContent = await response.Content.ReadAsStringAsync();
+
+ UserProfile actualUser = JsonSerializer.Deserialize(
+ responseContent, serializerOptionsCamelCase);
+
+ // These asserts check that deserializing with camel casing was successful.
+ Assert.Equal(Username, actualUser.UserName);
+ Assert.Equal(50005545, actualUser.Party.PartyId);
+ Assert.Equal("ORSTA OG HEGGEDAL ", actualUser.Party.Name);
+ Assert.Equal("ORSTA OG HEGGEDAL", actualUser.Party.Organization.Name);
+ Assert.Equal("nb", actualUser.ProfileSettingPreference.Language);
+ }
+
+ [Fact]
+ public async Task GetUserByUsername_SblBridgeReturnsNotFound_ResponseNotFound()
+ {
+ // Arrange
+ const string Username = "NonExistingUsername";
+
+ HttpRequestMessage sblRequest = null;
+ DelegatingHandlerStub messageHandler = new(async (request, token) =>
+ {
+ sblRequest = request;
+
+ return await Task.FromResult(new HttpResponseMessage() { StatusCode = HttpStatusCode.NotFound });
+ });
+ _webApplicationFactorySetup.SblBridgeHttpMessageHandler = messageHandler;
+
+ HttpRequestMessage httpRequestMessage = CreatePostRequest($"/profile/api/v1/internal/user/", new UserProfileLookup { Username = Username });
+
+ HttpClient client = _webApplicationFactorySetup.GetTestServerClient();
+
+ // Act
+ HttpResponseMessage response = await client.SendAsync(httpRequestMessage);
+
+ // Assert
+ Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
+
+ Assert.NotNull(sblRequest);
+ Assert.Equal(HttpMethod.Get, sblRequest.Method);
+ Assert.EndsWith($"sblbridge/profile/api/users/?username={Username}", sblRequest.RequestUri.ToString());
+ }
+
+ [Fact]
+ public async Task GetUserByUsername_SblBridgeReturnsUnavailable_ResponseNotFound()
+ {
+ // Arrange
+ const string Username = "OrstaECUser";
+
+ HttpRequestMessage sblRequest = null;
+ DelegatingHandlerStub messageHandler = new(async (request, token) =>
+ {
+ sblRequest = request;
+
+ return await Task.FromResult(new HttpResponseMessage() { StatusCode = HttpStatusCode.ServiceUnavailable });
+ });
+ _webApplicationFactorySetup.SblBridgeHttpMessageHandler = messageHandler;
+
+ HttpRequestMessage httpRequestMessage = CreatePostRequest($"/profile/api/v1/internal/user/", new UserProfileLookup { Username = Username });
+
+ HttpClient client = _webApplicationFactorySetup.GetTestServerClient();
+
+ // Act
+ HttpResponseMessage response = await client.SendAsync(httpRequestMessage);
+
+ // Assert
+ Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
+
+ Assert.NotNull(sblRequest);
+ Assert.Equal(HttpMethod.Get, sblRequest.Method);
+ Assert.EndsWith($"sblbridge/profile/api/users/?username={Username}", sblRequest.RequestUri.ToString());
+ }
+
+ [Fact]
+ public async Task GetUserEmptyInputModel_UserProfileInternalController_ResponseBadRequest()
+ {
+ // Arrange
+ UserProfileLookup emptyInputModel = new UserProfileLookup();
+
+ HttpRequestMessage httpRequestMessage = CreatePostRequest($"/profile/api/v1/internal/user/", emptyInputModel);
+
+ HttpClient client = _webApplicationFactorySetup.GetTestServerClient();
+
+ // Act
+ HttpResponseMessage response = await client.SendAsync(httpRequestMessage);
+
+ // Assert
+ Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
+ }
+
+ [Fact]
+ public async Task GetUserNullInputModel_UserProfileInternalController_ResponseBadRequest()
+ {
+ // Arrange
+ UserProfileLookup nullInputModel = null;
+
+ HttpRequestMessage httpRequestMessage = CreatePostRequest($"/profile/api/v1/internal/user/", nullInputModel);
+
+ HttpClient client = _webApplicationFactorySetup.GetTestServerClient();
+
+ // Act
+ HttpResponseMessage response = await client.SendAsync(httpRequestMessage);
+
+ // Assert
+ Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
+ }
+
+ private static HttpRequestMessage CreatePostRequest(string requestUri, UserProfileLookup lookupRequest)
+ {
+ HttpRequestMessage httpRequestMessage = new(HttpMethod.Post, requestUri);
+ httpRequestMessage.Content = new StringContent(JsonSerializer.Serialize(lookupRequest), Encoding.UTF8, "application/json");
+ return httpRequestMessage;
+ }
+ }
+}
diff --git a/test/Altinn.Profile.Tests/Testdata/UserProfile/OrstaECUser.json b/test/Altinn.Profile.Tests/Testdata/UserProfile/OrstaECUser.json
new file mode 100644
index 0000000..bb5173a
--- /dev/null
+++ b/test/Altinn.Profile.Tests/Testdata/UserProfile/OrstaECUser.json
@@ -0,0 +1,43 @@
+{
+ "UserId": 2001072,
+ "UserType": 3,
+ "UserName": "OrstaECUser",
+ "ExternalIdentity": "",
+ "PhoneNumber": null,
+ "Email": null,
+ "PartyId": 50005545,
+ "Party": {
+ "PartyTypeName": 2,
+ "SSN": "",
+ "OrgNumber": "910459880",
+ "Person": null,
+ "Organization": {
+ "OrgNumber": "910459880",
+ "Name": "ORSTA OG HEGGEDAL",
+ "UnitType": "AS",
+ "TelephoneNumber": "12345678",
+ "MobileNumber": "99999999",
+ "FaxNumber": "12345679",
+ "EMailAddress": "test@test.test",
+ "InternetAddress": null,
+ "MailingAddress": null,
+ "MailingPostalCode": "",
+ "MailingPostalCity": "",
+ "BusinessAddress": null,
+ "BusinessPostalCode": "",
+ "BusinessPostalCity": "",
+ "UnitStatus": "N"
+ },
+ "PartyId": 50005545,
+ "UnitType": "AS",
+ "Name": "ORSTA OG HEGGEDAL ",
+ "IsDeleted": false,
+ "OnlyHierarchyElementWithNoAccess": false,
+ "ChildParties": null
+ },
+ "ProfileSettingPreference": {
+ "Language": "nb",
+ "PreSelectedPartyId": 0,
+ "DoNotPromptForParty": false
+ }
+}
\ No newline at end of file
diff --git a/test/Altinn.Profile.Tests/UnitTests/UserProfileCachingDecoratorTest.cs b/test/Altinn.Profile.Tests/UnitTests/UserProfileCachingDecoratorTest.cs
index 52673e3..ef15cdb 100644
--- a/test/Altinn.Profile.Tests/UnitTests/UserProfileCachingDecoratorTest.cs
+++ b/test/Altinn.Profile.Tests/UnitTests/UserProfileCachingDecoratorTest.cs
@@ -166,5 +166,79 @@ public async Task GetUserUserSSN_NullFromDecoratedService_CacheNotPopulated()
Assert.Null(actual);
Assert.False(memoryCache.TryGetValue("User_UserId_2001607", out UserProfile _));
}
+
+ ///
+ /// Tests that the userprofile available in the cache is returned to the caller without forwarding request to decorated service.
+ ///
+ [Fact]
+ public async Task GetUserByUsername_UserInCache_decoratedServiceNotCalled()
+ {
+ // Arrange
+ const string Username = "OrstaECUser";
+ const int UserId = 2001072;
+ MemoryCache memoryCache = new(new MemoryCacheOptions());
+
+ var userProfile = await TestDataLoader.Load(Username);
+ memoryCache.Set("User_Username_OrstaECUser", userProfile);
+ var target = new UserProfileCachingDecorator(_decoratedServiceMock.Object, memoryCache, generalSettingsOptions.Object);
+
+ // Act
+ UserProfile actual = await target.GetUserByUsername(Username);
+
+ // Assert
+ _decoratedServiceMock.Verify(service => service.GetUser(It.IsAny()), Times.Never());
+ Assert.NotNull(actual);
+ Assert.Equal(UserId, actual.UserId);
+ Assert.Equal(Username, actual.UserName);
+ }
+
+ ///
+ /// Tests that when the userprofile is not available in the cache, the request is forwarded to the decorated service.
+ ///
+ [Fact]
+ public async Task GetUserByUsername_UserNotInCache_decoratedServiceCalledMockPopulated()
+ {
+ // Arrange
+ const string Username = "OrstaECUser";
+ const int UserId = 2001072;
+ MemoryCache memoryCache = new(new MemoryCacheOptions());
+
+ var userProfile = await TestDataLoader.Load(Username);
+ _decoratedServiceMock.Setup(service => service.GetUserByUsername(Username)).ReturnsAsync(userProfile);
+ var target = new UserProfileCachingDecorator(_decoratedServiceMock.Object, memoryCache, generalSettingsOptions.Object);
+
+ // Act
+ UserProfile actual = await target.GetUserByUsername(Username);
+
+ // Assert
+ _decoratedServiceMock.Verify(service => service.GetUserByUsername(Username), Times.Once());
+
+ Assert.NotNull(actual);
+ Assert.Equal(UserId, actual.UserId);
+ Assert.Equal(Username, actual.UserName);
+ Assert.True(memoryCache.TryGetValue("User_Username_OrstaECUser", out UserProfile _));
+ }
+
+ ///
+ /// Tests that if the result from decorated service is null, nothing is stored in cache and the null object returned to caller.
+ ///
+ [Fact]
+ public async Task GetUserByUsername_NullFromDecoratedService_CacheNotPopulated()
+ {
+ // Arrange
+ const string Username = "NonExistingUsername";
+ MemoryCache memoryCache = new(new MemoryCacheOptions());
+
+ _decoratedServiceMock.Setup(service => service.GetUserByUsername(Username)).ReturnsAsync((UserProfile)null);
+ var target = new UserProfileCachingDecorator(_decoratedServiceMock.Object, memoryCache, generalSettingsOptions.Object);
+
+ // Act
+ UserProfile actual = await target.GetUserByUsername(Username);
+
+ // Assert
+ _decoratedServiceMock.Verify(service => service.GetUserByUsername(Username), Times.Once());
+ Assert.Null(actual);
+ Assert.False(memoryCache.TryGetValue("User_Username_NonExistingUsername", out UserProfile _));
+ }
}
}