diff --git a/LICENSE b/LICENSE.md similarity index 100% rename from LICENSE rename to LICENSE.md diff --git a/diffo.livemd b/diffo.livemd index ea00ec9..eeb61a2 100644 --- a/diffo.livemd +++ b/diffo.livemd @@ -3,7 +3,7 @@ ```elixir Mix.install( [ - {:diffo, path: "/Users/beanlanda/git/diffo"} + {:diffo, "~> 0.1"} ], consolidate_protocols: false ) @@ -21,11 +21,11 @@ In this livebook tutorial you will learn: * Installing Neo4j and Configuring Boltx * Implementing a Minimal Service * Adding Initial Parties and Places -* Advancing Service State * Defining Service Features and Characteristics -* Relating a Service with other Services and Resources * Setting Service Expectations * Resolving the Outstanding Service +* Advancing Service State +* Relating a Service with other Services and Resources ## Installing Neo4j and Configuring Boltx @@ -43,7 +43,7 @@ Update the configuration below as necessary and evaluate. config = [ uri: "bolt://localhost:7687", auth: [username: "neo4j", password: "password"], - user_agent: "ashNeo4jLivebook/1", + user_agent: "diffoLivebook/1", pool_size: 15, max_overflow: 3, prefix: :default, @@ -106,6 +106,7 @@ alias Diffo.Provider.Party alias Diffo.Provider.PartyRef alias Diffo.Provider.Place alias Diffo.Provider.PartyRef +alias Diffo.Uuid import Jason, only: [encode: 2] use Outstand ``` @@ -130,8 +131,8 @@ broadband_0001 = Provider.create_instance!(%{name: "broadband_0001", specified_b mobile_backup_0001 = Provider.create_instance!(%{name: "mobileBackup_0001", specified_by: mobile_backup_v2.id}) services = [broadband_0001, mobile_backup_0001] -esim_0001 = Provider.create_instance!(%{name: "esim_0001", specified_by: esim_v1.id}) -nbn_ethernet_0001 = Provider.create_instance!(%{name: "nbnEthernet_0001", specified_by: nbn_ethernet_v1.id}) +esim_0001 = Provider.create_instance!(%{name: "esim_0001", type: :resource, specified_by: esim_v1.id}) +nbn_ethernet_0001 = Provider.create_instance!(%{name: "nbnEthernet_0001", type: :resource, specified_by: nbn_ethernet_v1.id}) resources = [esim_0001, nbn_ethernet_0001] ``` @@ -197,8 +198,8 @@ Jason.encode!(z_end, pretty: true) |> IO.puts And we'll relate this place to our broadband service using a PlaceRef ```elixir -place_ref = Diffo.Provider.create_place_ref(%{instance_id: broadband_0001.id, role: :CustomerSite, place_id: z_end.id}) -Jason.encode!(z_end, pretty: true) |> IO.puts +z_end_place_ref = Diffo.Provider.create_place_ref(%{instance_id: broadband_0001.id, role: :CustomerSite, place_id: z_end.id}) +Jason.encode!(z_end_place_ref, pretty: true) |> IO.puts ``` Now we should be able to refresh the broadband service and see it's related parties and places. @@ -241,9 +242,103 @@ broadband_0001 |> Jason.encode!(pretty: true) |> IO.puts ``` +## Setting Service Expectations + +We will set service expectations as goals. These can be generic goals for a particular stage of a service lifecycle (feasiblityChecked for example), or could be specific to a particular instance. Expectations can be high level, representing consumer or provider intent, and also can be low level, such as to how the service should be composed, configured and operated. The low level expectations can be derived from a combination of intent, policy, current expectations and current actual. + +We can write this in elixir as: + + + +```elixir +expected = fun(intended, expected, actual) +``` + +We can construct expectations using the struct Ash generates for our resources. Expectations may include functions and/or concrete values. We need to maintain compatibility with our Ash Resource attribute types, which does limit our ability to validate/persist resources using Ash. + +We'll construct a simple set of expectations for a feasible service: + +```elixir +expected_specification = %{name: "broadband", major_version: 1} +expected_features = [%{name: :backup, isEnabled: true}, %{name: :deviceManagement, isEnabled: true}] +expected_characteristics = [ + %{name: :e2e}, + %{name: :technology, value: %{access: {&Outstand.one_of/2, [:nbnEthernet, :fixed4g, :fixed5g]}}} + ] +expected_places = [ + %{role: :AccessNNI}, + %{role: :CustomerSite, place: %{name: "locationId"}}, + %{role: :CustomerSite, place: %{name: "addressId"}}, + %{role: :ServingArea} +] +expected_parties = [%{role: :Provider}, %{role: :Reseller}, %{role: :SiteContact}] +expected_instance = %{ + id: &Uuid.expect_uuid4/1, + specification: expected_specification, + service_state: :feasibilityChecked, + service_operating_status: :feasible, + characteristics: expected_characteristics, + places: expected_places, + parties: expected_parties} + + +``` + +The reason we set expectations is so that we can check whether our expectations are met (or exceeded) by the actuality. Unmet expectations represent 'outstanding' work. We'll calculate outstanding by comparing our expected_instance with the (actual) broadband_0001 service from the database: + +```elixir +broadband_0001 = Diffo.Provider.get_instance_by_id!(broadband_0001.id) +broadband_0001 |> Jason.encode!(pretty: true) |> IO.puts +outstanding = expected_instance --- broadband_0001 +``` + +## Resolving the Outstanding Service + +We'll have a few things outstanding which we would normally find out during service qualification. We expect a technology Characteristic, a provider Party and some network Places relating to service hinterland and edge location. + +We recommend using outstanding to drive next task logic, so that the orchestration is directed by the difference engine. This could look like an address lookup (where we learn the provider) followed by a provider service qualification (where we learn the technology) and the related network places. + +```elixir +nbn = Provider.create_party!(%{id: :nbn, name: "NBNCo", referredType: :Organization}) +nbn_party_ref = Provider.create_party_ref!(%{instance_id: broadband_0001.id, party_id: nbn.id, role: :Provider}) +provider_z_end = Provider.create_place!(%{id: "LOC000000899353", name: "locationId", href: "place/nbnco/LOC000000899353",referredType: :GeographicAddress}) +provider_z_end_place_ref = Provider.create_place_ref!(%{instance_id: broadband_0001.id, role: :CustomerSite, place_id: provider_z_end.id}) +csa = Provider.create_place!(%{id: "CSA200000000685", name: "csaId", href: "place/nbnco/CSA200000000685", referredType: :GeographicLocation}) +csa_place_ref = Provider.create_place_ref!(%{instance_id: broadband_0001.id, role: :ServingArea, place_id: csa.id}) +poi = Provider.create_place!(%{id: "2CAR", name: "poiId", href: "place/nbnco/2CAR",referredType: :GeographicSite}) +poi_place_ref = Provider.create_place_ref!(%{instance_id: broadband_0001.id, role: :AccessNNI, place_id: poi.id}) + +places = Diffo.Provider.list_place_refs!() +places |> Jason.encode!(pretty: true) |> IO.puts + + +``` + +This should have resolved the Parties and Places in the outstanding service: + +```elixir +broadband_0001 = Diffo.Provider.get_instance_by_id!(broadband_0001.id) +broadband_0001 |> Jason.encode!(pretty: true) |> IO.puts +outstanding = expected_instance --- broadband_0001 +``` + +We create and add the technology characteristic to the actual service. This should resolve the characteristic expectation. + +```elixir +technology = Provider.create_characteristic!(%{type: :instance, name: :technology, value: %{access: :nbnEthernet}}) +broadband_0001 |> Provider.relate_instance_characteristics!(%{characteristics: [technology.id]}) + + +broadband_0001 = Diffo.Provider.get_instance_by_id!(broadband_0001.id) + +outstanding = expected_instance --- broadband_0001 +``` + +We simply need to advance the services state to end the feasiblity + ## Advancing Service State -TMF638 Services implement a service state and also have an operating status. We create an actual service in the initial state, however generally when we do so we have an intention of advancing it towards a target state, such as operational. We may or may not pass through interim states, like feasibilityChecked, inactive. We also may not reach the target state, due to error, business rule or cancellation. +TMF638 Services implement a service_state and also have an service_operating_status. The service we created earlier was in the :initial service state. Diffo uses the [AshStateMachine Extension](https://github.com/ash-project/ash_state_machine). By default we allow all TMF638 state transitions, but these are customisable by manipulating the Instance DSL. @@ -253,17 +348,22 @@ From active state we can deactivate, suspend or terminate the service From inactive or suspended state we can activate or terminate the service. No transitions are possible from terminated or cancelled. +Given that our feasibilityCheck above was complete we want to set the :feasibilityChecked service_state, and because it was successful we'll set the :feasible service_operating_status: + ```elixir -broadband_0001 = Provider.get_instance_by_id!(broadband_0001.id) +broadband_0001 = broadband_0001 |> Provider.feasibilityCheck_service!(%{service_operating_status: :feasible}) broadband_0001 |> Jason.encode!(pretty: true) |> IO.puts ``` +This should have resolved the last part of the outstanding service: + ```elixir -broadband_0001 = broadband_0001 |> Provider.feasibilityCheck_service!() -broadband_0001 |> Jason.encode!(pretty: true) |> IO.puts +broadband_0001 = Diffo.Provider.get_instance_by_id!(broadband_0001.id) + +outstanding = expected_instance --- broadband_0001 ``` -AshStateMachine will error on invalid transitions. +AshStateMachine will also error on invalid transitions. Lets try and terminate the feasibilityChecked service (this is not allowed, instead cancel) @@ -274,12 +374,14 @@ error ## Relating a Service with other Services and Resources -The power Diffo has to simply orchestration come through the relationships a parent Service has with other Services and Resources. We will relate the services and resource instances we made earlier with our broadband service. +The power Diffo has to simplify orchestration comes through combination of the outstanding protocol and the relationships a parent Service has with other Services and Resources. We will relate the services and resource instances we made earlier with our broadband service. This is done with a Relationship resource, which links the source and target Instances. Relationship with source_id are stored on the source in the forward_relationships[] and be listed in TMF service serviceRelationship[] or resourceRelationship[] json accordingly. Each Relationship may have an alias, which must be unique for the source Instance. Alias's are important for reasoning about a Relationship independently of the target id, which intially may not be known or may change over the life of the composite service. The targets of aliased Relationships are considered TMF service supportingService[] or supportingResource[] accordingly. +If we went on to activate our broadband service, we'd create/acquire child services and resources, then configure and manage them over the life of the service. Both the composition and the orchestration can be dynamic. + Let's create a 'parent->child' relationship of the broadband service to its mobileBackup service: ```elixir @@ -300,90 +402,41 @@ broadband_0001 = Provider.get_instance_by_id!(broadband_0001.id) broadband_0001 |> Jason.encode!(pretty: true) |> IO.puts ``` -## Setting Service Expectations - -We will set service expectations as goals. These can be generic goals for a particular stage of a service lifecycle (feasiblityChecked for example), or could be specific to a particular instance. Expectations can be high level, representing consumer or provider intent, and also can be low level, such as to how the service should be composed, configured and operated. The low level expectations can be derived from a combination of intent, policy, current expectations and current actual. - -We can write this in elixir as: - - - -```elixir -expected = fun(intended, expected, actual) -``` - -We can construct expectations using the struct Ash generates for our resources. Expectations may include functions and/or concrete values. We need to maintain compatibility with our Ash Resource attribute types, which does limit our ability to validate/persist resources using Ash. - -We'll construct a simple set of expectations for our service: +We'll now relate sim resource with the mobile backup service ```elixir -expected_specification = %{name: "broadband", major_version: 1} -expected_features = [%{name: :backup, isEnabled: true}, %{name: :deviceManagement, isEnabled: true}] -expected_characteristics = [ - %{name: :e2e}, - %{name: :technology, value: %{access: {&Outstand.one_of/2, [:nbnEthernet, :fixed4g, :fixed5g]}}} - ] -expected_places = [ - %{name: :addressId, role: :CustomerSite}, - %{name: :locationId, role: :CustomerSite}, - %{role: :AccessNNI}, - %{role: :ServingArea} -] -expected_parties = [%{role: :Provider}, %{role: :Reseller}, %{role: :SiteOwner}] -expected_instance = %{ - id: &Diffo.Util.uuid4?/1, - specification: expected_specification, - service_state: :feasibilityChecked, - service_operating_status: :feasible, - characteristics: expected_characteristics, - places: expected_places, - parties: expected_parties} - - - +relationship = Provider.create_relationship!(%{ + alias: :sim, + source_id: mobile_backup_0001.id, + target_id: esim_0001.id, + type: :isAssigned +}) +relationship |> Jason.encode!(pretty: true) |> IO.puts ``` -The reason we set expectations is so that we can check whether our expectations are met (or exceeded) by the actuality. Unmet expectations represent 'outstanding' work. We'll calculate outstanding by comparing our expected_instance with the (actual) broadband_0001 service from the database: +Now when we refresh the mobile_backup_0001 service it should have both a resourceRelationship[] and supportingResource[]: ```elixir -use Outstand -outstanding = expected_instance --- broadband_0001 +mobile_backup_0001 = Provider.get_instance_by_id!(mobile_backup_0001.id) +mobile_backup_0001 |> Jason.encode!(pretty: true) |> IO.puts ``` -## Resolving the Outstanding Service - -We'll have a few things outstanding which we would normally find out during service qualification. We expect a technology Characteristic, a provider Party and some network Places relating to service hinterland and edge location. - -We recommend using outstanding to drive next task logic, so that the orchestration is directed by the difference engine. This could look like an address lookup (where we learn the provider) followed by a provider service qualification (where we learn the technology) and the related network places. +We'll also add the nbnEthernet resource directly to the broadband service: ```elixir -nbn = Provider.create_party!(%{id: :nbn, name: "NBNCo", referredType: :Organization}) -provider = Provider.create_party_ref!(%{instance_id: broadband_0001.id, party_id: nbn.id, role: :Provider}) -provider_z_end = Provider.create_place!(%{id: "LOC000000899353", name: :locationId, href: "place/nbnco/LOC000000899353",referredType: :GeographicAddress}) -place_ref = Provider.create_place_ref(%{instance_id: broadband_0001.id, role: :CustomerSite, place_id: provider_z_end.id}) -csa = = Provider.create_place!(%{id: "CSA200000000685", name: :poiId, href: "place/nbnco/CSA200000000685",referredType: :GeographicLocation}) -place_ref = Provider.create_place_ref(%{instance_id: broadband_0001.id, role: :ServingArea, place_id: csa.id}) -poi = = Provider.create_place!(%{id: "2CAR", name: :poiId, href: "place/nbnco/2CAR",referredType: :GeographicSite}) -place_ref = Provider.create_place_ref(%{instance_id: broadband_0001.id, role: :AccessNNI, place_id: poi.id}) - - -``` - -This should have resolved the Parties and Places in the outstanding service: +relationship = Provider.create_relationship!(%{ + alias: :access, + source_id: broadband_0001.id, + target_id: nbn_ethernet_0001.id, + type: :isAssigned +}) +relationship |> Jason.encode!(pretty: true) |> IO.puts -```elixir -outstanding = expected_instance --- broadband_0001 ``` -As an exercise create the technology characteristic to resolve the outstanding service by meeting the expectation: - ```elixir -technology = Provider.create_characteristic!(%{name: :technology, value: %{access: :nbnEthernet}}) -Provider.relate_instance_characteristics!(%{characteristics: [technology.id]}) - -broadband_0001 = Diffo.Provider.get_instance_by_id!(broadband_0001.id) - -outstanding = expected_instance --- broadband_0001 +broadband_0001 = Provider.get_instance_by_id!(broadband_0001.id) +broadband_0001 |> Jason.encode!(pretty: true) |> IO.puts ``` ## What Next? diff --git a/lib/CHANGELOG.md b/lib/CHANGELOG.md new file mode 100644 index 0000000..e82d554 --- /dev/null +++ b/lib/CHANGELOG.md @@ -0,0 +1,12 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](Https://conventionalcommits.org) for commit guidelines. + + + +## [v0.1.0](https://github.com/diffo-dev/diffo/compare/v0.1.0...v0.1.0) (2025-08-10) + +### Features: +* initial version using Neo4j DataLayer + diff --git a/lib/diffo/provider.ex b/lib/diffo/provider.ex index c13809a..d6992f0 100644 --- a/lib/diffo/provider.ex +++ b/lib/diffo/provider.ex @@ -41,7 +41,7 @@ defmodule Diffo.Provider do define :activate_service, action: :activate define :suspend_service, action: :suspend define :terminate_service, action: :terminate - define :status_instance, action: :status + define :status_service, action: :status define :specify_instance, action: :specify define :relate_instance_features, action: :relate_features define :unrelate_instance_features, action: :unrelate_features diff --git a/lib/diffo/provider/resources/instance.ex b/lib/diffo/provider/resources/instance.ex index 1e70ba6..9ddafc3 100644 --- a/lib/diffo/provider/resources/instance.ex +++ b/lib/diffo/provider/resources/instance.ex @@ -176,26 +176,17 @@ defmodule Diffo.Provider.Instance do attribute :service_state, :atom do allow_nil? false - default :initial + default Diffo.Provider.Service.default_service_state() public? true - constraints one_of: [ - :initial, - :cancelled, - :feasibilityChecked, - :reserved, - :active, - :inactive, - :suspended, - :terminated - ] + constraints one_of: Diffo.Provider.Service.service_states() end attribute :service_operating_status, :atom do description "the service operating status, if this instance is a service" allow_nil? true public? true - default Diffo.Provider.Service.default_service_operating_status() + default nil constraints one_of: Diffo.Provider.Service.service_operating_statuses() end @@ -348,9 +339,18 @@ defmodule Diffo.Provider.Instance do update :feasibilityCheck do description "feasibilityChecks a service instance" require_atomic? false + accept [:service_operating_status] validate attribute_equals(:type, :service) change transition_state(:feasibilityChecked) - change set_attribute(:service_operating_status, :pending) + + validate argument_in(:service_operating_status, [ + nil, + :initial, + :pending, + :unknown, + :feasible, + :not_feasible + ]) end update :reserve do diff --git a/lib/diffo/provider/resources/party_ref.ex b/lib/diffo/provider/resources/party_ref.ex index d3a20d3..4daf6b4 100644 --- a/lib/diffo/provider/resources/party_ref.ex +++ b/lib/diffo/provider/resources/party_ref.ex @@ -130,7 +130,7 @@ defmodule Diffo.Provider.PartyRef do preparations do prepare build( load: [:party], - sort: [role: :asc] + sort: [role: :asc, inserted_at: :desc] ) end diff --git a/lib/diffo/provider/resources/place_ref.ex b/lib/diffo/provider/resources/place_ref.ex index 4fe628e..88dd7ce 100644 --- a/lib/diffo/provider/resources/place_ref.ex +++ b/lib/diffo/provider/resources/place_ref.ex @@ -118,7 +118,7 @@ defmodule Diffo.Provider.PlaceRef do preparations do prepare build( load: [:place], - sort: [role: :asc] + sort: [role: :asc, inserted_at: :desc] ) end diff --git a/lib/diffo/provider/service.ex b/lib/diffo/provider/service.ex index 06aec4f..a77148d 100644 --- a/lib/diffo/provider/service.ex +++ b/lib/diffo/provider/service.ex @@ -26,6 +26,8 @@ defmodule Diffo.Provider.Service do def service_operating_statuses() do [ :pending, + :feasible, + :not_feasible, :configured, :starting, :running, diff --git a/lib/diffo/util.ex b/lib/diffo/util.ex index 315cb38..eafe488 100644 --- a/lib/diffo/util.ex +++ b/lib/diffo/util.ex @@ -379,9 +379,9 @@ defmodule Diffo.Util do ## Examples iex> duration = Duration.new!(month: 1) iex> list = [duration: duration] - iex> result = Diffo.Util.extract_suppress(list, :duration, :month, :months) - iex> List.last(result) - {:months, 1} + iex> tl(Diffo.Util.extract_suppress(list, :duration, :month, :months)) + [months: 1] + """ def extract_suppress(list, tuple_key, map_key, new_tuple_key) when is_list(list) do tuple_value = get(list, tuple_key) diff --git a/mix.exs b/mix.exs index 62aab8e..6f2f380 100644 --- a/mix.exs +++ b/mix.exs @@ -1,31 +1,27 @@ defmodule Diffo.MixProject do + @moduledoc false use Mix.Project + @version "0.1.0" + @name "Diffo" + @description "TMF Service and Resource Manager with a difference" + @github_url "https://github.com/diffo-dev/diffo" + def project do [ app: :diffo, - version: "0.1.0", + version: @version, + name: @name, + description: @description, elixir: "~> 1.18", start_permanent: Mix.env() == :prod, + package: package(), deps: deps(), aliases: aliases(), elixirc_paths: elixirc_paths(Mix.env()), - name: "Diffo", source_url: "https://github.com/diffo-dev/diffo/", homepage_url: "http://diffo.dev/diffo/", - docs: [ - main: "Diffo.Provider", - before_closing_body_tag: fn - :html -> - """ - - - """ - - _ -> - "" - end - ] + docs: docs() ] end @@ -55,10 +51,34 @@ defmodule Diffo.MixProject do end end + def docs do + [ + homepage_url: @github_url, + source_url: @github_url, + source_ref: "v#{@version}", + main: "readme", + logo: "logos/diffo.jpg", + extras: [ + "README.md": [title: "Guide"], + "LICENSE.md": [title: "License"] + ] + ] + end + + defp package do + [ + name: :diffo, + licenses: ["MIT"], + files: ~w(lib .formatter.exs mix.exs README* LICENSE* documentation), + links: %{ + GitHub: @github_url + } + ] + end + # Run "mix help deps" to learn about dependencies. defp deps do [ - {:outstanding, "~> 0.2.3"}, {:ash_outstanding, "~> 0.2.1"}, {:ash_jason, "~> 2.0"}, {:ash_state_machine, "~> 0.2.7"}, diff --git a/mix.lock b/mix.lock index 56710d1..751a08b 100644 --- a/mix.lock +++ b/mix.lock @@ -14,7 +14,7 @@ "finch": {:hex, :finch, "0.20.0", "5330aefb6b010f424dcbbc4615d914e9e3deae40095e73ab0c1bb0968933cadf", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2658131a74d051aabfcba936093c903b8e89da9a1b63e430bee62045fa9b2ee2"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, - "igniter": {:hex, :igniter, "0.6.25", "e2774a4605c2bc9fc38f689232604aea0fc925c7966ae8e928fd9ea2fa9d300c", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "b1916e1e45796d5c371c7671305e81277231617eb58b1c120915aba237fbce6a"}, + "igniter": {:hex, :igniter, "0.6.26", "a6b4f6680a7e158bd13cd3b2be047102e42c046b3b240578d68d89d1a39a83fa", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "a4f8c404fc4cbc05a1b536c8125ae64909e3a02d5f972ffe6a3a2ebd75530f3c"}, "iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, diff --git a/test/provider/characteristic_test.exs b/test/provider/characteristic_test.exs index 68eb711..a3b1f79 100644 --- a/test/provider/characteristic_test.exs +++ b/test/provider/characteristic_test.exs @@ -214,13 +214,37 @@ defmodule Diffo.Provider.CharacteristicTest do @port_range %Diffo.Provider.Characteristic{name: "port", value: 1..4} gen_nothing_outstanding_test("specific nothing outstanding", @port1, @port1) - gen_result_outstanding_test("specific name and value result", @port1, nil, Ash.Test.strip_metadata(@port1)) - gen_result_outstanding_test("specific name result", @port1, @pair1, Ash.Test.strip_metadata(@name_only)) - gen_result_outstanding_test("specific value result", @port1, @port3, Ash.Test.strip_metadata(@value_only)) + + gen_result_outstanding_test( + "specific name and value result", + @port1, + nil, + Ash.Test.strip_metadata(@port1) + ) + + gen_result_outstanding_test( + "specific name result", + @port1, + @pair1, + Ash.Test.strip_metadata(@name_only) + ) + + gen_result_outstanding_test( + "specific value result", + @port1, + @port3, + Ash.Test.strip_metadata(@value_only) + ) gen_nothing_outstanding_test("port range nothing outstanding, port1", @port_range, @port1) gen_nothing_outstanding_test("port range nothing outstanding, port3", @port_range, @port3) - gen_result_outstanding_test("port range name result, pair1", @port_range, @pair1, Ash.Test.strip_metadata(@name_only)) + + gen_result_outstanding_test( + "port range name result, pair1", + @port_range, + @pair1, + Ash.Test.strip_metadata(@name_only) + ) gen_result_outstanding_test( "port range value result, port5", diff --git a/test/provider/entity_ref_test.exs b/test/provider/entity_ref_test.exs index c03d5e8..6ecd68a 100644 --- a/test/provider/entity_ref_test.exs +++ b/test/provider/entity_ref_test.exs @@ -443,7 +443,13 @@ defmodule Diffo.Provider.EntityRefTest do } gen_nothing_outstanding_test("specific nothing outstanding", @specific_cost, @actual_cost) - gen_result_outstanding_test("specific cost result", @specific_cost, nil, Ash.Test.strip_metadata(@specific_cost)) + + gen_result_outstanding_test( + "specific cost result", + @specific_cost, + nil, + Ash.Test.strip_metadata(@specific_cost) + ) gen_result_outstanding_test( "specific role result", diff --git a/test/provider/feature_test.exs b/test/provider/feature_test.exs index e9869a9..1af479f 100644 --- a/test/provider/feature_test.exs +++ b/test/provider/feature_test.exs @@ -181,29 +181,65 @@ defmodule Diffo.Provider.FeatureTest do describe "Diffo.Provider outstanding Features" do use Outstand - @dynamicLineManagementEnabled %Diffo.Provider.Feature{name: :dynamicLineManagement, isEnabled: true} - @dynamicLineManagementDisabled %Diffo.Provider.Feature{name: :dynamicLineManagement, isEnabled: false} - @dynamicLineManagementEnabledSpeed %Diffo.Provider.Feature{name: :dynamicLineManagement, isEnabled: false, characteristics: - [ + + @dynamicLineManagementEnabled %Diffo.Provider.Feature{ + name: :dynamicLineManagement, + isEnabled: true + } + @dynamicLineManagementDisabled %Diffo.Provider.Feature{ + name: :dynamicLineManagement, + isEnabled: false + } + @dynamicLineManagementEnabledSpeed %Diffo.Provider.Feature{ + name: :dynamicLineManagement, + isEnabled: false, + characteristics: [ %Diffo.Provider.Characteristic{name: :optimiseFor, value: :speed} - ]} + ] + } - @dynamicLineManagementEnabledStable %Diffo.Provider.Feature{name: :dynamicLineManagement, isEnabled: false, characteristics: - [ + @dynamicLineManagementEnabledStable %Diffo.Provider.Feature{ + name: :dynamicLineManagement, + isEnabled: false, + characteristics: [ %Diffo.Provider.Characteristic{name: :optimiseFor, value: :stable} - ]} + ] + } @name_only %Diffo.Provider.Feature{name: :dynamicLineManagement} @isEnabled_only %Diffo.Provider.Feature{isEnabled: true} @isDisabled_only %Diffo.Provider.Feature{isEnabled: false} - @speed_only %Diffo.Provider.Feature{characteristics: - [ + @speed_only %Diffo.Provider.Feature{ + characteristics: [ %Diffo.Provider.Characteristic{value: :speed} - ]} + ] + } + + gen_nothing_outstanding_test( + "specific nothing outstanding", + @dynamicLineManagementEnabled, + @dynamicLineManagementEnabled + ) + + gen_result_outstanding_test( + "specific name and isEnabled result", + @dynamicLineManagementEnabled, + nil, + Ash.Test.strip_metadata(@dynamicLineManagementEnabled) + ) - gen_nothing_outstanding_test("specific nothing outstanding", @dynamicLineManagementEnabled, @dynamicLineManagementEnabled) - gen_result_outstanding_test("specific name and isEnabled result", @dynamicLineManagementEnabled, nil, Ash.Test.strip_metadata(@dynamicLineManagementEnabled)) - gen_result_outstanding_test("specific name result", @dynamicLineManagementEnabled, @isEnabled_only, Ash.Test.strip_metadata(@name_only)) - gen_result_outstanding_test("specific isEnabled result", @dynamicLineManagementDisabled, @name_only, Ash.Test.strip_metadata(@isDisabled_only)) + gen_result_outstanding_test( + "specific name result", + @dynamicLineManagementEnabled, + @isEnabled_only, + Ash.Test.strip_metadata(@name_only) + ) + + gen_result_outstanding_test( + "specific isEnabled result", + @dynamicLineManagementDisabled, + @name_only, + Ash.Test.strip_metadata(@isDisabled_only) + ) gen_result_outstanding_test( "feature characteristic outstanding", diff --git a/test/provider/instance_test.exs b/test/provider/instance_test.exs index 4b2f6d1..82f400c 100644 --- a/test/provider/instance_test.exs +++ b/test/provider/instance_test.exs @@ -73,7 +73,7 @@ defmodule Diffo.Provider.InstanceTest do assert Diffo.Uuid.uuid4?(instance.id) == true assert instance.type == :service assert instance.service_state == :initial - assert instance.service_operating_status == :unknown + refute instance.service_operating_status assert instance.specification.id == specification.id assert instance.href == "serviceInventoryManagement/v4/service/fibreAccess/#{instance.id}" end @@ -92,7 +92,7 @@ defmodule Diffo.Provider.InstanceTest do assert instance.id == uuid assert instance.type == :service assert instance.service_state == :initial - assert instance.service_operating_status == :unknown + refute instance.service_operating_status assert instance.specification.id == specification.id assert instance.href == "serviceInventoryManagement/v4/service/fibreAccess/#{instance.id}" end @@ -278,7 +278,20 @@ defmodule Diffo.Provider.InstanceTest do |> Diffo.Provider.feasibilityCheck_service!() assert updated_instance.service_state == :feasibilityChecked - assert updated_instance.service_operating_status == :pending + assert updated_instance.service_operating_status == nil + refute updated_instance.started_at + refute updated_instance.stopped_at + end + + test "feasibilityCheck an initial service instance, feasible - success" do + specification = Diffo.Provider.create_specification!(%{name: "initialFeasibilityChecked"}) + + updated_instance = + Diffo.Provider.create_instance!(%{specified_by: specification.id}) + |> Diffo.Provider.feasibilityCheck_service!(%{service_operating_status: :feasible}) + + assert updated_instance.service_state == :feasibilityChecked + assert updated_instance.service_operating_status == :feasible refute updated_instance.started_at refute updated_instance.stopped_at end @@ -330,7 +343,7 @@ defmodule Diffo.Provider.InstanceTest do updated_instance = Diffo.Provider.create_instance!(%{specified_by: specification.id}) |> Diffo.Provider.activate_service!() - |> Diffo.Provider.status_instance!(%{service_operating_status: :running}) + |> Diffo.Provider.status_service!(%{service_operating_status: :running}) assert updated_instance.service_state == :active assert updated_instance.service_operating_status == :running @@ -359,6 +372,18 @@ defmodule Diffo.Provider.InstanceTest do {:error, _error} = instance |> Diffo.Provider.terminate_service() end + test "status a feasibilityChecked service feasible - success" do + specification = Diffo.Provider.create_specification!(%{name: "feasibilityCheckedFeasible"}) + + updated_instance = + Diffo.Provider.create_instance!(%{specified_by: specification.id}) + |> Diffo.Provider.feasibilityCheck_service!() + |> Diffo.Provider.status_service!(%{service_operating_status: :feasible}) + + assert updated_instance.service_state == :feasibilityChecked + assert updated_instance.service_operating_status == :feasible + end + test "update a service instance name - success" do specification = Diffo.Provider.create_specification!(%{name: "wifiAccess"}) @@ -705,13 +730,13 @@ defmodule Diffo.Provider.InstanceTest do parent_encoding = Jason.encode!(loaded_instance) |> Diffo.Util.summarise_dates() assert parent_encoding == - ~s({\"id\":\"#{parent_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/siteConnection/#{parent_instance.id}\",\"category\":\"connectivity\",\"description\":\"Site Connection Service\",\"externalIdentifier\":[{\"externalIdentifierType\":\"siteId\",\"id\":\"ANS020000023234\",\"owner\":\"T3_ADAPTIVE_NETWORKS\"}],\"serviceSpecification\":{\"id\":\"#{parent_specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{parent_specification.id}\",\"name\":\"siteConnection\",\"version\":\"v1.0.0\"},"serviceDate\":\"now\",\"state\":\"initial\",\"operatingStatus\":\"unknown\",\"serviceRelationship\":[{\"type\":\"bestows\",\"service\":{\"id\":\"#{child_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/device/#{child_instance.id}\"},\"serviceRelationshipCharacteristic\":[{\"name\":\"role\",\"value\":\"gateway\"}]}],\"feature\":[{\"name\":\"management\",\"isEnabled\":true,\"featureCharacteristic\":[{\"name\":\"device\",\"value\":\"epic1000a\"}]}],\"serviceCharacteristic\":[{\"name\":\"device\",\"value\":\"managed\"}],\"place\":[{\"id\":\"LOC000000897353\",\"href\":\"place/nbnco/LOC000000897353\",\"name\":\"locationId\",\"role\":\"CustomerSite\",\"@referredType\":\"GeographicAddress\",\"@type\":\"PlaceRef\"}],"relatedParty\":[{\"id\":\"T3_ADAPTIVE_NETWORKS\",\"href\":\"entity/internal/T3_ADAPTIVE_NETWORKS\",\"name\":\"entityId\",\"role\":\"Consumer\",\"@referredType\":\"Entity\",\"@type\":\"PartyRef\"},{\"id\":\"T3_CONNECTIVITY\",\"href\":\"entity/internal/T3_CONNECTIVITY\",\"name\":\"entityId\",\"role\":\"Provider\",\"@referredType\":\"Entity\",\"@type\":\"PartyRef\"}]}) + ~s({\"id\":\"#{parent_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/siteConnection/#{parent_instance.id}\",\"category\":\"connectivity\",\"description\":\"Site Connection Service\",\"externalIdentifier\":[{\"externalIdentifierType\":\"siteId\",\"id\":\"ANS020000023234\",\"owner\":\"T3_ADAPTIVE_NETWORKS\"}],\"serviceSpecification\":{\"id\":\"#{parent_specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{parent_specification.id}\",\"name\":\"siteConnection\",\"version\":\"v1.0.0\"},"serviceDate\":\"now\",\"state\":\"initial\",\"serviceRelationship\":[{\"type\":\"bestows\",\"service\":{\"id\":\"#{child_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/device/#{child_instance.id}\"},\"serviceRelationshipCharacteristic\":[{\"name\":\"role\",\"value\":\"gateway\"}]}],\"feature\":[{\"name\":\"management\",\"isEnabled\":true,\"featureCharacteristic\":[{\"name\":\"device\",\"value\":\"epic1000a\"}]}],\"serviceCharacteristic\":[{\"name\":\"device\",\"value\":\"managed\"}],\"place\":[{\"id\":\"LOC000000897353\",\"href\":\"place/nbnco/LOC000000897353\",\"name\":\"locationId\",\"role\":\"CustomerSite\",\"@referredType\":\"GeographicAddress\",\"@type\":\"PlaceRef\"}],"relatedParty\":[{\"id\":\"T3_ADAPTIVE_NETWORKS\",\"href\":\"entity/internal/T3_ADAPTIVE_NETWORKS\",\"name\":\"entityId\",\"role\":\"Consumer\",\"@referredType\":\"Entity\",\"@type\":\"PartyRef\"},{\"id\":\"T3_CONNECTIVITY\",\"href\":\"entity/internal/T3_CONNECTIVITY\",\"name\":\"entityId\",\"role\":\"Provider\",\"@referredType\":\"Entity\",\"@type\":\"PartyRef\"}]}) refreshed_child_instance = Diffo.Provider.get_instance_by_id!(child_instance.id) child_encoding = Jason.encode!(refreshed_child_instance) |> Diffo.Util.summarise_dates() assert child_encoding == - ~s({\"id\":\"#{child_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/device/#{child_instance.id}\",\"category\":\"connectivity\",\"description\":\"Device Service\",\"externalIdentifier\":[{\"externalIdentifierType\":\"connectionId\",\"id\":\"EVC010000873982\",\"owner\":\"T3_CONNECTIVITY\"},{\"externalIdentifierType\":\"orderId\",\"id\":\"ORD00000123456\",\"owner\":\"T4_CPE\"}],\"serviceSpecification\":{\"id\":\"#{child_specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{child_specification.id}\",\"name\":\"device\",\"version\":\"v1.0.0\"},"serviceDate\":\"now\",\"state\":\"initial\",\"operatingStatus\":\"unknown\",\"processStatus\":[{\"code\":\"CPEDEV-1002\",\"severity\":\"WARN\",\"message\":\"device unmanagable\",\"timeStamp\":\"now\"},{\"code\":\"CPEDEV-1001\",\"severity\":\"INFO\",\"message\":\"device discovered\",\"timeStamp\":\"now\"}],\"serviceRelationship\":[{\"type\":\"providedTo\",\"service\":{\"id\":\"#{parent_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/siteConnection/#{parent_instance.id}\"}}],\"relatedEntity\":[{\"id\":\"COR000000123456\",\"name\":\"2025-01\",\"role\":\"expected\",\"@referredType\":\"cost\",\"@type\":\"EntityRef\"}],\"place\":[{\"id\":\"LOC000000897353\",\"href\":\"place/nbnco/LOC000000897353\",\"name\":\"locationId\",\"role\":\"CustomerSite\",\"@referredType\":\"GeographicAddress\",\"@type\":\"PlaceRef\"}],\"relatedParty\":[{\"id\":\"T3_CONNECTIVITY\",\"href\":\"entity/internal/T3_CONNECTIVITY\",\"name\":\"entityId\",\"role\":\"Consumer\",\"@referredType\":\"Entity\",\"@type\":\"PartyRef\"},{\"id\":\"T4_CPE\",\"href\":\"entity/internal/T4_CPE\",\"name\":\"entityId\",\"role\":\"Provider\",\"@referredType\":\"Entity\",\"@type\":\"PartyRef\"}]}) + ~s({\"id\":\"#{child_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/device/#{child_instance.id}\",\"category\":\"connectivity\",\"description\":\"Device Service\",\"externalIdentifier\":[{\"externalIdentifierType\":\"connectionId\",\"id\":\"EVC010000873982\",\"owner\":\"T3_CONNECTIVITY\"},{\"externalIdentifierType\":\"orderId\",\"id\":\"ORD00000123456\",\"owner\":\"T4_CPE\"}],\"serviceSpecification\":{\"id\":\"#{child_specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{child_specification.id}\",\"name\":\"device\",\"version\":\"v1.0.0\"},"serviceDate\":\"now\",\"state\":\"initial\",\"processStatus\":[{\"code\":\"CPEDEV-1002\",\"severity\":\"WARN\",\"message\":\"device unmanagable\",\"timeStamp\":\"now\"},{\"code\":\"CPEDEV-1001\",\"severity\":\"INFO\",\"message\":\"device discovered\",\"timeStamp\":\"now\"}],\"serviceRelationship\":[{\"type\":\"providedTo\",\"service\":{\"id\":\"#{parent_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/siteConnection/#{parent_instance.id}\"}}],\"relatedEntity\":[{\"id\":\"COR000000123456\",\"name\":\"2025-01\",\"role\":\"expected\",\"@referredType\":\"cost\",\"@type\":\"EntityRef\"}],\"place\":[{\"id\":\"LOC000000897353\",\"href\":\"place/nbnco/LOC000000897353\",\"name\":\"locationId\",\"role\":\"CustomerSite\",\"@referredType\":\"GeographicAddress\",\"@type\":\"PlaceRef\"}],\"relatedParty\":[{\"id\":\"T3_CONNECTIVITY\",\"href\":\"entity/internal/T3_CONNECTIVITY\",\"name\":\"entityId\",\"role\":\"Consumer\",\"@referredType\":\"Entity\",\"@type\":\"PartyRef\"},{\"id\":\"T4_CPE\",\"href\":\"entity/internal/T4_CPE\",\"name\":\"entityId\",\"role\":\"Provider\",\"@referredType\":\"Entity\",\"@type\":\"PartyRef\"}]}) end @tag bugged: true @@ -877,12 +902,12 @@ defmodule Diffo.Provider.InstanceTest do parent_encoding = Jason.encode!(refreshed_parent_instance) |> Diffo.Util.summarise_dates() assert parent_encoding == - ~s({\"id\":\"#{parent_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/siteConnection/#{parent_instance.id}\",\"category\":\"connectivity\",\"description\":\"Site Connection Service\",\"externalIdentifier\":[{\"externalIdentifierType\":\"siteId\",\"id\":\"ANS020000023234\",\"owner\":\"T3_ADAPTIVE_NETWORKS\"}],\"serviceSpecification\":{\"id\":\"#{parent_specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{parent_specification.id}\",\"name\":\"siteConnection\",\"version\":\"v1.0.0\"},"serviceDate\":\"now\",\"state\":\"initial\",\"operatingStatus\":\"unknown\",\"serviceRelationship\":[{\"type\":\"bestows\",\"service\":{\"id\":\"#{child_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/device/#{child_instance.id}\"},\"serviceRelationshipCharacteristic\":[{\"name\":\"role\",\"value\":\"gateway\"}]}],\"supportingService\":[{\"id\":\"#{child_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/device/#{child_instance.id}\"}],\"feature\":[{\"name\":\"management\",\"isEnabled\":true,\"featureCharacteristic\":[{\"name\":\"device\",\"value\":\"epic1000a\"}]}],\"serviceCharacteristic\":[{\"name\":\"device\",\"value\":\"managed\"}],\"place\":[{\"id\":\"LOC000000897353\",\"href\":\"place/nbnco/LOC000000897353\",\"name\":\"locationId\",\"role\":\"CustomerSite\",\"@referredType\":\"GeographicAddress\",\"@type\":\"PlaceRef\"}],\"relatedParty\":[{\"id\":\"T3_ADAPTIVE_NETWORKS\",\"href\":\"entity/internal/T3_ADAPTIVE_NETWORKS\",\"name\":\"entityId\",\"role\":\"Consumer\",\"@referredType\":\"Entity\",\"@type\":\"PartyRef\"},{\"id\":\"T3_CONNECTIVITY\",\"href\":\"entity/internal/T3_CONNECTIVITY\",\"name\":\"entityId\",\"role\":\"Provider\",\"@referredType\":\"Entity\",\"@type\":\"PartyRef\"}]}) + ~s({\"id\":\"#{parent_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/siteConnection/#{parent_instance.id}\",\"category\":\"connectivity\",\"description\":\"Site Connection Service\",\"externalIdentifier\":[{\"externalIdentifierType\":\"siteId\",\"id\":\"ANS020000023234\",\"owner\":\"T3_ADAPTIVE_NETWORKS\"}],\"serviceSpecification\":{\"id\":\"#{parent_specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{parent_specification.id}\",\"name\":\"siteConnection\",\"version\":\"v1.0.0\"},"serviceDate\":\"now\",\"state\":\"initial\",\"serviceRelationship\":[{\"type\":\"bestows\",\"service\":{\"id\":\"#{child_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/device/#{child_instance.id}\"},\"serviceRelationshipCharacteristic\":[{\"name\":\"role\",\"value\":\"gateway\"}]}],\"supportingService\":[{\"id\":\"#{child_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/device/#{child_instance.id}\"}],\"feature\":[{\"name\":\"management\",\"isEnabled\":true,\"featureCharacteristic\":[{\"name\":\"device\",\"value\":\"epic1000a\"}]}],\"serviceCharacteristic\":[{\"name\":\"device\",\"value\":\"managed\"}],\"place\":[{\"id\":\"LOC000000897353\",\"href\":\"place/nbnco/LOC000000897353\",\"name\":\"locationId\",\"role\":\"CustomerSite\",\"@referredType\":\"GeographicAddress\",\"@type\":\"PlaceRef\"}],\"relatedParty\":[{\"id\":\"T3_ADAPTIVE_NETWORKS\",\"href\":\"entity/internal/T3_ADAPTIVE_NETWORKS\",\"name\":\"entityId\",\"role\":\"Consumer\",\"@referredType\":\"Entity\",\"@type\":\"PartyRef\"},{\"id\":\"T3_CONNECTIVITY\",\"href\":\"entity/internal/T3_CONNECTIVITY\",\"name\":\"entityId\",\"role\":\"Provider\",\"@referredType\":\"Entity\",\"@type\":\"PartyRef\"}]}) child_encoding = Jason.encode!(refreshed_child_instance) |> Diffo.Util.summarise_dates() assert child_encoding == - ~s({\"id\":\"#{child_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/device/#{child_instance.id}\",\"category\":\"connectivity\",\"description\":\"Device Service\",\"externalIdentifier\":[{\"externalIdentifierType\":\"connectionId\",\"id\":\"EVC010000873982\",\"owner\":\"T3_CONNECTIVITY\"},{\"externalIdentifierType\":\"orderId\",\"id\":\"ORD00000123456\",\"owner\":\"T4_CPE\"}],\"serviceSpecification\":{\"id\":\"#{child_specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{child_specification.id}\",\"name\":\"device\",\"version\":\"v1.0.0\"},"serviceDate\":\"now\",\"state\":\"initial\",\"operatingStatus\":\"unknown\",\"serviceRelationship\":[{\"type\":\"providedTo\",\"service\":{\"id\":\"#{parent_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/siteConnection/#{parent_instance.id}\"}}],\"place\":[{\"id\":\"LOC000000897353\",\"href\":\"place/nbnco/LOC000000897353\",\"name\":\"locationId\",\"role\":\"CustomerSite\",\"@referredType\":\"GeographicAddress\",\"@type\":\"PlaceRef\"}],\"relatedParty\":[{\"id\":\"T3_CONNECTIVITY\",\"href\":\"entity/internal/T3_CONNECTIVITY\",\"name\":\"entityId\",\"role\":\"Consumer\",\"@referredType\":\"Entity\",\"@type\":\"PartyRef\"},{\"id\":\"T4_CPE\",\"href\":\"entity/internal/T4_CPE\",\"name\":\"entityId\",\"role\":\"Provider\",\"@referredType\":\"Entity\",\"@type\":\"PartyRef\"}]}) + ~s({\"id\":\"#{child_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/device/#{child_instance.id}\",\"category\":\"connectivity\",\"description\":\"Device Service\",\"externalIdentifier\":[{\"externalIdentifierType\":\"connectionId\",\"id\":\"EVC010000873982\",\"owner\":\"T3_CONNECTIVITY\"},{\"externalIdentifierType\":\"orderId\",\"id\":\"ORD00000123456\",\"owner\":\"T4_CPE\"}],\"serviceSpecification\":{\"id\":\"#{child_specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{child_specification.id}\",\"name\":\"device\",\"version\":\"v1.0.0\"},"serviceDate\":\"now\",\"state\":\"initial\",\"serviceRelationship\":[{\"type\":\"providedTo\",\"service\":{\"id\":\"#{parent_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/siteConnection/#{parent_instance.id}\"}}],\"place\":[{\"id\":\"LOC000000897353\",\"href\":\"place/nbnco/LOC000000897353\",\"name\":\"locationId\",\"role\":\"CustomerSite\",\"@referredType\":\"GeographicAddress\",\"@type\":\"PlaceRef\"}],\"relatedParty\":[{\"id\":\"T3_CONNECTIVITY\",\"href\":\"entity/internal/T3_CONNECTIVITY\",\"name\":\"entityId\",\"role\":\"Consumer\",\"@referredType\":\"Entity\",\"@type\":\"PartyRef\"},{\"id\":\"T4_CPE\",\"href\":\"entity/internal/T4_CPE\",\"name\":\"entityId\",\"role\":\"Provider\",\"@referredType\":\"Entity\",\"@type\":\"PartyRef\"}]}) end @tag bugged: true @@ -952,7 +977,7 @@ defmodule Diffo.Provider.InstanceTest do parent_encoding = Jason.encode!(refreshed_parent_instance) |> Diffo.Util.summarise_dates() assert parent_encoding == - ~s({\"id\":\"#{parent_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/adslAccess/#{parent_instance.id}\",\"category\":\"connectivity\",\"description\":\"ADSL Access Service\",\"serviceSpecification\":{\"id\":\"#{parent_specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{parent_specification.id}\",\"name\":\"adslAccess\",\"version\":\"v1.0.0\"},"serviceDate\":\"now\",\"state\":\"initial\",\"operatingStatus\":\"unknown\",\"resourceRelationship\":[{\"type\":\"isAssigned\",\"resource\":{\"id\":\"#{child_instance.id}\",\"href\":\"resourceInventoryManagement/v4/resource/can/#{child_instance.id}\"}}],\"feature\":[{\"name\":\"dynamicLineManagement\",\"isEnabled\":true,\"featureCharacteristic\":[{\"name\":\"goal\",\"value\":\"stability\"}]}],\"serviceCharacteristic\":[{\"name\":\"dslam",\"value\":\"QDONC1001\"}]}) + ~s({\"id\":\"#{parent_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/adslAccess/#{parent_instance.id}\",\"category\":\"connectivity\",\"description\":\"ADSL Access Service\",\"serviceSpecification\":{\"id\":\"#{parent_specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{parent_specification.id}\",\"name\":\"adslAccess\",\"version\":\"v1.0.0\"},"serviceDate\":\"now\",\"state\":\"initial\",\"resourceRelationship\":[{\"type\":\"isAssigned\",\"resource\":{\"id\":\"#{child_instance.id}\",\"href\":\"resourceInventoryManagement/v4/resource/can/#{child_instance.id}\"}}],\"feature\":[{\"name\":\"dynamicLineManagement\",\"isEnabled\":true,\"featureCharacteristic\":[{\"name\":\"goal\",\"value\":\"stability\"}]}],\"serviceCharacteristic\":[{\"name\":\"dslam",\"value\":\"QDONC1001\"}]}) _child_encoding = Jason.encode!(refreshed_child_instance) |> Diffo.Util.summarise_dates() @@ -1028,7 +1053,7 @@ defmodule Diffo.Provider.InstanceTest do parent_encoding = Jason.encode!(refreshed_parent_instance) |> Diffo.Util.summarise_dates() assert parent_encoding == - ~s({\"id\":\"#{parent_instance.id}\","href\":\"serviceInventoryManagement/v4/service/adslAccess/#{parent_instance.id}\",\"category\":\"connectivity\",\"description\":\"ADSL Access Service\",\"serviceSpecification\":{\"id\":\"#{parent_specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{parent_specification.id}\",\"name\":\"adslAccess\",\"version\":\"v1.0.0\"},"serviceDate\":\"now\",\"state\":\"initial\",\"operatingStatus\":\"unknown\",\"resourceRelationship\":[{\"type\":\"isAssigned\",\"resource\":{\"id\":\"#{child_instance.id}\",\"href\":\"resourceInventoryManagement/v4/resource/can/#{child_instance.id}\"}}],\"supportingResource\":[{\"id\":\"#{child_instance.id}\",\"href\":\"resourceInventoryManagement/v4/resource/can/#{child_instance.id}\"}],\"feature\":[{\"name\":\"dynamicLineManagement\",\"isEnabled\":true,\"featureCharacteristic\":[{\"name\":\"goal\",\"value\":\"stability\"}]}],\"serviceCharacteristic\":[{\"name\":\"dslam",\"value\":\"QDONC1001\"}]}) + ~s({\"id\":\"#{parent_instance.id}\","href\":\"serviceInventoryManagement/v4/service/adslAccess/#{parent_instance.id}\",\"category\":\"connectivity\",\"description\":\"ADSL Access Service\",\"serviceSpecification\":{\"id\":\"#{parent_specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{parent_specification.id}\",\"name\":\"adslAccess\",\"version\":\"v1.0.0\"},"serviceDate\":\"now\",\"state\":\"initial\",\"resourceRelationship\":[{\"type\":\"isAssigned\",\"resource\":{\"id\":\"#{child_instance.id}\",\"href\":\"resourceInventoryManagement/v4/resource/can/#{child_instance.id}\"}}],\"supportingResource\":[{\"id\":\"#{child_instance.id}\",\"href\":\"resourceInventoryManagement/v4/resource/can/#{child_instance.id}\"}],\"feature\":[{\"name\":\"dynamicLineManagement\",\"isEnabled\":true,\"featureCharacteristic\":[{\"name\":\"goal\",\"value\":\"stability\"}]}],\"serviceCharacteristic\":[{\"name\":\"dslam",\"value\":\"QDONC1001\"}]}) child_encoding = Jason.encode!(refreshed_child_instance) |> Diffo.Util.summarise_dates() @@ -1077,7 +1102,7 @@ defmodule Diffo.Provider.InstanceTest do parent_encoding = Jason.encode!(refreshed_parent_instance) |> Diffo.Util.summarise_dates() assert parent_encoding == - ~s({\"id\":\"#{parent_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/broadband/#{parent_instance.id}\",\"serviceSpecification\":{\"id\":\"#{parent_specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{parent_specification.id}\",\"name\":\"broadband\",\"version\":\"v1.0.0\"},\"serviceDate\":\"now\",\"state\":\"initial\",\"operatingStatus\":\"unknown\",\"serviceRelationship\":[{\"type\":\"bestows\",\"service\":{\"id\":\"#{aggregation_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/aggregation/#{aggregation_instance.id}\"}},{\"type\":\"bestows\",\"service\":{\"id\":\"#{edge_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/edge/#{edge_instance.id}\"}},{\"type\":\"bestows\",\"service\":{\"id\":\"#{access_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/fibreAccess/#{access_instance.id}\"}}],\"supportingService\":[{\"id\":\"#{aggregation_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/aggregation/#{aggregation_instance.id}\"},{\"id\":\"#{edge_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/edge/#{edge_instance.id}\"},{\"id\":\"#{access_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/fibreAccess/#{access_instance.id}\"}]}) + ~s({\"id\":\"#{parent_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/broadband/#{parent_instance.id}\",\"serviceSpecification\":{\"id\":\"#{parent_specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{parent_specification.id}\",\"name\":\"broadband\",\"version\":\"v1.0.0\"},\"serviceDate\":\"now\",\"state\":\"initial\",\"serviceRelationship\":[{\"type\":\"bestows\",\"service\":{\"id\":\"#{aggregation_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/aggregation/#{aggregation_instance.id}\"}},{\"type\":\"bestows\",\"service\":{\"id\":\"#{edge_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/edge/#{edge_instance.id}\"}},{\"type\":\"bestows\",\"service\":{\"id\":\"#{access_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/fibreAccess/#{access_instance.id}\"}}],\"supportingService\":[{\"id\":\"#{aggregation_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/aggregation/#{aggregation_instance.id}\"},{\"id\":\"#{edge_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/edge/#{edge_instance.id}\"},{\"id\":\"#{access_instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/fibreAccess/#{access_instance.id}\"}]}) end test "encode sorts features - success" do @@ -1095,7 +1120,7 @@ defmodule Diffo.Provider.InstanceTest do encoding = Jason.encode!(instance) |> Diffo.Util.summarise_dates() assert encoding == - ~s({\"id\":\"#{instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/siteConnection/#{instance.id}\",\"serviceSpecification\":{\"id\":\"#{specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{specification.id}\",\"name\":\"siteConnection\",\"version\":\"v1.0.0\"},\"serviceDate\":\"now\",\"state\":\"initial\",\"operatingStatus\":\"unknown\",\"feature\":[{\"name\":\"management\",\"isEnabled\":true},{\"name\":\"optimisation\",\"isEnabled\":true},{\"name\":\"security\",\"isEnabled\":true}]}) + ~s({\"id\":\"#{instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/siteConnection/#{instance.id}\",\"serviceSpecification\":{\"id\":\"#{specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{specification.id}\",\"name\":\"siteConnection\",\"version\":\"v1.0.0\"},\"serviceDate\":\"now\",\"state\":\"initial\",\"feature\":[{\"name\":\"management\",\"isEnabled\":true},{\"name\":\"optimisation\",\"isEnabled\":true},{\"name\":\"security\",\"isEnabled\":true}]}) end test "encode sorts characteristics within features - success" do @@ -1140,7 +1165,7 @@ defmodule Diffo.Provider.InstanceTest do encoding = Jason.encode!(refreshed_instance) |> Diffo.Util.summarise_dates() assert encoding == - ~s({\"id\":\"#{instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/siteConnection/#{instance.id}\",\"serviceSpecification\":{\"id\":\"#{specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{specification.id}\",\"name\":\"siteConnection\",\"version\":\"v1.0.0\"},\"serviceDate\":\"now\",\"state\":\"initial\",\"operatingStatus\":\"unknown\",\"feature\":[{\"name\":\"automations\",\"isEnabled\":true,\"featureCharacteristic\":[{\"name\":\"management\",\"value\":true},{\"name\":\"optimisation\",\"value\":true},{\"name\":\"security\",\"value\":true}]}]}) + ~s({\"id\":\"#{instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/siteConnection/#{instance.id}\",\"serviceSpecification\":{\"id\":\"#{specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{specification.id}\",\"name\":\"siteConnection\",\"version\":\"v1.0.0\"},\"serviceDate\":\"now\",\"state\":\"initial\",\"feature\":[{\"name\":\"automations\",\"isEnabled\":true,\"featureCharacteristic\":[{\"name\":\"management\",\"value\":true},{\"name\":\"optimisation\",\"value\":true},{\"name\":\"security\",\"value\":true}]}]}) end test "encode sorts characteristics - success" do @@ -1183,7 +1208,7 @@ defmodule Diffo.Provider.InstanceTest do encoding = Jason.encode!(refreshed_instance) |> Diffo.Util.summarise_dates() assert encoding == - ~s({\"id\":\"#{instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/siteConnection/#{instance.id}\",\"serviceSpecification\":{\"id\":\"#{specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{specification.id}\",\"name\":\"siteConnection\",\"version\":\"v1.0.0\"},\"serviceDate\":\"now\",\"state\":\"initial\",\"operatingStatus\":\"unknown\",\"serviceCharacteristic\":[{\"name\":\"management\",\"value\":true},{\"name\":\"optimisation\",\"value\":true},{\"name\":\"security\",\"value\":true}]}) + ~s({\"id\":\"#{instance.id}\",\"href\":\"serviceInventoryManagement/v4/service/siteConnection/#{instance.id}\",\"serviceSpecification\":{\"id\":\"#{specification.id}\",\"href\":\"serviceCatalogManagement/v4/serviceSpecification/#{specification.id}\",\"name\":\"siteConnection\",\"version\":\"v1.0.0\"},\"serviceDate\":\"now\",\"state\":\"initial\",\"serviceCharacteristic\":[{\"name\":\"management\",\"value\":true},{\"name\":\"optimisation\",\"value\":true},{\"name\":\"security\",\"value\":true}]}) end test "encode cancelled service - success" do diff --git a/test/provider/note_test.exs b/test/provider/note_test.exs index 986192e..7bfc1a7 100644 --- a/test/provider/note_test.exs +++ b/test/provider/note_test.exs @@ -584,7 +584,13 @@ defmodule Diffo.Provider.NoteTest do } gen_nothing_outstanding_test("specific nothing outstanding", @specific_note, @actual_note) - gen_result_outstanding_test("specific note result", @specific_note, nil, Ash.Test.strip_metadata(@specific_note)) + + gen_result_outstanding_test( + "specific note result", + @specific_note, + nil, + Ash.Test.strip_metadata(@specific_note) + ) gen_result_outstanding_test( "specific text result", diff --git a/test/provider/party_ref_test.exs b/test/provider/party_ref_test.exs index ca2c513..fa430a5 100644 --- a/test/provider/party_ref_test.exs +++ b/test/provider/party_ref_test.exs @@ -47,9 +47,9 @@ defmodule Diffo.Provider.PartyRefTest do party_refs = Diffo.Provider.list_party_refs!() assert length(party_refs) == 2 - # should be sorted - assert List.first(party_refs).party_id == "IND000000123456" - assert List.last(party_refs).party_id == "IND000000897353" + # should be sorted by role, then newest to oldest + assert List.first(party_refs).party_id == party2.id + assert List.last(party_refs).party_id == party1.id end test "list party refs by related instance - success" do diff --git a/test/provider/place_ref_test.exs b/test/provider/place_ref_test.exs index 79288b5..1e5d794 100644 --- a/test/provider/place_ref_test.exs +++ b/test/provider/place_ref_test.exs @@ -47,9 +47,9 @@ defmodule Diffo.Provider.PlaceRefTest do place_refs = Diffo.Provider.list_place_refs!() assert length(place_refs) == 2 - # should be sorted - assert List.first(place_refs).place_id == "LOC000000123456" - assert List.last(place_refs).place_id == "LOC000000897353" + # should be sorted by role, then newest to oldest + assert List.first(place_refs).place_id == place2.id + assert List.last(place_refs).place_id == place1.id end test "list place refs by related instance - success" do