Skip to content

Commit

Permalink
0.11.0 Release.
Browse files Browse the repository at this point in the history
  • Loading branch information
Adminiuga committed Nov 11, 2019
2 parents 2e1806d + 261bd99 commit ca55a67
Show file tree
Hide file tree
Showing 18 changed files with 457 additions and 47 deletions.
22 changes: 22 additions & 0 deletions .github/release-drafter.yml
@@ -0,0 +1,22 @@
name-template: '$NEXT_PATCH_VERSION Release.'
tag-template: '$NEXT_PATCH_VERSION'
categories:
- title: 'Breaking changes'
labels:
- 'breaking'
- title: '🚀 Features'
labels:
- 'feature'
- 'enhancement'
- title: '🐛 Bug Fixes'
labels:
- 'fix'
- 'bugfix'
- 'bug'
- title: '🧰 Maintenance'
label: 'chore'
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
template: |
## Changes
$CHANGES
16 changes: 16 additions & 0 deletions .github/workflows/release-management.yml
@@ -0,0 +1,16 @@
name: Release Management

on:
push:
# branches to consider in the event; optional, defaults to all
branches:
- master

jobs:
update_draft_release:
runs-on: ubuntu-latest
steps:
# Drafts your next Release notes as Pull Requests are merged into "master"
- uses: toolmantim/release-drafter@v5.2.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
6 changes: 3 additions & 3 deletions .travis.yml
Expand Up @@ -2,16 +2,16 @@ language: python
matrix:
fast_finish: true
include:
- python: "3.5"
- python: "3.6"
env: TOXENV=lint
- python: "3.5"
env: TOXENV=py35
- python: "3.6"
env: TOXENV=py36
- python: "3.7"
env: TOXENV=py37
dist: xenial
sudo: true
- python: "3.8"
env: TOXENV=py38
install: pip install -U setuptools tox coveralls
script: tox
after_success: coveralls
3 changes: 3 additions & 0 deletions README.md
Expand Up @@ -17,6 +17,9 @@ zigpy works with separate radio libraries which can each interface with multiple
- [Nortek GoControl QuickStick Combo Model HUSBZB-1 (Z-Wave & Zigbee USB Adapter)](https://www.nortekcontrol.com/products/2gig/husbzb-1-gocontrol-quickstick-combo/)
- [Elelabs Zigbee USB Adapter](https://elelabs.com/products/elelabs_usb_adapter.html)
- [Elelabs Zigbee Raspberry Pi Shield](https://elelabs.com/products/elelabs_zigbee_shield.html)
- Telegesis ETRX357USB (Note! First have to be flashed with other EmberZNet firmware)
- Telegesis ETRX357USB-LRS (Note! First have to be flashed with other EmberZNet firmware)
- Telegesis ETRX357USB-LRS+8M (Note! First have to be flashed with other EmberZNet firmware)
- XBee Zigbee based radios (via the [zigpy-xbee](https://github.com/zigpy/zigpy-xbee) library for zigpy)
- Digi XBee Series 2C (S2C) modules
- Digi XBee Series 2 (S2) modules. Note: These will need to be manually flashed with the Zigbee Coordinator API firmware via XCTU.
Expand Down
2 changes: 2 additions & 0 deletions setup.py
Expand Up @@ -18,6 +18,8 @@
'crccheck',
],
tests_require=[
'asynctest',
'pytest',
'pytest-asyncio',
],
)
9 changes: 9 additions & 0 deletions tests/test_application.py
Expand Up @@ -264,3 +264,12 @@ def test_props(app):
assert app.extended_pan_id is None
assert app.pan_id is None
assert app.nwk_update_id is None


@pytest.mark.asyncio
async def test_mrequest(app):
s = mock.sentinel
with pytest.raises(NotImplementedError):
await app.mrequest(
s.group_id, s.profile_id, s.cluster, s.src_ep, s.sequence, s.data
)
141 changes: 137 additions & 4 deletions tests/test_group.py
@@ -1,13 +1,13 @@
from unittest import mock

import asynctest
import pytest

import zigpy.types as t
from zigpy.application import ControllerApplication
import zigpy.device
import zigpy.group
import zigpy.endpoint

import zigpy.group
import zigpy.types as t
import zigpy.zcl

FIXTURE_GRP_ID = 0x1001
FIXTURE_GRP_NAME = "fixture group"
Expand Down Expand Up @@ -36,6 +36,12 @@ def group():
return zigpy.group.Group(FIXTURE_GRP_ID, FIXTURE_GRP_NAME, groups_mock)


@pytest.fixture
def group_endpoint(group):
group.request = asynctest.CoroutineMock()
return zigpy.group.GroupEndpoint(group)


def test_add_group(groups, monkeypatch):
monkeypatch.setattr(
zigpy.group,
Expand Down Expand Up @@ -174,3 +180,130 @@ def test_group_magic_methods(group, endpoint):
assert endpoint.unique_id in group.members
assert endpoint.unique_id in group
assert group[endpoint.unique_id] is endpoint


def test_groups_properties(groups: zigpy.group.Groups):
"""Test groups properties."""
assert groups.application is not None


def test_group_properties(group: zigpy.group.Group):
"""Test group properties."""
assert group.application is not None
assert group.groups is not None
assert isinstance(group.endpoint, zigpy.group.GroupEndpoint)


def test_group_cluster_from_cluster_id():
"""Group cluster by cluster id."""

cls = zigpy.group.GroupCluster.from_id(mock.MagicMock(), 6)
assert isinstance(cls, zigpy.zcl.Cluster)

with pytest.raises(KeyError):
zigpy.group.GroupCluster.from_id(mock.MagicMock(), 0xFFFF)


def test_group_cluster_from_cluster_name():
"""Group cluster by cluster name."""

cls = zigpy.group.GroupCluster.from_attr(mock.MagicMock(), "on_off")
assert isinstance(cls, zigpy.zcl.Cluster)

with pytest.raises(AttributeError):
zigpy.group.GroupCluster.from_attr(mock.MagicMock(), "no_such_cluster")


def test_group_ep_request(group_endpoint):
assert group_endpoint.device is not None
group_endpoint.request(
mock.sentinel.cluster,
mock.sentinel.seq,
mock.sentinel.data,
mock.sentinel.extra_arg,
extra_kwarg=mock.sentinel.extra_kwarg,
)
assert group_endpoint.device.request.call_count == 1
assert group_endpoint.device.request.call_args[0][1] is mock.sentinel.cluster
assert group_endpoint.device.request.call_args[0][2] is mock.sentinel.seq
assert group_endpoint.device.request.call_args[0][3] is mock.sentinel.data


def test_group_ep_reply(group_endpoint):
group_endpoint.request = mock.MagicMock()
group_endpoint.reply(
mock.sentinel.cluster,
mock.sentinel.seq,
mock.sentinel.data,
mock.sentinel.extra_arg,
extra_kwarg=mock.sentinel.extra_kwarg,
)
assert group_endpoint.request.call_count == 1
assert group_endpoint.request.call_args[0][0] is mock.sentinel.cluster
assert group_endpoint.request.call_args[0][1] is mock.sentinel.seq
assert group_endpoint.request.call_args[0][2] is mock.sentinel.data
assert group_endpoint.request.call_args[0][3] is mock.sentinel.extra_arg
assert (
group_endpoint.request.call_args[1]["extra_kwarg"] is mock.sentinel.extra_kwarg
)


def test_group_ep_by_cluster_id(group_endpoint, monkeypatch):
clusters = {}
group_endpoint._clusters = mock.MagicMock(return_value=clusters)
group_endpoint._clusters.__getitem__.side_effect = clusters.__getitem__
group_endpoint._clusters.__setitem__.side_effect = clusters.__setitem__

group_cluster_mock = mock.MagicMock()
group_cluster_mock.from_id.return_value = mock.sentinel.group_cluster
monkeypatch.setattr(zigpy.group, "GroupCluster", group_cluster_mock)

assert len(clusters) == 0
cluster = group_endpoint[6]
assert cluster is mock.sentinel.group_cluster
assert group_cluster_mock.from_id.call_count == 1

assert len(clusters) == 1
cluster = group_endpoint[6]
assert cluster is mock.sentinel.group_cluster
assert group_cluster_mock.from_id.call_count == 1


def test_group_ep_by_cluster_attr(group_endpoint, monkeypatch):
cluster_by_attr = {}
group_endpoint._cluster_by_attr = mock.MagicMock(return_value=cluster_by_attr)
group_endpoint._cluster_by_attr.__getitem__.side_effect = (
cluster_by_attr.__getitem__
)
group_endpoint._cluster_by_attr.__setitem__.side_effect = (
cluster_by_attr.__setitem__
)

group_cluster_mock = mock.MagicMock()
group_cluster_mock.from_attr.return_value = mock.sentinel.group_cluster
monkeypatch.setattr(zigpy.group, "GroupCluster", group_cluster_mock)

assert len(cluster_by_attr) == 0
cluster = group_endpoint.on_off
assert cluster is mock.sentinel.group_cluster
assert group_cluster_mock.from_attr.call_count == 1

assert len(cluster_by_attr) == 1
cluster = group_endpoint.on_off
assert cluster is mock.sentinel.group_cluster
assert group_cluster_mock.from_attr.call_count == 1


def test_group_request(group):
group.request(
mock.sentinel.profile,
mock.sentinel.cluster,
mock.sentinel.sequence,
mock.sentinel.data,
)
assert group.application.mrequest.call_count == 1
assert group.application.mrequest.call_args[0][0] == group.group_id
assert group.application.mrequest.call_args[0][1] is mock.sentinel.profile
assert group.application.mrequest.call_args[0][2] is mock.sentinel.cluster
assert group.application.mrequest.call_args[0][4] is mock.sentinel.sequence
assert group.application.mrequest.call_args[0][5] is mock.sentinel.data
11 changes: 11 additions & 0 deletions tests/test_zcl_foundation.py
Expand Up @@ -306,3 +306,14 @@ def test_data_types():
data_types_set = set([d[1] for d in foundation.DATA_TYPES.values()])
dt_2_id_set = set(foundation.DATA_TYPE_IDX.keys())
assert data_types_set == dt_2_id_set


def test_attribute_report():
a = foundation.AttributeReportingConfig()
a.direction = 0x01
a.attrid = 0xAA55
a.timeout = 900
b = foundation.AttributeReportingConfig(a)
assert a.attrid == b.attrid
assert a.direction == b.direction
assert a.timeout == b.timeout
90 changes: 70 additions & 20 deletions tests/test_zigbee_util.py
Expand Up @@ -250,27 +250,77 @@ def test_zigbee_security_hash():
]


def test_convert_install_code():
message = bytes([0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x4A, 0xF7])
@pytest.mark.parametrize(
"message, expected_key",
[
(
bytes([0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x4A, 0xF7]),
[
0x41,
0x61,
0x8F,
0xC0,
0xC8,
0x3B,
0x0E,
0x14,
0xA5,
0x89,
0x95,
0x4B,
0x16,
0xE3,
0x14,
0x66,
],
),
(
bytes(
[
0x83,
0xFE,
0xD3,
0x40,
0x7A,
0x93,
0x97,
0x23,
0xA5,
0xC6,
0x39,
0xB2,
0x69,
0x16,
0xD5,
0x05,
0xC3,
0xB5,
]
),
[
0x66,
0xB6,
0x90,
0x09,
0x81,
0xE1,
0xEE,
0x3C,
0xA4,
0x20,
0x6B,
0x6B,
0x86,
0x1C,
0x02,
0xBB,
],
),
],
)
def test_convert_install_code(message, expected_key):
key = util.convert_install_code(message)
assert key == [
0x41,
0x61,
0x8F,
0xC0,
0xC8,
0x3B,
0x0E,
0x14,
0xA5,
0x89,
0x95,
0x4B,
0x16,
0xE3,
0x14,
0x66,
]
assert key == expected_key


def test_fail_convert_install_code():
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Expand Up @@ -4,7 +4,7 @@
# and then run "tox" from this directory.

[tox]
envlist = py35, py36, py37, lint
envlist = py36, py37, py38, lint
skip_missing_interpreters = True

[testenv]
Expand Down
2 changes: 1 addition & 1 deletion zigpy/__init__.py
@@ -1,6 +1,6 @@
# coding: utf-8
MAJOR_VERSION = 0
MINOR_VERSION = 10
MINOR_VERSION = 11
PATCH_VERSION = "0"
__short_version__ = "{}.{}".format(MAJOR_VERSION, MINOR_VERSION)
__version__ = "{}.{}".format(__short_version__, PATCH_VERSION)

0 comments on commit ca55a67

Please sign in to comment.