Compare commits

...

5 Commits

29 changed files with 407 additions and 64 deletions

View File

@ -48,7 +48,7 @@ lint:
tags: tags:
- medium - medium
test: test-linux:
stage: test stage: test
only: only:
- branches - branches
@ -65,6 +65,14 @@ test:
tags: tags:
- medium - medium
test-windows:
extends: .build-windows-base
stage: test
only:
- branches
script:
- make test
test-integration: test-integration:
stage: test stage: test
only: only:
@ -96,6 +104,7 @@ build-qml:
- cd internal/frontend/qml - cd internal/frontend/qml
- tar -cvzf ../../../bridge_qml.tgz ./* - tar -cvzf ../../../bridge_qml.tgz ./*
.build-base: .build-base:
stage: build stage: build
only: only:
@ -134,6 +143,7 @@ build-linux-qa:
paths: paths:
- bridge_*.tgz - bridge_*.tgz
.build-darwin-base: .build-darwin-base:
extends: .build-base extends: .build-base
before_script: before_script:
@ -170,6 +180,40 @@ build-darwin-qa:
paths: paths:
- bridge_*.tgz - bridge_*.tgz
.build-windows-base:
extends: .build-base
before_script:
- export GOROOT=/c/Go
- export PATH=$GOROOT/bin:$PATH
- export GOARCH=amd64
- export GOPATH=~/go
- export GO111MODULE=on
- export PATH=$GOPATH/bin:$PATH
- export MSYSTEM=
- export PATH=$PATH:/c/grrrQt/5.13.2/mingw73_64/bin
tags:
- windows-bridge
build-windows:
extends: .build-windows-base
artifacts:
name: "bridge-windows-$CI_COMMIT_SHORT_SHA"
paths:
- bridge_*.tgz
build-windows-qa:
extends: .build-windows-base
only:
- web
- branches
script:
- BUILD_TAGS="build_qa" make build
artifacts:
name: "bridge-windows-qa-$CI_COMMIT_SHORT_SHA"
paths:
- bridge_*.tgz
# Stage: MIRROR # Stage: MIRROR
mirror-repo: mirror-repo:

View File

@ -2,6 +2,17 @@
Changelog [format](http://keepachangelog.com/en/1.0.0/) Changelog [format](http://keepachangelog.com/en/1.0.0/)
## [Bridge 2.1.0] London
## Added
* GODT-1376: Add first userID to sentry scope.
* GODT-1375: Add host architecture to sentry reports.
* GODT-1364: Add windows CI machine for tests, and build.
### Fixed
* GODT-1499: Remove message from DB once it is not on server any more.
## [Bridge 2.1.0] London ## [Bridge 2.1.0] London
### Fixed ### Fixed

View File

@ -10,7 +10,7 @@ TARGET_OS?=${GOOS}
.PHONY: build build-nogui build-launcher versioner hasher .PHONY: build build-nogui build-launcher versioner hasher
# Keep version hardcoded so app build works also without Git repository. # Keep version hardcoded so app build works also without Git repository.
BRIDGE_APP_VERSION?=2.1.0+git BRIDGE_APP_VERSION?=2.1.1+git
APP_VERSION:=${BRIDGE_APP_VERSION} APP_VERSION:=${BRIDGE_APP_VERSION}
SRC_ICO:=logo.ico SRC_ICO:=logo.ico
SRC_ICNS:=Bridge.icns SRC_ICNS:=Bridge.icns

6
go.mod
View File

@ -28,6 +28,8 @@ require (
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect
github.com/cucumber/godog v0.12.1 github.com/cucumber/godog v0.12.1
github.com/cucumber/messages-go/v16 v16.0.1 github.com/cucumber/messages-go/v16 v16.0.1
github.com/elastic/go-sysinfo v1.7.1
github.com/elastic/go-windows v1.0.1 // indirect
github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a
github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342 github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342
github.com/emersion/go-imap-quota v0.0.0-20210203125329-619074823f3c github.com/emersion/go-imap-quota v0.0.0-20210203125329-619074823f3c
@ -53,6 +55,7 @@ require (
github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce
github.com/olekukonko/tablewriter v0.0.4 // indirect github.com/olekukonko/tablewriter v0.0.4 // indirect
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/prometheus/procfs v0.7.3 // indirect
github.com/ricochet2200/go-disk-usage/du v0.0.0-20210707232629-ac9918953285 github.com/ricochet2200/go-disk-usage/du v0.0.0-20210707232629-ac9918953285
github.com/sirupsen/logrus v1.7.0 github.com/sirupsen/logrus v1.7.0
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
@ -64,8 +67,9 @@ require (
github.com/vmihailenco/msgpack/v5 v5.1.3 github.com/vmihailenco/msgpack/v5 v5.1.3
go.etcd.io/bbolt v1.3.6 go.etcd.io/bbolt v1.3.6
golang.org/x/net v0.0.0-20211008194852-3b03d305991f golang.org/x/net v0.0.0-20211008194852-3b03d305991f
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e golang.org/x/sys v0.0.0-20220111092808-5a964db01320
golang.org/x/text v0.3.7 golang.org/x/text v0.3.7
howett.net/plist v1.0.0 // indirect
) )
replace ( replace (

21
go.sum
View File

@ -113,6 +113,11 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
github.com/elastic/go-sysinfo v1.7.1 h1:Wx4DSARcKLllpKT2TnFVdSUJOsybqMYCNQZq1/wO+s0=
github.com/elastic/go-sysinfo v1.7.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0=
github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU=
github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0=
github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss=
github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a h1:bMdSPm6sssuOFpIaveu3XGAijMS3Tq2S3EqFZmZxidc= github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a h1:bMdSPm6sssuOFpIaveu3XGAijMS3Tq2S3EqFZmZxidc=
github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a/go.mod h1:ikgISoP7pRAolqsVP64yMteJa2FIpS6ju88eBT6K1yQ= github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a/go.mod h1:ikgISoP7pRAolqsVP64yMteJa2FIpS6ju88eBT6K1yQ=
github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342 h1:5p1t3e1PomYgLWwEwhwEU5kVBwcyAcVrOpexv8AeZx0= github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342 h1:5p1t3e1PomYgLWwEwhwEU5kVBwcyAcVrOpexv8AeZx0=
@ -179,6 +184,7 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
@ -241,6 +247,9 @@ github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0Gqw
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7 h1:g0fAGBisHaEQ0TRq1iBvemFRf+8AEWEmBESSiWB3Vsc= github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7 h1:g0fAGBisHaEQ0TRq1iBvemFRf+8AEWEmBESSiWB3Vsc=
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@ -347,7 +356,10 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/ricochet2200/go-disk-usage/du v0.0.0-20210707232629-ac9918953285 h1:d54EL9l+XteliUfUCGsEwwuk65dmmxX85VXF+9T6+50= github.com/ricochet2200/go-disk-usage/du v0.0.0-20210707232629-ac9918953285 h1:d54EL9l+XteliUfUCGsEwwuk65dmmxX85VXF+9T6+50=
github.com/ricochet2200/go-disk-usage/du v0.0.0-20210707232629-ac9918953285/go.mod h1:fxIDly1xtudczrZeOOlfaUvd2OPb2qZAPuWdU2BsBTk= github.com/ricochet2200/go-disk-usage/du v0.0.0-20210707232629-ac9918953285/go.mod h1:fxIDly1xtudczrZeOOlfaUvd2OPb2qZAPuWdU2BsBTk=
@ -509,6 +521,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -532,11 +545,13 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/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-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -547,6 +562,8 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -622,6 +639,7 @@ gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@ -635,4 +653,7 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=

View File

@ -189,6 +189,8 @@ func New( // nolint[funlen]
cm := pmapi.New(cfg) cm := pmapi.New(cfg)
sentryReporter.SetClientFromManager(cm)
cm.AddConnectionObserver(pmapi.NewConnectionObserver( cm.AddConnectionObserver(pmapi.NewConnectionObserver(
func() { listener.Emit(events.InternetOffEvent, "") }, func() { listener.Emit(events.InternetOffEvent, "") },
func() { listener.Emit(events.InternetOnEvent, "") }, func() { listener.Emit(events.InternetOnEvent, "") },

View File

@ -25,81 +25,118 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
const testPrefFilePath = "/tmp/pref.json"
func TestLoadNoKeyValueStore(t *testing.T) { func TestLoadNoKeyValueStore(t *testing.T) {
pref := newTestEmptyKeyValueStore(t) r := require.New(t)
require.Equal(t, "", pref.Get("key")) pref, clean := newTestEmptyKeyValueStore(r)
defer clean()
r.Equal("", pref.Get("key"))
} }
func TestLoadBadKeyValueStore(t *testing.T) { func TestLoadBadKeyValueStore(t *testing.T) {
require.NoError(t, ioutil.WriteFile(testPrefFilePath, []byte("{\"key\":\"value"), 0700)) r := require.New(t)
pref := newKeyValueStore(testPrefFilePath) path, clean := newTmpFile(r)
require.Equal(t, "", pref.Get("key")) defer clean()
r.NoError(ioutil.WriteFile(path, []byte("{\"key\":\"MISSING_QUOTES"), 0700))
pref := newKeyValueStore(path)
r.Equal("", pref.Get("key"))
} }
func TestKeyValueStoreGet(t *testing.T) { func TestKeyValueStor(t *testing.T) {
pref := newTestKeyValueStore(t) r := require.New(t)
require.Equal(t, "value", pref.Get("str")) pref, clean := newTestKeyValueStore(r)
require.Equal(t, "42", pref.Get("int")) defer clean()
require.Equal(t, "true", pref.Get("bool"))
require.Equal(t, "t", pref.Get("falseBool")) r.Equal("value", pref.Get("str"))
r.Equal("42", pref.Get("int"))
r.Equal("true", pref.Get("bool"))
r.Equal("t", pref.Get("falseBool"))
} }
func TestKeyValueStoreGetInt(t *testing.T) { func TestKeyValueStoreGetInt(t *testing.T) {
pref := newTestKeyValueStore(t) r := require.New(t)
require.Equal(t, 0, pref.GetInt("str")) pref, clean := newTestKeyValueStore(r)
require.Equal(t, 42, pref.GetInt("int")) defer clean()
require.Equal(t, 0, pref.GetInt("bool"))
require.Equal(t, 0, pref.GetInt("falseBool")) r.Equal(0, pref.GetInt("str"))
r.Equal(42, pref.GetInt("int"))
r.Equal(0, pref.GetInt("bool"))
r.Equal(0, pref.GetInt("falseBool"))
} }
func TestKeyValueStoreGetBool(t *testing.T) { func TestKeyValueStoreGetBool(t *testing.T) {
pref := newTestKeyValueStore(t) r := require.New(t)
require.Equal(t, false, pref.GetBool("str")) pref, clean := newTestKeyValueStore(r)
require.Equal(t, false, pref.GetBool("int")) defer clean()
require.Equal(t, true, pref.GetBool("bool"))
require.Equal(t, false, pref.GetBool("falseBool")) r.Equal(false, pref.GetBool("str"))
r.Equal(false, pref.GetBool("int"))
r.Equal(true, pref.GetBool("bool"))
r.Equal(false, pref.GetBool("falseBool"))
} }
func TestKeyValueStoreSetDefault(t *testing.T) { func TestKeyValueStoreSetDefault(t *testing.T) {
pref := newTestEmptyKeyValueStore(t) r := require.New(t)
pref, clean := newTestEmptyKeyValueStore(r)
defer clean()
pref.setDefault("key", "value") pref.setDefault("key", "value")
pref.setDefault("key", "othervalue") pref.setDefault("key", "othervalue")
require.Equal(t, "value", pref.Get("key")) r.Equal("value", pref.Get("key"))
} }
func TestKeyValueStoreSet(t *testing.T) { func TestKeyValueStoreSet(t *testing.T) {
pref := newTestEmptyKeyValueStore(t) r := require.New(t)
pref, clean := newTestEmptyKeyValueStore(r)
defer clean()
pref.Set("str", "value") pref.Set("str", "value")
checkSavedKeyValueStore(t, "{\n\t\"str\": \"value\"\n}") checkSavedKeyValueStore(r, pref.path, "{\n\t\"str\": \"value\"\n}")
} }
func TestKeyValueStoreSetInt(t *testing.T) { func TestKeyValueStoreSetInt(t *testing.T) {
pref := newTestEmptyKeyValueStore(t) r := require.New(t)
pref, clean := newTestEmptyKeyValueStore(r)
defer clean()
pref.SetInt("int", 42) pref.SetInt("int", 42)
checkSavedKeyValueStore(t, "{\n\t\"int\": \"42\"\n}") checkSavedKeyValueStore(r, pref.path, "{\n\t\"int\": \"42\"\n}")
} }
func TestKeyValueStoreSetBool(t *testing.T) { func TestKeyValueStoreSetBool(t *testing.T) {
pref := newTestEmptyKeyValueStore(t) r := require.New(t)
pref, clean := newTestEmptyKeyValueStore(r)
defer clean()
pref.SetBool("trueBool", true) pref.SetBool("trueBool", true)
pref.SetBool("falseBool", false) pref.SetBool("falseBool", false)
checkSavedKeyValueStore(t, "{\n\t\"falseBool\": \"false\",\n\t\"trueBool\": \"true\"\n}") checkSavedKeyValueStore(r, pref.path, "{\n\t\"falseBool\": \"false\",\n\t\"trueBool\": \"true\"\n}")
} }
func newTestEmptyKeyValueStore(t *testing.T) *keyValueStore { func newTmpFile(r *require.Assertions) (path string, clean func()) {
require.NoError(t, os.RemoveAll(testPrefFilePath)) tmpfile, err := ioutil.TempFile("", "pref.*.json")
return newKeyValueStore(testPrefFilePath) r.NoError(err)
defer r.NoError(tmpfile.Close())
return tmpfile.Name(), func() {
r.NoError(os.Remove(tmpfile.Name()))
}
} }
func newTestKeyValueStore(t *testing.T) *keyValueStore { func newTestEmptyKeyValueStore(r *require.Assertions) (*keyValueStore, func()) {
require.NoError(t, ioutil.WriteFile(testPrefFilePath, []byte("{\"str\":\"value\",\"int\":\"42\",\"bool\":\"true\",\"falseBool\":\"t\"}"), 0700)) path, clean := newTmpFile(r)
return newKeyValueStore(testPrefFilePath) return newKeyValueStore(path), clean
} }
func checkSavedKeyValueStore(t *testing.T, expected string) { func newTestKeyValueStore(r *require.Assertions) (*keyValueStore, func()) {
data, err := ioutil.ReadFile(testPrefFilePath) path, clean := newTmpFile(r)
require.NoError(t, err) r.NoError(ioutil.WriteFile(path, []byte("{\"str\":\"value\",\"int\":\"42\",\"bool\":\"true\",\"falseBool\":\"t\"}"), 0700))
require.Equal(t, expected, string(data)) return newKeyValueStore(path), clean
}
func checkSavedKeyValueStore(r *require.Assertions, path, expected string) {
data, err := ioutil.ReadFile(path)
r.NoError(err)
r.Equal(expected, string(data))
} }

View File

@ -0,0 +1,49 @@
// Copyright (c) 2022 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
//go:build darwin
// +build darwin
package sentry
import (
"github.com/elastic/go-sysinfo"
"golang.org/x/sys/unix"
)
const translatedProcDarwin = "sysctl.proc_translated"
func getHostAarch() string {
host, err := sysinfo.Host()
if err != nil {
return "not-detected"
}
// It is not possible to retrieve real hardware architecture once using
// rosetta. But it is possible to detect the process translation if
// rosetta is used.
res, err := unix.SysctlRaw(translatedProcDarwin)
if err != nil || len(res) > 4 {
return host.Info().Architecture + "_err"
}
if res[0] == 1 {
return host.Info().Architecture + "_rosetta"
}
return host.Info().Architecture
}

View File

@ -0,0 +1,31 @@
// Copyright (c) 2022 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
//go:build !darwin
// +build !darwin
package sentry
import "github.com/elastic/go-sysinfo"
func getHostAarch() string {
host, err := sysinfo.Host()
if err != nil {
return "not-detected"
}
return host.Info().Architecture
}

View File

@ -20,18 +20,20 @@ package sentry
import ( import (
"errors" "errors"
"fmt" "fmt"
"log"
"os" "os"
"runtime" "runtime"
"time" "time"
"github.com/ProtonMail/proton-bridge/internal/constants" "github.com/ProtonMail/proton-bridge/internal/constants"
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
"github.com/getsentry/sentry-go" "github.com/getsentry/sentry-go"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
var skippedFunctions = []string{} //nolint[gochecknoglobals] var skippedFunctions = []string{} //nolint[gochecknoglobals]
func init() { // nolint[noinit] func init() { //nolint[noinit, gochecknoinits]
if err := sentry.Init(sentry.ClientOptions{ if err := sentry.Init(sentry.ClientOptions{
Dsn: constants.DSNSentry, Dsn: constants.DSNSentry,
Release: constants.Revision, Release: constants.Revision,
@ -42,13 +44,20 @@ func init() { // nolint[noinit]
sentry.ConfigureScope(func(scope *sentry.Scope) { sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.SetFingerprint([]string{"{{ default }}"}) scope.SetFingerprint([]string{"{{ default }}"})
scope.SetTag("UserID", "not-defined")
}) })
sentry.Logger = log.New(
logrus.WithField("pkg", "sentry-go").WriterLevel(logrus.WarnLevel),
"", 0,
)
} }
type Reporter struct { type Reporter struct {
appName string appName string
appVersion string appVersion string
userAgent fmt.Stringer userAgent fmt.Stringer
hostArch string
} }
// NewReporter creates new sentry reporter with appName and appVersion to report. // NewReporter creates new sentry reporter with appName and appVersion to report.
@ -57,6 +66,7 @@ func NewReporter(appName, appVersion string, userAgent fmt.Stringer) *Reporter {
appName: appName, appName: appName,
appVersion: appVersion, appVersion: appVersion,
userAgent: userAgent, userAgent: userAgent,
hostArch: getHostAarch(),
} }
} }
@ -109,7 +119,7 @@ func (r *Reporter) scopedReport(context map[string]interface{}, doReport func())
"Client": r.appName, "Client": r.appName,
"Version": r.appVersion, "Version": r.appVersion,
"UserAgent": r.userAgent.String(), "UserAgent": r.userAgent.String(),
"UserID": "", "HostArch": r.hostArch,
} }
sentry.WithScope(func(scope *sentry.Scope) { sentry.WithScope(func(scope *sentry.Scope) {
@ -179,3 +189,6 @@ func isFunctionFilteredOut(function string) bool {
func Flush(maxWaiTime time.Duration) { func Flush(maxWaiTime time.Duration) {
sentry.Flush(maxWaiTime) sentry.Flush(maxWaiTime)
} }
func (r *Reporter) SetClientFromManager(cm pmapi.Manager) {
}

View File

@ -23,6 +23,7 @@ import (
"github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/ProtonMail/gopenpgp/v2/crypto"
"github.com/ProtonMail/proton-bridge/internal/store/cache" "github.com/ProtonMail/proton-bridge/internal/store/cache"
"github.com/ProtonMail/proton-bridge/pkg/message" "github.com/ProtonMail/proton-bridge/pkg/message"
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
bolt "go.etcd.io/bbolt" bolt "go.etcd.io/bbolt"
) )
@ -126,6 +127,7 @@ func (store *Store) getCachedMessage(messageID string) ([]byte, error) {
literal, err := job.GetResult() literal, err := job.GetResult()
if err != nil { if err != nil {
store.checkAndRemoveDeletedMessage(err, messageID)
return nil, err return nil, err
} }
@ -184,8 +186,21 @@ func (store *Store) BuildAndCacheMessage(ctx context.Context, messageID string)
literal, err := job.GetResult() literal, err := job.GetResult()
if err != nil { if err != nil {
store.checkAndRemoveDeletedMessage(err, messageID)
return err return err
} }
return store.cache.Set(store.user.ID(), messageID, literal) return store.cache.Set(store.user.ID(), messageID, literal)
} }
func (store *Store) checkAndRemoveDeletedMessage(err error, msgID string) {
if _, ok := err.(pmapi.ErrUnprocessableEntity); !ok {
return
}
l := store.log.WithError(err).WithField("msgID", msgID)
l.Warn("Deleting message which was not found on API")
if deleteErr := store.deleteMessageEvent(msgID); deleteErr != nil {
l.WithField("deleteErr", deleteErr).Error("Failed to delete non-existed API message from DB")
}
}

View File

@ -63,10 +63,16 @@ func NewOnDiskCache(path string, cmp Compressor, opts Options) (Cache, error) {
} }
file, err := ioutil.TempFile(path, "tmp") file, err := ioutil.TempFile(path, "tmp")
defer func() {
file.Close() //nolint[errcheck]
os.Remove(file.Name()) //nolint[errcheck]
}()
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot open test write target: %w", err)
}
if _, err := file.Write([]byte("test-write")); err != nil {
return nil, fmt.Errorf("cannot write to target: %w", err) return nil, fmt.Errorf("cannot write to target: %w", err)
} }
os.Remove(file.Name()) //nolint[errcheck]
usage := du.NewDiskUsage(path) usage := du.NewDiskUsage(path)

View File

@ -229,7 +229,10 @@ func (u *Users) MigrateCache(srcPath, dstPath string) error {
// (read-only is conserved). Do copy instead. // (read-only is conserved). Do copy instead.
tmp, err := ioutil.TempFile(srcPath, "tmp") tmp, err := ioutil.TempFile(srcPath, "tmp")
if err == nil { if err == nil {
defer os.Remove(tmp.Name()) //nolint[errcheck] defer func() {
tmp.Close() //nolint[errcheck]
os.Remove(tmp.Name()) //nolint[errcheck]
}()
if err := os.Rename(srcPath, dstPath); err == nil { if err := os.Rename(srcPath, dstPath); err == nil {
return nil return nil

View File

@ -175,6 +175,7 @@ func initMocks(t *testing.T) mocks {
cacheFile, err := ioutil.TempFile("", "bridge-store-cache-*.db") cacheFile, err := ioutil.TempFile("", "bridge-store-cache-*.db")
r.NoError(t, err, "could not get temporary file for store cache") r.NoError(t, err, "could not get temporary file for store cache")
r.NoError(t, cacheFile.Close())
m := mocks{ m := mocks{
t: t, t: t,
@ -201,6 +202,7 @@ func initMocks(t *testing.T) mocks {
dbFile, err := ioutil.TempFile(t.TempDir(), "bridge-store-db-*.db") dbFile, err := ioutil.TempFile(t.TempDir(), "bridge-store-db-*.db")
r.NoError(t, err, "could not get temporary file for store db") r.NoError(t, err, "could not get temporary file for store db")
r.NoError(t, dbFile.Close())
return store.New( return store.New(
sentryReporter, sentryReporter,

View File

@ -32,7 +32,7 @@ import (
// RemoveOldVersions is a noop on darwin; we don't test it there. // RemoveOldVersions is a noop on darwin; we don't test it there.
func TestRemoveOldVersions(t *testing.T) { func TestRemoveOldVersions(t *testing.T) {
updates, err := ioutil.TempDir("", "updates") updates, err := ioutil.TempDir(t.TempDir(), "updates")
require.NoError(t, err) require.NoError(t, err)
v := newTestVersioner(t, "myCoolApp", updates, "2.3.4-beta", "2.3.4", "2.3.5", "2.4.0") v := newTestVersioner(t, "myCoolApp", updates, "2.3.4-beta", "2.3.4", "2.3.5", "2.4.0")

View File

@ -65,11 +65,13 @@ func makeDummyVersionDirectory(t *testing.T, exeName, updates, version string) s
exe, err := os.Create(filepath.Join(target, getExeName(exeName))) exe, err := os.Create(filepath.Join(target, getExeName(exeName)))
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, exe) require.NotNil(t, exe)
require.NoError(t, exe.Close())
require.NoError(t, os.Chmod(exe.Name(), 0700)) require.NoError(t, os.Chmod(exe.Name(), 0700))
sig, err := os.Create(filepath.Join(target, getExeName(exeName)+".sig")) sig, err := os.Create(filepath.Join(target, getExeName(exeName)+".sig"))
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, sig) require.NotNil(t, sig)
require.NoError(t, sig.Close())
return target return target
} }

View File

@ -21,6 +21,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"math" "math"
"runtime"
"testing" "testing"
"time" "time"
@ -33,6 +34,7 @@ var (
wantOutput = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} wantOutput = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
testProcessSleep = 100 // ms testProcessSleep = 100 // ms
runParallelTimeOverhead = 150 // ms runParallelTimeOverhead = 150 // ms
windowsCIExtra = 250 // ms - estimated experimentally
) )
func TestParallel(t *testing.T) { func TestParallel(t *testing.T) {
@ -56,6 +58,9 @@ func TestParallel(t *testing.T) {
wantMinDuration := int(math.Ceil(float64(len(testInput))/float64(workers))) * testProcessSleep wantMinDuration := int(math.Ceil(float64(len(testInput))/float64(workers))) * testProcessSleep
wantMaxDuration := wantMinDuration + runParallelTimeOverhead wantMaxDuration := wantMinDuration + runParallelTimeOverhead
if runtime.GOOS == "windows" {
wantMaxDuration += windowsCIExtra
}
r.True(t, duration.Nanoseconds() > int64(wantMinDuration*1000000), "Duration too short: %v (expected: %v)", duration, wantMinDuration) r.True(t, duration.Nanoseconds() > int64(wantMinDuration*1000000), "Duration too short: %v (expected: %v)", duration, wantMinDuration)
r.True(t, duration.Nanoseconds() < int64(wantMaxDuration*1000000), "Duration too long: %v (expected: %v)", duration, wantMaxDuration) r.True(t, duration.Nanoseconds() < int64(wantMaxDuration*1000000), "Duration too long: %v (expected: %v)", duration, wantMaxDuration)
}) })

View File

@ -82,4 +82,5 @@ type AuthRefreshHandler func(*AuthRefresh)
type clientManager interface { type clientManager interface {
r(context.Context) *resty.Request r(context.Context) *resty.Request
authRefresh(context.Context, string, string) (*AuthRefresh, error) authRefresh(context.Context, string, string) (*AuthRefresh, error)
setSentryUserID(userID string)
} }

View File

@ -32,9 +32,9 @@ var (
) )
type ErrUnprocessableEntity struct { type ErrUnprocessableEntity struct {
originalError error OriginalError error
} }
func (err ErrUnprocessableEntity) Error() string { func (err ErrUnprocessableEntity) Error() string {
return err.originalError.Error() return err.OriginalError.Error()
} }

View File

@ -23,6 +23,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/getsentry/sentry-go"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
) )
@ -37,6 +38,7 @@ type manager struct {
pingMutex *sync.RWMutex pingMutex *sync.RWMutex
isPinging bool isPinging bool
setSentryUserIDOnce sync.Once
} }
func New(cfg Config) Manager { func New(cfg Config) Manager {
@ -50,6 +52,7 @@ func newManager(cfg Config) *manager {
locker: &sync.Mutex{}, locker: &sync.Mutex{},
pingMutex: &sync.RWMutex{}, pingMutex: &sync.RWMutex{},
isPinging: false, isPinging: false,
setSentryUserIDOnce: sync.Once{},
} }
proxyDialer, transport := newProxyDialerAndTransport(cfg) proxyDialer, transport := newProxyDialerAndTransport(cfg)
@ -158,3 +161,11 @@ func (m *manager) handleRequestFailure(req *resty.Request, err error) {
go m.pingUntilSuccess() go m.pingUntilSuccess()
} }
func (m *manager) setSentryUserID(userID string) {
m.setSentryUserIDOnce.Do(func() {
sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.SetTag("UserID", userID)
})
})
}

View File

@ -21,7 +21,6 @@ import (
"context" "context"
"github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/ProtonMail/gopenpgp/v2/crypto"
"github.com/getsentry/sentry-go"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -126,7 +125,7 @@ func (c *client) UpdateUser(ctx context.Context) (*User, error) {
c.user = user c.user = user
c.addresses = addresses c.addresses = addresses
sentry.ConfigureScope(func(scope *sentry.Scope) { scope.SetUser(sentry.User{ID: user.ID}) }) c.manager.setSentryUserID(user.ID)
return user, err return user, err
} }

View File

@ -1,7 +1,7 @@
.PHONY: check-go check-godog install-godog test test-bridge test-live test-live-bridge test-stage test-debug test-live-debug bench .PHONY: check-go check-godog install-godog test test-bridge test-live test-live-bridge test-stage test-debug test-live-debug bench
export GO111MODULE=on export GO111MODULE=on
export BRIDGE_VERSION:=2.1.0+integrationtests export BRIDGE_VERSION:=2.1.1+integrationtests
export VERBOSITY?=fatal export VERBOSITY?=fatal
export TEST_DATA=testdata export TEST_DATA=testdata

View File

@ -45,6 +45,7 @@ type PMAPIController interface {
GetCalls(method, path string) [][]byte GetCalls(method, path string) [][]byte
LockEvents(username string) LockEvents(username string)
UnlockEvents(username string) UnlockEvents(username string)
RemoveUserMessageWithoutEvent(username, messageID string) error
} }
func newPMAPIController(listener listener.Listener) (PMAPIController, pmapi.Manager) { func newPMAPIController(listener listener.Listener) (PMAPIController, pmapi.Manager) {

View File

@ -234,3 +234,19 @@ func (ctl *Controller) LockEvents(string) {}
// UnlockEvents doesn't needs to be implemented for fakeAPI. // UnlockEvents doesn't needs to be implemented for fakeAPI.
func (ctl *Controller) UnlockEvents(string) {} func (ctl *Controller) UnlockEvents(string) {}
func (ctl *Controller) RemoveUserMessageWithoutEvent(username string, messageID string) error {
msgs, ok := ctl.messagesByUsername[username]
if !ok {
return nil
}
for i, message := range msgs {
if message.ID == messageID {
ctl.messagesByUsername[username] = append(msgs[:i], msgs[i+1:]...)
return nil
}
}
return errors.New("message not found")
}

View File

@ -37,7 +37,7 @@ func (api *FakePMAPI) GetMessage(_ context.Context, apiID string) (*pmapi.Messag
if msg := api.getMessage(apiID); msg != nil { if msg := api.getMessage(apiID); msg != nil {
return msg, nil return msg, nil
} }
return nil, fmt.Errorf("message %s not found", apiID) return nil, pmapi.ErrUnprocessableEntity{OriginalError: fmt.Errorf("message %s not found", apiID)}
} }
// ListMessages does not implement following filters: // ListMessages does not implement following filters:

View File

@ -177,3 +177,14 @@ Feature: IMAP fetch messages
# We had bug to incorectly set empty date, so let's make sure # We had bug to incorectly set empty date, so let's make sure
# there is no reference anywhere in the response. # there is no reference anywhere in the response.
And IMAP response does not contain "\nDate: Thu, 01 Jan 1970" And IMAP response does not contain "\nDate: Thu, 01 Jan 1970"
Scenario: Fetch of message which was deleted without event processed
Given there are 10 messages in mailbox "INBOX" for "user"
And message "5" was deleted forever without event processed for "user"
And there is IMAP client logged in as "user"
And there is IMAP client selected in "INBOX"
When IMAP client fetches bodies "1:*"
Then IMAP response is "NO"
When IMAP client fetches bodies "1:*"
Then IMAP response is "OK"
And IMAP response has 9 messages

View File

@ -104,3 +104,14 @@ func (ctl *Controller) GetMessages(username, labelID string) ([]*pmapi.Message,
return messages, nil return messages, nil
} }
func (ctl *Controller) RemoveUserMessageWithoutEvent(username string, messageID string) error {
client, err := getPersistentClient(username)
if err != nil {
return err
}
addMessageIDToSkipEventOnceDeleted(messageID)
return client.DeleteMessages(context.Background(), []string{messageID})
}

View File

@ -49,6 +49,7 @@ var persistentClients = struct {
saltByName map[string]string saltByName map[string]string
eventsPaused sync.WaitGroup eventsPaused sync.WaitGroup
skipDeletedMessageID map[string]struct{}
}{} }{}
type persistentClient struct { type persistentClient struct {
@ -79,7 +80,40 @@ func (pc *persistentClient) GetEvent(ctx context.Context, eventID string) (*pmap
if !ok { if !ok {
return nil, errors.New("cannot convert to normal client") return nil, errors.New("cannot convert to normal client")
} }
return normalClient.GetEvent(ctx, eventID)
event, err := normalClient.GetEvent(ctx, eventID)
if err != nil {
return event, err
}
return skipDeletedMessageIDs(event), nil
}
func addMessageIDToSkipEventOnceDeleted(msgID string) {
if persistentClients.skipDeletedMessageID == nil {
persistentClients.skipDeletedMessageID = map[string]struct{}{}
}
persistentClients.skipDeletedMessageID[msgID] = struct{}{}
}
func skipDeletedMessageIDs(event *pmapi.Event) *pmapi.Event {
if len(event.Messages) == 0 {
return event
}
n := 0
for i, m := range event.Messages {
if _, ok := persistentClients.skipDeletedMessageID[m.ID]; ok && m.Action == pmapi.EventDelete {
delete(persistentClients.skipDeletedMessageID, m.ID)
continue
}
event.Messages[i] = m
n++
}
event.Messages = event.Messages[:n]
return event
} }
func SetupPersistentClients() { func SetupPersistentClients() {

View File

@ -38,6 +38,7 @@ func StoreSetupFeatureContext(s *godog.ScenarioContext) {
s.Step(`^there are messages for "([^"]*)" as follows$`, thereAreSomeMessagesForUserAsFollows) s.Step(`^there are messages for "([^"]*)" as follows$`, thereAreSomeMessagesForUserAsFollows)
s.Step(`^there are (\d+) messages in mailbox(?:es)? "([^"]*)" for address "([^"]*)" of "([^"]*)"$`, thereAreSomeMessagesInMailboxesForAddressOfUser) s.Step(`^there are (\d+) messages in mailbox(?:es)? "([^"]*)" for address "([^"]*)" of "([^"]*)"$`, thereAreSomeMessagesInMailboxesForAddressOfUser)
s.Step(`^wait for Sphinx to create duplication indices$`, waitForSphinx) s.Step(`^wait for Sphinx to create duplication indices$`, waitForSphinx)
s.Step(`^message(?:s)? "([^"]*)" (?:was|were) deleted forever without event processed for "([^"]*)"$`, messageWasDeletedWithoutEvent)
} }
func thereIsUserWithMailboxes(bddUserID string, mailboxes *godog.Table) error { func thereIsUserWithMailboxes(bddUserID string, mailboxes *godog.Table) error {
@ -319,3 +320,16 @@ func waitForSphinx() error {
time.Sleep(15 * time.Second) time.Sleep(15 * time.Second)
return nil return nil
} }
func messageWasDeletedWithoutEvent(bddMessageID, bddUserID string) error {
account := ctx.GetTestAccount(bddUserID)
if account == nil {
return godog.ErrPending
}
apiID, err := ctx.GetAPIMessageID(account.Username(), bddMessageID)
if err != nil {
return internalError(err, "getting BDD message ID %s", bddMessageID)
}
return ctx.GetPMAPIController().RemoveUserMessageWithoutEvent(account.Username(), apiID)
}