Декларативний підхід до налаштування емуляторів зовнішніх систем для спрощення тестування зовнішніх інтеграцій реєстру

🌐 Цей документ доступний українською та англійською мовами. Використовуйте перемикач у правому верхньому куті, щоб змінити версію.

1. Загальний опис

Існує проблема, що поточне рішення для мокування виконується за допомогою SoapUI та сервіси моку інтеграційних точок поставляється разом з платформою. Це призводить до того що не можливо швидко додати новий мок інтеграційної точки або змінити вже існуючий без надання апдейту платформи.

Для вирішення цієї проблеми необхідно замістити поточний підхід для створення моків на реалізацію нової унифікованої стратегії яка дає можливість конфігурувати власні моки для інтеграційниї точок в режимі реального часу без постачання нової версії платформи.

2. Актори та ролі користувачів

  • Розробник реєстрів

  • Розробник платформи

3. Глосарій

  • WM - WireMock

  • WMS - WireMock Studio

  • Mocks - заглушки точки інтеграції

  • Control Plane Console - консоль адміністратора платформи

4. Поточна робота мокування інтеграційних точок

current mocking solution

На даній діаграмі можна побачити, що для оновлення/додавання моку треба:

  • Розробник платформи створює мок у SOAP UI

  • Розробник платформи додає зміну у інсталлер

  • Розробник реєстру може використовувати загальний мок після оновлення платформи

Також варто зазначити, що мок знаходиться на рівні платформи, а не реєстру, тобто він загальній на усі реєстри які є на кластері.

4.1. Недоліки поточного рішення

  • Моки постачаються разом з платформою що унеможливлює зміни розробником регламенту

  • Немає можливості швидко інтегруватися з новою зовнішньою системою адміністратору реєстру без допомоги розробника платформи

  • Немає можливості персонизувати мок інтеграційної точки для реєстру

5. Технічний дизайн рішення

5.1. Налаштування моків через Control Plane

enable-mocking
Зображення 1. Налаштування конфігурації моку зовнішньої точки інтеграції

Важливо відзначити, що після збереження конфігурації відбувається виконнаня флоу яке описане в рамках дизайну Управління налаштуваннями та секретами зовнішніх інтеграцій з врахуванням наступних ремарок:

  • Якщо користувач хоче замокувати зовнішню REST систему (не Трембіту) яка була створена - необхідно видалити service entry для неї

  • Якщо користувач хоче додати мок зовнішньої REST системи - необхідно створити секрет без service entry

5.1.1. Порядок дій для розгортання власного моку інтеграційної точки

Налаштування інтеграції реєстру з моком зовнішної точки інтеграції
Зображення 2. Налаштування інтеграції реєстру з моком зовнішної точки інтеграції
  • Адміністратор платформи додає зовнішню інтеграцію для dev реєстру з Трембіта або іншою зовнішньою системою

  • У герріті Control Plane Console оновився файл конфігурації для інтеграції з зовнішньою системою

control-plane-gerrit:<registry>.git/deployment-templates/values.yaml
trembita:
#SOAP external systems integration
  registries:
    edr-registry:
      #Link on registry wiremock
      url: "http://wiremock:9021/"
      mock: true
      ...
    dracs-registry:
      #Link on registry wiremock
      url: "http://wiremock:9021/"
      mock: true
      ...
    idp-exchange-service-registry:
      #Link on registry wiremock
      url: "http://wiremock:9021/"
      mock: true
      ...
external-systems:
#REST external systems integration
  diia:
    #Link on registry wiremock
    url: "http://wiremock:9021/"
    mock: true
    ...
  http-bin:
    #Link on registry wiremock
    url: "http://wiremock:9021/"
    mock: true
    ...
  secured-service:
    #Link on registry wiremock
    url: "http://wiremock:9021/"
    mock: true
    ...
