add e2e tests
This commit is contained in:
parent
4a4362715c
commit
690987010d
2 changed files with 501 additions and 0 deletions
402
api.yml
Normal file
402
api.yml
Normal file
|
@ -0,0 +1,402 @@
|
|||
openapi: '3.0.0'
|
||||
info:
|
||||
description: ''
|
||||
version: 0.1.0-dev
|
||||
title: Nomilo
|
||||
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
ApiToken:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
|
||||
parameters:
|
||||
ZoneName:
|
||||
name: zone
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
|
||||
schemas:
|
||||
UserRequest:
|
||||
type: object
|
||||
required:
|
||||
- username
|
||||
- password
|
||||
- email
|
||||
properties:
|
||||
username:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
role:
|
||||
type: string
|
||||
enum:
|
||||
- admin
|
||||
- zoneadmin
|
||||
|
||||
TokenRequest:
|
||||
type: object
|
||||
required:
|
||||
- username
|
||||
- password
|
||||
properties:
|
||||
username:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
|
||||
TokenResponse:
|
||||
type: object
|
||||
required:
|
||||
- token
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
|
||||
AddZoneMemberRequest:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
|
||||
CreateZoneRequest:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
|
||||
Zone:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
|
||||
ZoneList:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Zone'
|
||||
|
||||
RecordBase:
|
||||
type: object
|
||||
required:
|
||||
- Name
|
||||
- Class
|
||||
- TTL
|
||||
- Type
|
||||
properties:
|
||||
Name:
|
||||
type: string
|
||||
Class:
|
||||
type: string
|
||||
enum:
|
||||
- IN
|
||||
- CH
|
||||
- HS
|
||||
- NONE
|
||||
- ANY
|
||||
TTL:
|
||||
type: integer
|
||||
Type:
|
||||
type: string
|
||||
|
||||
RecordTypeA:
|
||||
type: object
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/RecordBase'
|
||||
- type: object
|
||||
required:
|
||||
- Address
|
||||
properties:
|
||||
Address:
|
||||
type: string
|
||||
|
||||
RecordTypeAAAA:
|
||||
type: object
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/RecordBase'
|
||||
- type: object
|
||||
required:
|
||||
- Address
|
||||
properties:
|
||||
Address:
|
||||
type: string
|
||||
|
||||
RecordTypeCAA:
|
||||
type: object
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/RecordBase'
|
||||
required:
|
||||
- IssuerCritical
|
||||
- Value
|
||||
- PropertyTag
|
||||
properties:
|
||||
IssuerCritical:
|
||||
type: boolean
|
||||
Value:
|
||||
type: string
|
||||
PropertyTag:
|
||||
type: string
|
||||
|
||||
RecordTypeCNAME:
|
||||
type: object
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/RecordBase'
|
||||
- type: object
|
||||
required:
|
||||
- Target
|
||||
properties:
|
||||
Target:
|
||||
type: string
|
||||
|
||||
RecordTypeMX:
|
||||
type: object
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/RecordBase'
|
||||
- type: object
|
||||
required:
|
||||
- Preference
|
||||
- MailExchanger
|
||||
properties:
|
||||
Preference:
|
||||
type: integer
|
||||
MailExchanger:
|
||||
type: string
|
||||
|
||||
RecordTypeNS:
|
||||
type: object
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/RecordBase'
|
||||
- type: object
|
||||
required:
|
||||
- Target
|
||||
properties:
|
||||
Target:
|
||||
type: string
|
||||
|
||||
RecordTypePTR:
|
||||
type: object
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/RecordBase'
|
||||
- type: object
|
||||
required:
|
||||
- Target
|
||||
properties:
|
||||
Target:
|
||||
type: string
|
||||
|
||||
RecordTypeSOA:
|
||||
type: object
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/RecordBase'
|
||||
- type: object
|
||||
required:
|
||||
- MasterServerName
|
||||
- MaintainerName
|
||||
- Refresh
|
||||
- Retry
|
||||
- Expire
|
||||
- Minimum
|
||||
- Serial
|
||||
properties:
|
||||
MasterServerName:
|
||||
type: string
|
||||
MaintainerName:
|
||||
type: string
|
||||
Refresh:
|
||||
type: integer
|
||||
Retry:
|
||||
type: integer
|
||||
Expire:
|
||||
type: integer
|
||||
Minimum:
|
||||
type: integer
|
||||
Serial:
|
||||
type: integer
|
||||
|
||||
RecordTypeSRV:
|
||||
type: object
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/RecordBase'
|
||||
- type: object
|
||||
required:
|
||||
- Server
|
||||
- Port
|
||||
- Priority
|
||||
- Weight
|
||||
properties:
|
||||
Server:
|
||||
type: string
|
||||
Port:
|
||||
type: integer
|
||||
Priority:
|
||||
type: integer
|
||||
Weight:
|
||||
type: integer
|
||||
|
||||
RecordTypeSSHFP:
|
||||
type: object
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/RecordBase'
|
||||
- type: object
|
||||
required:
|
||||
- Algorithm
|
||||
- DigestType
|
||||
- Fingerprint
|
||||
properties:
|
||||
Algorithm:
|
||||
type: integer
|
||||
DigestType:
|
||||
type: integer
|
||||
Fingerprint:
|
||||
type: string
|
||||
|
||||
RecordTypeTXT:
|
||||
type: object
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/RecordBase'
|
||||
- type: object
|
||||
required:
|
||||
- Text
|
||||
properties:
|
||||
Text:
|
||||
type: string
|
||||
|
||||
Record:
|
||||
type: object
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/RecordTypeA'
|
||||
- $ref: '#/components/schemas/RecordTypeAAAA'
|
||||
- $ref: '#/components/schemas/RecordTypeCAA'
|
||||
- $ref: '#/components/schemas/RecordTypeCNAME'
|
||||
- $ref: '#/components/schemas/RecordTypeMX'
|
||||
- $ref: '#/components/schemas/RecordTypeNS'
|
||||
- $ref: '#/components/schemas/RecordTypePTR'
|
||||
- $ref: '#/components/schemas/RecordTypeSOA'
|
||||
- $ref: '#/components/schemas/RecordTypeSRV'
|
||||
- $ref: '#/components/schemas/RecordTypeSSHFP'
|
||||
- $ref: '#/components/schemas/RecordTypeTXT'
|
||||
discriminator:
|
||||
propertyName: Type
|
||||
mapping:
|
||||
A: '#/components/schemas/RecordTypeA'
|
||||
AAAA: '#/components/schemas/RecordTypeAAAA'
|
||||
CAA: '#/components/schemas/RecordTypeCAA'
|
||||
CNAME: '#/components/schemas/RecordTypeCNAME'
|
||||
MX: '#/components/schemas/RecordTypeMX'
|
||||
NS: '#/components/schemas/RecordTypeNS'
|
||||
PTR: '#/components/schemas/RecordTypePTR'
|
||||
SOA: '#/components/schemas/RecordTypeSOA'
|
||||
SRV: '#/components/schemas/RecordTypeSRV'
|
||||
SSHFP: '#/components/schemas/RecordTypeSSHFP'
|
||||
TXT: '#/components/schemas/RecordTypeTXT'
|
||||
|
||||
RecordList:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Record'
|
||||
|
||||
|
||||
paths:
|
||||
'/users':
|
||||
post:
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UserRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: ''
|
||||
|
||||
'/users/me/token':
|
||||
post:
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TokenRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TokenResponse'
|
||||
'/zones':
|
||||
get:
|
||||
security:
|
||||
- ApiToken: []
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ZoneList'
|
||||
post:
|
||||
security:
|
||||
- ApiToken: []
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CreateZoneRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Zone'
|
||||
|
||||
'/zones/{zone}/members':
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/ZoneName'
|
||||
post:
|
||||
security:
|
||||
- ApiToken: []
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AddZoneMemberRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: ''
|
||||
|
||||
'/zones/{zone}/records':
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/ZoneName'
|
||||
get:
|
||||
security:
|
||||
- ApiToken: []
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RecordList'
|
||||
post:
|
||||
security:
|
||||
- ApiToken: []
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RecordList'
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
99
e2e/zones.py
Normal file
99
e2e/zones.py
Normal file
|
@ -0,0 +1,99 @@
|
|||
from nomilo_client import ApiClient, Configuration
|
||||
from nomilo_client.api.default_api import DefaultApi
|
||||
from nomilo_client.models import (
|
||||
TokenRequest,
|
||||
RecordTypeSOA,
|
||||
RecordTypeAAAA,
|
||||
RecordTypeCNAME,
|
||||
RecordTypeNS,
|
||||
RecordTypeTXT,
|
||||
RecordList
|
||||
)
|
||||
|
||||
import logging
|
||||
import string
|
||||
import random
|
||||
|
||||
import unittest
|
||||
import warnings
|
||||
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
HOST = 'http://localhost:8000/api/v1'
|
||||
USER='toto'
|
||||
PASSWORD='supersecure'
|
||||
|
||||
|
||||
def build_api(host: str):
|
||||
conf = Configuration(host=HOST)
|
||||
api_client = ApiClient(configuration=conf)
|
||||
return DefaultApi(api_client)
|
||||
|
||||
def build_authenticated_api(host: str, token: TokenRequest):
|
||||
auth_conf = Configuration(host=host, access_token=token.token)
|
||||
api_client = ApiClient(configuration=auth_conf)
|
||||
return DefaultApi(api_client)
|
||||
|
||||
def random_string(length):
|
||||
return ''.join(random.choice(string.ascii_lowercase) for x in range(length))
|
||||
|
||||
def random_name(zone):
|
||||
return '%s.%s' % (random_string(16), zone)
|
||||
|
||||
|
||||
class TestZones(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# Ignore warning about unclosed socket
|
||||
warnings.filterwarnings(action="ignore", message="unclosed", category=ResourceWarning)
|
||||
|
||||
api = build_api(HOST)
|
||||
token = api.users_me_token_post(token_request=TokenRequest(username=USER,password=PASSWORD))
|
||||
cls.api = build_authenticated_api(HOST, token)
|
||||
|
||||
def test_get_zones(self):
|
||||
zones = self.api.zones_get()
|
||||
zone_name = zones.value[0].name
|
||||
self.assertEqual(zone_name, 'example.com.')
|
||||
|
||||
def test_get_records(self):
|
||||
records = self.api.zones_zone_records_get(zone='example.com.')
|
||||
for record in records.value:
|
||||
if type(record) is RecordTypeSOA:
|
||||
with self.subTest(type='soa'):
|
||||
self.assertEqual(record.name, 'example.com.')
|
||||
|
||||
if type(record) is RecordTypeAAAA:
|
||||
with self.subTest(type='ns'):
|
||||
self.assertEqual(record.name, 'srv1.example.com.')
|
||||
self.assertEqual(record.address, '2001:db8:cafe:bc68::2')
|
||||
|
||||
if type(record) is RecordTypeCNAME:
|
||||
with self.subTest(type='cname'):
|
||||
self.assertEqual(record.name, 'www.example.com.')
|
||||
self.assertEqual(record.target, 'srv1.example.com.')
|
||||
|
||||
if type(record) is RecordTypeNS:
|
||||
with self.subTest(type='ns'):
|
||||
self.assertEqual(record.name, 'example.com.')
|
||||
self.assertEqual(record.target, 'ns.example.com.')
|
||||
|
||||
def test_create_records(self):
|
||||
new_record = RecordTypeTXT(
|
||||
_class='IN',
|
||||
ttl=300,
|
||||
name=random_name('example.com.'),
|
||||
text=random_string(32),
|
||||
type='TXT'
|
||||
)
|
||||
|
||||
self.api.zones_zone_records_post(zone='example.com.', record_list=RecordList(value=[new_record]))
|
||||
records = self.api.zones_zone_records_get(zone='example.com.')
|
||||
found = False
|
||||
for record in records.value:
|
||||
if type(record) is RecordTypeTXT and record.name == new_record.name:
|
||||
self.assertEqual(record.text, new_record.text, msg='New record does not have the expected value')
|
||||
found = True
|
||||
|
||||
self.assertTrue(found, msg='New record not found in zone records')
|
Loading…
Reference in a new issue