Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
C
csentry
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Anders Harrisson
csentry
Commits
573d1c87
Commit
573d1c87
authored
7 years ago
by
Benjamin Bertrand
Browse files
Options
Downloads
Patches
Plain Diff
Add network to API
- Allow to pass several mandatory fields in create_generic_model - Add tests
parent
704f4f6b
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
app/api/main.py
+24
-5
24 additions, 5 deletions
app/api/main.py
tests/functional/test_api.py
+111
-9
111 additions, 9 deletions
tests/functional/test_api.py
with
135 additions
and
14 deletions
app/api/main.py
+
24
−
5
View file @
573d1c87
...
@@ -14,7 +14,7 @@ from flask import (current_app, Blueprint, jsonify, request)
...
@@ -14,7 +14,7 @@ from flask import (current_app, Blueprint, jsonify, request)
from
flask_jwt_extended
import
create_access_token
,
jwt_required
from
flask_jwt_extended
import
create_access_token
,
jwt_required
from
flask_ldap3_login
import
AuthenticationResponseStatus
from
flask_ldap3_login
import
AuthenticationResponseStatus
from
..extensions
import
ldap_manager
,
db
from
..extensions
import
ldap_manager
,
db
from
..models
import
Item
,
Manufacturer
,
Model
,
Location
,
Status
,
Action
from
..models
import
Item
,
Manufacturer
,
Model
,
Location
,
Status
,
Action
,
Network
from
..
import
utils
from
..
import
utils
from
..decorators
import
jwt_groups_accepted
from
..decorators
import
jwt_groups_accepted
...
@@ -48,13 +48,14 @@ def get_generic_model(model, args):
...
@@ -48,13 +48,14 @@ def get_generic_model(model, args):
return
jsonify
(
data
)
return
jsonify
(
data
)
def
create_generic_model
(
model
,
mandatory_field
=
'
name
'
):
def
create_generic_model
(
model
,
mandatory_field
s
=
(
'
name
'
,)
):
data
=
request
.
get_json
()
data
=
request
.
get_json
()
if
data
is
None
:
if
data
is
None
:
raise
utils
.
CSEntryError
(
'
Body should be a JSON object
'
)
raise
utils
.
CSEntryError
(
'
Body should be a JSON object
'
)
current_app
.
logger
.
debug
(
f
'
Received:
{
data
}
'
)
current_app
.
logger
.
debug
(
f
'
Received:
{
data
}
'
)
if
mandatory_field
not
in
data
:
for
mandatory_field
in
mandatory_fields
:
raise
utils
.
CSEntryError
(
f
"
Missing mandatory field
'
{
mandatory_field
}
'"
,
status_code
=
422
)
if
mandatory_field
not
in
data
:
raise
utils
.
CSEntryError
(
f
"
Missing mandatory field
'
{
mandatory_field
}
'"
,
status_code
=
422
)
try
:
try
:
instance
=
model
(
**
data
)
instance
=
model
(
**
data
)
except
TypeError
as
e
:
except
TypeError
as
e
:
...
@@ -119,7 +120,7 @@ def create_item():
...
@@ -119,7 +120,7 @@ def create_item():
# an item so ics_id should also be a mandatory field.
# an item so ics_id should also be a mandatory field.
# But there are existing items (in confluence and JIRA) that we want to
# But there are existing items (in confluence and JIRA) that we want to
# import and associate after they have been created.
# import and associate after they have been created.
return
create_generic_model
(
Item
,
mandatory_field
=
'
serial_number
'
)
return
create_generic_model
(
Item
,
mandatory_field
s
=
(
'
serial_number
'
,)
)
@bp.route
(
'
/items/<id_>
'
,
methods
=
[
'
PATCH
'
])
@bp.route
(
'
/items/<id_>
'
,
methods
=
[
'
PATCH
'
])
...
@@ -234,3 +235,21 @@ def get_status():
...
@@ -234,3 +235,21 @@ def get_status():
@jwt_groups_accepted
(
'
admin
'
,
'
create
'
)
@jwt_groups_accepted
(
'
admin
'
,
'
create
'
)
def
create_status
():
def
create_status
():
return
create_generic_model
(
Status
)
return
create_generic_model
(
Status
)
@bp.route
(
'
/networks
'
)
@jwt_required
def
get_networks
():
# TODO: add pagination
query
=
utils
.
get_query
(
Network
.
query
,
request
.
args
)
networks
=
query
.
order_by
(
Network
.
id
)
data
=
[
network
.
to_dict
()
for
network
in
networks
]
return
jsonify
(
data
)
@bp.route
(
'
/networks
'
,
methods
=
[
'
POST
'
])
@jwt_required
@jwt_groups_accepted
(
'
admin
'
)
def
create_network
():
"""
Create a new network
"""
return
create_generic_model
(
Network
,
mandatory_fields
=
(
'
prefix
'
,
'
first
'
,
'
last
'
))
This diff is collapsed.
Click to expand it.
tests/functional/test_api.py
+
111
−
9
View file @
573d1c87
...
@@ -21,9 +21,10 @@ ENDPOINT_MODEL = {
...
@@ -21,9 +21,10 @@ ENDPOINT_MODEL = {
'
locations
'
:
models
.
Location
,
'
locations
'
:
models
.
Location
,
'
status
'
:
models
.
Status
,
'
status
'
:
models
.
Status
,
'
items
'
:
models
.
Item
,
'
items
'
:
models
.
Item
,
'
networks
'
:
models
.
Network
,
}
}
GENERIC_GET_ENDPOINTS
=
[
key
for
key
in
ENDPOINT_MODEL
.
keys
()
if
key
!=
'
items
'
]
GENERIC_GET_ENDPOINTS
=
[
key
for
key
in
ENDPOINT_MODEL
.
keys
()
if
key
not
in
(
'
items
'
,
'
networks
'
)
]
GENERIC_CREATE_ENDPOINTS
=
[
key
for
key
in
ENDPOINT_MODEL
.
keys
()
if
key
not
in
(
'
items
'
,
'
actions
'
)]
GENERIC_CREATE_ENDPOINTS
=
[
key
for
key
in
ENDPOINT_MODEL
.
keys
()
if
key
not
in
(
'
items
'
,
'
actions
'
,
'
networks
'
)]
CREATE_AUTH_ENDPOINTS
=
[
key
for
key
in
ENDPOINT_MODEL
.
keys
()
if
key
!=
'
actions
'
]
CREATE_AUTH_ENDPOINTS
=
[
key
for
key
in
ENDPOINT_MODEL
.
keys
()
if
key
!=
'
actions
'
]
...
@@ -106,10 +107,10 @@ def check_names(response, names):
...
@@ -106,10 +107,10 @@ def check_names(response, names):
assert
set
(
names
)
==
response_names
assert
set
(
names
)
==
response_names
def
check_i
tems
(
response
,
inputs
):
def
check_i
nput_is_subset_of_response
(
response
,
inputs
):
# Sort the response by id to match the inputs order
# Sort the response by id to match the inputs order
response_
item
s
=
sorted
(
response
.
json
,
key
=
lambda
d
:
d
[
'
id
'
])
response_
elt
s
=
sorted
(
response
.
json
,
key
=
lambda
d
:
d
[
'
id
'
])
for
d1
,
d2
in
zip
(
inputs
,
response_
item
s
):
for
d1
,
d2
in
zip
(
inputs
,
response_
elt
s
):
assert
set
(
d1
.
items
()).
issubset
(
set
(
d2
.
items
()))
assert
set
(
d1
.
items
()).
issubset
(
set
(
d2
.
items
()))
...
@@ -211,7 +212,7 @@ def test_create_item(client, user_token):
...
@@ -211,7 +212,7 @@ def test_create_item(client, user_token):
# check all items that were created
# check all items that were created
assert
models
.
Item
.
query
.
count
()
==
3
assert
models
.
Item
.
query
.
count
()
==
3
response
=
get
(
client
,
'
/api/items
'
,
user_token
)
response
=
get
(
client
,
'
/api/items
'
,
user_token
)
check_i
tems
(
response
,
(
data
,
data
,
data2
))
check_i
nput_is_subset_of_response
(
response
,
(
data
,
data
,
data2
))
def
test_create_item_invalid_ics_id
(
client
,
user_token
):
def
test_create_item_invalid_ics_id
(
client
,
user_token
):
...
@@ -410,20 +411,121 @@ def test_get_items(client, session, readonly_token):
...
@@ -410,20 +411,121 @@ def test_get_items(client, session, readonly_token):
response
=
get
(
client
,
'
/api/items
'
,
token
=
readonly_token
)
response
=
get
(
client
,
'
/api/items
'
,
token
=
readonly_token
)
assert
response
.
status_code
==
200
assert
response
.
status_code
==
200
assert
len
(
response
.
json
)
==
3
assert
len
(
response
.
json
)
==
3
check_i
tems
(
response
,
(
item1
.
to_dict
(),
item2
.
to_dict
(),
item3
.
to_dict
()))
check_i
nput_is_subset_of_response
(
response
,
(
item1
.
to_dict
(),
item2
.
to_dict
(),
item3
.
to_dict
()))
# test filtering
# test filtering
response
=
get
(
client
,
'
/api/items?serial_number=234567
'
,
token
=
readonly_token
)
response
=
get
(
client
,
'
/api/items?serial_number=234567
'
,
token
=
readonly_token
)
assert
response
.
status_code
==
200
assert
response
.
status_code
==
200
assert
len
(
response
.
json
)
==
1
assert
len
(
response
.
json
)
==
1
check_i
tems
(
response
,
(
item2
.
to_dict
(),))
check_i
nput_is_subset_of_response
(
response
,
(
item2
.
to_dict
(),))
# filtering on location_id works but not location (might want to change that)
# filtering on location_id works but not location (might want to change that)
response
=
get
(
client
,
f
'
/api/items?location_id=
{
item1
.
location_id
}
'
,
token
=
readonly_token
)
response
=
get
(
client
,
f
'
/api/items?location_id=
{
item1
.
location_id
}
'
,
token
=
readonly_token
)
assert
response
.
status_code
==
200
assert
response
.
status_code
==
200
assert
len
(
response
.
json
)
==
1
assert
len
(
response
.
json
)
==
1
check_i
tems
(
response
,
(
item1
.
to_dict
(),))
check_i
nput_is_subset_of_response
(
response
,
(
item1
.
to_dict
(),))
response
=
get
(
client
,
'
/api/items?location=ESS
'
,
token
=
readonly_token
)
response
=
get
(
client
,
'
/api/items?location=ESS
'
,
token
=
readonly_token
)
check_response_message
(
response
,
'
Invalid query arguments
'
,
422
)
check_response_message
(
response
,
'
Invalid query arguments
'
,
422
)
# using an unknown key raises a 422
# using an unknown key raises a 422
response
=
get
(
client
,
'
/api/items?foo=bar
'
,
token
=
readonly_token
)
response
=
get
(
client
,
'
/api/items?foo=bar
'
,
token
=
readonly_token
)
check_response_message
(
response
,
'
Invalid query arguments
'
,
422
)
check_response_message
(
response
,
'
Invalid query arguments
'
,
422
)
def
test_get_networks
(
client
,
session
,
readonly_token
):
# Create some networks
location
=
models
.
Location
(
name
=
'
G02
'
)
session
.
add
(
location
)
session
.
flush
()
network1
=
models
.
Network
(
prefix
=
'
172.16.1.0/24
'
,
first
=
'
172.16.1.1
'
,
last
=
'
172.16.1.254
'
,
label
=
'
network1
'
)
network2
=
models
.
Network
(
prefix
=
'
172.16.20.0/22
'
,
first
=
'
172.16.20.11
'
,
last
=
'
172.16.20.250
'
)
network3
=
models
.
Network
(
prefix
=
'
172.16.5.0/24
'
,
first
=
'
172.16.5.10
'
,
last
=
'
172.16.5.254
'
,
location_id
=
location
.
id
)
for
network
in
(
network1
,
network2
,
network3
):
session
.
add
(
network
)
session
.
commit
()
response
=
get
(
client
,
'
/api/networks
'
,
token
=
readonly_token
)
assert
response
.
status_code
==
200
assert
len
(
response
.
json
)
==
3
check_input_is_subset_of_response
(
response
,
(
network1
.
to_dict
(),
network2
.
to_dict
(),
network3
.
to_dict
()))
# test filtering by location_id
response
=
get
(
client
,
f
'
/api/networks?location_id=
{
location
.
id
}
'
,
token
=
readonly_token
)
assert
response
.
status_code
==
200
assert
len
(
response
.
json
)
==
1
check_input_is_subset_of_response
(
response
,
(
network3
.
to_dict
(),))
# test filtering by prefix
response
=
get
(
client
,
'
/api/networks?prefix=172.16.20.0/22
'
,
token
=
readonly_token
)
assert
response
.
status_code
==
200
assert
len
(
response
.
json
)
==
1
check_input_is_subset_of_response
(
response
,
(
network2
.
to_dict
(),))
def
test_create_network_auth_fail
(
client
,
session
,
user_token
):
# admin is required to create networks
response
=
post
(
client
,
'
/api/networks
'
,
data
=
{},
token
=
user_token
)
check_response_message
(
response
,
"
User doesn
'
t have the required group
"
,
403
)
def
test_create_network
(
client
,
session
,
admin_token
):
location
=
models
.
Location
(
name
=
'
G02
'
)
session
.
add
(
location
)
session
.
commit
()
# check that prefix, first and last are mandatory
response
=
post
(
client
,
'
/api/networks
'
,
data
=
{},
token
=
admin_token
)
check_response_message
(
response
,
"
Missing mandatory field
'
prefix
'"
,
422
)
response
=
post
(
client
,
'
/api/networks
'
,
data
=
{
'
first
'
:
'
172.16.1.10
'
,
'
last
'
:
'
172.16.1.250
'
},
token
=
admin_token
)
check_response_message
(
response
,
"
Missing mandatory field
'
prefix
'"
,
422
)
response
=
post
(
client
,
'
/api/networks
'
,
data
=
{
'
prefix
'
:
'
172.16.1.0/24
'
},
token
=
admin_token
)
check_response_message
(
response
,
"
Missing mandatory field
'
first
'"
,
422
)
response
=
post
(
client
,
'
/api/networks
'
,
data
=
{
'
prefix
'
:
'
172.16.1.0/24
'
,
'
first
'
:
'
172.16.1.10
'
},
token
=
admin_token
)
check_response_message
(
response
,
"
Missing mandatory field
'
last
'"
,
422
)
data
=
{
'
prefix
'
:
'
172.16.1.0/24
'
,
'
first
'
:
'
172.16.1.10
'
,
'
last
'
:
'
172.16.1.250
'
}
response
=
post
(
client
,
'
/api/networks
'
,
data
=
data
,
token
=
admin_token
)
assert
response
.
status_code
==
201
assert
{
'
id
'
,
'
prefix
'
,
'
first
'
,
'
last
'
,
'
label
'
,
'
vlanid
'
,
'
gateway
'
,
'
location
'
}
==
set
(
response
.
json
.
keys
())
assert
response
.
json
[
'
prefix
'
]
==
'
172.16.1.0/24
'
assert
response
.
json
[
'
first
'
]
==
'
172.16.1.10
'
assert
response
.
json
[
'
last
'
]
==
'
172.16.1.250
'
# Check that prefix shall be unique
response
=
post
(
client
,
'
/api/networks
'
,
data
=
data
,
token
=
admin_token
)
check_response_message
(
response
,
'
IntegrityError
'
,
409
)
# Check that all parameters can be passed
data2
=
{
'
prefix
'
:
'
172.16.5.0/24
'
,
'
first
'
:
'
172.16.5.11
'
,
'
last
'
:
'
172.16.5.250
'
,
'
label
'
:
'
G02
'
,
'
gateway
'
:
'
172.16.5.10
'
,
'
vlanid
'
:
1601
,
'
location_id
'
:
location
.
id
}
response
=
post
(
client
,
'
/api/networks
'
,
data
=
data2
,
token
=
admin_token
)
assert
response
.
status_code
==
201
assert
response
.
json
[
'
location
'
]
==
location
.
name
# check all items that were created
assert
models
.
Network
.
query
.
count
()
==
2
def
test_create_network_constraint_fail
(
client
,
session
,
admin_token
):
# first not in prefix
data
=
{
'
prefix
'
:
'
172.16.1.0/24
'
,
'
first
'
:
'
172.16.2.10
'
,
'
last
'
:
'
172.16.1.250
'
}
response
=
post
(
client
,
'
/api/networks
'
,
data
=
data
,
token
=
admin_token
)
check_response_message
(
response
,
'
IntegrityError
'
,
409
)
# last not in prefix
data
=
{
'
prefix
'
:
'
172.16.1.0/24
'
,
'
first
'
:
'
172.16.1.10
'
,
'
last
'
:
'
172.16.5.250
'
}
response
=
post
(
client
,
'
/api/networks
'
,
data
=
data
,
token
=
admin_token
)
check_response_message
(
response
,
'
IntegrityError
'
,
409
)
# first > last
data
=
{
'
prefix
'
:
'
172.16.1.0/24
'
,
'
first
'
:
'
172.16.1.10
'
,
'
last
'
:
'
172.16.1.9
'
}
response
=
post
(
client
,
'
/api/networks
'
,
data
=
data
,
token
=
admin_token
)
check_response_message
(
response
,
'
IntegrityError
'
,
409
)
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment