diff --git a/README_INFINERA.md b/README_INFINERA.md
new file mode 100644
index 0000000000000000000000000000000000000000..4d3c1a3f00a537827324cced1ccf830481dfe372
--- /dev/null
+++ b/README_INFINERA.md
@@ -0,0 +1,82 @@
+# Infinera Readme
+
+This file will be removed before uploading to origin.
+
+There are some instructions at https://gitlab.com/teraflow-h2020/controller/-/tree/develop/tutorial . They are not completely up to date and don't 100% work.
+
+Note that many of the scripts expect this and that K8s namespace being used, they are not consistent, so use manual kubectl commands where necessary.
+
+Infinera repo (cloned from upstream) is https://bitbucket.infinera.com/projects/XRCA/repos/teraflow/browse . The main development branch for us is xr-development (branched of origin/develop).
+
+## Preliminaries
+
+Kubernetes must be installed and configured.
+
+Note that if runninc MicroK8s (I would highly recommend it), then install also regular kubectl so that scripts work. That is, download the kubectl, and also export credidentials to standard location.
+
+```bash
+# As a root
+su -
+cd /usr/local/bin
+curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
+chmod 755 kubectl
+exit
+
+# As your local user
+cd ~/.kube
+microk8s config > config
+```
+
+Local Docker registry is needed for build results. Use the following command to start local registry (docker will pull necessary images from Internet)
+
+```bash
+docker run -d -p 32000:5000 --restart=always --name registry registry:2
+```
+
+Setup mydeploy script outside the git repo. E.g. following will do. SOURCE IT ON ALL SHELLS.
+
+```bash
+export TFS_REGISTRY_IMAGE="http://localhost:32000/tfs/"
+
+export TFS_COMPONENTS="context device automation service compute monitoring webui"
+export TFS_IMAGE_TAG="dev"
+export TFS_K8S_NAMESPACE="tfs"
+export TFS_EXTRA_MANIFESTS="manifests/nginx_ingress_http.yaml"
+export TFS_GRAFANA_PASSWORD="admin123+"
+```
+
+Build is containerized, pytest used for setup is not. Teraflow has some third party venv suggestion in docs. However standard venv works. Create:
+
+```bash
+python -m venv .venv
+source .venv/bin/activate
+./install_requirements.sh
+```
+
+SOURCE VENV ACTIVATE ON ANY SHELL USED FOR PYTHON RELATED WORK (e.g. pytest).
+
+Use apt-get to install any missing tools (e.g. jq is required).
+
+## Building
+
+Run deploy script to build in docker containers and then instantiate to configured K8s cluster. Deploy script must be sources for this to work!
+
+```bash
+./deploy.sh
+```
+
+## Testing
+
+Upload descriptors_emulatex_xr.json via WEB UI to setup fake topology.
+
+Setup service by following commands in src directory. Kubernetes endpoins change on every build, so setup script is mandatory.
+
+```bash
+    source tests/ofc22/setup_test_env.sh 
+    python -m pytest --verbose tests/ofc22/tests/test_functional_create_service_xr.py 
+```
+
+Good logs to check are:
+
+* kubectl logs   service/deviceservice     --namespace tfs
+* kubectl logs   service/webuiservice     --namespace tfs
diff --git a/src/common/tools/object_factory/Device.py b/src/common/tools/object_factory/Device.py
index 32baff9ae5cfb9a9a41d1d06bfec7df5fd5c0e4a..0b597a77a58773e4e8811e801b98fa6154980cc6 100644
--- a/src/common/tools/object_factory/Device.py
+++ b/src/common/tools/object_factory/Device.py
@@ -15,7 +15,7 @@
 import copy
 from typing import Dict, List, Tuple
 from common.DeviceTypes import DeviceTypeEnum
-from common.proto.context_pb2 import DeviceDriverEnum, DeviceOperationalStatusEnum
+from common.proto.context_pb2 import DEVICEDRIVER_XR, DeviceDriverEnum, DeviceOperationalStatusEnum
 from common.tools.object_factory.ConfigRule import json_config_rule_set
 
 DEVICE_DISABLED = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED
@@ -32,6 +32,9 @@ DEVICE_PR_DRIVERS   = [DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG]
 DEVICE_TAPI_TYPE    = DeviceTypeEnum.OPTICAL_LINE_SYSTEM.value
 DEVICE_TAPI_DRIVERS = [DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API]
 
+DEVICE_XR_CONSTELLATION_TYPE    = DeviceTypeEnum.XR_CONSTELLATION.value
+DEVICE_XR_CONSTELLATION_DRIVERS = [DeviceDriverEnum.DEVICEDRIVER_XR]
+
 # check which enum type and value assign to microwave device
 DEVICE_MICROWAVE_TYPE    = DeviceTypeEnum.MICROVAWE_RADIO_SYSTEM.value
 DEVICE_MICROWAVE_DRIVERS = [DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY]
