C# Client Library
A C# Client Library for the AnalyzeRe REST API
Loading...
Searching...
No Matches
Test_LayerView.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Linq.Expressions;
5using System.Net;
6using System.Reflection;
7
8using AnalyzeRe;
19
20using RestSharp;
21
22#if MSTEST
23
24using Microsoft.VisualStudio.TestTools.UnitTesting;
25
26#elif NUNIT
27using NUnit.Framework;
28using TestClass = NUnit.Framework.TestFixtureAttribute;
29using TestMethod = NUnit.Framework.TestAttribute;
30using TestCategory = NUnit.Framework.CategoryAttribute;
31#endif
32
34{
35 #region Base LayerView Class Tests
36
37 [TestClass]
39 {
40 private const string TypeName = "LayerView";
41
42 protected override bool PUT_Allowed => false;
44
47 [TestMethod, TestCategory(TypeName)]
48 public override void Test_Resource_PUT_BadlyFormed()
49 {
50 //base.Test_Resource_PUT_BadlyFormed();
52 Assert.Inconclusive("RUN_OFFLINE = true");
53 AssertApi.ExceptionThrown(
54 () => GenericTest.Mock<PortfolioView>("MALFORMED").Put(),
55 // Should be MethodNotAllowed like the base class would assert.
57 }
58
61 [TestMethod, TestCategory(TypeName)]
63 {
65 Assert.Inconclusive("RUN_OFFLINE = true");
70
71 // Create a valid event catalog that's different from the analysis profile
73 badCatalog.description = "A Different Event Catalog";
74 badCatalog = badCatalog.Post("Event,Rate\n1,0");
75 // Create an analysis profile that uses this different event catalog
77 AnalysisProfile badAnalysisProfile = Reflection.Resolve(badLayerView.analysis_profile).ShallowCopy();
78 badAnalysisProfile.event_catalogs = new List<IReference<EventCatalog>> { badCatalog.ToReference() };
79 badAnalysisProfile.loss_filters = new List<IReference<LossFilter>> { anyFilter.AsReference };
80 // Assert that an exception is thrown.
81 AssertApi.ExceptionThrown(() => badAnalysisProfile.Post(),
83 }
84
87 [TestMethod, TestCategory(TypeName)]
89 {
90 AnalysisProfile filteringProfile = Samples.AnalysisProfile.Unposted
91 .Change(a => a.yelt_loss_set_simulation_filtering, true)
92 .Post().PollUntilReady(Samples.DataPollingOptions);
93
94 // Samples.Layer_CatXL uses YELT loss set which currently 100% matches SimGrid
97
98 double el = catXl.tail_metrics_blocking(1,
100 Assert.AreNotEqual(el, 0, "Expected not zero EL.");
101 }
102
105 [TestMethod, TestCategory(TypeName)]
107 {
108 AnalysisProfile filteringProfile = Samples.AnalysisProfile.Unposted
109 .Change(a => a.round_sequences, true)
110 .Post().PollUntilReady(Samples.DataPollingOptions);
111
112 // Samples.Layer_CatXL uses YELT loss set which currently 100% matches SimGrid
115
116 double el = catXl.tail_metrics_blocking(1,
118 Assert.AreNotEqual(el, 0, "Expected not zero EL.");
119 }
120 }
121
122 #endregion Base LayerView Class Tests
123
124 #region Instantiable LayerView Types Tests
125
126 [TestClass]
128 {
129 #region Set Up and Configuration
130
131 private const string TypeName = "LayerView<AggXL>";
132
135
137 l => l.aggregate_limit;
138
139 #endregion Set Up and Configuration
140 }
141
142 [TestClass]
144 {
145 #region Set Up and Configuration
146
147 private const string TypeName = "LayerView<CatXL>";
148
151
153 l => l.limit;
154
155 #endregion Set Up and Configuration
156 }
157
158 [TestClass]
160 {
161 #region Set Up and Configuration
162
163 private const string TypeName = "LayerView<Generic>";
164
167
169 l => l.aggregate_limit;
170
171 #endregion Set Up and Configuration
172 }
173
174 [TestClass]
175 public sealed class TestSuite_LayerView_QuotaShare : TestSuite_LayerView<QuotaShare>
176 {
177 #region Set Up and Configuration
178
179 private const string TypeName = "LayerView<QuotaShare>";
180
183
185 l => l.event_limit;
186
187 #endregion Set Up and Configuration
188 }
189
190 [TestClass]
191 public sealed class TestSuite_LayerView_AggregateQuotaShare : TestSuite_LayerView<AggregateQuotaShare>
192 {
193 #region Set Up and Configuration
194
195 private const string TypeName = "LayerView<AggregateQuotaShare>";
196
199
201 l => l.aggregate_limit;
202
203 #endregion Set Up and Configuration
204 }
205
206 [TestClass]
207 public sealed class TestSuite_LayerView_SurplusShare : TestSuite_LayerView<SurplusShare>
208 {
209 #region Set Up and Configuration
210
211 private const string TypeName = "LayerView<SurplusShare>";
212
215
217 l => l.retained_line;
218
219 #endregion Set Up and Configuration
220 }
221
222 [TestClass]
223 public sealed class TestSuite_LayerView_IndustryLossWarranty : TestSuite_LayerView<IndustryLossWarranty>
224 {
225 #region Set Up and Configuration
226
227 private const string TypeName = "LayerView<IndustryLossWarranty>";
228
231
233 l => l.payout;
234
235 #endregion Set Up and Configuration
236 }
237
238 [TestClass]
240 {
241 #region Set Up and Configuration
242
243 private const string TypeName = "LayerView<Nested>";
244
247
248 #endregion Set Up and Configuration
249
250 #region Overidden Tests
251
252 [TestMethod, TestCategory(TypeName)]
254 {
255 // Demonstrate that the target currency comes from the sink layer
257 {
258 analysis_profile = Samples.AnalysisProfile.AsReference,
259 layer = new Nested
260 {
261 sink = new QuotaShare { event_limit = new MonetaryUnit(1, "CAD") }.ToReference()
262 }
263 };
264 // Predict the target currency using the "TargetCurrencyDefault" attribute.
266 POST_ThenDoAction(testNestedLayerView, fromServer =>
267 {
268 // Assert that the currency and prediction are both "CAD"
269 Assert.AreEqual("CAD", fromServer.target_currency);
270 Assert.AreEqual("CAD", predicted);
271 });
272
273 // To prove ensure it's not a fluke, change the currency
275 {
276 analysis_profile = Samples.AnalysisProfile.AsReference,
277 layer = new Nested
278 {
279 sink = new QuotaShare { event_limit = new MonetaryUnit(1, "EUR") }.ToReference()
280 }
281 };
282 // Predict the target currency using the "TargetCurrencyDefault" attribute.
284 POST_ThenDoAction(test2, fromServer =>
285 {
286 // Assert that the currency and prediction are now both "EUR"
287 Assert.AreEqual("EUR", fromServer.target_currency);
288 Assert.AreEqual("EUR", predicted2);
289 });
290 }
291
292 #endregion Overidden Tests
293
294 #region Additional LayerView Nested Layer Type Tests
295
296 [TestMethod, TestCategory(TypeName)]
298 {
299 Test_LayerView_Nested_POST_EverySinkAndSourceType(false);
300 }
301
302 [TestMethod, TestCategory(TypeName)]
304 {
305 Test_LayerView_Nested_POST_EverySinkAndSourceType(true);
306 }
307
308 // Helper method to run two nearly identical tests.
309 private void Test_LayerView_Nested_POST_EverySinkAndSourceType(bool useInlinedObjects)
310 {
311 // Loop over each layer type, generate and test POST a testResource with it.
313 {
314 // If the current choice of sinkLayer isn't saveable, and we're testing layer references,
315 // we must skip this type, because layers are not saveable.
316 if (sinkLayer.UnderlyingType.IsAttributeDefinedFast<NotSaveableAttribute>())
317 {
318 Console.WriteLine("Skipping sink layer reference test of un-saveable layer type " +
319 sinkLayer.UnderlyingType.NiceTypeName());
320 continue;
321 }
322
323 // Change source description so it can be distinguished from the identical source.
324 ILayer current = sinkLayer.Unposted;
325 current.id = null;
326 current.description = "Sink";
327 // Create a new LayerView for testing from a new nested layer containing the
328 // current sink type, and all source types, using the configured inlining option.
330
332 Samples.AllLayerTypesTestList : Samples.AllSaveableLayerTypesTestList;
335 POST_WithValue(lv => lv.layer, nestedSink.Unposted, true);
336 }
337 }
338
339 [TestMethod, TestCategory(TypeName)]
341 {
342 // Loop over each layer type, generate a layer_view for it, and test referencing
343 // that layer_view in a Nested layer_view layer definition.
345 .ValidSinkLayerTypesTestList.Select(layer => Samples.GetInjectableLayerView(layer)))
346 {
347 // Try this layer_view reference as a sink, and all layer_views as the sources
350 }
351 }
352
353 [TestMethod, TestCategory(TypeName)]
355 {
356 Nested testLayer = TestResource.layer;
357 // Test invalid types as layer references
359 {
360 // Test invalid types as layer references
361 POST_WithValue(lv => lv.layer, testLayer.ShallowCopy().Change(l => l.sink,
362 layer.AsReference), false);
363 // Test invalid types as inlined layer definitions
364 POST_WithValue(lv => lv.layer, testLayer.ShallowCopy().Change(l => l.sink,
365 layer.AsInlinedReference), false);
366 // Test invalid types as layer_view references
367 POST_WithValue(lv => lv.layer, testLayer.ShallowCopy().Change(l => l.sink,
368 Samples.GetInjectableLayerView(layer).AsReference), false);
369 }
370 }
371
372 // Test what happens when a LayerView contains an inlined nested layer whose sink also
373 // contains an inlined nested layer.
374 [TestMethod, TestCategory(TypeName)]
376 {
377 // An inlined nested layer within the sink of an inlined nested layer.
380 new List<IInjectableResource<ILayer>> { Samples.Layer_CatXL }, true),
381 new List<IInjectableResource<ILayer>> { Samples.Layer_QuotaShare }, true);
382 POST_WithValue(lv => lv.layer, nested.Unposted, true);
383 }
384
385 // Test what happens when a LayerView contains an inlined nested layer whose source also
386 // contains an inlined nested layer.
387 [TestMethod, TestCategory(TypeName)]
389 {
390 // An inlined nested layer within the source of an inlined nested layer.
393 {
394 Samples.GetInjectableNestedLayer(Samples.Layer_AggXL,
395 new List<IInjectableResource<ILayer>> { Samples.Layer_CatXL }, true)
396 }, true);
397 POST_WithValue(lv => lv.layer, nested.Unposted, true);
398 }
399
400 [TestMethod, TestCategory(TypeName)]
402 {
403 // The source and sink layers must all use loss_sets with the same loss_type (for now)
405 layerNetAggDefinition.loss_sets =
406 new List<IReference<LossSet>> { Samples.LossSet_YLTLossSet.AsReference };
409 new List<IInjectableResource<ILayer>> { layerNetAgg }, true);
410 // Any LossSet fed into a nested layer source should have no impact on the view's
411 // ability to return metrics at gross perspectives, since the Nested Layer sources are
412 // treated as gross loss sources when feeding into the sink layer.
413 POST_ThenDoAction(Samples.GetInjectableLayerView(nested).Unposted,
414 posted => Test_IAPIResourceView_Metrics_MixedLossTypes(posted, Perspective.LossGross));
415 }
416
417 [TestMethod, TestCategory(TypeName)]
419 {
420 // Use an inlined sink, and three sources, one inlined layer, one layer reference,
421 // and one layer_view reference.
422 POST_WithValue(lv => lv.layer, new Nested
423 {
424 description = "Nested layer with mixed reference types",
425 sink = Samples.Layer_CatXL.Unposted.ToReference(),
426 sources = new Nested.Sources(
427 Samples.Layer_AggXL.Posted.ToReference(),
428 Samples.Layer_Generic.Unposted.ToReference(),
429 Samples.LayerView_Nested.Posted.ToReference())
430 }, true);
431 }
432
433 [TestMethod, TestCategory(TypeName)]
435 {
438 // The sink layer_view references a different analysis profile from the root layer_view
439 GenericTest.POST_InvalidResource_Fails(Samples.GetInjectableLayerView(
441 Samples.GetInjectableLayerView(Samples.Layer_CatXL, ap2),
443 }
444
445 #endregion Additional LayerView Nested Layer Type Tests
446 }
447
448 [TestClass]
449 public sealed class TestSuite_LayerView_ValueAllocator : TestSuite_LayerView<ValueAllocator>
450 {
451 #region Set Up and Configuration
452
453 private const string TypeName = "LayerView<ValueAllocator>";
454
455 protected override IInjectableResource<ILayerView<ValueAllocator>> TestInjectableResource =>
457
458 #endregion Set Up and Configuration
459
460 #region Overidden Tests
461
462 [TestMethod, TestCategory(TypeName)]
464 {
465 // Demonstrate that the target currency comes from the source layer
467 {
468 analysis_profile = Samples.AnalysisProfile.AsReference,
469 layer = Samples.Layer_ValueAllocator.Unposted.Change(l => l.source,
470 new QuotaShare { event_limit = new MonetaryUnit(1, "CAD") }.ToReference())
471 };
472 // Predict the target currency using the "TargetCurrencyDefault" attribute.
474 POST_ThenDoAction(testValueAllocatorLayerView, fromServer =>
475 {
476 // Assert that the currency and prediction are both "CAD"
477 Assert.AreEqual("CAD", fromServer.target_currency);
478 Assert.AreEqual("CAD", predicted);
479 });
480
481 // To prove ensure it's not a fluke, change the currency
483 {
484 analysis_profile = Samples.AnalysisProfile.AsReference,
485 layer = Samples.Layer_ValueAllocator.Unposted.Change(l => l.source,
486 new QuotaShare { event_limit = new MonetaryUnit(1, "EUR") }.ToReference())
487 };
488 // Predict the target currency using the "TargetCurrencyDefault" attribute.
490 POST_ThenDoAction(test2, fromServer =>
491 {
492 // Assert that the currency and prediction are now both "EUR"
493 Assert.AreEqual("EUR", fromServer.target_currency);
494 Assert.AreEqual("EUR", predicted2);
495 });
496 }
497
498 #endregion Overidden Tests
499
500 #region Additional LayerView ValueAllocator Layer Type Tests
501
505 [TestMethod, TestCategory(TypeName)]
507 {
508 // Loop over each layer type, generate and test POST a testResource with it.
510 {
511 // Test using inlined layer definitions
512 IReference<ILayer> asInlinedLayer = layer.AsInlinedReference;
514 .Change(va => va.source, asInlinedLayer)
515 .Change(va => va.target, asInlinedLayer)
516 .Change(va => va.group, asInlinedLayer), true);
517
518 // Test again using referenced layers (only if layer type is saveable)
519 if (!layer.UnderlyingType.IsAttributeDefinedFast<NotSaveableAttribute>())
520 {
521 IReference<ILayer> asLayerRef = layer.AsReference;
523 .Change(va => va.source, asLayerRef)
524 .Change(va => va.target, asLayerRef)
525 .Change(va => va.group, asLayerRef), true);
526 }
527
528 // Test once more using referenced layer_views
530 Samples.GetInjectableLayerView(layer).AsReference;
532 .Change(va => va.source, asLayerViewRef)
533 .Change(va => va.target, asLayerViewRef)
534 .Change(va => va.group, asLayerViewRef), true);
535 }
536 }
537
540 [TestMethod, TestCategory(TypeName)]
542 {
543 // The sink layer_view references a different analysis profile from the root layer_view
544 GenericTest.POST_InvalidResource_Fails(Samples.GetInjectableLayerView(
545 Samples.Layer_ValueAllocator.Unposted.Change(va => va.source,
546 Samples.GetInjectableLayerView(Samples.Layer_CatXL, Samples.AnalysisProfile).AsReference),
548 }
549
550 #endregion Additional LayerView ValueAllocator Layer Type Tests
551 }
552
553 [TestClass]
554 public sealed class TestSuite_LayerView_BackAllocatedLayer : TestSuite_LayerView<BackAllocatedLayer>
555 {
556 #region Set Up and Configuration
557
558 private const string TypeName = "LayerView<BackAllocatedLayer>";
559
560 protected override IInjectableResource<ILayerView<BackAllocatedLayer>> TestInjectableResource =>
562
563 #endregion Set Up and Configuration
564
565 #region Overidden Tests
566
567 [TestMethod, TestCategory(TypeName)]
569 {
571 // Demonstrate that the target currency comes from the sink layer
573 {
574 analysis_profile = Samples.AnalysisProfile.AsReference,
575 layer = original.Change(l => l.sink, new QuotaShare
576 {
577 event_limit = new MonetaryUnit(1, "CAD"),
578 loss_sets = new List<IReference<LossSet>> { Samples.LossSet_ELTLossSet.AsReference }
579 }.ToReference())
580 };
581 // Predict the target currency using the "TargetCurrencyDefault" attribute.
583 POST_ThenDoAction(testBackAllocatedLayerLayerView, fromServer =>
584 {
585 // Assert that the currency and prediction are both "CAD"
586 Assert.AreEqual("CAD", fromServer.target_currency);
587 Assert.AreEqual("CAD", predicted);
588 });
589
590 // To prove ensure it's not a fluke, change the currency
592 {
593 analysis_profile = Samples.AnalysisProfile.AsReference,
594 layer = original.Change(l => l.sink, new QuotaShare
595 {
596 event_limit = new MonetaryUnit(1, "EUR"),
597 loss_sets = new List<IReference<LossSet>> { Samples.LossSet_ELTLossSet.AsReference }
598 }.ToReference())
599 };
600 // Predict the target currency using the "TargetCurrencyDefault" attribute.
602 POST_ThenDoAction(test2, fromServer =>
603 {
604 // Assert that the currency and prediction are now both "EUR"
605 Assert.AreEqual("EUR", fromServer.target_currency);
606 Assert.AreEqual("EUR", predicted2);
607 });
608 }
609
610 #endregion Overidden Tests
611
612 #region Additional LayerView BackAllocatedLayer Layer Type Tests
613
617 [TestMethod, TestCategory(TypeName)]
619 {
620 // Loop over each layer type, generate and test POST a testResource with it.
622 {
624 .UnsupportedBackAllocatedLayerSinkTypes.Contains(layer.UnderlyingType);
625
626 // TODO: ARE-7212 - Remove once fixed and these are returning the right error
627 if (!isSupportedType && (TestSuite_Layer_Base.PaymentPatternTypes.Contains(layer.UnderlyingType)))
628 {
629 Console.WriteLine($"Skipping tests for type {layer.UnderlyingType} until ARE-7212");
630 continue; // Skip.Indefinitely("ARE-7212");
631 }
632
633 // Test using inlined layer definitions
634 IReference<ILayer> asInlinedLayer = layer.AsInlinedReference;
636 .Change(ba => ba.sink, asInlinedLayer), isSupportedType);
637
638 // Test again using referenced layers (only if layer type is saveable)
639 if (!layer.UnderlyingType.IsAttributeDefinedFast<NotSaveableAttribute>())
640 {
641 IReference<ILayer> asLayerRef = layer.AsReference;
643 .Change(ba => ba.sink, asLayerRef), isSupportedType);
644 }
645
646 // Test once more using referenced layer_views
648 Samples.GetInjectableLayerView(layer).AsReference;
650 .Change(ba => ba.sink, asLayerViewRef), isSupportedType);
651 }
652 }
653
656 [TestMethod, TestCategory(TypeName)]
658 {
659 // The sink layer_view references a different analysis profile from the root layer_view
660 GenericTest.POST_InvalidResource_Fails(Samples.GetInjectableLayerView(
662 Samples.GetInjectableLayerView(Samples.Layer_Nested, Samples.AnalysisProfile).AsReference),
664 }
665
666 [TestMethod, TestCategory(TypeName)]
667 [Obsolete("This tests a now obsolete class (NestedLayerLossSet) for backwards compatibility purposes.")]
669 {
670 // Test Bug ARE-6437 which found that the NestedLayerLossSet ids cannot be used as the source_id
672 ILayerView sink = Samples.GetInjectableLayerView(Samples.Layer_CatXL.Unposted
673 .Change(l => l.loss_sets, new List<IReference<LossSet>> { nlls.ToReference() })).Posted;
674 // This should work (back-allocate to loss set id) but may fail due to ARE-6437.
675 GenericTest.POST_ValidResource(Samples.GetInjectableLayerView(new BackAllocatedLayer
676 {
677 sink = sink.ToReference(),
678 source_id = nlls.id,
679 }).Unposted);
680 }
681
682 [TestMethod, TestCategory(TypeName)]
684 {
685 // Test Bug ARE-6439 which found that the target_currency broke the ability to find the sink.
687 // For this to work, we should be sure that the sink layer_view has its own target currency
688 Assert.AreNotEqual("EUR", sink.target_currency);
689 // This should work (back-allocate to self) but may fail due to ARE-6439.
690 GenericTest.POST_ValidResource(Samples.GetInjectableLayerView(new BackAllocatedLayer
691 {
692 sink = sink.ToReference(),
693 source_id = sink.id,
694 }, Samples.AnalysisProfile, "EUR").Unposted);
695 }
696
697 #endregion Additional LayerView BackAllocatedLayer Layer Type Tests
698 }
699
700 [TestClass]
702 {
703 #region Set Up and Configuration
704
705 private const string TypeName = "LayerView<Filter>";
706
707 protected override IInjectableResource<ILayerView<Filter>> TestInjectableResource =>
709
710 #endregion Set Up and Configuration
711
712 #region Additional LayerView Filter Layer Type Tests
713
714 [TestMethod, TestCategory(TypeName)]
716 {
717 POST_ThenDoAction(TestResource, filteredLayerView =>
718 {
720 double? filtered_el = null, original_el = null, inverted_el = null;
721
722 try
723 {
724 // Verify we can get metrics.
725 filtered_el = filteredLayerView.tail_metrics_blocking(1,
726 MetricsOptions.Default, SimulationPolling).mean;
727
728 // Verify these are different from the loss_set's unfiltered EL
729 Filter unfiltered = filteredLayerView.layer.DeepCopy();
730 // Empty filters and invert to include all losses.
731 unfiltered.filters.Clear();
732 unfiltered.invert = true;
734 unfiltered, filteredLayerView.analysis_profile, filteredLayerView.target_currency).Post();
735 original_el = unfilteredLayerView.tail_metrics_blocking(1,
736 MetricsOptions.Default, SimulationPolling).mean;
737
738 // Now verify that the inverted filter makes up the difference.
739 Filter inverted = filteredLayerView.layer.DeepCopy();
740 inverted.invert = !inverted.invert;
742 inverted, filteredLayerView.analysis_profile, filteredLayerView.target_currency).Post();
743 inverted_el = invertedLayerView.tail_metrics_blocking(1,
744 MetricsOptions.Default, SimulationPolling).mean;
745
746 // Assert that the filtered ELs are less than the original EL
747 Assert.AreNotEqual(filtered_el, original_el, "Expected a reduced EL.");
748 Assert.AreNotEqual(0d, filtered_el, "This test assumes a filter has been set up " +
749 "that reduces losses but not to 0.");
750 Assert.AreNotEqual(inverted_el, original_el, "Expected a reduced EL.");
751
752 // The next assertion requires the test data such that the filtered losses
753 // aren't exactly half the unfiltered losses, otherwise we can't check that
754 // the invert flag works.
755 Assert.IsFalse(AssertApi.AlmostEquals(filtered_el.Value, original_el.Value / 2d),
756 "The filtered EL (" + filtered_el + ") is exactly half of the " +
757 "original unfiltered EL (" + original_el + "). This makes it " +
758 "impossible to assert that the inverted filter is working " +
759 "correctly. Please revise the test data or filter used to ensure " +
760 "it doesn't match exactly half of the total losses.");
761
762 // Check that the invert flag is working
763 Assert.AreNotEqual(inverted_el, filtered_el, "According to this test, " +
764 "the inverted filter returned the same EL as the original filter. " +
765 "This indicates that the 'invert' property is not working.");
766
767 // Finally assert that the filtered and unfiltered ELs sum to the original EL
769 "Expected filtered ELs to add up to the unfiltered EL.");
770 }
771 catch (Exception)
772 {
773 try
774 {
775 Console.WriteLine("\n\nAn error occurred. Dumping detailed logs.");
776 Console.WriteLine("Filtered EL is: " + filtered_el);
777 Console.WriteLine("Empty Filter (unfiltered) EL is: " + original_el);
778 Console.WriteLine("Inverted Filter EL is: " + inverted_el);
779
780 // Print the full layer_view definition
781 Console.WriteLine("\n\nFilter LayerView Definition:\n" +
782 filteredLayerView.Get_AsType<IRestResponse>().PrettyPrint());
783 Console.WriteLine("\nEmpty Filter Full Definition:\n" +
784 unfilteredLayerView.Get_AsType<IRestResponse>().PrettyPrint());
785 Console.WriteLine("\nInverted Filter Full Definition:\n" +
786 invertedLayerView.Get_AsType<IRestResponse>().PrettyPrint());
787
788 // And information about the resources they reference
789 Console.WriteLine("\n\nFilter Definition:\n" +
790 filteredLayerView.layer.filters.First().GetValue().Get_AsType<IRestResponse>().PrettyPrint());
791 Console.WriteLine("\nFull Loss Set Data:\n" +
792 (filteredLayerView.layer.loss_sets.First().GetValue() as IAPIResource_WithDataEndpoint).data.Get());
793 Console.WriteLine("\n\nAnalysis Profile Definition:\n" +
794 filteredLayerView.analysis_profile.GetValue().Get_AsType<IRestResponse>(
795 API.Parameters.ExpandReferences()).PrettyPrint());
796 Console.WriteLine("\nFull Catalog Data:\n" +
797 filteredLayerView.analysis_profile.GetValue().event_catalogs.First().GetValue().data.Get());
798 }
799 catch (Exception)
800 {
801 Console.WriteLine("\nAnother error occurred while dumping detailed logs.");
802 /* Regardless, we want to re-throw the original exception */
803 }
804 Console.WriteLine("\nRe-throwing original error.");
805 throw;
806 }
807 });
808 }
809
810 #endregion Additional LayerView Filter Layer Type Tests
811 }
812
813 [TestClass]
815 : TestSuite_LayerView<FixedRateCurrencyConverter>
816 {
817 #region Set Up and Configuration
818
819 private const string TypeName = "LayerView<FixedRateCurrencyConverter>";
820
823
825 TargetCurrencyProperty => l => l.out_currency;
826
827 #endregion Set Up and Configuration
828
830 [TestMethod, TestCategory(TypeName)]
832 {
834 Assert.Inconclusive("RUN_OFFLINE = true");
836 TailMetrics original_metrics = original.tail_metrics_blocking(1,
837 MetricsOptions.Default, SimulationPolling);
838 // Metrics are 100% - have to apply participation (Nested layer will do the same)
839 double original_mean = original_metrics.mean * original.layer.participation;
840 Console.WriteLine($"Original mean is: {original_mean} {original_metrics.context.currency}");
841
842 // We should be able to convert to any currency, since we supply the rate
843 string in_currency = original_metrics.context.currency;
844 string out_currency = "ZZZ";
845 double rate = 1000;
846 Console.WriteLine($"Rate is: {rate} {out_currency} to 1 {in_currency}");
847
848 // Put the source layer through the fixed rate currency converter
849 GenericTest.POST_ThenDoAction(LayerViews.Create(new Nested
850 {
851 sink = new FixedRateCurrencyConverter
852 {
853 in_currency = in_currency,
854 out_currency = out_currency,
855 rate = rate
856 }.ToReference(),
857 sources = new Nested.Sources(original.layer.ToReference())
858 }, original.analysis_profile, out_currency), converted =>
859 {
861 converted.tail_metrics_blocking(1, MetricsOptions.Default);
862 Console.WriteLine("Resulting mean is: " + converted_metrics.mean +
863 " " + converted_metrics.context.currency);
864
865 // Verify the metrics have the new currency, and the rate was applied
866 Assert.AreEqual(out_currency, converted.target_currency);
867 Assert.AreEqual(out_currency, converted_metrics.context.currency);
869 });
870 }
871 }
872
873 [TestClass]
874 public sealed class TestSuite_LayerView_LossRank : TestSuite_LayerView<LossRank>
875 {
876 #region Set Up and Configuration
877
878 private const string TypeName = "LayerView<LossRank>";
879
880 protected override IInjectableResource<ILayerView<LossRank>> TestInjectableResource =>
882
883 #endregion Set Up and Configuration
884 }
885
886 [TestClass]
887 public sealed class TestSuite_LayerView_NoClaimsBonus : TestSuite_LayerView<NoClaimsBonus>
888 {
889 #region Set Up and Configuration
890
891 private const string TypeName = "LayerView<NoClaimsBonus>";
892
893 protected override IInjectableResource<ILayerView<NoClaimsBonus>> TestInjectableResource =>
895
896 protected override Expression<Func<NoClaimsBonus, object>> TargetCurrencyProperty =>
897 l => l.payout_amount;
898
899 #endregion Set Up and Configuration
900
901 #region Overidden Tests
902
903 [TestMethod, TestCategory(TypeName), Obsolete("Tests the legacy back_allocations endpoint")]
905 {
906 Skip.Indefinitely("ARE-4335 - Back Allocation of NoClaimsBonus with ELT Loss Set Results in Error");
907
908 base.Test_IAPIResourceView_GET_BackAllocations_Self();
909 }
910
911 #endregion Overidden Tests
912 }
913
914 [TestClass]
915 public sealed class TestSuite_LayerView_DelayedPayment : TestSuite_LayerView<DelayedPayment>
916 {
917 #region Set Up and Configuration
918
919 private const string TypeName = "LayerView<DelayedPayment>";
920
921 protected override IInjectableResource<ILayerView<DelayedPayment>> TestInjectableResource =>
923
924 #endregion Set Up and Configuration
925 }
926
927 [TestClass]
928 public sealed class TestSuite_LayerView_FixedDatePayment : TestSuite_LayerView<FixedDatePayment>
929 {
930 #region Set Up and Configuration
931
932 private const string TypeName = "LayerView<FixedDatePayment>";
933
934 protected override IInjectableResource<ILayerView<FixedDatePayment>> TestInjectableResource =>
936
937 #endregion Set Up and Configuration
938 }
939
940 #endregion Instantiable LayerView Types Tests
941
942 #region Abstract Base LayerView Tests
943
944 [TestClass]
945 public abstract class TestSuite_LayerView<T> : TestSuite_APIResourceView<ILayerView<T>>
946 where T : ILayer
947 {
948 #region Set Up and Configuration
949
950 private const string TypeName = "LayerView";
951
952 #endregion Set Up and Configuration
953
957 protected virtual Expression<Func<T, object>> TargetCurrencyProperty => null;
958
959 [TestMethod, TestCategory(TypeName)]
961 {
962 ILayerView<T> modifiedResource = TestResource;
963 if (!(modifiedResource.layer is ILayer_WithLossSets layer))
964 return; //Test does not apply when layer type isn't an ILayer_WithLossSets
965
966 layer.loss_sets = Samples.AllLossSetTypesTestList.Select(ls => ls.AsReference).ToList();
967 POST_ThenDoAction(modifiedResource, posted =>
968 Test_IAPIResourceView_Metrics_MixedLossTypes(posted, Perspective.LossGross));
969 }
970
973 [TestMethod, TestCategory(TypeName)]
975 {
976 // If the inheiting method hasn't overriden this test or specified the TargetCurrencyProperty,
977 // Proceed under the assumption that associated Analysis Profile is responsible.
978 if (TargetCurrencyProperty == null)
979 {
980 AssertTargetCurrencyMatchesAnalysisProfile();
981 return;
982 }
983
984 string targetPropertyName = ReflectionUtilities.GetMemberInfo(TargetCurrencyProperty).Name;
985 PropertyInfo[] monetaryUnitProperties = typeof(T).GetUserFacingProperties(true, true)
986 .Where(pi => pi.PropertyType == typeof(MonetaryUnit)).ToArray();
987 PropertyInfo[] stringProperties = typeof(T).GetUserFacingProperties(true, true)
988 .Where(pi => pi.PropertyType == typeof(string)).ToArray();
989
990 // First make sure all monetaryUnits are set to a single currency
991 ILayerView<T> allUSD = TestResource;
992 allUSD.target_currency = null;
994 monetaryUnit.SetValue(allUSD.layer, new MonetaryUnit(1, "USD"));
995 // Set all strings to this too, in case one of those strings impact currency
997 stringProperty.SetValue(allUSD.layer, "USD");
998
999 // Post this all-USD layer and ensure the target currency is USD:
1000 POST_ThenDoAction(allUSD, postResult =>
1001 {
1002 Assert.AreEqual("USD", postResult.target_currency, "Expected a target currency of USD");
1003 // Now change each property one at a time and assert that only
1004 // the expected property affects the target currency of the layer.
1006 {
1007 // Make a copy of the layer_view and its layer, and unset target currency.
1008 ILayerView modified = postResult.ShallowCopy();
1009 modified.layer = modified.layer.ShallowCopy();
1010 modified.target_currency = null;
1011
1012 bool is_monetary_unit = typeof(MonetaryUnit).IsAssignableFrom(property.PropertyType);
1013 property.SetValue(modified.layer, is_monetary_unit ? new MonetaryUnit(1, "CAD") : (object)"CAD");
1014 // Predict the target currency using the "TargetCurrencyDefault" attribute.
1016 GenericTest.POST_ThenDoAction(modified, modifiedResult =>
1017 {
1018 if (property.Name == targetPropertyName)
1019 Assert.AreEqual("CAD", modifiedResult.target_currency, "Expected changing the " +
1020 targetPropertyName + " currency to change the target currency.");
1021 else
1022 Assert.AreEqual("USD", modifiedResult.target_currency, "Expected the " +
1023 property.Name + " currency to have no impact on the target currency.");
1024 // Check that the predicted currency matched the resulting currency
1025 Assert.AreEqual(modifiedResult.target_currency, predicted,
1026 "The TargetCurrencyDefault attribute failed to predict the correct currency");
1027 });
1028 }
1029 });
1030 }
1031
1033 private void AssertTargetCurrencyMatchesAnalysisProfile()
1034 {
1036 Assert.Inconclusive("RUN_OFFLINE = true");
1037 // Test that the target currency matches the analysis profile
1038 string expected_currency = Reflection.Resolve(Reflection.Resolve(Reflection.Resolve(
1039 TestResource.analysis_profile).exchange_rate_profile).exchange_rate_table).base_currency;
1040 Assert.AreEqual(expected_currency, TestResource_Existing.target_currency);
1041 // Also check that the correct target currency was predicted by our TargetCurrencyDefault attribute
1043
1044 // Show that if we use a new analysis profile with a different base currency, the target_currency changes.
1045 // Pick CAD as the new currency (unless it was the original, then pick EUR)
1046 string newCCY = expected_currency == "CAD" ? "EUR" : "CAD";
1047 AnalysisProfile newProfile = Samples.AnalysisProfile_OneFilter.Unposted
1048 .Change(ap => ap.exchange_rate_profile, Samples.ExchangeRateProfile.Unposted
1049 .Change(ep => ep.exchange_rate_table, Samples.ExchangeRateTable.Unposted
1050 .Change(fx => fx.base_currency, newCCY).Post(Samples.CSV.Exchange_Rate_Table
1051 // Change the CSV data to swap the old target_currency for the new one
1052 .Replace(newCCY, expected_currency)).PollUntilReady(Samples.DataPollingOptions).ToReference())
1053 .Post().ToReference())
1054 .Post().PollUntilReady(Samples.DataPollingOptions);
1055 ILayerView layerView = LayerViews.Create(TestResource.layer, newProfile);
1056 // Check that the correct target currency is predicted by our TargetCurrencyDefault attribute
1058 // Post the new layerView and check that the expected target_currency is set by the server
1059 Assert.AreEqual(newCCY, layerView.Post().target_currency);
1060 }
1061
1065 [TestMethod, TestCategory(TypeName)]
1067 {
1068 bool expect_error = true;
1069 ILayerView<T> modifiedResource = TestResource;
1070
1071 // If this layer has a participation, we will set it to zero
1072 if (modifiedResource.layer is ILayer_WithTerms layer)
1073 {
1074 if (layer is SurplusShare surplusShare)
1075 surplusShare.number_of_lines = 0;
1076 else
1077 layer.participation = 0.0;
1078 }
1079 else
1080 // Layers that do not have participation
1081 expect_error = false;
1082
1083 double threshold = 1.0;
1085 new ExceedanceProbabilityOptions(threshold_includes_participation: true);
1086
1087 if (expect_error)
1088 POST_ThenDoAction(modifiedResource, view => AssertApi.ExceptionThrown(
1089 () => _ = view.exceedance_probability_blocking(threshold, options, SimulationPolling),
1091 else
1092 // We expect this to succeed with the unmodified layer
1093 Test_IAPIResourceView_GET_ExceedanceProbability_Succeeds(threshold, options);
1094 }
1095
1096 [TestMethod, TestCategory(TypeName), Obsolete("Tests the legacy back_allocations endpoint")]
1098 {
1100 {
1101 Skip.Indefinitely("ARE-7212: BackAllocating Payment Patterns cause Internal Server Errors");
1103 view => view.back_allocations_blocking(view.id, SimulationPolling),
1105 }
1106 else
1107 base.Test_IAPIResourceView_GET_BackAllocations_Self();
1108 }
1109
1110 [TestMethod, TestCategory(TypeName), Obsolete("Tests the legacy back_allocations endpoint")]
1112 {
1114 Skip.Indefinitely("ARE-7212: BackAllocating Payment Patterns cause Internal Server Errors");
1115 base.Test_IAPIResourceView_GET_BackAllocations_SourceID_Invalid();
1116 }
1117 }
1118
1119 #endregion Abstract Base LayerView Tests
1120
1121}
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.
Exposes the various sample CSV files as strings.
Definition Samples.CSV.cs:9
static string Exchange_Rate_Table
Exposes sample resource objects, with built-in methods for injecting dependencies.
Definition Samples.cs:14
IInjectableResource< ILayerView< FixedDatePayment > > LayerView_FixedDatePayment
static readonly PollingOptions DataPollingOptions
Polling options to use when uploading a data file.
List< IInjectableResource< ILayerView > > AllLayerViewTypesTestList
A list of one of each type of layer.
IInjectableResource< YELTLossSet > LossSet_YELTLossSet
IInjectableResource< Nested > Layer_Nested
A simple nested layer retaining a CatXL source's losses to an AggXL sink.
IInjectableResource< ILayerView< DelayedPayment > > LayerView_DelayedPayment
IInjectableResource< ILayerView< Generic > > LayerView_Generic
IInjectableResource< ILayerView< AggXL > > LayerView_AggXL
IInjectableResource< ILayerView< BackAllocatedLayer > > LayerView_BackAllocatedLayer
IInjectableResource< AggXL > Layer_AggXL
IInjectableResource< ILayerView< Nested > > LayerView_Nested
IInjectableResource< ILayerView< QuotaShare > > LayerView_QuotaShare
IInjectableResource< ILayerView< FixedRateCurrencyConverter > > LayerView_FixedRateCurrencyConverter
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< ExchangeRateProfile > ExchangeRateProfile
IInjectableResource< ILayerView< NoClaimsBonus > > LayerView_NoClaimsBonus
IInjectableResource< AnalysisProfile > AnalysisProfile
An analysis profile with one of each possible type of filter.
IInjectableResource< BackAllocatedLayer > Layer_BackAllocatedLayer
IInjectableResource< NestedLayerLossSet > LossSet_NestedLayerLossSet
A simple NestedLayerLossSet retaining a CatXL layer's losses.
IInjectableResource< ILayerView< Filter > > LayerView_Filter
IInjectableResource< ILayerView< LossRank > > LayerView_LossRank
IInjectableResource< ExchangeRateTable > ExchangeRateTable
IInjectableResource< ILayerView< SurplusShare > > LayerView_SurplusShare
IInjectableResource< ValueAllocator > Layer_ValueAllocator
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< Nested > GetInjectableNestedLayer(IInjectableResource< ILayerSource > sink, IEnumerable< IInjectableResource< ILayerSource > > sources, bool inline=false)
Factory for producing injectable NestedLayers using a POSTable injectable Layer for use in testing.
IInjectableResource< ILayerView< IndustryLossWarranty > > LayerView_IndustryLossWarranty
IInjectableResource< ILayerView< CatXL > > LayerView_CatXL
IInjectableResource< AnalysisProfile > AnalysisProfile_OneFilter
An analysis profile containing only an AnyFilter.
IInjectableResource< AnyFilter > LossFilter_AnyFilter
IInjectableResource< ILayerView< AggregateQuotaShare > > LayerView_AggregateQuotaShare
IInjectableResource< QuotaShare > Layer_QuotaShare
IInjectableResource< ILayerView< ValueAllocator > > LayerView_ValueAllocator
IInjectableResource< EventCatalog > EventCatalog
Contains static helper methods for testing IAPIResourceView instances.
static readonly PollingOptions SimulationPolling
Settings used to ensure simulation requests are retried frequently and timeout after a reasonable amo...
override IInjectableResource< ILayerView< AggXL > > TestInjectableResource
override Expression< Func< AggXL, object > > TargetCurrencyProperty
override Expression< Func< AggregateQuotaShare, object > > TargetCurrencyProperty
override IInjectableResource< ILayerView< AggregateQuotaShare > > TestInjectableResource
void Test_LayerView_BackAllocatedLayer_POST_EveryReferenceType()
Test what happens when a LayerView's BackAllocatedLayer layer definition has its sink property set to...
override void Test_LayerView_POST_TargetCurrencyDefault()
Check that the target currency is determined by the expected property for each layer type.
void Test_LayerView_BackAllocatedLayer_POST_MismatchedLayerViewAnalysisProfiles()
Test what happens when a LayerView's BackAllocatedLayer layer definition references another LayerView...
override void Test_Resource_PUT_BadlyFormed()
Bug ARE-6381: The server returns the wrong status on PUT when the id is malformed.
override IResourceCollection< ILayerView > collection_source
void Test_LayerView_LossSet_EventCatalog_Mismatch()
The API should forbid posting a layer_view containing a loss set whose event catalog doesn't match th...
override Expression< Func< CatXL, object > > TargetCurrencyProperty
override IInjectableResource< ILayerView< CatXL > > TestInjectableResource
void Test_LayerView_FixedRateCurrencyConverter_Results()
Demonstrate that the fixed rate is used for conversion.
override IInjectableResource< ILayerView< Generic > > TestInjectableResource
override Expression< Func< Generic, object > > TargetCurrencyProperty
override Expression< Func< IndustryLossWarranty, object > > TargetCurrencyProperty
override IInjectableResource< ILayerView< IndustryLossWarranty > > TestInjectableResource
override IInjectableResource< ILayerView< Nested > > TestInjectableResource
override void Test_LayerView_POST_TargetCurrencyDefault()
Check that the target currency is determined by the expected property for each layer type.
override IInjectableResource< ILayerView< QuotaShare > > TestInjectableResource
override Expression< Func< QuotaShare, object > > TargetCurrencyProperty
override IInjectableResource< ILayerView< SurplusShare > > TestInjectableResource
override Expression< Func< SurplusShare, object > > TargetCurrencyProperty
void Test_LayerView_ValueAllocator_POST_EveryReferenceType()
Test what happens when a LayerView's ValueAllocator layer definition has source, target,...
override void Test_LayerView_POST_TargetCurrencyDefault()
Check that the target currency is determined by the expected property for each layer type.
void Test_LayerView_ValueAllocator_POST_MismatchedLayerViewAnalysisProfiles()
Test what happens when a LayerView's ValueAllocator layer definition references another LayerView wit...
virtual void Test_LayerView_GET_ExceedanceProbability_Filter_ZeroParticipation()
virtual void Test_LayerView_POST_TargetCurrencyDefault()
Check that the target currency is determined by the expected property for each layer type.
static HashSet< Type > UnsupportedBackAllocatedLayerSinkTypes
Types that cannot be the sink of a Back-Allocated layer.
static IEnumerable< Type > PaymentPatternTypes
A list of "PaymentPattern" layer types for convenience (because they comes up in a lot of validation ...
Definition Test_Layer.cs:35
static IEnumerable< IInjectableResource< ILayer > > ForbiddenSinkLayerTypesTestList
A set of injectable test layers that are not valid to use as a sink.
static IEnumerable< IInjectableResource< ILayer > > ValidSinkLayerTypesTestList
A set of injectable test layers that are valid to use as a sink.
static bool AlmostEquals(double d1, double d2, double tolerance=DEFAULT_DOUBLE_EQUIVALENCE_TOLERANCE)
Determines if two doubles are equivalent within the specified tolerance.
Definition AssertApi.cs:622
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
Attribute used to define the default value assigned to the target_currency property by the server whe...
static string GetDefaultTargetCurrency(IAPIResource resource)
Determine what the default target currency will be based on the resource type and properties.
Describes a collection of resources which can be listed.
Parameters that can be added to your REST requests to access additional API features.
static RequestParameters ExpandReferences()
Can be added to your GET requests to recursively resolve resource references in the response....
API methods / requests made available to the user.
static readonly ResourceCollection< ILayerView > LayerViews
The collection of LayerViews on the server.
A configuration of resources used to simulate a layer or portfolio.
Indicates that while the current APIResource-derived class can be constructed and potentially inlined...
Representation of an event catalog. The event catalog may cover multiple region/perils,...
LayerView factory class.
Definition LayerViews.cs:9
Representation of an Aggregate Catastrophe Excess of Loss layer.
Definition AggXL.cs:8
Acts as a replacement for IAPIResourceView.back_allocations. Computes the proportion of some sink str...
Filter is like a layer whose 'terms' are to filter events out of the loss sources....
Definition Filter.cs:13
A wrapper for a List<T> of IReference<ILayerSource> references that simplifies the construction and u...
Definition Nested.cs:67
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 Surplus Share contract.
Representation of a Nested layer loss set, which represents any loss set whose losses are derived fro...
Optional parameters which can be specified for exceedance probability requests.
Optional parameters which can be specified for all metrics requests.
static new MetricsOptions Default
The default metrics request options used when none are specified.
The structure returned when requesting Tail Metrics for a view.
Representation of a monetary value with a currency.
The loss perspective determines what factors to include when computing a distribution.
static readonly Perspective LossGross
Construct a distribution from the structure's gross losses.
Represents the Analysis of a Portfolio.
Utilities that reflect on a type or property expression.
IReference< T > AsReference
A reference to the posted resource.
T Unposted
The unPOSTed resource definition.
T Posted
The posted resource, ready to be referenced.
string target_currency
The default currency results are returned in. If not specified, the server will automatically select ...
Describes an APIResource class that adds a "/data" sub-resource, since this functionality is common t...
Represents the Analysis of a Layer.
ILayer layer
The layer contained in this LayerView.
Definition ILayerView.cs:12
Abstract representation of a layer.
Definition ILayer.cs:7
Abstract representation of a layer with terms.
Abstract representation of a layer with terms.