-
Notifications
You must be signed in to change notification settings - Fork 261
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
refactor(service): Add a ProgressHandler for the Wait interface #234
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// Copyright © 2019 The Knative Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package wait | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
) | ||
|
||
// A callback which is informed about the progress of an operation | ||
type ProgressHandler interface { | ||
// Called when the operation starts | ||
Start() | ||
|
||
// Called with a percentage indicating completion | ||
// The argument will be in the range 0..100 if the progress percentage can be calculated | ||
// or -1 if only an ongoing operation should be indicated | ||
Tic(complete int) | ||
|
||
// Called when operation finished sucessfully | ||
Success() | ||
|
||
// Called when the operation failed with the erro | ||
Fail(err error) | ||
} | ||
|
||
// No operation progress handler which just stays silent | ||
type NoopProgressHandler struct{} | ||
|
||
func (w NoopProgressHandler) Start() {} | ||
func (w NoopProgressHandler) Tic(int) {} | ||
func (w NoopProgressHandler) Fail(error) {} | ||
func (w NoopProgressHandler) Success() {} | ||
|
||
// Standard progress handler for printing out progress to a given writer | ||
type simpleProgressHandler struct { | ||
out io.Writer | ||
startLabel string | ||
ticMark string | ||
errorLabel string | ||
successLabel string | ||
} | ||
|
||
// Create a new progress handler which writes out to the given stream. | ||
// The label will be printed right after start, error & success are terminal message depending on the outcome | ||
// In case of an error, the error itself is not printed as it is supposed that the calling function | ||
// will deal with the error and eventually print it out. | ||
func NewSimpleProgressHandler(out io.Writer, label string, tic string, error string, success string) ProgressHandler { | ||
return &simpleProgressHandler{out, label, tic, error, success} | ||
} | ||
|
||
// Print our intial label | ||
func (w *simpleProgressHandler) Start() { | ||
fmt.Fprint(w.out, w.startLabel) | ||
} | ||
|
||
// Tic progress | ||
func (w *simpleProgressHandler) Tic(complete int) { | ||
if complete < 0 { | ||
fmt.Fprint(w.out, w.ticMark) | ||
} else { | ||
fmt.Fprintf(w.out, " %d%%", complete) | ||
} | ||
} | ||
|
||
// Printout ERROR label, but not the error. | ||
// The error will be printed out later anyway | ||
func (w *simpleProgressHandler) Fail(err error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unsure of this code. I feel like the contract "the progress handler will print an ERROR label but you-the-caller have to fill out the rest of the line" kind of splits responsibilities uncomfortably. Do we have any other reasonable options? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tbh, the handler is free to do what it wants to do with the error (so the documentation is misleading and explains the default implementation). The contract is, that this method will be called when error occurs and the WaitForServce() method will return this error. Thinking about this, maybe we don't even need the ProgressHandler as success/error can be easily handled based on the return value of the method (it's a synchronous method). Only for the progress indication (which we currently don't really use), we would need the callback, but the start and end indicators can be completely handled outside the method. Let me check, how I can make that simpler. |
||
fmt.Fprintln(w.out, w.errorLabel) | ||
} | ||
|
||
// Printout success label | ||
func (w *simpleProgressHandler) Success() { | ||
fmt.Fprintln(w.out, w.successLabel) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// Copyright © 2019 The Knative Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package wait | ||
|
||
import ( | ||
"bytes" | ||
"errors" | ||
"strings" | ||
"testing" | ||
|
||
"gotest.tools/assert" | ||
) | ||
|
||
func TestSimpleProgressHandler(t *testing.T) { | ||
buf := new(bytes.Buffer) | ||
ph := NewSimpleProgressHandler(buf, "START", ".", "ERROR", "OK") | ||
ph.Start() | ||
assert.Assert(t, strings.Contains(buf.String(), "START")) | ||
ph.Tic(-1) | ||
assert.Assert(t, strings.Contains(buf.String(), ".")) | ||
ph.Tic(-1) | ||
assert.Assert(t, strings.Contains(buf.String(), "..")) | ||
ph.Tic(8) | ||
assert.Assert(t, strings.Contains(buf.String(), " 8%")) | ||
ph.Tic(42) | ||
assert.Assert(t, strings.Contains(buf.String(), " 8% 42%"), buf.String()) | ||
ph.Fail(errors.New("foobar")) | ||
assert.Assert(t, strings.Contains(buf.String(), "ERROR\n")) | ||
assert.Assert(t, !strings.Contains(buf.String(), "foobar")) | ||
ph.Success() | ||
assert.Assert(t, strings.Contains(buf.String(), "OK\n"), buf.String()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about
UpdateProgress
instead ofTic
? Or at leastTick
?