@@ -85,6 +88,14 @@ def json_device_tapi_disabled(
     return json_device(
         device_uuid, DEVICE_TAPI_TYPE, DEVICE_DISABLED, endpoints=endpoints, config_rules=config_rules, drivers=drivers)
 
+def json_device_xr_constellation_disabled(
+        device_uuid : str, endpoints : List[Dict] = [], config_rules : List[Dict] = [],
+        drivers : List[Dict] = DEVICE_XR_CONSTELLATION_DRIVERS
+    ):
+    return json_device(
+        device_uuid, DEVICE_XR_CONSTELLATION_TYPE, DEVICE_DISABLED, endpoints=endpoints, config_rules=config_rules, drivers=drivers)
+
+
 def json_device_microwave_disabled(
         device_uuid : str, endpoints : List[Dict] = [], config_rules : List[Dict] = [],
         drivers : List[Dict] = DEVICE_MICROWAVE_DRIVERS
diff --git a/src/device/service/drivers/__init__.py b/src/device/service/drivers/__init__.py
index 4b67a77ea75399dd11bf48131b403f9e39b293a9..e4f9c8d54f51c93459295adb2704056b216d1867 100644
--- a/src/device/service/drivers/__init__.py
+++ b/src/device/service/drivers/__init__.py
@@ -36,8 +36,7 @@ DRIVERS = [
             FilterFieldEnum.DRIVER     : [
                 ORM_DeviceDriverEnum.UNDEFINED,
                 ORM_DeviceDriverEnum.OPENCONFIG,
-                ORM_DeviceDriverEnum.TRANSPORT_API,
-                ORM_DeviceDriverEnum.XR
+                ORM_DeviceDriverEnum.TRANSPORT_API
             ],
         }
     ]),
diff --git a/src/device/service/drivers/xr/XrDriver.py b/src/device/service/drivers/xr/XrDriver.py
index 8f40012a26d05bd164ed58b0f432eaca4e31fddc..81898d7c73d4263b71b0b1e81fa0684affed070f 100644
--- a/src/device/service/drivers/xr/XrDriver.py
+++ b/src/device/service/drivers/xr/XrDriver.py
@@ -33,6 +33,8 @@ class XrDriver(_Driver):
         self.__audience = settings["audience"] if "audience" in settings else "test"
         self.__client_id = settings["client_id"] if "client_id" in settings else "test"
 
+        self.__services = {}
+
         # FIXME: remove
         LOGGER.info(f"FIXME!!! XrDriver, cm {address}:{port}, {settings=}");
 
@@ -76,28 +78,61 @@ class XrDriver(_Driver):
         with self.__lock:
             return []
 
+    def fake_interface_names(self) -> List[str]:
+        interfaces = []
+        # Using 4 as max leaf and lane to keep prints small during development
+        for lane in range(0,4):
+            interfaces.append(f"HUB-LANE-{lane:02}")
+        for leaf in range(1,5):
+            for lane in range(0,4):
+                interfaces.append(f"LEAF-{leaf:02}-LANE-{lane:02}")
+        return interfaces
+
     def GetConfig(self, resource_keys : List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]:
         chk_type('resources', resource_keys, list)
         results = []
 
-        # TODO
+        # TODO: Completely fake interface information until we get same info from CM
+        for ifname in self.fake_interface_names():
+            results.append((f"/endpoints/endpoint[{ifname}]", {'uuid': ifname, 'type': 'optical', 'sample_types': {}}))
 
         return results
 
+
     def SetConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+        LOGGER.info(f"FIXME!!! XrDriver, SetConfig {resources=}");
+
+        # Logged config seems like:
+           #[('/service[44ca3570-4e1a-49b5-8aab-06c92f239fab:optical]', '{"capacity_unit": "GHz", "capacity_value": 1, "direction": "UNIDIRECTIONAL", "input_sip": "HUB-LANE-01", "layer_protocol_name": "PHOTONIC_MEDIA", "layer_protocol_qualifier": "tapi-photonic-media:PHOTONIC_LAYER_QUALIFIER_NMC", "output_sip": "LEAF-02-LANE-01", "uuid": "44ca3570-4e1a-49b5-8aab-06c92f239fab:optical"}')]
         results = []
         if len(resources) == 0:
             return results
 
-        # TODO
+        # Temporary dummy version
+        for key, config in resources:
+            self.__services[key] = config
+            
+            # TODO: config to CM
+            # Ignore "direction=UNIDIRECITONAL", it seems that controller only creates one direction...
+            results.append(True)
 
         return results
 
     def DeleteConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+        LOGGER.info(f"FIXME!!! XrDriver, DeleteConfig {resources=}");
+
         results = []
         if len(resources) == 0: return results
 
-        #TODO
+        # Temporary dummy version
+        for key, config in resources:
+            if key in self.__services[key]:
+                del self.__services[key]
+                # TODO: Delete config from CM
+                results.append(True)
+            else:
+                results.append(False)
+
 
         return results
 
diff --git a/src/device/service/drivers/xr/__init__.py b/src/device/service/drivers/xr/__init__.py
index 329bbc30656a9ba2e33d0360786ef1786c670a1d..6c466ff9849537949120f492df1aa18261572da0 100644
--- a/src/device/service/drivers/xr/__init__.py
+++ b/src/device/service/drivers/xr/__init__.py
@@ -15,13 +15,13 @@
 from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES
 
 ALL_RESOURCE_KEYS = [
-#    RESOURCE_ENDPOINTS,
-#    RESOURCE_INTERFACES,
+    RESOURCE_ENDPOINTS,
+    RESOURCE_INTERFACES,
 #    RESOURCE_NETWORK_INSTANCES,
 ]
 
 RESOURCE_KEY_MAPPINGS = {
-#    RESOURCE_ENDPOINTS        : 'component',
-#    RESOURCE_INTERFACES       : 'interface',
+    RESOURCE_ENDPOINTS        : 'component',
+    RESOURCE_INTERFACES       : 'interface',
 #    RESOURCE_NETWORK_INSTANCES: 'network_instance',
 }
