Skip to content

Fix quit message not being printed #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions .github/workflows/test-go-task.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/test-go-task.md
name: Test Go

env:
# See: https://github.com/actions/setup-go/tree/v2#readme
GO_VERSION: "1.16"

# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
on:
create:
push:
paths:
- ".github/workflows/test-go-task.ya?ml"
- "codecov.ya?ml"
- "**/go.mod"
- "**/go.sum"
- "Taskfile.ya?ml"
- "**.go"
- "**/testdata/**"
pull_request:
paths:
- ".github/workflows/test-go-task.ya?ml"
- "codecov.ya?ml"
- "**/go.mod"
- "**/go.sum"
- "Taskfile.ya?ml"
- "**.go"
- "**/testdata/**"
workflow_dispatch:
repository_dispatch:

jobs:
run-determination:
runs-on: ubuntu-latest
outputs:
result: ${{ steps.determination.outputs.result }}
steps:
- name: Determine if the rest of the workflow should run
id: determination
run: |
RELEASE_BRANCH_REGEX="refs/heads/[0-9]+.[0-9]+.x"
# The `create` event trigger doesn't support `branches` filters, so it's necessary to use Bash instead.
if [[ \
"${{ github.event_name }}" != "create" || \
"${{ github.ref }}" =~ $RELEASE_BRANCH_REGEX \
]]; then
# Run the other jobs.
RESULT="true"
else
# There is no need to run the other jobs.
RESULT="false"
fi
echo "::set-output name=result::$RESULT"
test:
name: test (${{ matrix.module.path }} - ${{ matrix.operating-system }})
needs: run-determination
if: needs.run-determination.outputs.result == 'true'

strategy:
fail-fast: false

matrix:
operating-system:
- ubuntu-latest
- windows-latest
- macos-latest
module:
- path: ./
codecov-flags: unit

runs-on: ${{ matrix.operating-system }}

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Install Go
uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}

- name: Install Task
uses: arduino/setup-task@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
version: 3.x

- name: Run tests
env:
GO_MODULE_PATH: ${{ matrix.module.path }}
run: task go:test

