C# Client Library
A C# Client Library for the AnalyzeRe REST API
Loading...
Searching...
No Matches
Test_PortfolioView.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Net;
5
6using AnalyzeRe;
14
15#if MSTEST
16using Microsoft.VisualStudio.TestTools.UnitTesting;
17#elif NUNIT
18using NUnit.Framework;
19using TestClass = NUnit.Framework.TestFixtureAttribute;
20using TestMethod = NUnit.Framework.TestAttribute;
21using TestCategory = NUnit.Framework.CategoryAttribute;
22#endif
23
25{
26 [TestClass]
28 {
29 private const string TypeName = "PortfolioView";
30
31 protected override bool PUT_Allowed => false;
33
36 [TestMethod, TestCategory(TypeName)]
37 public override void Test_Resource_PUT_BadlyFormed()
38 {
39 //base.Test_Resource_PUT_BadlyFormed();
41 Assert.Inconclusive("RUN_OFFLINE = true");
42 AssertApi.ExceptionThrown(
43 () => GenericTest.Mock<PortfolioView>("MALFORMED").Put(),
44 // Should be MethodNotAllowed like the base class would assert.
46 }
47
48 [TestMethod, TestCategory(TypeName)]
50 {
52 invalid.portfolio = Samples.Portfolio.AsReference;
53 //"layer_views or portfolio must be provided, but not both."
54 GenericTest.POST_InvalidResource_Fails(invalid);
55 }
56
60 [TestMethod, TestCategory(TypeName)]
62 {
64 Assert.Inconclusive("RUN_OFFLINE = true");
67 IReference<ILayerView> removed = basePortfolio.layer_views.First();
69 basePortfolio.ToReference(),
70 new[] { added.ToReference() },
71 new[] { removed });
72 // Check that the new marginal portfolio looks like what we would expect.
73 PortfolioView resolved = result.GetValue();
74 // Added layer now exists
75 Assert.IsTrue(resolved.layer_views.Any(lv => lv.ref_id == added.id));
76 // Removed layer is gone
77 Assert.IsFalse(resolved.layer_views.Any(lv => lv.ref_id == removed.ref_id));
78 // All other layers from the original portfolio still exist.
79 Assert.IsTrue(basePortfolio.layer_views.Skip(1)
80 .All(lv => resolved.layer_views.Any(newlv => newlv.ref_id == lv.ref_id)));
81 }
82
83 #region Target Currency
84 [TestMethod, TestCategory(TypeName)]
86 {
88 Assert.Inconclusive("RUN_OFFLINE = true");
90 // Create two USD and one EUR layer.
91 baseLayer.limit = new MonetaryUnit(baseLayer.limit.value, "USD");
92 CatXL l1_usd = baseLayer.Post();
93 CatXL l5_usd = baseLayer.Post();
94 baseLayer.limit = new MonetaryUnit(baseLayer.limit.value, "EUR");
95 CatXL l2_eur = baseLayer.Post();
96 CatXL l3_eur = baseLayer.Post();
97 CatXL l4_eur = baseLayer.Post();
98 // Create a portfolio that references all these layers.
100 {
101 layers = new HashSet<IReference<ILayer>>
102 {
103 l1_usd.ToReference(), l2_eur.ToReference(), l3_eur.ToReference(),
104 l4_eur.ToReference(), l5_usd.ToReference()
105 },
106 name = "5 layers",
107 description = "5 layers"
108 }.Post();
109 // Now post as a portfolio view.
110 IReference<AnalysisProfile> analysis_profile =
112 GenericTest.POST_ThenDoAction(
113 new PortfolioView
114 {
115 analysis_profile = analysis_profile,
116 portfolio = toReference.ToReference()
117 },
118 // Assert that the target currency returned by the server is EUR
119 pv => Assert.AreEqual("EUR", pv.target_currency));
120 }
121
122 [TestMethod, TestCategory(TypeName)]
124 {
126 Assert.Inconclusive("RUN_OFFLINE = true");
128 IReference<AnalysisProfile> analysis_profile =
130 PortfolioView toPost = new PortfolioView { analysis_profile = analysis_profile };
131 // Create a USD layer_view, then 3 EUR layer_views, then another USD layer_view.
132 toPost.layer_views.Add(LayerViews.Create(baseLayer, analysis_profile, "USD").Post().ToReference());
133 baseLayer.description = "Layer 2";
134 toPost.layer_views.Add(LayerViews.Create(baseLayer, analysis_profile, "EUR").Post().ToReference());
135 baseLayer.description = "Layer 3";
136 toPost.layer_views.Add(LayerViews.Create(baseLayer, analysis_profile, "EUR").Post().ToReference());
137 baseLayer.description = "Layer 4";
138 toPost.layer_views.Add(LayerViews.Create(baseLayer, analysis_profile, "EUR").Post().ToReference());
139 baseLayer.description = "Layer 5";
140 toPost.layer_views.Add(LayerViews.Create(baseLayer, analysis_profile, "USD").Post().ToReference());
141 // Now test that the majority target currency got set on the PortfolioView
142 GenericTest.POST_ThenDoAction(toPost, pv => Assert.AreEqual("EUR", pv.target_currency));
143 }
144 #endregion Target Currency
145 }
146
147 [TestClass]
149 {
150 #region Set Up and Configuration
151 private const string TypeName = "PortfolioView";
154 #endregion Set Up and Configuration
155
156 #region POST
157 #region portfolio
158 [TestMethod, TestCategory(TypeName)]
160 {
161 POST_WithValue(l => l.portfolio, null, false);
162 }
163 [TestMethod, TestCategory(TypeName)]
168 [TestMethod, TestCategory(TypeName)]
173 [TestMethod, TestCategory(TypeName)]
178
179 [TestMethod, TestCategory(TypeName)]
181 {
182 GenericTest.POST_ThenDoAction(
184 {
185 name = "All Layer Types",
186 description = "All Layer Types",
187 layers = new HashSet<IReference<ILayer>>(
188 Samples.AllSaveableLayerTypesTestList.Select(ly => ly.AsReference))
189 }, allLayerTypes =>
190 POST_WithValue(l => l.portfolio, allLayerTypes.ToReference(), true));
191 }
192 #endregion portfolio
193
194 #region MixedLossSetTypes
195 [TestMethod, TestCategory(TypeName)]
197 {
199 Assert.Inconclusive("RUN_OFFLINE = true");
200 // Not all metrics are available for a PortfolioView whose layerViews reference
201 // a mixture of loss_set loss_types
203 layerNetAggDefinition.loss_sets =
204 new List<IReference<LossSet>> { Samples.LossSet_YLTLossSet.AsReference };
209 {
210 name = "Profile of Mixed Layer LossSet Types",
211 description = "Profile of Mixed Layer LossSet Types",
212 layers = new HashSet<IReference<ILayer>>
213 {
215 layerNetAgg.AsReference
216 }
217 });
218 POST_ThenDoAction(TestResource.Change(pv => pv.portfolio, mixedPortfolio.AsReference),
220 }
221
222 [TestMethod, TestCategory(TypeName)]
224 {
226 Assert.Inconclusive("RUN_OFFLINE = true");
227 // A layer may be posted such that it contains mixed loss set types, but this
228 // the resulting portfolio_view metrics must only support perspectives corresponding
229 // to the highest granularity source loss data supplied.
232 {
233 name = "Profile of Mixed Layer LossSet Types",
234 description = "Profile of Mixed Layer LossSet Types",
235 layers = new HashSet<IReference<ILayer>>
236 {
238 .Change(l => l.loss_sets, Samples.AllLossSetTypesTestList
239 .Select(ls => ls.AsReference).ToList())).AsReference
240 }
241 });
242 POST_ThenDoAction(TestResource.Change(pv => pv.portfolio, mixedPortfolio.AsReference),
244 }
245 #endregion MixedLossSetTypes
246
251 [TestMethod, TestCategory(TypeName)]
252 public override void Test_Resource_POST_ExistingId()
253 {
254 PortfolioView original = TestResource_Existing;
255 Console.WriteLine($"Test resource unposted: {TestResource.Serialize()}");
256 Console.WriteLine($"Test resource posted: {original.Serialize()}");
257 // Test posting a resource with the same id, same list of layer_views
258 PortfolioView test1 = original.DeepCopy().Change(pv => pv.layer_views, null);
259 POST_ThenDoAction(test1, copy =>
260 {
261 Assert.AreEqual(original.ylt_id, copy.ylt_id, "Expected the same portfolio_view ylt_id " +
262 "regardless of whether it's created with a portfolio reference or layer_views.");
263 // Bug: ARE-6210 - Server-Generated properties (ylt_id) impact portfolio_view id on POST
264 //Assert.AreEqual(original.id, copy.id, "Expected the same portfolio_view id " +
265 // "because the original was also posted using a portfolio reference.");
266 Assert.AreNotEqual(original.id, copy.id, "Bug ARE-6210 changes the id even though the " +
267 "resources are identical. Let us know when this is no longer the case.");
268 });
269 // ARE-6210 can be avoided by further stripping out server-generated properties
270 PortfolioView test2 = original.DeepCopy().Change(pv => pv.layer_views, null)
271 .Change(pv => pv.target_currency, null).Change(pv => pv.ylt_id, null).Change(pv => pv.id, null);
272 POST_ThenDoAction(test2, copy =>
273 {
274 Assert.AreEqual(original.ylt_id, copy.ylt_id, "Expected the same portfolio_view ylt_id " +
275 "regardless of whether it's created with a portfolio reference or layer_views.");
276 Assert.AreEqual(original.id, copy.id, "Expected the same portfolio_view id " +
277 "because all server generated properties were removed for ARE-6210.");
278 });
279
280 PortfolioView test3 = original.DeepCopy().Change(pv => pv.portfolio, null);
281 POST_ThenDoAction(test3, copy =>
282 {
283 Assert.AreEqual(original.ylt_id, copy.ylt_id, "Expected the same portfolio_view ylt_id " +
284 "regardless of whether it's created with a portfolio reference or layer_views.");
285 Assert.AreNotEqual(original.id, copy.id, "The server currently does not return the " +
286 "same id when a portfolio_view is posted from the equivalent set of layer_views. " +
287 "If this changes, great! - we just want to know about it.");
288 });
289 }
290 #endregion POST
291 }
292
293 [TestClass]
295 {
296 #region Set Up and Configuration
297 private const string TypeName = "PortfolioView";
300 #endregion Set Up and Configuration
301
302 #region POST
303 #region layer_views
304 [TestMethod, TestCategory(TypeName)]
306 {
307 POST_WithValue(l => l.layer_views, null, false);
308 }
309 [TestMethod, TestCategory(TypeName)]
311 {
312 POST_WithValue(a => a.layer_views, new HashSet<IReference<ILayerView>>(), false);
313 }
314 [TestMethod, TestCategory(TypeName)]
321 [TestMethod, TestCategory(TypeName)]
328
329 [TestMethod, TestCategory(TypeName)]
331 {
333 Assert.Inconclusive("RUN_OFFLINE = true");
334 IReference<AnalysisProfile> ap = TestResource.analysis_profile;
337 LayerViews.Create(ly.Unposted, ap).Post().ToReference()));
338 POST_WithValue(l => l.layer_views, allLayerTypes, true);
339 }
340 #endregion layer_views
341
342 #region MixedLossSetTypes
343 [TestMethod, TestCategory(TypeName)]
345 {
347 Assert.Inconclusive("RUN_OFFLINE = true");
348 IReference<AnalysisProfile>analysis_profile = TestResource.analysis_profile;
350 LayerViews.Create(Samples.Layer_AggXL.Unposted, analysis_profile).Post();
351 ILayer_WithLossSets layerNetAgg = layerViewGross.layer.ShallowCopy();
352 layerNetAgg.loss_sets =
353 new List<IReference<LossSet>> { Samples.LossSet_YLTLossSet.AsReference };
356 {
357 layer = layerNetAgg,
358 analysis_profile = analysis_profile
359 });
361 {
362 layerViewGross.ToReference(),
363 layerViewNetAgg.AsReference
364 };
365 POST_ThenDoAction(TestResource.Change(pv => pv.layer_views, references),
367 }
368
369 // This test is needed as a result of a Bug (ARE-1330) that was (behind the scenes)
370 // changing the loss type of NestedLayer losses when converting them to a NestedLayerLossSet.
371 [TestMethod, TestCategory(TypeName)]
373 {
375 Assert.Inconclusive("RUN_OFFLINE = true");
376 IReference<AnalysisProfile> analysis_profile = TestResource.analysis_profile;
377 // Create a simple DiracDistribution that returns a loss of 1
378 DiracDistribution oneDistribution = new DiracDistribution { description = "One", value = 1 }.Post();
379 // Create a simple LossNetOfAggregateTerms Parametric LossSet
381 {
382 currency = "USD",
383 description = "Gross Loss of 1",
384 frequency = oneDistribution.ToReference(),
385 seasonality = oneDistribution.ToReference(),
386 severity = oneDistribution.ToReference(),
387 loss_type = LossType.LossGross
388 }.Post();
389 // Create a simple QuotaShare layerView that uses this lossSet
391 qsLayer.description = "Simple 1 loss layer";
392 qsLayer.loss_sets = new List<IReference<LossSet>> { oneLoss.ToReference() };
393 qsLayer = qsLayer.Post();
394 QuotaShare qsLayer2 = qsLayer.Post();
395 // Create a simple NestedLayer that uses 2 (identical) QuotaShare layers.
397 {
398 description = "Simple nested layer",
399 sources = new List<IReference<ILayer>> { qsLayer.ToReference(), qsLayer2.ToReference() },
400 sink = qsLayer.ToReference()
401 }.Post();
402 // Turn both layers into layerViews
403 ILayerView<Nested> nestedLayerView = LayerViews.Create(nestedLayer, analysis_profile).Post();
404
405 // Create a PortfolioView that references these two LayerViews
407 {
408 nestedLayerView.ToReference()
409 };
410 new PortfolioView { layer_views = layer_views, analysis_profile = analysis_profile }.Post();
411 POST_WithValue(a => a.layer_views, layer_views, true);
412 }
413 #endregion MixedLossSetTypes
414 #endregion POST
415 }
416
417 #region Abstract Base Test Class
418 [TestClass]
419 public abstract class TestSuite_PortfolioView : TestSuite_APIResourceView<PortfolioView>
420 {
421 private const string TypeName = "PortfolioView";
422
423 [TestMethod, TestCategory(TypeName)]
424 public virtual void Test_PortfolioView_Premium()
425 {
426 // Assert that the server computes and returns the correct premium for the portfolio_view
427 PortfolioView portfolioView = TestResource_Existing;
428 Assert.IsNotNull(portfolioView.premium);
429 Console.WriteLine($"PortfolioView Premium: {portfolioView.premium}");
430 Assert.AreEqual(portfolioView.target_currency, portfolioView.premium.currency);
431 // To compute premium we need to get all referenced layer_views.
432 List<ILayer_WithTerms> constituentsWithPremium = portfolioView.layer_views
433 .Select(lv => Reflection.Resolve(lv).layer).OfType<ILayer_WithTerms>().ToList();
434 Console.WriteLine("Constituents:\n" + String.Join("\n", constituentsWithPremium
435 .Select(l => $"- Premium: {l.premium} Share: {l.participation}")));
436
437 // This simple test is only designed to work if all premiums are in the same currency.
438 // API unit tests should verify that currency conversion is working as expected.
439 Assert.IsTrue(constituentsWithPremium.All(lyr => lyr.premium.currency == portfolioView.target_currency),
440 "Expected all constituent layer premiums to have the same currency. Test cannot proceed.");
441 // Compute the premium
442 double expectedPremium = constituentsWithPremium.Sum(lyr => lyr.premium.value * lyr.participation);
444 }
445
446 #region BackAllocations
447 [TestMethod, TestCategory(TypeName), Obsolete("Tests the legacy back_allocations endpoint")]
449 {
450 // TODO: PortfolioViews currently can't be used as a back-allocation target.
451 Skip.Indefinitely("ARE-5129: 'Source not found' erroneously raised when back-allocating to self.");
452 base.Test_IAPIResourceView_GET_BackAllocations_Self();
453 }
454
455 [TestMethod, TestCategory(TypeName), Obsolete("Tests the legacy back_allocations endpoint")]
457 {
459 {
460 BackAllocations result = view.back_allocations_blocking(
461 view.layer_views.First().ref_id, SimulationPolling);
463 });
464 }
465 #endregion BackAllocations
466
467 #region PostMarginalPortfolioView
468 [TestMethod, TestCategory(TypeName)]
470 {
472 Assert.Inconclusive("RUN_OFFLINE = true");
473 PortfolioView portfolioView = TestResource_Existing;
474 IReference<ILayerView> layer_view_to_add = Samples.LayerView_Nested.Unposted
475 .Change(lv => lv.analysis_profile, portfolioView.analysis_profile)
476 .Post().ToReference();
477 IReference<PortfolioView> newPv = portfolioView.PostMarginalPortfolio(
478 new[] { layer_view_to_add });
479
480 PortfolioView created = newPv.GetValue();
481 // The new layer_view should appear in the new portfolio_view
482 Assert.AreEqual(portfolioView.layer_views.Count + 1, created.layer_views.Count);
483 Assert.IsTrue(created.layer_views.Any(lv => lv.ref_id == layer_view_to_add.ref_id));
484 }
485
486 [TestMethod, TestCategory(TypeName), TestCategory("Skipped")]
488 {
489 Skip.Indefinitely("ARE-2767 - " +
490 "Support Duplicate Layers in Portfolios and LayerViews in PortfolioViews");
491 PortfolioView portfolioView = TestResource_Existing;
492 IReference<ILayerView> existing = portfolioView.layer_views.First();
493 IReference<PortfolioView> newPv = portfolioView.PostMarginalPortfolio(
494 new[] { existing });
495
496 PortfolioView created = newPv.GetValue();
497 // The layer_view should appear in the new portfolio_view twice
498 Assert.AreEqual(portfolioView.layer_views.Count + 1, created.layer_views.Count);
499 Assert.AreEqual(2, created.layer_views.Count(lv => lv.ref_id == existing.ref_id));
500 }
501
502 [TestMethod, TestCategory(TypeName)]
504 {
506 Assert.Inconclusive("RUN_OFFLINE = true");
507 PortfolioView portfolioView = TestResource_Existing;
508 IReference<ILayerView> existing = portfolioView.layer_views.First();
509 IReference<PortfolioView> newPv = portfolioView.PostMarginalPortfolio(
510 layerViewsToRemove: new[] { existing });
511
512 PortfolioView created = newPv.GetValue();
513 // The layer_view should no longer appear in the new portfolio_view
514 Assert.AreEqual(portfolioView.layer_views.Count - 1, created.layer_views.Count);
515 Assert.IsFalse(created.layer_views.Any(lv => lv.ref_id == existing.ref_id));
516 }
517
518 [TestMethod, TestCategory(TypeName)]
520 {
521 AssertApi.ExceptionThrown(() => TestResource_Existing.PostMarginalPortfolio(),
522 (ArgumentException ex) => Assert.AreEqual(
523 "You must specify either layers to add or layers to remove, or both.", ex.Message));
524 }
525
526 [TestMethod, TestCategory(TypeName)]
528 {
529 AssertApi.ExceptionThrown(() => TestResource.PostMarginalPortfolio(),
530 (ArgumentException ex) => Assert.AreEqual(
531 "The referenced base portfolio_view reference has no id.", ex.Message));
532 }
533 #endregion PostMarginalPortfolioView
534 }
535 #endregion Abstract Base Test Class
536}
Tests for a collection (or base resource type) which do not require an instance of that resource to b...
A class containing a resource that can be Posted with dependencies.
IReference< T > AsReference
A reference to the posted resource.
Exposes sample resource objects, with built-in methods for injecting dependencies.
Definition Samples.cs:14
IInjectableResource< ILayerView< Generic > > LayerView_Generic
IInjectableResource< AggXL > Layer_AggXL
List< IInjectableResource< ILayer > > AllSaveableLayerTypesTestList
A list of one of each type of layer that can be POSTed. Layer types that cannot be posted on their ow...
IInjectableResource< AnalysisProfile > AnalysisProfile
An analysis profile with one of each possible type of filter.
IInjectableResource< StaticPortfolio > Portfolio
IInjectableResource< PortfolioView > PortfolioView_WithLayerViews
static string Valid_NonExistant_UUID
Definition Samples.cs:41
IInjectableResource< CatXL > Layer_CatXL
List< IInjectableResource< LossSet > > AllLossSetTypesTestList
One sample of each loss set type, all with the loss_type set to LossType.LossGross to maximize potent...
List< IInjectableResource< ILayer > > AllLayerTypesTestList
A list of one of each type of layer.
IInjectableResource< QuotaShare > Layer_QuotaShare
IInjectableResource< PortfolioView > PortfolioView_WithPortfolio
Contains static helper methods for testing IAPIResourceView instances.
static void Test_IAPIResourceView_Metrics_MixedLossTypes(T posted, Perspective leastGranularPerspective=null)
static readonly PollingOptions SimulationPolling
Settings used to ensure simulation requests are retried frequently and timeout after a reasonable amo...
void Test_PortfolioView_POST_Marginal()
Test that the API.PortfolioViewMarginals collection (which behaves unlike any other root endpoint to ...
override IResourceCollection< PortfolioView > collection_source
override void Test_Resource_PUT_BadlyFormed()
Bug ARE-6381: The server returns the wrong status on PUT when the id is malformed.
override IInjectableResource< PortfolioView > TestInjectableResource
override IInjectableResource< PortfolioView > TestInjectableResource
override void Test_Resource_POST_ExistingId()
Special case for PortfolioView: Can't just re-POST the object returned from the server,...
static Action< APIRequestException > ApiExceptionTest(HttpStatusCode expectedStatusCode)
Generate a function that will test a REST request exception in a standard way.
Definition AssertApi.cs:539
static void DoublesAreEqual(double expected, double actual, Func< string > message, double? relative_tolerance=null)
Determines if two doubles are equivalent within the accepted tolerance.
Definition AssertApi.cs:594
Retrieve settings from environment variables if they exist, or the project settings file otherwise.
static bool RUN_OFFLINE
Controls whether tests that normally require a connection to the server should be allowed to try to r...
Generic Unit test implementations that will test REST methods on arbitrary resources.
A collection of filthy hacks to populate some fields of APIResources objects of any type.
Definition Reflection.cs:41
Class used in unit tests to mark tests as skipped by using Assert.Inconclusive() method.
Definition SkipUntil.cs:14
static void Indefinitely(string ticket=null)
Skip the specified test.
Definition SkipUntil.cs:54
Describes a collection of resources which can be listed.
Represents the endpoint on the server for requesting marginal portfolios.
static IReference< PortfolioView > Post(IReference< PortfolioView > basePortfolio, IEnumerable< IReference< ILayerView > > layerViewsToAdd=null, IEnumerable< IReference< ILayerView > > layerViewsToRemove=null, IEnumerable< Parameter > requestParameters=null, int? timeout=null)
Construct a "marginal" PortfolioView by adding and/or removing one or more LayerViews to/from some ba...
API methods / requests made available to the user.
static readonly ResourceCollection< PortfolioView > PortfolioViews
The collection of PortfolioViews on the server.
Describes a distribution that always returns the same value. This distribution can be used as either ...
LayerView factory class.
Definition LayerViews.cs:9
Representation of an Aggregate Catastrophe Excess of Loss layer.
Definition AggXL.cs:8
Representation of a Catastrophe Excess of Loss (CatXL) layer.
Definition CatXL.cs:9
Allows one or more source layers or layer_views to be attached as loss sources to some other layer de...
Definition Nested.cs:22
Representation of a Quota Share contract.
Definition QuotaShare.cs:9
Representation of a Parametric loss set.
The structure returned when requesting back-allocated metrics for a view.
Representation of a monetary value with a currency.
Represents the Analysis of a Portfolio.
HashSet< IReference< ILayerView > > layer_views
The LayerViews included in this PortfolioView. Must be supplied when posting a new PortfolioView,...
Representation of a portfolio.
IReference< T > AsReference
A reference to the posted resource.
T Unposted
The unPOSTed resource definition.
T Posted
The posted resource, ready to be referenced.
Represents the Analysis of a Layer.
Abstract representation of a layer with terms.
Abstract representation of a layer with terms.
@ currency
Reinstatement values represent a fixed dollar amount.