diff --git a/src/policy/src/main/java/eu/teraflow/policy/Serializer.java b/src/policy/src/main/java/eu/teraflow/policy/Serializer.java
index 9121f1ba98b36e7b9ee3ca3d59c5f814a30a8a40..ede45d0c2dd0c2944be8f31db845e6c05784caca 100644
--- a/src/policy/src/main/java/eu/teraflow/policy/Serializer.java
+++ b/src/policy/src/main/java/eu/teraflow/policy/Serializer.java
@@ -2080,6 +2080,8 @@ public class Serializer {
                 return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY;
             case ONF_TR_352:
                 return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_ONF_TR_352;
+            case XR:
+                return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_XR;
             case UNDEFINED:
             default:
                 return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_UNDEFINED;
diff --git a/src/service/service/service_handlers/__init__.py b/src/service/service/service_handlers/__init__.py
index 6abe4048fb6771efc0a44f11aa40fc7739a87648..07a653a4faf7974561341abbbbe953061bca787d 100644
--- a/src/service/service/service_handlers/__init__.py
+++ b/src/service/service/service_handlers/__init__.py
@@ -33,7 +33,7 @@ SERVICE_HANDLERS = [
     (TapiServiceHandler, [
         {
             FilterFieldEnum.SERVICE_TYPE  : ORM_ServiceTypeEnum.TAPI_CONNECTIVITY_SERVICE,
-            FilterFieldEnum.DEVICE_DRIVER : ORM_DeviceDriverEnum.TRANSPORT_API,
+            FilterFieldEnum.DEVICE_DRIVER : [ORM_DeviceDriverEnum.TRANSPORT_API, ORM_DeviceDriverEnum.XR],
         }
     ]),
-]
+]
\ No newline at end of file
diff --git a/src/tests/ofc22/descriptors_emulated_xr.json b/src/tests/ofc22/descriptors_emulated_xr.json
index 1f0474e8675f45113dbdd86a3776db14dad0cdc3..a3fc07bcfa89206a509da4e9e8048aea2ae79def 100644
--- a/src/tests/ofc22/descriptors_emulated_xr.json
+++ b/src/tests/ofc22/descriptors_emulated_xr.json
@@ -62,57 +62,46 @@
             "device_drivers": [0],
             "device_endpoints": []
         },
-        {
-            "device_id": {"device_uuid": {"uuid": "O1-OLS"}},
-            "device_type": "emu-optical-line-system",
-            "device_config": {"config_rules": [
-                {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
-                {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
-                {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": "{\"endpoints\": [{\"sample_types\": [], \"type\": \"optical\", \"uuid\": \"aade6001-f00b-5e2f-a357-6a0a9d3de870\"}, {\"sample_types\": [], \"type\": \"optical\", \"uuid\": \"eb287d83-f05e-53ec-ab5a-adf6bd2b5418\"}, {\"sample_types\": [], \"type\": \"optical\", \"uuid\": \"0ef74f99-1acc-57bd-ab9d-4b958b06c513\"}, {\"sample_types\": [], \"type\": \"optical\", \"uuid\": \"50296d99-58cc-5ce7-82f5-fc8ee4eec2ec\"}]}"}}
-            ]},
-            "device_operational_status": 1,
-            "device_drivers": [0],
-            "device_endpoints": []
-        },
         {
             "device_id": {"device_uuid": {"uuid": "X1-XR-CONSTELLATION"}},
             "device_type": "xr-constellation",
             "device_config": {"config_rules": [
                 {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "172.19.219.44"}},
-                {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "443"}}
+                {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "443"}},
+                {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": "{\"endpoints\": [{\"sample_types\": [], \"type\": \"optical\", \"uuid\": \"HUB-LANE-01\"}, {\"sample_types\": [], \"type\": \"optical\", \"uuid\": \"LEAF-01-LANE-01\"}]}"}}
             ]},
             "device_operational_status": 1,
-            "device_drivers": [0],
+            "device_drivers": [6],
             "device_endpoints": []
         }
     ],
     "links": [
         {
-            "link_id": {"link_uuid": {"uuid": "R1-EMU/13/0/0==O1-OLS/aade6001-f00b-5e2f-a357-6a0a9d3de870"}},
+            "link_id": {"link_uuid": {"uuid": "R1-EMU/13/0/0==XR1-HUB-LANE-01"}},
             "link_endpoint_ids": [
                 {"device_id": {"device_uuid": {"uuid": "R1-EMU"}}, "endpoint_uuid": {"uuid": "13/0/0"}},
-                {"device_id": {"device_uuid": {"uuid": "O1-OLS"}}, "endpoint_uuid": {"uuid": "aade6001-f00b-5e2f-a357-6a0a9d3de870"}}
+                {"device_id": {"device_uuid": {"uuid": "X1-XR-CONSTELLATION"}}, "endpoint_uuid": {"uuid": "HUB-LANE-01"}}
             ]
         },
         {
-            "link_id": {"link_uuid": {"uuid": "R2-EMU/13/0/0==O1-OLS/eb287d83-f05e-53ec-ab5a-adf6bd2b5418"}},
+            "link_id": {"link_uuid": {"uuid": "R2-EMU/13/0/0==XR1-LEAF-01-LANE-01"}},
             "link_endpoint_ids": [
                 {"device_id": {"device_uuid": {"uuid": "R2-EMU"}}, "endpoint_uuid": {"uuid": "13/0/0"}},
-                {"device_id": {"device_uuid": {"uuid": "O1-OLS"}}, "endpoint_uuid": {"uuid": "eb287d83-f05e-53ec-ab5a-adf6bd2b5418"}}
+                {"device_id": {"device_uuid": {"uuid": "X1-XR-CONSTELLATION"}}, "endpoint_uuid": {"uuid": "LEAF-01-LANE-01"}}
             ]
         },
         {
-            "link_id": {"link_uuid": {"uuid": "R3-EMU/13/0/0==O1-OLS/0ef74f99-1acc-57bd-ab9d-4b958b06c513"}},
+            "link_id": {"link_uuid": {"uuid": "R3-EMU/13/0/0==XR1-LEAF-02-LANE-01"}},
             "link_endpoint_ids": [
                 {"device_id": {"device_uuid": {"uuid": "R3-EMU"}}, "endpoint_uuid": {"uuid": "13/0/0"}},
-                {"device_id": {"device_uuid": {"uuid": "O1-OLS"}}, "endpoint_uuid": {"uuid": "0ef74f99-1acc-57bd-ab9d-4b958b06c513"}}
+                {"device_id": {"device_uuid": {"uuid": "X1-XR-CONSTELLATION"}}, "endpoint_uuid": {"uuid": "LEAF-02-LANE-01"}}
             ]
         },
         {
-            "link_id": {"link_uuid": {"uuid": "R4-EMU/13/0/0==O1-OLS/50296d99-58cc-5ce7-82f5-fc8ee4eec2ec"}},
+            "link_id": {"link_uuid": {"uuid": "R4-EMU/13/0/0==XR1-LEAF-03-LANE-01"}},
             "link_endpoint_ids": [
                 {"device_id": {"device_uuid": {"uuid": "R4-EMU"}}, "endpoint_uuid": {"uuid": "13/0/0"}},
-                {"device_id": {"device_uuid": {"uuid": "O1-OLS"}}, "endpoint_uuid": {"uuid": "50296d99-58cc-5ce7-82f5-fc8ee4eec2ec"}}
+                {"device_id": {"device_uuid": {"uuid": "X1-XR-CONSTELLATION"}}, "endpoint_uuid": {"uuid": "LEAF-03-LANE-01"}}
             ]
         }
     ]