- name: Send unit tests coverage to Codecov
if: runner.os == 'Linux'
uses: codecov/codecov-action@v2
with:
file: ${{ matrix.module.path }}coverage_unit.txt
flags: ${{ matrix.module.codecov-flags }}
fail_ci_if_error: ${{ github.repository == 'arduino/pluggable-discovery-protocol-handler' }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
dist/

coverage_*.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
name: github.com/arduino/go-paths-helper
version: v1.0.1
version: v1.6.1
type: go
summary:
summary:
homepage: https://pkg.go.dev/github.com/arduino/go-paths-helper
license: gpl-2.0-or-later
licenses:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: github.com/arduino/go-properties-orderedmap
version: v1.4.0
version: v1.6.0
type: go
summary: Package properties is a library for handling maps of hierarchical properties.
homepage: https://pkg.go.dev/github.com/arduino/go-properties-orderedmap
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
name: github.com/pkg/errors
version: v0.9.1
type: go
summary: Package errors provides simple error handling primitives.
homepage: https://pkg.go.dev/github.com/pkg/errors
license: bsd-2-clause
licenses:
- sources: LICENSE
text: |
Copyright (c) 2015, Dave Cheney <[email protected]>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- sources: README.md
text: BSD-2-Clause
notices: []
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
<!-- NOTE: update the pkg.go.dev badge URL on each major release -->

[![Go Reference](https://pkg.go.dev/badge/github.com/arduino/pluggable-discovery-protocol-handler.svg)](https://pkg.go.dev/github.com/arduino/pluggable-discovery-protocol-handler/v2)
[![Test Go status](https://github.com/arduino/pluggable-discovery-protocol-handler/actions/workflows/test-go-task.yml/badge.svg)](https://github.com/arduino/pluggable-discovery-protocol-handler/actions/workflows/test-go-task.yml)
[![Codecov](https://codecov.io/gh/arduino/pluggable-discovery-protocol-handler/branch/main/graph/badge.svg)](https://codecov.io/gh/arduino/pluggable-discovery-protocol-handler)

This project is a library to ease implementation of pluggable discoveries for the [Arduino CLI](https://github.com/arduino/arduino-cli)
following the [official specification](https://arduino.github.io/arduino-cli/latest/platform-specification/#pluggable-discovery).
Expand Down
22 changes: 21 additions & 1 deletion Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ vars:
DUMMY_DISCOVERY_LDFLAGS: >
-X github.com/arduino/pluggable-discovery-protocol-handler/dummy-discovery/args.Tag={{.DUMMY_DISCOVERY_VERSION}}
-X github.com/arduino/pluggable-discovery-protocol-handler/dummy-discovery/args.Timestamp={{.DUMMY_DISCOVERY_TIMESTAMP}}
# Path of the project's primary Go module:
DEFAULT_GO_MODULE_PATH: ./
DEFAULT_GO_PACKAGES:
sh: echo $(go list ./... | tr '\n' ' ')
sh: |
echo $(cd {{default .DEFAULT_GO_MODULE_PATH .GO_MODULE_PATH}} && go list ./... | tr '\n' ' ' || echo '"ERROR: Unable to discover Go packages"')
# `-ldflags` flag to use for `go test` command
TEST_LDFLAGS:

tasks:
build-dummy-discovery:
Expand All @@ -20,6 +25,21 @@ tasks:
cmds:
- go build -o dist/{{.EXECUTABLE}} -v -ldflags '{{.DUMMY_DISCOVERY_LDFLAGS}}' ./dummy-discovery

# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/test-go-task/Taskfile.yml
go:test:
desc: Run unit tests
dir: "{{default .DEFAULT_GO_MODULE_PATH .GO_MODULE_PATH}}"
cmds:
- |
go test \
-v \
-short \
-run '{{default ".*" .GO_TEST_REGEX}}' \
{{default "-timeout 10m -coverpkg=./... -covermode=atomic" .GO_TEST_FLAGS}} \
-coverprofile=coverage_unit.txt \
{{.TEST_LDFLAGS}} \
{{default .DEFAULT_GO_PACKAGES .GO_PACKAGES}}
# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/check-workflows-task/Taskfile.yml
ci:validate:
desc: Validate GitHub Actions workflows against their JSON schema
Expand Down
27 changes: 22 additions & 5 deletions discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"regexp"
"strconv"
"strings"
"sync"

"github.com/arduino/go-properties-orderedmap"
)
Expand Down Expand Up @@ -86,6 +87,7 @@ type ErrorCallback func(err string)
type Server struct {
impl Discovery
outputChan chan *message
outputWaiter sync.WaitGroup
userAgent string
reqProtocolVersion int
initialized bool
Expand All @@ -111,8 +113,7 @@ func NewServer(impl Discovery) *Server {
// the input stream is closed. In case of IO error the error is
// returned.
func (d *Server) Run(in io.Reader, out io.Writer) error {
go d.outputProcessor(out)
defer close(d.outputChan)
d.startOutputProcessor(out)
reader := bufio.NewReader(in)
for {
fullCmd, err := reader.ReadString('\n')
Expand Down Expand Up @@ -141,8 +142,7 @@ func (d *Server) Run(in io.Reader, out io.Writer) error {
case "STOP":
d.stop()
case "QUIT":
d.impl.Quit()
d.outputChan <- messageOk("quit")
d.quit()
return nil
default:
d.outputChan <- messageError("command_error", fmt.Sprintf("Command %s not supported", cmd))
Expand Down Expand Up @@ -276,12 +276,26 @@ func (d *Server) syncEvent(event string, port *Port) {
}
}

func (d *Server) quit() {
d.impl.Quit()
d.outputChan <- messageOk("quit")
close(d.outputChan)
// If we don't wait for all messages
// to be consumed by the output processor
// we risk not printing the "quit" message.
// This may cause issues to consumers of
// the discovery since they expect a message
// that is never sent.
d.outputWaiter.Wait()
}

func (d *Server) errorEvent(msg string) {
d.outputChan <- messageError("start_sync", msg)
}

func (d *Server) outputProcessor(outWriter io.Writer) {
func (d *Server) startOutputProcessor(outWriter io.Writer) {
// Start go routine to serialize messages printing
d.outputWaiter.Add(1)
go func() {
for msg := range d.outputChan {
data, err := json.MarshalIndent(msg, "", " ")
Expand All @@ -292,5 +306,8 @@ func (d *Server) outputProcessor(outWriter io.Writer) {
}
fmt.Fprintln(outWriter, string(data))
}
// We finished consuming all messages, now
// we can exit for real
d.outputWaiter.Done()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about dropping the channel + goroutine + waitgroup + d.quit in change of a mutex?

outputMutext.Lock()
output.Write(data)
outputMutex.Unlock()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be mean refactor everything again, I'd prefer to avoid that. 😖

}()
}
62 changes: 62 additions & 0 deletions discovery_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//
// This file is part of dummy-discovery.
//
// Copyright 2021 ARDUINO SA (http://www.arduino.cc/)
//
// This software is released under the GNU General Public License version 3,
// which covers the main part of arduino-cli.
// The terms of this license can be found at:
// https://www.gnu.org/licenses/gpl-3.0.en.html
//
// You can be released from the requirements of the above licenses by purchasing
// a commercial license. Buying such a license is mandatory if you want to modify or
// otherwise use the software for commercial activities involving the Arduino
// software without disclosing the source code of your own applications. To purchase
// a commercial license, send an email to [email protected].
//

package discovery

import (
"testing"

"github.com/arduino/arduino-cli/executils"
"github.com/stretchr/testify/require"
)

func runDummyDiscovery(t *testing.T) *executils.Process {
discoveryDir := "dummy-discovery"
// Build dummy-discovery for testing
builder, err := executils.NewProcess("go", "build")
require.NoError(t, err)
builder.SetDir(discoveryDir)
require.NoError(t, builder.Run())
discovery, err := executils.NewProcess("./dummy-discovery")
require.NoError(t, err)
discovery.SetDir(discoveryDir)
return discovery
}

func TestDiscoveryStdioHandling(t *testing.T) {
discovery := runDummyDiscovery(t)

stdout, err := discovery.StdoutPipe()
require.NoError(t, err)
stdin, err := discovery.StdinPipe()
require.NoError(t, err)

require.NoError(t, discovery.Start())
defer discovery.Kill()

n, err := stdin.Write([]byte("quit\n"))
require.Greater(t, n, 0)
require.NoError(t, err)
output := [1024]byte{}
// require.NoError(t, discovery.Wait())
n, err = stdout.Read(output[:])
require.Greater(t, n, 0)
require.NoError(t, err)

expectedOutput := "{\n \"eventType\": \"quit\",\n \"message\": \"OK\"\n}\n"
require.Equal(t, expectedOutput, string(output[:n]))
}
2 changes: 2 additions & 0 deletions dummy-discovery/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dummy-discovery
dummy-discovery.exe
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ module github.com/arduino/pluggable-discovery-protocol-handler/v2

go 1.16

require github.com/arduino/go-properties-orderedmap v1.4.0
require (
github.com/arduino/arduino-cli v0.0.0-20211123110800-c756a0f1305d
github.com/arduino/go-properties-orderedmap v1.6.0
github.com/stretchr/testify v1.7.0
)
Loading