mirror of
https://github.com/pushbits/server.git
synced 2025-05-03 20:26:23 +02:00
Merge branch 'pushbits:master' into master
This commit is contained in:
commit
944e7da818
22 changed files with 1037 additions and 107 deletions
32
.github/workflows/main.yml
vendored
32
.github/workflows/main.yml
vendored
|
@ -1,34 +1,26 @@
|
|||
name: Main
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
tags:
|
||||
- '**'
|
||||
- '!v[0-9]+.[0-9]+.[0-9]+'
|
||||
pull_request:
|
||||
jobs:
|
||||
test_build_publish:
|
||||
name: Test, build, and publish
|
||||
test_build:
|
||||
name: Test and build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install dependencies
|
||||
run: make setup
|
||||
- name: Export GOBIN
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.16
|
||||
- name: Install dependencies
|
||||
run: make setup
|
||||
- name: Run tests
|
||||
run: make test
|
||||
- name: Build image
|
||||
run: make build_image
|
||||
- name: Get Branch # Needed to evaluate env.BRANCH.
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/v') && github.event_name == 'push' }} # Otherwise will fail on pull requests.
|
||||
run: |
|
||||
raw=$(git branch -r --contains ${{ github.ref }})
|
||||
branch=${raw##*/}
|
||||
echo "BRANCH=$branch" >> $GITHUB_ENV
|
||||
- name: Login to Docker Hub
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/v') && github.event_name == 'push' && env.BRANCH == 'master' }} # Only login for tagged commits pushed to master.
|
||||
uses: docker/login-action@v1
|
||||
with: # Secrets are not exposed to pull request contexts.
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Publish image
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/v') && github.event_name == 'push' && env.BRANCH == 'master' }} # Only publish for tagged commits pushed to master.
|
||||
run: make push_image
|
||||
|
|
29
.github/workflows/publish.yml
vendored
Normal file
29
.github/workflows/publish.yml
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
name: Publish
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v[0-9]+.[0-9]+.[0-9]+'
|
||||
jobs:
|
||||
test_build_publish:
|
||||
name: Test, build, and publish
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Export GOBIN
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.16
|
||||
- name: Install dependencies
|
||||
run: make setup
|
||||
- name: Run tests
|
||||
run: make test
|
||||
- name: Build image
|
||||
run: make build_image
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Publish image
|
||||
run: make push_image
|
4
Makefile
4
Makefile
|
@ -18,8 +18,8 @@ test:
|
|||
|
||||
.PHONY: setup
|
||||
setup:
|
||||
go get -u github.com/fzipp/gocyclo/cmd/gocyclo
|
||||
go get -u honnef.co/go/tools/cmd/staticcheck
|
||||
go install github.com/fzipp/gocyclo/cmd/gocyclo@latest
|
||||
go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||
|
||||
.PHONY: build_image
|
||||
build_image:
|
||||
|
|
63
README.md
63
README.md
|
@ -30,15 +30,14 @@ can be reused.
|
|||
|
||||
### Why Matrix instead of X?
|
||||
|
||||
I would totally do this with Signal if there was a proper API.
|
||||
Unfortunately, neither [Signal](https://signal.org/) nor [WhatsApp](https://www.whatsapp.com/) come with an API through which PushBits could interact.
|
||||
This project totally would've used Signal if it would offer a proper API.
|
||||
Sadly, neither [Signal](https://signal.org/) nor [WhatsApp](https://www.whatsapp.com/) come with an API (at the time of writing) through which PushBits could interact.
|
||||
|
||||
In [Telegram](https://telegram.org/) there is an API to run bots, but these are limited in that they cannot create chats by themselves.
|
||||
If you insist on going with Telegram, have a look at [webhook2telegram](https://github.com/muety/webhook2telegram).
|
||||
|
||||
I myself started using Matrix only for this project.
|
||||
The idea of a federated, synchronized but yet end-to-end encrypted protocol is awesome, but its clients simply aren't really there yet.
|
||||
Still, if you haven't tried it yet, I suggest you to check it out.
|
||||
Still, if you haven't tried it yet, we'd encourage you to check it out.
|
||||
|
||||
## 🤘 Features
|
||||
|
||||
|
@ -98,12 +97,12 @@ The SQLite database would be written to `./data/pushbits.db`.
|
|||
## 📄 Usage
|
||||
|
||||
Now, how can you interact with the server?
|
||||
I wrote [a little CLI tool called pbcli](https://github.com/PushBits/cli) to make basic API requests to the server.
|
||||
We provide [a little CLI tool called pbcli](https://github.com/PushBits/cli) to make basic API requests to the server.
|
||||
It helps you to create new users and applications.
|
||||
You will find further instructions in the linked repository.
|
||||
|
||||
At the time of writing, there is no fancy GUI built-in, and I'm not sure if this is necessary at all.
|
||||
I don't do much front end development myself, so if you want to contribute in this regard I'm happy if you reach out!
|
||||
At the time of writing, there is no fancy GUI built-in, and we're not sure if this is necessary at all.
|
||||
Currently, we would like to avoid front end development, so if you want to contribute in this regard we're happy if you reach out!
|
||||
|
||||
After you have created a user and an application, you can use the API to send a push notification to your Matrix account.
|
||||
|
||||
|
@ -124,13 +123,13 @@ pbcli application show $PB_APPLICATION --url https://pushbits.example.com --user
|
|||
|
||||
### Message options
|
||||
|
||||
Messages are supporting three different syntaxes:
|
||||
Messages can be specified in three different syntaxes:
|
||||
|
||||
* text/plain
|
||||
* text/html
|
||||
* text/markdown
|
||||
* `text/plain`
|
||||
* `text/html`
|
||||
* `text/markdown`
|
||||
|
||||
To set a specific syntax you need to set the `extras` ([inspired by Gotifys message extras](https://gotify.net/docs/msgextras#clientdisplay)):
|
||||
To set a specific syntax you need to set the `extras` parameter ([inspired by Gotify's message extras](https://gotify.net/docs/msgextras#clientdisplay)):
|
||||
|
||||
```bash
|
||||
curl \
|
||||
|
@ -140,13 +139,16 @@ curl \
|
|||
"https://pushbits.example.com/message?token=$PB_TOKEN"
|
||||
```
|
||||
|
||||
HTML-Content might not be fully rendered in your Matrix-Client - see the corresponding [Matrix specs](https://spec.matrix.org/unstable/client-server-api/#mroommessage-msgtypes). This also holds for Markdown, as it is transfered to the corresponding HTML-syntax.
|
||||
HTML content might not be fully rendered in your Matrix client; see the corresponding [Matrix specs](https://spec.matrix.org/unstable/client-server-api/#mroommessage-msgtypes).
|
||||
This also holds for Markdown, as it is translated into the corresponding HTML syntax.
|
||||
|
||||
### Deleting a Message
|
||||
|
||||
You can delete a message, this will send a notification in response to the original message informing you that the message is "deleted".
|
||||
You can delete a message, this will send a notification in response to the original message informing you that the message is "deleted".
|
||||
|
||||
You need the message ID for deleting a message. As it might contain characters not valid in uris we provide an additional `id_url_encoded` field for messages, use that value for deleting a message.
|
||||
To delete a message, you need its message ID which is provided as part of the response when you send the message.
|
||||
The ID might contain characters not valid in URIs.
|
||||
We hence provide an additional `id_url_encoded` field for messages; you can directly use it when deleting a message without performing encoding yourself.
|
||||
|
||||
```bash
|
||||
curl \
|
||||
|
@ -169,3 +171,34 @@ git clone https://github.com/pushbits/server.git
|
|||
```
|
||||
|
||||
[](https://starchart.cc/pushbits/server)
|
||||
|
||||
### Testing
|
||||
|
||||
Testing is essential for delivering good and reliable software.
|
||||
PushBits uses Go's integrated test features.
|
||||
Unfortunately, writing tests is quite time consuming and therefore not every feature and every line of code is automatically tested.
|
||||
Feel free to help us improve our tests.
|
||||
|
||||
To run tests for a single (sub)module you can simply execute the following command in the module's folder.
|
||||
|
||||
```bash
|
||||
go test
|
||||
```
|
||||
|
||||
To get the testing coverage for a module use the `-cover` flag.
|
||||
|
||||
```bash
|
||||
go test -cover
|
||||
```
|
||||
|
||||
To execute a single test use the `-run` flag.
|
||||
|
||||
```bash
|
||||
go test -run "TestApi_getUser"
|
||||
```
|
||||
|
||||
Running tests for all PushBits module is done like this:
|
||||
|
||||
```bash
|
||||
make test
|
||||
```
|
||||
|
|
|
@ -57,6 +57,6 @@ crypto:
|
|||
saltlength: 16
|
||||
keylength: 32
|
||||
|
||||
formatting:
|
||||
formatting:
|
||||
# Whether to use colored titles based on the message priority (<0: grey, 0-3: default, 4-10: yellow, 10-20: orange, >20: red).
|
||||
coloredtitle: false
|
||||
|
|
9
go.mod
9
go.mod
|
@ -1,10 +1,9 @@
|
|||
module github.com/pushbits/server
|
||||
|
||||
go 1.14
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/alexedwards/argon2id v0.0.0-20201228115903-cf543ebc1f7b
|
||||
github.com/fzipp/gocyclo v0.3.1 // indirect
|
||||
github.com/gin-contrib/location v0.0.2
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
github.com/go-playground/validator/v10 v10.3.0 // indirect
|
||||
|
@ -18,12 +17,12 @@ require (
|
|||
github.com/mattn/go-sqlite3 v1.14.6 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/ugorji/go v1.2.4 // indirect
|
||||
golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 // indirect
|
||||
golang.org/x/tools v0.1.3 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gorm.io/driver/mysql v1.0.4
|
||||
gorm.io/driver/sqlite v1.1.4
|
||||
gorm.io/gorm v1.20.12
|
||||
honnef.co/go/tools v0.2.0 // indirect
|
||||
)
|
||||
|
|
49
go.sum
49
go.sum
|
@ -5,8 +5,6 @@ github.com/alexedwards/argon2id v0.0.0-20201228115903-cf543ebc1f7b/go.mod h1:Kmn
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fzipp/gocyclo v0.3.1 h1:A9UeX3HJSXTBzvHzhqoYVuE0eAhe+aM8XBCCwsPMZOc=
|
||||
github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E=
|
||||
github.com/gin-contrib/location v0.0.2 h1:QZKh1+K/LLR4KG/61eIO3b7MLuKi8tytQhV6texLgP4=
|
||||
github.com/gin-contrib/location v0.0.2/go.mod h1:NGoidiRlf0BlA/VKSVp+g3cuSMeTmip/63PhEjRhUAc=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
|
@ -19,13 +17,11 @@ github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8c
|
|||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/go-playground/validator/v10 v10.3.0 h1:nZU+7q+yJoFmwvNgv/LnPUkwPal62+b2xXj0AU1Es7o=
|
||||
github.com/go-playground/validator/v10 v10.3.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
|
@ -48,11 +44,9 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
|
|||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
|
||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
|
@ -63,11 +57,9 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
|
|||
github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
|
||||
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
|
@ -75,64 +67,30 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go v1.2.4 h1:cTciPbZ/VSOzCLKclmssnfQ/jyoVyOcJ3aoJyUV1Urc=
|
||||
github.com/ugorji/go v1.2.4/go.mod h1:EuaSCk8iZMdIspsu6HXH7X2UGKw1ezO4wCfGszGmmo4=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ugorji/go/codec v1.2.4 h1:C5VurWRRCKjuENsbM6GYVw8W++WVW9rSxoACKIvxzz8=
|
||||
github.com/ugorji/go/codec v1.2.4/go.mod h1:bWBu1+kIRWcF8uMklKaJrR6fTWQOwAlrIzX22pHwryA=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 h1:C+AwYEtBp/VQwoLntUmQ/yx3MS9vmZaKNdw5eOpoQe8=
|
||||
golang.org/x/sys v0.0.0-20210608053332-aa57babbf139/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.3 h1:L69ShwSZEyCsLKoAxDKeMvLDZkumEe8gXUZAjab0tX8=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
@ -146,7 +104,6 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
|
@ -159,5 +116,3 @@ gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9D
|
|||
gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/gorm v1.20.12 h1:ebZ5KrSHzet+sqOCVdH9mTjW91L298nX3v5lVxAzSUY=
|
||||
gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
honnef.co/go/tools v0.2.0 h1:ws8AfbgTX3oIczLPNPCu5166oBg9ST2vNs0rcht+mDE=
|
||||
honnef.co/go/tools v0.2.0/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
|
||||
|
|
|
@ -114,6 +114,7 @@ func (h *ApplicationHandler) CreateApplication(ctx *gin.Context) {
|
|||
var createApplication model.CreateApplication
|
||||
|
||||
if err := ctx.Bind(&createApplication); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
348
internal/api/application_test.go
Normal file
348
internal/api/application_test.go
Normal file
|
@ -0,0 +1,348 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pushbits/server/internal/configuration"
|
||||
"github.com/pushbits/server/internal/database"
|
||||
"github.com/pushbits/server/internal/model"
|
||||
"github.com/pushbits/server/tests"
|
||||
"github.com/pushbits/server/tests/mockups"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var TestApplicationHandler *ApplicationHandler
|
||||
var TestUsers []*model.User
|
||||
var TestDatabase *database.Database
|
||||
|
||||
// Collect all created applications to check & delete them later
|
||||
var SuccessAplications map[uint][]model.Application
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
// Get main config and adapt
|
||||
config := &configuration.Configuration{}
|
||||
|
||||
config.Database.Connection = "pushbits-test.db"
|
||||
config.Database.Dialect = "sqlite3"
|
||||
config.Crypto.Argon2.Iterations = 4
|
||||
config.Crypto.Argon2.Parallelism = 4
|
||||
config.Crypto.Argon2.Memory = 131072
|
||||
config.Crypto.Argon2.SaltLength = 16
|
||||
config.Crypto.Argon2.KeyLength = 32
|
||||
|
||||
// Set up test environment
|
||||
db, err := mockups.GetEmptyDatabase(config.Crypto)
|
||||
if err != nil {
|
||||
cleanUp()
|
||||
log.Println("Can not set up database: ", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
TestDatabase = db
|
||||
|
||||
appHandler, err := getApplicationHandler(config)
|
||||
if err != nil {
|
||||
cleanUp()
|
||||
log.Println("Can not set up application handler: ", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
TestApplicationHandler = appHandler
|
||||
TestUsers = mockups.GetUsers(config)
|
||||
SuccessAplications = make(map[uint][]model.Application)
|
||||
|
||||
// Run
|
||||
m.Run()
|
||||
cleanUp()
|
||||
}
|
||||
|
||||
func TestApi_RegisterApplicationWithoutUser(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
reqWoUser := tests.Request{Name: "Invalid JSON Data", Method: "POST", Endpoint: "/application", Data: `{"name": "test1", "strict_compatibility": true}`, Headers: map[string]string{"Content-Type": "application/json"}}
|
||||
_, c, err := reqWoUser.GetRequest()
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
assert.Panicsf(func() { TestApplicationHandler.CreateApplication(c) }, "CreateApplication did not panic altough user is not in context")
|
||||
|
||||
}
|
||||
|
||||
func TestApi_RegisterApplication(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
testCases := make([]tests.Request, 0)
|
||||
testCases = append(testCases, tests.Request{Name: "Invalid Form Data", Method: "POST", Endpoint: "/application", Data: "k=1&v=abc", ShouldStatus: 400})
|
||||
testCases = append(testCases, tests.Request{Name: "Invalid JSON Data", Method: "POST", Endpoint: "/application", Data: `{"name": "test1", "strict_compatibility": "oh yes"}`, Headers: map[string]string{"Content-Type": "application/json"}, ShouldStatus: 400})
|
||||
testCases = append(testCases, tests.Request{Name: "Valid JSON Data", Method: "POST", Endpoint: "/application", Data: `{"name": "test2", "strict_compatibility": true}`, Headers: map[string]string{"Content-Type": "application/json"}, ShouldStatus: 200})
|
||||
|
||||
for _, user := range TestUsers {
|
||||
SuccessAplications[user.ID] = make([]model.Application, 0)
|
||||
for _, req := range testCases {
|
||||
var application model.Application
|
||||
w, c, err := req.GetRequest()
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
c.Set("user", user)
|
||||
TestApplicationHandler.CreateApplication(c)
|
||||
|
||||
// Parse body only for successful requests
|
||||
if req.ShouldStatus >= 200 && req.ShouldStatus < 300 {
|
||||
body, err := ioutil.ReadAll(w.Body)
|
||||
assert.NoErrorf(err, "Can not read request body")
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
err = json.Unmarshal(body, &application)
|
||||
assert.NoErrorf(err, "Can not unmarshal request body")
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
SuccessAplications[user.ID] = append(SuccessAplications[user.ID], application)
|
||||
}
|
||||
|
||||
assert.Equalf(w.Code, req.ShouldStatus, "CreateApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApi_GetApplications(t *testing.T) {
|
||||
var applications []model.Application
|
||||
|
||||
assert := assert.New(t)
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
testCases := make([]tests.Request, 0)
|
||||
testCases = append(testCases, tests.Request{Name: "Valid Request", Method: "GET", Endpoint: "/application", ShouldStatus: 200})
|
||||
|
||||
for _, user := range TestUsers {
|
||||
for _, req := range testCases {
|
||||
w, c, err := req.GetRequest()
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
c.Set("user", user)
|
||||
TestApplicationHandler.GetApplications(c)
|
||||
|
||||
// Parse body only for successful requests
|
||||
if req.ShouldStatus >= 200 && req.ShouldStatus < 300 {
|
||||
body, err := ioutil.ReadAll(w.Body)
|
||||
assert.NoErrorf(err, "Can not read request body")
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
err = json.Unmarshal(body, &applications)
|
||||
assert.NoErrorf(err, "Can not unmarshal request body")
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
assert.Truef(validateAllApplications(user, applications), "Did not find application created previously")
|
||||
assert.Equalf(len(applications), len(SuccessAplications[user.ID]), "Created %d application(s) but got %d back", len(SuccessAplications[user.ID]), len(applications))
|
||||
}
|
||||
|
||||
assert.Equalf(w.Code, req.ShouldStatus, "GetApplications (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApi_GetApplicationsWithoutUser(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
testCase := tests.Request{Name: "Valid Request", Method: "GET", Endpoint: "/application"}
|
||||
|
||||
_, c, err := testCase.GetRequest()
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
assert.Panicsf(func() { TestApplicationHandler.GetApplications(c) }, "GetApplications did not panic altough user is not in context")
|
||||
|
||||
}
|
||||
|
||||
func TestApi_GetApplicationErrors(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
// Arbitrary test cases
|
||||
testCases := make(map[uint]tests.Request)
|
||||
testCases[0] = tests.Request{Name: "Requesting unknown application 0", Method: "GET", Endpoint: "/application/0", ShouldStatus: 404}
|
||||
testCases[5555] = tests.Request{Name: "Requesting unknown application 5555", Method: "GET", Endpoint: "/application/5555", ShouldStatus: 404}
|
||||
testCases[99999999999999999] = tests.Request{Name: "Requesting unknown application 99999999999999999", Method: "GET", Endpoint: "/application/99999999999999999", ShouldStatus: 404}
|
||||
|
||||
for _, user := range TestUsers {
|
||||
for id, req := range testCases {
|
||||
w, c, err := req.GetRequest()
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
c.Set("user", user)
|
||||
c.Set("id", id)
|
||||
TestApplicationHandler.GetApplication(c)
|
||||
|
||||
assert.Equalf(w.Code, req.ShouldStatus, "GetApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApi_GetApplication(t *testing.T) {
|
||||
var application model.Application
|
||||
|
||||
assert := assert.New(t)
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
// Previously generated applications
|
||||
for _, user := range TestUsers {
|
||||
for _, app := range SuccessAplications[user.ID] {
|
||||
req := tests.Request{Name: fmt.Sprintf("Requesting application %s (%d)", app.Name, app.ID), Method: "GET", Endpoint: fmt.Sprintf("/application/%d", app.ID), ShouldStatus: 200}
|
||||
|
||||
w, c, err := req.GetRequest()
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
c.Set("user", user)
|
||||
c.Set("id", app.ID)
|
||||
TestApplicationHandler.GetApplication(c)
|
||||
|
||||
// Parse body only for successful requests
|
||||
if req.ShouldStatus >= 200 && req.ShouldStatus < 300 {
|
||||
body, err := ioutil.ReadAll(w.Body)
|
||||
assert.NoErrorf(err, "Can not read request body")
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
err = json.Unmarshal(body, &application)
|
||||
assert.NoErrorf(err, "Can not unmarshal request body: %v", err)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
assert.Equalf(application.ID, app.ID, "Application ID should be %d but is %d", app.ID, application.ID)
|
||||
assert.Equalf(application.Name, app.Name, "Application Name should be %s but is %s", app.Name, application.Name)
|
||||
assert.Equalf(application.UserID, app.UserID, "Application user ID should be %d but is %d", app.UserID, application.UserID)
|
||||
|
||||
}
|
||||
|
||||
assert.Equalf(w.Code, req.ShouldStatus, "GetApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApi_UpdateApplication(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
for _, user := range TestUsers {
|
||||
testCases := make(map[uint]tests.Request)
|
||||
// Previously generated applications
|
||||
for _, app := range SuccessAplications[user.ID] {
|
||||
newName := app.Name + "-new_name"
|
||||
updateApp := model.UpdateApplication{
|
||||
Name: &newName,
|
||||
}
|
||||
updateAppBytes, err := json.Marshal(updateApp)
|
||||
assert.NoErrorf(err, "Error on marshaling updateApplication struct")
|
||||
|
||||
// Valid
|
||||
testCases[app.ID] = tests.Request{Name: fmt.Sprintf("Update application (valid) %s (%d)", app.Name, app.ID), Method: "PUT", Endpoint: fmt.Sprintf("/application/%d", app.ID), ShouldStatus: 200, Data: string(updateAppBytes), Headers: map[string]string{"Content-Type": "application/json"}}
|
||||
// Invalid
|
||||
testCases[app.ID] = tests.Request{Name: fmt.Sprintf("Update application (invalid) %s (%d)", app.Name, app.ID), Method: "PUT", Endpoint: fmt.Sprintf("/application/%d", app.ID), ShouldStatus: 200, Data: "{}", Headers: map[string]string{"Content-Type": "application/json"}}
|
||||
}
|
||||
// Arbitrary test cases
|
||||
testCases[5555] = tests.Request{Name: "Update application 5555", Method: "PUT", Endpoint: "/application/5555", ShouldStatus: 404, Data: "random data"}
|
||||
testCases[5556] = tests.Request{Name: "Update application 5556", Method: "PUT", Endpoint: "/application/5556", ShouldStatus: 404, Data: `{"new_name": "new name"}`, Headers: map[string]string{"Content-Type": "application/json"}}
|
||||
|
||||
for id, req := range testCases {
|
||||
w, c, err := req.GetRequest()
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
c.Set("user", user)
|
||||
c.Set("id", id)
|
||||
TestApplicationHandler.UpdateApplication(c)
|
||||
|
||||
assert.Equalf(w.Code, req.ShouldStatus, "UpdateApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApi_DeleteApplication(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
for _, user := range TestUsers {
|
||||
testCases := make(map[uint]tests.Request)
|
||||
// Previously generated applications
|
||||
for _, app := range SuccessAplications[user.ID] {
|
||||
testCases[app.ID] = tests.Request{Name: fmt.Sprintf("Delete application %s (%d)", app.Name, app.ID), Method: "DELETE", Endpoint: fmt.Sprintf("/application/%d", app.ID), ShouldStatus: 200}
|
||||
}
|
||||
// Arbitrary test cases
|
||||
testCases[5555] = tests.Request{Name: "Delete application 5555", Method: "DELETE", Endpoint: "/application/5555", ShouldStatus: 404}
|
||||
|
||||
for id, req := range testCases {
|
||||
w, c, err := req.GetRequest()
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
c.Set("user", user)
|
||||
c.Set("id", id)
|
||||
TestApplicationHandler.DeleteApplication(c)
|
||||
|
||||
assert.Equalf(w.Code, req.ShouldStatus, "DeleteApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetApplicationHandler creates and returns an application handler
|
||||
func getApplicationHandler(c *configuration.Configuration) (*ApplicationHandler, error) {
|
||||
dispatcher := &mockups.MockDispatcher{}
|
||||
|
||||
return &ApplicationHandler{
|
||||
DB: TestDatabase,
|
||||
DP: dispatcher,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// True if all created applications are in list
|
||||
func validateAllApplications(user *model.User, apps []model.Application) bool {
|
||||
if _, ok := SuccessAplications[user.ID]; !ok {
|
||||
return len(apps) == 0
|
||||
}
|
||||
|
||||
for _, successApp := range SuccessAplications[user.ID] {
|
||||
foundApp := false
|
||||
for _, app := range apps {
|
||||
if app.ID == successApp.ID {
|
||||
foundApp = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !foundApp {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func cleanUp() {
|
||||
os.Remove("pushbits-test.db")
|
||||
}
|
117
internal/api/context_test.go
Normal file
117
internal/api/context_test.go
Normal file
|
@ -0,0 +1,117 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pushbits/server/internal/model"
|
||||
"github.com/pushbits/server/tests"
|
||||
"github.com/pushbits/server/tests/mockups"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestApi_getID(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
gin.SetMode(gin.TestMode)
|
||||
testValue := uint(1337)
|
||||
|
||||
testCases := make(map[interface{}]tests.Request)
|
||||
testCases[-1] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 500}
|
||||
testCases[uint(1)] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 200}
|
||||
testCases[uint(0)] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 200}
|
||||
testCases[uint(500)] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 200}
|
||||
testCases[500] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 500}
|
||||
testCases["test"] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 500}
|
||||
testCases[model.Application{}] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 500}
|
||||
testCases[&model.Application{}] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 500}
|
||||
testCases[&testValue] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 500}
|
||||
|
||||
for id, req := range testCases {
|
||||
w, c, err := req.GetRequest()
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
c.Set("id", id)
|
||||
idReturned, err := getID(c)
|
||||
|
||||
if req.ShouldStatus >= 200 && req.ShouldStatus < 300 {
|
||||
idUint, ok := id.(uint)
|
||||
if ok {
|
||||
assert.Equalf(idReturned, idUint, "getApi id was set to %d but result is %d", idUint, idReturned)
|
||||
}
|
||||
assert.NoErrorf(err, "getId with id %v (%t) returned an error altough it should not: %v", id, id, err)
|
||||
} else {
|
||||
assert.Errorf(err, "getId with id %v (%t) returned no error altough it should", id, id)
|
||||
}
|
||||
|
||||
assert.Equalf(w.Code, req.ShouldStatus, "getApi id was set to %v (%T) and should result in status code %d but code is %d", id, id, req.ShouldStatus, w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApi_getApplication(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
applications := mockups.GetAllApplications()
|
||||
mockups.AddApplicationsToDb(TestDatabase, applications)
|
||||
|
||||
// No testing of invalid ids as that is tested in TestApi_getID already
|
||||
testCases := make(map[uint]tests.Request)
|
||||
testCases[500] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 404}
|
||||
testCases[1] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 200}
|
||||
testCases[2] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 200}
|
||||
|
||||
for id, req := range testCases {
|
||||
w, c, err := req.GetRequest()
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
c.Set("id", id)
|
||||
app, err := getApplication(c, TestDatabase)
|
||||
|
||||
if req.ShouldStatus >= 200 && req.ShouldStatus < 300 {
|
||||
assert.Equalf(app.ID, id, "getApplication id was set to %d but resulting app id is %d", id, app.ID)
|
||||
assert.NoErrorf(err, "getApplication with id %v (%t) returned an error altough it should not: %v", id, id, err)
|
||||
} else {
|
||||
assert.Errorf(err, "getApplication with id %v (%t) returned no error altough it should", id, id)
|
||||
}
|
||||
|
||||
assert.Equalf(w.Code, req.ShouldStatus, "getApplication id was set to %v (%T) and should result in status code %d but code is %d", id, id, req.ShouldStatus, w.Code)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestApi_getUser(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
_, err := mockups.AddUsersToDb(TestDatabase, TestUsers)
|
||||
assert.NoErrorf(err, "Adding users to database failed: %v", err)
|
||||
|
||||
// No testing of invalid ids as that is tested in TestApi_getID already
|
||||
testCases := make(map[uint]tests.Request)
|
||||
testCases[500] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 404}
|
||||
testCases[1] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 200}
|
||||
testCases[2] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 200}
|
||||
|
||||
for id, req := range testCases {
|
||||
w, c, err := req.GetRequest()
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
c.Set("id", id)
|
||||
user, err := getUser(c, TestDatabase)
|
||||
|
||||
if req.ShouldStatus >= 200 && req.ShouldStatus < 300 {
|
||||
assert.Equalf(user.ID, id, "getUser id was set to %d but resulting app id is %d", id, user.ID)
|
||||
assert.NoErrorf(err, "getUser with id %v (%t) returned an error altough it should not: %v", id, id, err)
|
||||
} else {
|
||||
assert.Errorf(err, "getUser with id %v (%t) returned no error altough it should", id, id)
|
||||
}
|
||||
|
||||
assert.Equalf(w.Code, req.ShouldStatus, "getUser id was set to %v (%T) and should result in status code %d but code is %d", id, id, req.ShouldStatus, w.Code)
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package api
|
||||
|
||||
import "errors"
|
||||
|
||||
var ErrorMessageNotFound = errors.New("message not found")
|
|
@ -5,6 +5,7 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/pushbits/server/internal/authentication"
|
||||
"github.com/pushbits/server/internal/pberrors"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
@ -13,7 +14,7 @@ func successOrAbort(ctx *gin.Context, code int, err error) bool {
|
|||
if err != nil {
|
||||
// If we know the error force error code
|
||||
switch err {
|
||||
case ErrorMessageNotFound:
|
||||
case pberrors.ErrorMessageNotFound:
|
||||
ctx.AbortWithError(http.StatusNotFound, err)
|
||||
default:
|
||||
ctx.AbortWithError(code, err)
|
||||
|
|
|
@ -4,6 +4,9 @@ import (
|
|||
"github.com/jinzhu/configor"
|
||||
)
|
||||
|
||||
// testMode indicates if the package is run in test mode
|
||||
var testMode bool
|
||||
|
||||
// Argon2Config holds the parameters used for creating hashes with Argon2.
|
||||
type Argon2Config struct {
|
||||
Memory uint32 `default:"131072"`
|
||||
|
@ -23,6 +26,13 @@ type Formatting struct {
|
|||
ColoredTitle bool `default:"false"`
|
||||
}
|
||||
|
||||
// Matrix holds credentials for a matrix account
|
||||
type Matrix struct {
|
||||
Homeserver string `default:"https://matrix.org"`
|
||||
Username string `required:"true"`
|
||||
Password string `required:"true"`
|
||||
}
|
||||
|
||||
// Configuration holds values that can be configured by the user.
|
||||
type Configuration struct {
|
||||
Debug bool `default:"false"`
|
||||
|
@ -39,11 +49,7 @@ type Configuration struct {
|
|||
Password string `default:"admin"`
|
||||
MatrixID string `required:"true"`
|
||||
}
|
||||
Matrix struct {
|
||||
Homeserver string `default:"https://matrix.org"`
|
||||
Username string `required:"true"`
|
||||
Password string `required:"true"`
|
||||
}
|
||||
Matrix Matrix
|
||||
Security struct {
|
||||
CheckHIBP bool `default:"false"`
|
||||
}
|
||||
|
@ -52,6 +58,9 @@ type Configuration struct {
|
|||
}
|
||||
|
||||
func configFiles() []string {
|
||||
if testMode {
|
||||
return []string{"config_unittest.yml"}
|
||||
}
|
||||
return []string{"config.yml"}
|
||||
}
|
||||
|
||||
|
|
205
internal/configuration/configuration_test.go
Normal file
205
internal/configuration/configuration_test.go
Normal file
|
@ -0,0 +1,205 @@
|
|||
package configuration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/jinzhu/configor"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type Pair struct {
|
||||
Is interface{}
|
||||
Should interface{}
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testMode = true
|
||||
m.Run()
|
||||
cleanUp()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func TestConfiguration_GetMinimal(t *testing.T) {
|
||||
err := writeMinimalConfig()
|
||||
if err != nil {
|
||||
fmt.Println("Could not write minimal config: ", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
validateConfig(t)
|
||||
}
|
||||
|
||||
func TestConfiguration_GetValid(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
err := writeValidConfig()
|
||||
if err != nil {
|
||||
fmt.Println("Could not write valid config: ", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
validateConfig(t)
|
||||
|
||||
config := Get()
|
||||
|
||||
expectedValues := make(map[string]Pair)
|
||||
expectedValues["config.Admin.MatrixID"] = Pair{config.Admin.MatrixID, "000000"}
|
||||
expectedValues["config.Matrix.Username"] = Pair{config.Matrix.Username, "default-username"}
|
||||
expectedValues["config.Matrix.Password"] = Pair{config.Matrix.Password, "default-password"}
|
||||
|
||||
for name, pair := range expectedValues {
|
||||
assert.Equalf(pair.Is, pair.Should, fmt.Sprintf("%s should be %v but is %v", name, pair.Should, pair.Is))
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfiguration_GetEmpty(t *testing.T) {
|
||||
err := writeEmptyConfig()
|
||||
if err != nil {
|
||||
fmt.Println("Could not write empty config: ", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
assert.Panicsf(t, func() { Get() }, "Get() did not panic altough config is empty")
|
||||
}
|
||||
|
||||
func TestConfiguration_GetInvalid(t *testing.T) {
|
||||
err := writeInvalidConfig()
|
||||
if err != nil {
|
||||
fmt.Println("Could not write empty config: ", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
assert.Panicsf(t, func() { Get() }, "Get() did not panic altough config is empty")
|
||||
}
|
||||
|
||||
func TestConfiguaration_ConfigFiles(t *testing.T) {
|
||||
files := configFiles()
|
||||
|
||||
assert.Greater(t, len(files), 0)
|
||||
for _, file := range files {
|
||||
assert.Truef(t, strings.HasSuffix(file, ".yml"), "%s is no yaml file", file)
|
||||
}
|
||||
}
|
||||
|
||||
// Checks if the values in the configuration are plausible
|
||||
func validateConfig(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
assert.NotPanicsf(func() { Get() }, "Get configuration should not panic")
|
||||
|
||||
config := Get()
|
||||
asGreater := make(map[string]Pair)
|
||||
asGreater["config.Crypto.Argon2.Memory"] = Pair{config.Crypto.Argon2.Memory, uint32(0)}
|
||||
asGreater["config.Crypto.Argon2.Iterations"] = Pair{config.Crypto.Argon2.Iterations, uint32(0)}
|
||||
asGreater["config.Crypto.Argon2.SaltLength"] = Pair{config.Crypto.Argon2.SaltLength, uint32(0)}
|
||||
asGreater["config.Crypto.Argon2.KeyLength"] = Pair{config.Crypto.Argon2.KeyLength, uint32(0)}
|
||||
asGreater["config.Crypto.Argon2.Parallelism"] = Pair{config.Crypto.Argon2.Parallelism, uint8(0)}
|
||||
asGreater["config.HTTP.Port"] = Pair{config.HTTP.Port, 0}
|
||||
for name, pair := range asGreater {
|
||||
assert.Greaterf(pair.Is, pair.Should, fmt.Sprintf("%s should be > %v but is %v", name, pair.Should, pair.Is))
|
||||
}
|
||||
|
||||
asFalse := make(map[string]bool)
|
||||
asFalse["config.Formatting.ColoredTitle"] = config.Formatting.ColoredTitle
|
||||
asFalse["config.Debug"] = config.Debug
|
||||
asFalse["config.Security.CheckHIBP"] = config.Security.CheckHIBP
|
||||
for name, value := range asFalse {
|
||||
assert.Falsef(value, fmt.Sprintf("%s should be false but is %t", name, value))
|
||||
}
|
||||
}
|
||||
|
||||
type MinimalConfiguration struct {
|
||||
Admin struct {
|
||||
MatrixID string
|
||||
}
|
||||
Matrix struct {
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
}
|
||||
|
||||
type InvalidConfiguration struct {
|
||||
Debug int
|
||||
HTTP struct {
|
||||
ListenAddress bool
|
||||
}
|
||||
Admin struct {
|
||||
Name int
|
||||
}
|
||||
Formatting string
|
||||
}
|
||||
|
||||
// Writes a minimal config to config.yml
|
||||
func writeMinimalConfig() error {
|
||||
cleanUp()
|
||||
config := MinimalConfiguration{}
|
||||
config.Admin.MatrixID = "000000"
|
||||
config.Matrix.Username = "default-username"
|
||||
config.Matrix.Password = "default-password"
|
||||
|
||||
configString, err := yaml.Marshal(&config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile("config_unittest.yml", configString, 0644)
|
||||
}
|
||||
|
||||
// Writes a config with default values to config.yml
|
||||
func writeValidConfig() error {
|
||||
cleanUp()
|
||||
|
||||
// Load minimal config to get default values
|
||||
writeMinimalConfig()
|
||||
config := &Configuration{}
|
||||
err := configor.New(&configor.Config{
|
||||
Environment: "production",
|
||||
ENVPrefix: "PUSHBITS",
|
||||
ErrorOnUnmatchedKeys: true,
|
||||
}).Load(config, "config_unittest.yml")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config.Admin.MatrixID = "000000"
|
||||
config.Matrix.Username = "default-username"
|
||||
config.Matrix.Password = "default-password"
|
||||
|
||||
configString, err := yaml.Marshal(&config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile("config_unittest.yml", configString, 0644)
|
||||
}
|
||||
|
||||
// Writes a config that is empty
|
||||
func writeEmptyConfig() error {
|
||||
cleanUp()
|
||||
return ioutil.WriteFile("config_unittest.yml", []byte(""), 0644)
|
||||
}
|
||||
|
||||
// Writes a config with invalid entries
|
||||
func writeInvalidConfig() error {
|
||||
cleanUp()
|
||||
config := InvalidConfiguration{}
|
||||
config.Debug = 1337
|
||||
config.HTTP.ListenAddress = true
|
||||
config.Admin.Name = 23
|
||||
config.Formatting = "Nice"
|
||||
|
||||
configString, err := yaml.Marshal(&config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile("config_unittest.yml", configString, 0644)
|
||||
}
|
||||
|
||||
func cleanUp() error {
|
||||
return os.Remove("config_unittest.yml")
|
||||
}
|
|
@ -8,8 +8,8 @@ import (
|
|||
|
||||
"github.com/gomarkdown/markdown"
|
||||
"github.com/matrix-org/gomatrix"
|
||||
"github.com/pushbits/server/internal/api"
|
||||
"github.com/pushbits/server/internal/model"
|
||||
"github.com/pushbits/server/internal/pberrors"
|
||||
)
|
||||
|
||||
// MessageFormat is a matrix message format
|
||||
|
@ -77,7 +77,7 @@ func (d *Dispatcher) DeleteNotification(a *model.Application, n *model.DeleteNot
|
|||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return api.ErrorMessageNotFound
|
||||
return pberrors.ErrorMessageNotFound
|
||||
}
|
||||
|
||||
oldBody, oldFormattedBody, err = bodiesFromMessage(deleteMessage)
|
||||
|
@ -182,7 +182,7 @@ func (d *Dispatcher) getMessage(a *model.Application, id string) (gomatrix.Event
|
|||
}
|
||||
start = messages.End
|
||||
}
|
||||
return gomatrix.Event{}, api.ErrorMessageNotFound
|
||||
return gomatrix.Event{}, pberrors.ErrorMessageNotFound
|
||||
}
|
||||
|
||||
// Replaces the content of a matrix message
|
||||
|
@ -254,19 +254,19 @@ func bodiesFromMessage(message gomatrix.Event) (body, formattedBody string, err
|
|||
body, ok := val.(string)
|
||||
|
||||
if !ok {
|
||||
return "", "", api.ErrorMessageNotFound
|
||||
return "", "", pberrors.ErrorMessageNotFound
|
||||
}
|
||||
|
||||
formattedBody = body
|
||||
|
||||
} else {
|
||||
return "", "", api.ErrorMessageNotFound
|
||||
return "", "", pberrors.ErrorMessageNotFound
|
||||
}
|
||||
|
||||
if val, ok := message.Content["formatted_body"]; ok {
|
||||
body, ok := val.(string)
|
||||
if !ok {
|
||||
return "", "", api.ErrorMessageNotFound
|
||||
return "", "", pberrors.ErrorMessageNotFound
|
||||
}
|
||||
|
||||
formattedBody = body
|
||||
|
|
6
internal/pberrors/errors.go
Normal file
6
internal/pberrors/errors.go
Normal file
|
@ -0,0 +1,6 @@
|
|||
package pberrors
|
||||
|
||||
import "errors"
|
||||
|
||||
// ErrorMessageNotFound indicates that a message does not exist
|
||||
var ErrorMessageNotFound = errors.New("message not found")
|
32
tests/mockups/application.go
Normal file
32
tests/mockups/application.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
package mockups
|
||||
|
||||
import "github.com/pushbits/server/internal/model"
|
||||
|
||||
// GetApplication1 returns an application with id 1
|
||||
func GetApplication1() *model.Application {
|
||||
return &model.Application{
|
||||
ID: 1,
|
||||
Token: "1234567890abcdefghijklmn",
|
||||
UserID: 1,
|
||||
Name: "App1",
|
||||
}
|
||||
}
|
||||
|
||||
// GetApplication2 returns an application with id 2
|
||||
func GetApplication2() *model.Application {
|
||||
return &model.Application{
|
||||
ID: 2,
|
||||
Token: "0987654321xyzabcdefghij",
|
||||
UserID: 1,
|
||||
Name: "App2",
|
||||
}
|
||||
}
|
||||
|
||||
// GetAllApplications returns all mock-applications as a list
|
||||
func GetAllApplications() []*model.Application {
|
||||
applications := make([]*model.Application, 0)
|
||||
applications = append(applications, GetApplication1())
|
||||
applications = append(applications, GetApplication2())
|
||||
|
||||
return applications
|
||||
}
|
43
tests/mockups/config.go
Normal file
43
tests/mockups/config.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
package mockups
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/pushbits/server/internal/configuration"
|
||||
)
|
||||
|
||||
// ReadConfig copies the given filename to the current folder and parses it as a config file. RemoveFile indicates whether to remove the copied file or not
|
||||
func ReadConfig(filename string, removeFile bool) (config *configuration.Configuration, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Println(r)
|
||||
err = errors.New("paniced while reading config")
|
||||
}
|
||||
}()
|
||||
|
||||
if filename == "" {
|
||||
return nil, errors.New("empty filename")
|
||||
}
|
||||
|
||||
file, err := ioutil.ReadFile(filename)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile("config.yml", file, 0644)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config = configuration.Get()
|
||||
|
||||
if removeFile {
|
||||
os.Remove("config.yml")
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
52
tests/mockups/database.go
Normal file
52
tests/mockups/database.go
Normal file
|
@ -0,0 +1,52 @@
|
|||
package mockups
|
||||
|
||||
import (
|
||||
"github.com/pushbits/server/internal/authentication/credentials"
|
||||
"github.com/pushbits/server/internal/configuration"
|
||||
"github.com/pushbits/server/internal/database"
|
||||
"github.com/pushbits/server/internal/model"
|
||||
)
|
||||
|
||||
// GetEmptyDatabase returns an empty sqlite database object
|
||||
func GetEmptyDatabase(confCrypto configuration.CryptoConfig) (*database.Database, error) {
|
||||
cm := credentials.CreateManager(false, confCrypto)
|
||||
return database.Create(cm, "sqlite3", "pushbits-test.db")
|
||||
}
|
||||
|
||||
// AddApplicationsToDb inserts the applications apps into the database db
|
||||
func AddApplicationsToDb(db *database.Database, apps []*model.Application) error {
|
||||
for _, app := range apps {
|
||||
err := db.CreateApplication(app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddUsersToDb adds the users to the database and sets their username as a password, returns list of added users
|
||||
func AddUsersToDb(db *database.Database, users []*model.User) ([]*model.User, error) {
|
||||
addedUsers := make([]*model.User, 0)
|
||||
|
||||
for _, user := range users {
|
||||
extUser := model.ExternalUser{
|
||||
ID: user.ID,
|
||||
Name: user.Name,
|
||||
IsAdmin: user.IsAdmin,
|
||||
MatrixID: user.MatrixID,
|
||||
}
|
||||
credentials := model.UserCredentials{
|
||||
Password: user.Name,
|
||||
}
|
||||
createUser := model.CreateUser{ExternalUser: extUser, UserCredentials: credentials}
|
||||
|
||||
newUser, err := db.CreateUser(createUser)
|
||||
addedUsers = append(addedUsers, newUser)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return addedUsers, nil
|
||||
}
|
23
tests/mockups/dispatcher.go
Normal file
23
tests/mockups/dispatcher.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
package mockups
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pushbits/server/internal/model"
|
||||
)
|
||||
|
||||
// MockDispatcher is a dispatcher used for testing - it does not need any storage interface
|
||||
type MockDispatcher struct {
|
||||
}
|
||||
|
||||
func (d *MockDispatcher) RegisterApplication(id uint, name, token, user string) (string, error) {
|
||||
return fmt.Sprintf("%d-%s", id, name), nil
|
||||
}
|
||||
|
||||
func (d *MockDispatcher) DeregisterApplication(a *model.Application, u *model.User) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *MockDispatcher) UpdateApplication(a *model.Application) error {
|
||||
return nil
|
||||
}
|
43
tests/mockups/user.go
Normal file
43
tests/mockups/user.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
package mockups
|
||||
|
||||
import (
|
||||
"github.com/pushbits/server/internal/authentication/credentials"
|
||||
"github.com/pushbits/server/internal/configuration"
|
||||
"github.com/pushbits/server/internal/model"
|
||||
)
|
||||
|
||||
// GetAdminUser returns an admin user
|
||||
func GetAdminUser(c *configuration.Configuration) *model.User {
|
||||
credentialsManager := credentials.CreateManager(false, c.Crypto)
|
||||
hash, _ := credentialsManager.CreatePasswordHash(c.Admin.Password)
|
||||
|
||||
return &model.User{
|
||||
ID: 1,
|
||||
Name: c.Admin.Name,
|
||||
PasswordHash: hash,
|
||||
IsAdmin: true,
|
||||
MatrixID: c.Admin.MatrixID,
|
||||
}
|
||||
}
|
||||
|
||||
// GetUser returns an user
|
||||
func GetUser(c *configuration.Configuration) *model.User {
|
||||
credentialsManager := credentials.CreateManager(false, c.Crypto)
|
||||
hash, _ := credentialsManager.CreatePasswordHash(c.Admin.Password)
|
||||
|
||||
return &model.User{
|
||||
ID: 2,
|
||||
Name: c.Admin.Name + "-normalo",
|
||||
PasswordHash: hash,
|
||||
IsAdmin: false,
|
||||
MatrixID: c.Admin.MatrixID,
|
||||
}
|
||||
}
|
||||
|
||||
// GetUsers returns a list of users
|
||||
func GetUsers(c *configuration.Configuration) []*model.User {
|
||||
var users []*model.User
|
||||
users = append(users, GetAdminUser(c))
|
||||
users = append(users, GetUser(c))
|
||||
return users
|
||||
}
|
47
tests/request.go
Normal file
47
tests/request.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
package tests
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// Request holds information for a HTTP request
|
||||
type Request struct {
|
||||
Name string
|
||||
Method string
|
||||
Endpoint string
|
||||
Data interface{}
|
||||
Headers map[string]string
|
||||
ShouldStatus int
|
||||
}
|
||||
|
||||
// GetRequest returns a ResponseRecorder and gin context according to the data set in the Request.
|
||||
// String data is passed as is, all other data types are marshaled before.
|
||||
func (r *Request) GetRequest() (w *httptest.ResponseRecorder, c *gin.Context, err error) {
|
||||
var body io.Reader
|
||||
w = httptest.NewRecorder()
|
||||
|
||||
switch r.Data.(type) {
|
||||
case string:
|
||||
body = strings.NewReader(r.Data.(string))
|
||||
default:
|
||||
dataMarshaled, err := json.Marshal(r.Data)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
body = strings.NewReader(string(dataMarshaled))
|
||||
}
|
||||
|
||||
c, _ = gin.CreateTestContext(w)
|
||||
c.Request = httptest.NewRequest(r.Method, r.Endpoint, body)
|
||||
|
||||
for name, value := range r.Headers {
|
||||
c.Request.Header.Set(name, value)
|
||||
}
|
||||
|
||||
return w, c, nil
|
||||
}
|
Loading…
Add table
Reference in a new issue