diff --git a/src/tests/ofc22/setup_test_env.sh b/src/tests/ofc22/setup_test_env.sh
new file mode 100755
index 0000000000000000000000000000000000000000..1f8b0a5a7a8dc986715c6f54a62151f6afa4ad80
--- /dev/null
+++ b/src/tests/ofc22/setup_test_env.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+export CONTEXTSERVICE_SERVICE_HOST=$(kubectl get service/contextservice --namespace tfs  --template '{{.spec.clusterIP}}')
+export CONTEXTSERVICE_SERVICE_PORT_GRPC=$(kubectl get service/contextservice --namespace tfs  -o jsonpath='{.spec.ports[?(@.name=="grpc")].port}')
+export COMPUTESERVICE_SERVICE_HOST=$(kubectl get service/computeservice --namespace tfs  --template '{{.spec.clusterIP}}')
+export COMPUTESERVICE_SERVICE_PORT_HTTP=$(kubectl get service/computeservice --namespace tfs  -o jsonpath='{.spec.ports[?(@.name=="http")].port}')
+echo "CONTEXTSERVICE_SERVICE_HOST=$CONTEXTSERVICE_SERVICE_HOST"
+echo "CONTEXTSERVICE_SERVICE_PORT_GRPC=$CONTEXTSERVICE_SERVICE_PORT_GRPC"
+echo "COMPUTESERVICE_SERVICE_HOST=$COMPUTESERVICE_SERVICE_HOST"
+echo "COMPUTESERVICE_SERVICE_PORT_HTTP=$COMPUTESERVICE_SERVICE_PORT_HTTP"
diff --git a/src/tests/ofc22/tests/ObjectsXr.py b/src/tests/ofc22/tests/ObjectsXr.py
new file mode 100644
index 0000000000000000000000000000000000000000..12d2b48eeed96c274da9756161727f64e5eaa399
--- /dev/null
+++ b/src/tests/ofc22/tests/ObjectsXr.py
@@ -0,0 +1,232 @@
+# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from typing import Dict, List, Tuple
+from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID
+from common.tools.object_factory.Context import json_context, json_context_id
+from common.tools.object_factory.Device import (
+    json_device_connect_rules, json_device_emulated_connect_rules, json_device_emulated_packet_router_disabled,
+    json_device_emulated_tapi_disabled, json_device_id, json_device_packetrouter_disabled, json_device_tapi_disabled)
+from common.tools.object_factory.EndPoint import json_endpoint, json_endpoint_id
+from common.tools.object_factory.Link import json_link, json_link_id
+from common.tools.object_factory.Topology import json_topology, json_topology_id
+from context.proto.kpi_sample_types_pb2 import KpiSampleType
+
+# ----- Context --------------------------------------------------------------------------------------------------------
+CONTEXT_ID = json_context_id(DEFAULT_CONTEXT_UUID)
+CONTEXT    = json_context(DEFAULT_CONTEXT_UUID)
+
+# ----- Topology -------------------------------------------------------------------------------------------------------
+TOPOLOGY_ID = json_topology_id(DEFAULT_TOPOLOGY_UUID, context_id=CONTEXT_ID)
+TOPOLOGY    = json_topology(DEFAULT_TOPOLOGY_UUID, context_id=CONTEXT_ID)
+
+# ----- Monitoring Samples ---------------------------------------------------------------------------------------------
+PACKET_PORT_SAMPLE_TYPES = [
+    KpiSampleType.KPISAMPLETYPE_PACKETS_TRANSMITTED,
+    KpiSampleType.KPISAMPLETYPE_PACKETS_RECEIVED,
+    KpiSampleType.KPISAMPLETYPE_BYTES_TRANSMITTED,
+    KpiSampleType.KPISAMPLETYPE_BYTES_RECEIVED,
+]
+
+# ----- Device Credentials and Settings --------------------------------------------------------------------------------
+try:
+    from .Credentials import DEVICE_R1_ADDRESS, DEVICE_R1_PORT, DEVICE_R1_USERNAME, DEVICE_R1_PASSWORD
+    from .Credentials import DEVICE_R3_ADDRESS, DEVICE_R3_PORT, DEVICE_R3_USERNAME, DEVICE_R3_PASSWORD
+    #from .Credentials import DEVICE_O1_ADDRESS, DEVICE_O1_PORT
+    USE_REAL_DEVICES = True     # Use real devices
+except ImportError:
+    USE_REAL_DEVICES = False    # Use emulated devices
+
+    DEVICE_R1_ADDRESS  = '0.0.0.0'
+    DEVICE_R1_PORT     = 830
+    DEVICE_R1_USERNAME = 'admin'
+    DEVICE_R1_PASSWORD = 'admin'
+
+    DEVICE_R3_ADDRESS  = '0.0.0.0'
+    DEVICE_R3_PORT     = 830
+    DEVICE_R3_USERNAME = 'admin'
+    DEVICE_R3_PASSWORD = 'admin'
+
+DEVICE_X1_ADDRESS  = '172.19.219.44'
+DEVICE_X1_PORT     = 443
+
+#USE_REAL_DEVICES = False     # Uncomment to force to use emulated devices
+
+def json_endpoint_ids(device_id : Dict, endpoint_descriptors : List[Tuple[str, str, List[int]]]):
+    return [
+        json_endpoint_id(device_id, ep_uuid, topology_id=None)
+        for ep_uuid, _, _ in endpoint_descriptors
+    ]
+
+def json_endpoints(device_id : Dict, endpoint_descriptors : List[Tuple[str, str, List[int]]]):
+    return [
+        json_endpoint(device_id, ep_uuid, ep_type, topology_id=None, kpi_sample_types=ep_sample_types)
+        for ep_uuid, ep_type, ep_sample_types in endpoint_descriptors
+    ]
+
+def get_link_uuid(a_device_id : Dict, a_endpoint_id : Dict, z_device_id : Dict, z_endpoint_id : Dict) -> str:
+    return '{:s}/{:s}=={:s}/{:s}'.format(
+        a_device_id['device_uuid']['uuid'], a_endpoint_id['endpoint_uuid']['uuid'],
+        z_device_id['device_uuid']['uuid'], z_endpoint_id['endpoint_uuid']['uuid'])
+
+
+# ----- Devices --------------------------------------------------------------------------------------------------------
+if not USE_REAL_DEVICES:
+    json_device_packetrouter_disabled = json_device_emulated_packet_router_disabled
+    json_device_tapi_disabled         = json_device_emulated_tapi_disabled
+
+DEVICE_R1_UUID          = 'R1-EMU'
+DEVICE_R1_TIMEOUT       = 120
+DEVICE_R1_ENDPOINT_DEFS = [('13/0/0', 'optical', []), ('13/1/2', 'copper', PACKET_PORT_SAMPLE_TYPES)]
+DEVICE_R1_ID            = json_device_id(DEVICE_R1_UUID)
+#DEVICE_R1_ENDPOINTS     = json_endpoints(DEVICE_R1_ID, DEVICE_R1_ENDPOINT_DEFS)
+DEVICE_R1_ENDPOINT_IDS  = json_endpoint_ids(DEVICE_R1_ID, DEVICE_R1_ENDPOINT_DEFS)
+DEVICE_R1               = json_device_packetrouter_disabled(DEVICE_R1_UUID)
+ENDPOINT_ID_R1_13_0_0   = DEVICE_R1_ENDPOINT_IDS[0]
+ENDPOINT_ID_R1_13_1_2   = DEVICE_R1_ENDPOINT_IDS[1]
+DEVICE_R1_CONNECT_RULES = json_device_connect_rules(DEVICE_R1_ADDRESS, DEVICE_R1_PORT, {
+    'username': DEVICE_R1_USERNAME,
+    'password': DEVICE_R1_PASSWORD,
+    'timeout' : DEVICE_R1_TIMEOUT,
+}) if USE_REAL_DEVICES else json_device_emulated_connect_rules(DEVICE_R1_ENDPOINT_DEFS)
+
+
+DEVICE_R2_UUID          = 'R2-EMU'
+DEVICE_R2_ENDPOINT_DEFS = [('13/0/0', 'optical', []), ('13/1/2', 'copper', PACKET_PORT_SAMPLE_TYPES)]
+DEVICE_R2_ID            = json_device_id(DEVICE_R2_UUID)
+#DEVICE_R2_ENDPOINTS     = json_endpoints(DEVICE_R2_ID, DEVICE_R2_ENDPOINT_DEFS)
+DEVICE_R2_ENDPOINT_IDS  = json_endpoint_ids(DEVICE_R2_ID, DEVICE_R2_ENDPOINT_DEFS)
+DEVICE_R2               = json_device_emulated_packet_router_disabled(DEVICE_R2_UUID)
+ENDPOINT_ID_R2_13_0_0   = DEVICE_R2_ENDPOINT_IDS[0]
+ENDPOINT_ID_R2_13_1_2   = DEVICE_R2_ENDPOINT_IDS[1]
+DEVICE_R2_CONNECT_RULES = json_device_emulated_connect_rules(DEVICE_R2_ENDPOINT_DEFS)
+
+
+DEVICE_R3_UUID          = 'R3-EMU'
+DEVICE_R3_TIMEOUT       = 120
+DEVICE_R3_ENDPOINT_DEFS = [('13/0/0', 'optical', []), ('13/1/2', 'copper', PACKET_PORT_SAMPLE_TYPES)]
+DEVICE_R3_ID            = json_device_id(DEVICE_R3_UUID)
+#DEVICE_R3_ENDPOINTS     = json_endpoints(DEVICE_R3_ID, DEVICE_R3_ENDPOINT_DEFS)
+DEVICE_R3_ENDPOINT_IDS  = json_endpoint_ids(DEVICE_R3_ID, DEVICE_R3_ENDPOINT_DEFS)
+DEVICE_R3               = json_device_packetrouter_disabled(DEVICE_R3_UUID)
+ENDPOINT_ID_R3_13_0_0   = DEVICE_R3_ENDPOINT_IDS[0]
+ENDPOINT_ID_R3_13_1_2   = DEVICE_R3_ENDPOINT_IDS[1]
+DEVICE_R3_CONNECT_RULES = json_device_connect_rules(DEVICE_R3_ADDRESS, DEVICE_R3_PORT, {
+    'username': DEVICE_R3_USERNAME,
+    'password': DEVICE_R3_PASSWORD,
+    'timeout' : DEVICE_R3_TIMEOUT,
+}) if USE_REAL_DEVICES else json_device_emulated_connect_rules(DEVICE_R3_ENDPOINT_DEFS)
+
+
+DEVICE_R4_UUID          = 'R4-EMU'
+DEVICE_R4_ENDPOINT_DEFS = [('13/0/0', 'optical', []), ('13/1/2', 'copper', PACKET_PORT_SAMPLE_TYPES)]
+DEVICE_R4_ID            = json_device_id(DEVICE_R4_UUID)
+#DEVICE_R4_ENDPOINTS     = json_endpoints(DEVICE_R4_ID, DEVICE_R4_ENDPOINT_DEFS)
+DEVICE_R4_ENDPOINT_IDS  = json_endpoint_ids(DEVICE_R4_ID, DEVICE_R4_ENDPOINT_DEFS)
+DEVICE_R4               = json_device_emulated_packet_router_disabled(DEVICE_R4_UUID)
+ENDPOINT_ID_R4_13_0_0   = DEVICE_R4_ENDPOINT_IDS[0]
+ENDPOINT_ID_R4_13_1_2   = DEVICE_R4_ENDPOINT_IDS[1]
+DEVICE_R4_CONNECT_RULES = json_device_emulated_connect_rules(DEVICE_R4_ENDPOINT_DEFS)
+
+
+DEVICE_X1_UUID          = 'X1-XR-CONSTELLATION'
+DEVICE_X1_TIMEOUT       = 120
+DEVICE_X1_ENDPOINT_DEFS = [
+    ('HUB-LANE-01', 'optical', []),
+    ('LEAF-01-LANE-01', 'optical', []),
+    ('LEAF-02-LANE-01', 'optical', []),
+    ('LEAF-03-LANE-01', 'optical', []),
+]
+DEVICE_X1_ID            = json_device_id(DEVICE_X1_UUID)
+DEVICE_X1               = json_device_tapi_disabled(DEVICE_X1_UUID)
+DEVICE_X1_ENDPOINT_IDS  = json_endpoint_ids(DEVICE_X1_ID, DEVICE_X1_ENDPOINT_DEFS)
+ENDPOINT_ID_X1_EP1      = DEVICE_X1_ENDPOINT_IDS[0]
+ENDPOINT_ID_X1_EP2      = DEVICE_X1_ENDPOINT_IDS[1]
+ENDPOINT_ID_X1_EP3      = DEVICE_X1_ENDPOINT_IDS[2]
+ENDPOINT_ID_X1_EP4      = DEVICE_X1_ENDPOINT_IDS[3]
+DEVICE_X1_CONNECT_RULES = json_device_connect_rules(DEVICE_X1_ADDRESS, DEVICE_X1_PORT, {
+    'timeout' : DEVICE_X1_TIMEOUT,
+})
+# Always using real device (CM, whether CM has emulated backend is another story)
+#if USE_REAL_DEVICES else json_device_emulated_connect_rules(DEVICE_X1_ENDPOINT_DEFS)
+
+
+# ----- Links ----------------------------------------------------------------------------------------------------------
+LINK_R1_X1_UUID = get_link_uuid(DEVICE_R1_ID, ENDPOINT_ID_R1_13_0_0, DEVICE_X1_ID, ENDPOINT_ID_X1_EP1)
+LINK_R1_X1_ID   = json_link_id(LINK_R1_X1_UUID)
+LINK_R1_X1      = json_link(LINK_R1_X1_UUID, [ENDPOINT_ID_R1_13_0_0, ENDPOINT_ID_X1_EP1])
+
+LINK_R2_X1_UUID = get_link_uuid(DEVICE_R2_ID, ENDPOINT_ID_R2_13_0_0, DEVICE_X1_ID, ENDPOINT_ID_X1_EP2)
+LINK_R2_X1_ID   = json_link_id(LINK_R2_X1_UUID)
+LINK_R2_X1      = json_link(LINK_R2_X1_UUID, [ENDPOINT_ID_R2_13_0_0, ENDPOINT_ID_X1_EP2])
+
+LINK_R3_X1_UUID = get_link_uuid(DEVICE_R3_ID, ENDPOINT_ID_R3_13_0_0, DEVICE_X1_ID, ENDPOINT_ID_X1_EP3)
+LINK_R3_X1_ID   = json_link_id(LINK_R3_X1_UUID)
+LINK_R3_X1      = json_link(LINK_R3_X1_UUID, [ENDPOINT_ID_R3_13_0_0, ENDPOINT_ID_X1_EP3])
+
+LINK_R4_X1_UUID = get_link_uuid(DEVICE_R4_ID, ENDPOINT_ID_R4_13_0_0, DEVICE_X1_ID, ENDPOINT_ID_X1_EP4)
+LINK_R4_X1_ID   = json_link_id(LINK_R4_X1_UUID)
+LINK_R4_X1      = json_link(LINK_R4_X1_UUID, [ENDPOINT_ID_R4_13_0_0, ENDPOINT_ID_X1_EP4])
+
+
+# ----- WIM Service Settings -------------------------------------------------------------------------------------------
+
+def compose_service_endpoint_id(endpoint_id):
+    device_uuid = endpoint_id['device_id']['device_uuid']['uuid']
+    endpoint_uuid = endpoint_id['endpoint_uuid']['uuid']
+    return ':'.join([device_uuid, endpoint_uuid])
+
+WIM_SEP_R1_ID      = compose_service_endpoint_id(ENDPOINT_ID_R1_13_1_2)
+WIM_SEP_R1_SITE_ID = '1'
+WIM_SEP_R1_BEARER  = WIM_SEP_R1_ID
+WIM_SRV_R1_VLAN_ID = 400
+
+WIM_SEP_R3_ID      = compose_service_endpoint_id(ENDPOINT_ID_R3_13_1_2)
+WIM_SEP_R3_SITE_ID = '2'
+WIM_SEP_R3_BEARER  = WIM_SEP_R3_ID
+WIM_SRV_R3_VLAN_ID = 500
+
+WIM_USERNAME = 'admin'
+WIM_PASSWORD = 'admin'
+
+WIM_MAPPING  = [
+    {'device-id': DEVICE_R1_UUID, 'service_endpoint_id': WIM_SEP_R1_ID,
+     'service_mapping_info': {'bearer': {'bearer-reference': WIM_SEP_R1_BEARER}, 'site-id': WIM_SEP_R1_SITE_ID}},
+    {'device-id': DEVICE_R3_UUID, 'service_endpoint_id': WIM_SEP_R3_ID,
+     'service_mapping_info': {'bearer': {'bearer-reference': WIM_SEP_R3_BEARER}, 'site-id': WIM_SEP_R3_SITE_ID}},
+]
+WIM_SERVICE_TYPE = 'ELINE'
+WIM_SERVICE_CONNECTION_POINTS = [
+    {'service_endpoint_id': WIM_SEP_R1_ID,
+        'service_endpoint_encapsulation_type': 'dot1q',
+        'service_endpoint_encapsulation_info': {'vlan': WIM_SRV_R1_VLAN_ID}},
+    {'service_endpoint_id': WIM_SEP_R3_ID,
+        'service_endpoint_encapsulation_type': 'dot1q',
+        'service_endpoint_encapsulation_info': {'vlan': WIM_SRV_R3_VLAN_ID}},
+]
+
+# ----- Object Collections ---------------------------------------------------------------------------------------------
+
+CONTEXTS = [CONTEXT]
+TOPOLOGIES = [TOPOLOGY]
+
+DEVICES = [
+    (DEVICE_R1, DEVICE_R1_CONNECT_RULES),
+    (DEVICE_R2, DEVICE_R2_CONNECT_RULES),
+    (DEVICE_R3, DEVICE_R3_CONNECT_RULES),
+    (DEVICE_R4, DEVICE_R4_CONNECT_RULES),
+    (DEVICE_X1, DEVICE_X1_CONNECT_RULES),
+]
+
+LINKS = [LINK_R1_X1, LINK_R2_X1, LINK_R3_X1, LINK_R4_X1]
diff --git a/src/tests/ofc22/tests/test_functional_create_service_xr.py b/src/tests/ofc22/tests/test_functional_create_service_xr.py
new file mode 100644
index 0000000000000000000000000000000000000000..882950cd57ab7836f1f52d28d9c4fb0dd5d7bf65
--- /dev/null
+++ b/src/tests/ofc22/tests/test_functional_create_service_xr.py
@@ -0,0 +1,130 @@
+# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import logging, pytest
+from common.DeviceTypes import DeviceTypeEnum
+from common.Settings import get_setting
+from common.tests.EventTools import EVENT_CREATE, EVENT_UPDATE, check_events
+from common.tools.object_factory.Connection import json_connection_id
+from common.tools.object_factory.Device import json_device_id
+from common.tools.object_factory.Service import json_service_id
+from common.tools.grpc.Tools import grpc_message_to_json_string
+from compute.tests.mock_osm.MockOSM import MockOSM
+from context.client.ContextClient import ContextClient
+from context.client.EventsCollector import EventsCollector
+from context.proto.context_pb2 import ContextId, Empty
+from .ObjectsXr import (
+    CONTEXT_ID, CONTEXTS, DEVICE_X1_UUID, DEVICE_R1_UUID, DEVICE_R3_UUID, DEVICES, LINKS, TOPOLOGIES,
+    WIM_MAPPING, WIM_PASSWORD, WIM_SERVICE_CONNECTION_POINTS, WIM_SERVICE_TYPE, WIM_USERNAME)
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+DEVTYPE_EMU_PR  = DeviceTypeEnum.EMULATED_PACKET_ROUTER.value
+#DEVTYPE_EMU_OLS = DeviceTypeEnum.EMULATED_OPTICAL_LINE_SYSTEM.value
+DEVTYPE_EMU_OLS = DeviceTypeEnum.XR_CONSTELLATION.value
+
+
+@pytest.fixture(scope='session')
+def context_client():
+    _client = ContextClient(get_setting('CONTEXTSERVICE_SERVICE_HOST'), get_setting('CONTEXTSERVICE_SERVICE_PORT_GRPC'))
+    yield _client
+    _client.close()
+
+
+@pytest.fixture(scope='session')
+def osm_wim():
+    wim_url = 'http://{:s}:{:s}'.format(
+        get_setting('COMPUTESERVICE_SERVICE_HOST'), str(get_setting('COMPUTESERVICE_SERVICE_PORT_HTTP')))
+    return MockOSM(wim_url, WIM_MAPPING, WIM_USERNAME, WIM_PASSWORD)
+
+
+def test_scenario_is_correct(context_client : ContextClient):  # pylint: disable=redefined-outer-name
+    # ----- List entities - Ensure links are created -------------------------------------------------------------------
+    response = context_client.ListContexts(Empty())
+    assert len(response.contexts) == len(CONTEXTS)
+
+    response = context_client.ListTopologies(ContextId(**CONTEXT_ID))
+    assert len(response.topologies) == len(TOPOLOGIES)
+
+    response = context_client.ListDevices(Empty())
+    assert len(response.devices) == len(DEVICES)
+
+    response = context_client.ListLinks(Empty())
+    assert len(response.links) == len(LINKS)
+
+    response = context_client.ListServices(ContextId(**CONTEXT_ID))
+    assert len(response.services) == 0
+
+
+def test_service_creation(context_client : ContextClient, osm_wim : MockOSM): # pylint: disable=redefined-outer-name
+    # ----- Start the EventsCollector ----------------------------------------------------------------------------------
+    events_collector = EventsCollector(context_client, log_events_received=True)
+    events_collector.start()
+
+    # ----- Create Service ---------------------------------------------------------------------------------------------
+    service_uuid = osm_wim.create_connectivity_service(WIM_SERVICE_TYPE, WIM_SERVICE_CONNECTION_POINTS)
+    osm_wim.get_connectivity_service_status(service_uuid)
+
+    # ----- Validate collected events ----------------------------------------------------------------------------------
+
+    packet_connection_uuid = '{:s}:{:s}'.format(service_uuid, DEVTYPE_EMU_PR)
+    optical_connection_uuid = '{:s}:optical:{:s}'.format(service_uuid, DEVTYPE_EMU_OLS)
+    optical_service_uuid = '{:s}:optical'.format(service_uuid)
+
+    expected_events = [
+        # Create packet service and add first endpoint
+        ('ServiceEvent',    EVENT_CREATE, json_service_id(service_uuid, context_id=CONTEXT_ID)),
+        ('ServiceEvent',    EVENT_UPDATE, json_service_id(service_uuid, context_id=CONTEXT_ID)),
+
+        # Configure OLS controller, create optical service, create optical connection
+        ('DeviceEvent',     EVENT_UPDATE, json_device_id(DEVICE_X1_UUID)),
+        ('ServiceEvent',    EVENT_CREATE, json_service_id(optical_service_uuid, context_id=CONTEXT_ID)),
+        ('ConnectionEvent', EVENT_CREATE, json_connection_id(optical_connection_uuid)),
+
+        # Configure endpoint packet devices, add second endpoint to service, create connection
+        ('DeviceEvent',     EVENT_UPDATE, json_device_id(DEVICE_R1_UUID)),
+        ('DeviceEvent',     EVENT_UPDATE, json_device_id(DEVICE_R3_UUID)),
+        ('ServiceEvent',    EVENT_UPDATE, json_service_id(service_uuid, context_id=CONTEXT_ID)),
+        ('ConnectionEvent', EVENT_CREATE, json_connection_id(packet_connection_uuid)),
+    ]
+    check_events(events_collector, expected_events)
+
+    # ----- Stop the EventsCollector -----------------------------------------------------------------------------------
+    events_collector.stop()
+
+
+def test_scenario_service_created(context_client : ContextClient):  # pylint: disable=redefined-outer-name
+    # ----- List entities - Ensure service is created ------------------------------------------------------------------
+    response = context_client.ListContexts(Empty())
+    assert len(response.contexts) == len(CONTEXTS)
+
+    response = context_client.ListTopologies(ContextId(**CONTEXT_ID))
+    assert len(response.topologies) == len(TOPOLOGIES)
+
+    response = context_client.ListDevices(Empty())
+    assert len(response.devices) == len(DEVICES)
+
+    response = context_client.ListLinks(Empty())
+    assert len(response.links) == len(LINKS)
+
+    response = context_client.ListServices(ContextId(**CONTEXT_ID))
+    LOGGER.info('Services[{:d}] = {:s}'.format(len(response.services), grpc_message_to_json_string(response)))
+    assert len(response.services) == 2 # L3NM + TAPI
+    for service in response.services:
+        service_id = service.service_id
+        response = context_client.ListConnections(service_id)
+        LOGGER.info('  ServiceId[{:s}] => Connections[{:d}] = {:s}'.format(
+            grpc_message_to_json_string(service_id), len(response.connections), grpc_message_to_json_string(response)))
+        assert len(response.connections) == 1 # one connection per service
diff --git a/src/webui/service/static/topology_icons/xr-constellation.png b/src/webui/service/static/topology_icons/xr-constellation.png
new file mode 100644
index 0000000000000000000000000000000000000000..518ca5a60b1d6b9c674783873189566430adccf9
Binary files /dev/null and b/src/webui/service/static/topology_icons/xr-constellation.png differ