Посилання змінюється лише для обраної системи на реєстровий WM доступ до якого здійснюється за адресю сервіса (http://wiremock:9021/).

Якщо для зовніщньої системи обрене мокування то у файл зберігається флаг, який дозволяє ідентифікувати систему яка посилається на мок.

5.1.2. Управління конфігурацїєю мокування

registry-integrations-management
Зображення 3. Налаштування взаємодії реєстру через Тримбіту для dev реєстру
registry-integrations-management
Зображення 4. Налаштування взаємодії з моком інтеграційних точок Трембіта для dev реєстру
registry-integrations-management
Зображення 5. Налаштування взаємодії реєстру з зовнішньою системою
registry-integrations-management
Зображення 6. Налаштування взаємодії реєстру з моком інтеграційних точок зовнішніх систем

5.1.3. Інтеграційні сценарії

Назва системи Рівень Протокол Вид інтеграції

diia

Реєстр

REST

Зовнішня інтеграція

trembita

Реєстр

SOAP

Зовнішня інтеграція

<Інші зовнішні системи>

Реєстр

REST/SOAP

Зовнішня інтеграція

5.2. Додавання моку зовнішньої точки інтеграції

Для мокування інтеграційних точок пропонується використовувати WM. За даним підходом можливо мокуватия як REST так і SOAP API.

import mapping flow
Зображення 7. Застосування власних моків для реєстру
Додавання власного моку для використання у реєстрі
Зображення 8. Додавання власного моку для використання у реєстрі

5.3. Доступи з сервісів

Для певних реєстрових та платформених сервісів необхідо дати можливість взаємодіяти з реєстровим WM сервісом за портом 9021.

  • Нетворк полісі які необхідні для взаємодії з сервісом мокування зовнішньої інтеграцій на рівні реєстру

Назва сервісу Лейбл сервісу

admin-tools-jenkins

app=jenkins

bpms

app=bpms

ddm-notification-service

app.kubernetes.io/instance = ddm-notification-service

  • Істіо полісі які необхідні для взаємодії з сервісом мокування зовнішньої інтеграції на рівні платформи

Назва сервісу Лейбл сервісу

keycloak-manag

app.kubernetes.io/name=keycloak

6. Моделювання регламенту

6.1. Додавання мапінгу

Для збереження мапінгів у реєстровому репозиторії необхідно слідувати структурі. Файл з мапінгом зберігає і відповідь яку надає мок зовнішньої точки інтеграції

Приклад налаштування _mock-integrations_
Зображення 9. Приклад налаштування mock-integrations

6.1.1. Приклад файлів мапінгів та обробки респонсу

WM підтримує як SOAP так і REST запити тому нижче наведено приклад обробки обох типів запитів

Файл з мапінгами для EDR моку edr-registry.json (Завантажити)
{
  "mappings": [
    {
      "request": {
        "urlPath": "/mockEdr",
        "method": "POST"
      },
      "response": {
        "status": 200,
        "body": "<soap11env:Envelope\n        xmlns:soap11env=\"http://schemas.xmlsoap.org/soap/envelope/\"\n        xmlns:tns=\"http://nais.gov.ua/api/sevdeir/EDR\"\n        xmlns:xroad=\"http://x-road.eu/xsd/xroad.xsd\"\n        xmlns:id=\"http://x-road.eu/xsd/identifiers\">\n    <soap11env:Header>\n        <tns:AuthorizationToken>token</tns:AuthorizationToken>\n        <xroad:userId>MDTUDDM</xroad:userId>\n        <xroad:client id:objectType=\"SUBSYSTEM\">\n            <id:xRoadInstance>SEVDEIR-TEST</id:xRoadInstance>\n            <id:memberClass>GOV</id:memberClass>\n            <id:memberCode>43395033</id:memberCode>\n            <id:subsystemCode>IDGOV_TEST_01</id:subsystemCode>\n        </xroad:client>\n        <xroad:service id:objectType=\"SERVICE\">\n            <id:xRoadInstance>SEVDEIR-TEST</id:xRoadInstance>\n            <id:memberClass>GOV</id:memberClass>\n            <id:memberCode>00015622</id:memberCode>\n            <id:subsystemCode>2_MJU_EDR_prod</id:subsystemCode>\n            <id:serviceCode>SearchSubjects</id:serviceCode>\n        </xroad:service>\n        <xroad:protocolVersion>4.0</xroad:protocolVersion>\n        <xroad:id>MDTUDDM</xroad:id>\n        <xroad:requestHash algorithmId=\"http://www.w3.org/2001/04/xmldsig-more#gost34311\">YzS4MYmFiW8tkoncbQL624RllowfcK8B8FGNTWZ5QFE=</xroad:requestHash>\n    </soap11env:Header>\n    <soap11env:Body>\n        <tns:SearchSubjectsResponse>\n            <tns:SubjectList>\n                <!--Темплейтинг мапінгу-->\n                {{#each (soapXPath request.body '/SearchSubjects/code/text()') as |thing|}}\n                {{#if (contains thing '101')}}\n                <tns:state>1</tns:state>\n                <tns:state_text>зареєстровано</tns:state_text>\n                <tns:name>Сидоренко Василь Леонідович</tns:name>\n                <tns:url>http://zqedr-api.nais.gov.ua/1.0/subjects/3</tns:url>\n                <tns:code>{{thing}}</tns:code>\n                <tns:id>3</tns:id>\n                {{else if (contains thing '123213123')}}\n                <tns:state>1</tns:state>\n                <tns:state_text>зареєстровано</tns:state_text>\n                <tns:name>Петренко Петро Петрович</tns:name>\n                <tns:url>http://zqedr-api.nais.gov.ua/1.0/subjects/3</tns:url>\n                <tns:code>{{thing}}</tns:code>\n                <tns:id>3</tns:id>\n                {{/if}}\n                {{/each}}\n                <tns:SubjectInfo>\n                </tns:SubjectInfo>\n            </tns:SubjectList>\n        </tns:SearchSubjectsResponse>\n    </soap11env:Body>\n</soap11env:Envelope>",
        "headers": {
          "Content-Type": "text/xml"
        },
      "transformers": [
        "response-template",
        "body-transformer"
      ]
      }
    }
  ]
}
Форматована відповідь mock-integration/edr-registry.json (Завантажити)
<soap11env:Envelope
        xmlns:soap11env="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:tns="http://nais.gov.ua/api/sevdeir/EDR"
        xmlns:xroad="http://x-road.eu/xsd/xroad.xsd"
        xmlns:id="http://x-road.eu/xsd/identifiers">
    <soap11env:Header>
        <tns:AuthorizationToken>token</tns:AuthorizationToken>
        <xroad:userId>MDTUDDM</xroad:userId>
        <xroad:client id:objectType="SUBSYSTEM">
            <id:xRoadInstance>SEVDEIR-TEST</id:xRoadInstance>
            <id:memberClass>GOV</id:memberClass>
            <id:memberCode>43395033</id:memberCode>
            <id:subsystemCode>IDGOV_TEST_01</id:subsystemCode>
        </xroad:client>
        <xroad:service id:objectType="SERVICE">
            <id:xRoadInstance>SEVDEIR-TEST</id:xRoadInstance>
            <id:memberClass>GOV</id:memberClass>
            <id:memberCode>00015622</id:memberCode>
            <id:subsystemCode>2_MJU_EDR_prod</id:subsystemCode>
            <id:serviceCode>SearchSubjects</id:serviceCode>
        </xroad:service>
        <xroad:protocolVersion>4.0</xroad:protocolVersion>
        <xroad:id>MDTUDDM</xroad:id>
        <xroad:requestHash algorithmId="http://www.w3.org/2001/04/xmldsig-more#gost34311">YzS4MYmFiW8tkoncbQL624RllowfcK8B8FGNTWZ5QFE=</xroad:requestHash>
    </soap11env:Header>
    <soap11env:Body>
        <tns:SearchSubjectsResponse>
            <tns:SubjectList>
                <!--Темплейтинг мапінгу-->
                {{#each (soapXPath request.body '/SearchSubjects/code/text()') as |thing|}}
                {{#if (contains thing '101')}}
                <tns:state>1</tns:state>
                <tns:state_text>зареєстровано</tns:state_text>
                <tns:name>Сидоренко Василь Леонідович</tns:name>
                <tns:url>http://zqedr-api.nais.gov.ua/1.0/subjects/3</tns:url>
                <tns:code>{{thing}}</tns:code>
                <tns:id>3</tns:id>
                {{else if (contains thing '123213123')}}
                <tns:state>1</tns:state>
                <tns:state_text>зареєстровано</tns:state_text>
                <tns:name>Петренко Петро Петрович</tns:name>
                <tns:url>http://zqedr-api.nais.gov.ua/1.0/subjects/3</tns:url>
                <tns:code>{{thing}}</tns:code>
                <tns:id>3</tns:id>
                {{/if}}
                {{/each}}
                <tns:SubjectInfo>
                </tns:SubjectInfo>
            </tns:SubjectList>
        </tns:SearchSubjectsResponse>
    </soap11env:Body>
</soap11env:Envelope>
Файл мапінгу diia.json (Завантажити)
{
  "mappings": [
    {
      "request": {
        "urlPath": "/api/partner-token/post-info",
        "method": "POST",
        "headers": {
          "Accept": {
            "contains": ".*"
          }
        },
        "bodyPatterns": [{
          "matchesJsonPath": "$.info"
        }]
      },
      "response": {
        "status": 200,
        "body": "{\n  \"info\": \"string\"\n}",
        "headers": {
          "Content-Type": "text/xml"
        },
        "transformers": [
          "response-template",
          "body-transformer"
        ]
      }
    }
  ]
}
Користувач після додавання моку зможе піти за адресою http:registry-wiremock/mockEdr щоб отримати замокану відповідь
  • Під час виконання пайплайну registry-regulations-management при наявності мапінгів виконується запит

curl -v -d @mapping.json http://wiremock:9021/__admin/mappings/import
Мапінги можуть зберігатись у декількох файлах, тому треба імпортувати за допомогою API усі файли з мапінгами

6.2. План міграції поточних рішень для мокування

  • Створити мапінгів моків поточних зовнішнії систем

  • Додати імпорт мапінгів до post-upgrade скриптів

  • Оновити інструкції користувача для викроистання нових моків за бажанням користувача

  • Відмітити існуючі моки як ті компоненти які будуть замінені у наступних релізах

6.3. Приклад створення власного моку WMS

Мапінг для імпорту можна створити у WMS, для цього треба:

  • Перейти до WMS та натиснути Mock API кнопку

mock api
  • Обрати пустий шаблон та заповнити назву

create new mock
  • Перейти до вкладки Stubs

stubs
  • Натиснути кнопку New

new stub
  • Заповнити налаштування мапінгу та зберегти його

save stub
  • Експортувати файл для завантаження його у реєстровий герріт

export mock

7. Високорівневий план розробки

7.2. План розробки

  • Деплой WM виконується тільки під час розгортання dev реєстрів та для нього відсутній роут

  • Оновлення Control Plane Console під нову функціональність

  • Оновити Control Plane Jenkins пайплайн для розгортання реєстру з урахуванням описаних змін

  • Додавання стейджу у registry-regulations пайплайну для імпорту мапінгів

  • Розробити WM мапінги поточних рішень та мапінги для Diia і додати їх до демо реєстру

  • Розробка інструкцій користувачів з вказівками як розробити, додати, оновити мапінги з посиланням на демо реєстр