How to perform integration testing in Go?
2020-09-29
Integration testing can be triggered by using Drone downstream plugin:
steps:
- name: trigger
image: plugins/downstream:linux-amd64
settings:
params:
- COMMIT_BRANCH=${DRONE_COMMIT_BRANCH}
repositories:
- repo/integration-test@${DRONE_COMMIT_BRANCH}
server: https://drone.example.com
token:
from_secret: drone_token
It can be separated with unit tests by using build tags:
// +build integration
package webserver_test
Then we can write code to perform integration test as usual.
How to trigger build steps based on modified directory?
2020-06-26
Using monorepo with multiple micro services, every single commit will trigger a full lint/test/build/publish for every service. What can I do to limit the scope?
To do that, we can use git diff to show changes between commits:
if [[ -n "${DRONE_PULL_REQUEST}" ]]; then
most_recent_before="origin/${DRONE_TARGET_BRANCH}"
elif [[ "${DRONE_BUILD_EVENT}" = "push" && ("${DRONE_COMMIT_BRANCH}" = "master" || "${DRONE_COMMIT_BRANCH}" = "release-"*) ]]; then
if [[ "${DRONE_COMMIT_BEFORE}" = "$zero" ]]; then
exit 0
else
most_recent_before="${DRONE_COMMIT_BEFORE}"
fi
fi
modified_files=$(git --no-pager diff --name-only "${DRONE_COMMIT_SHA}".."${most_recent_before}");
Drone build is not triggered after pushing code to Gitea?
2020-05-06
I pushed code to Gitea and nothing happens in Drone. Why?
But if I go to Settings -> Webhooks, then click “Test Delivery” -> build pipeline will be executed. Why?
First, look at the “Recent Deliveries” to see if a webhook is triggerd here when you pushing code. In my case, it’s not. So, looks like the problem is on Gitea side.
By pay close attention to the git output when pushing:
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 2.02 KiB | 2.02 MiB/s, done.
Total 4 (delta 2), reused 0 (delta 0)
hint: The 'hooks/pre-receive' hook was ignored because it's not set as executable.
hint: You can disable this warning with `git config advice.ignoredHook false`.
hint: The 'hooks/update' hook was ignored because it's not set as executable.
hint: You can disable this warning with `git config advice.ignoredHook false`.
hint: The 'hooks/post-receive' hook was ignored because it's not set as executable.
hint: You can disable this warning with `git config advice.ignoredHook false`.
To gitea.pi:quanta/blog.git
+ d29f63d...47e9ed3 master -> master (forced update)
How a gRPC message uses length-prefixed framing?
2020-05-06
Once we have the encoded data to send to the other end, we need to package the data in a way that other end can easily extract the information. gRPC uses a message framing technique called length-prefixed framing.
Filter gRPC messages:
$ tshark -r grpc.pcapng -Y 'grpc'
Find out a stream: DATA:
216 923.033355 127.0.0.1 → 127.0.0.1 GRPC 108 DATA[1] (GRPC) (PROTOBUF)
and show the packet details:
tshark -r grpc.pcapng -Y "frame.number == 216" -V
How to show all HTTP2 headers using tshark?
2020-05-05
After sniffing with tcpdump, how can I show all HTTP2 header using tshark?
First, find the frame number based on method:
$ tshark -r grpc.pcapng -Y 'http2.headers.path contains "getBook"'
214 923.033174 127.0.0.1 → 127.0.0.1 HTTP2 150 HEADERS[1]: POST /book.BookInfo/getBook
and then show the packet details:
tshark -r grpc.pcapng -Y "frame.number == 214" -V
HyperText Transfer Protocol 2
Stream: HEADERS, Stream ID: 1, Length 85, POST /book.BookInfo/getBook
Length: 85
Type: HEADERS (1)
Flags: 0x04
.... ...0 = End Stream: False
.... .1.. = End Headers: True
.... 0... = Padded: False
..0. .... = Priority: False
00.0 ..0. = Unused: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
[Pad Length: 0]
Header Block Fragment: 8386459162339faaf74e7eb92a94ec4c54dd39faff418b08…
[Header Length: 216]
[Header Count: 8]
Header: :method: POST
Name Length: 7
Name: :method
Value Length: 4
Value: POST
:method: POST
[Unescaped: POST]
Representation: Indexed Header Field
Index: 3
Header: :scheme: http
Name Length: 7
Name: :scheme
Value Length: 4
Value: http
:scheme: http
[Unescaped: http]
Representation: Indexed Header Field
Index: 6
Header: :path: /book.BookInfo/getBook
Name Length: 5
Name: :path
Value Length: 22
Value: /book.BookInfo/getBook
:path: /book.BookInfo/getBook
[Unescaped: /book.BookInfo/getBook]
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Index: 5
Header: :authority: 127.0.0.1:50051
Name Length: 10
Name: :authority
Value Length: 15
Value: 127.0.0.1:50051
:authority: 127.0.0.1:50051
[Unescaped: 127.0.0.1:50051]
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Index: 1
Header: content-type: application/grpc
Name Length: 12
Name: content-type
Value Length: 16
Value: application/grpc
content-type: application/grpc
[Unescaped: application/grpc]
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Index: 31
Header: user-agent: grpc-go/1.24.0
Name Length: 10
Name: user-agent
Value Length: 14
Value: grpc-go/1.24.0
user-agent: grpc-go/1.24.0
[Unescaped: grpc-go/1.24.0]
Representation: Literal Header Field with Incremental Indexing - Indexed Name
Index: 58
Header: te: trailers
Name Length: 2
Name: te
Value Length: 8
Value: trailers
[Unescaped: trailers]
Representation: Literal Header Field with Incremental Indexing - New Name
Header: grpc-client: evans
Name Length: 11
Name: grpc-client
Value Length: 5
Value: evans
[Unescaped: evans]
Representation: Literal Header Field with Incremental Indexing - New Name
brew info gets stuck
2020-04-25
I managed my Mac with SaltStack.
For some reasons, it gets stuck when running brew state:
[INFO ] Executing command '/usr/local/bin/brew info --json=v1 --installed' as user 'quanta' in directory '/Users/quanta'
As usual, whenever you get a problem, let’s enable debug mode to see what happens:
brew info --json=v1 --installed -d
Now I can see that it stucked at drone/drone repo. By just untap this repo, and it’s solved.
Why my golang docker container exits immediately (code 127)?
2019-10-30
To trim the binary size, I used LDFLAGS='-w -s', pack with upx, then build from scratch. The thing is when starting, it exited immediately with code 127. Why?
My Dockerfile:
FROM scratch
WORKDIR /app
COPY build/linux/<binary> .
ENTRYPOINT [ "/app/<binary>" ]
When starting:
0fbce782a9bd quantonganh/<binary>:T276-dockerize "/app/<binary>" 6 seconds ago Exited (127) 4 seconds ago relaxed_thompson
Command-line autocomplete for Go documentation
2019-09-26
Go has a great, well documented standard library. You may find yourself spending a fairly significant chunk of your Go programming time digging in stdlib docs, which is reasonable to expect at least for novice Go coders.
https://eli.thegreenplace.net/2018/command-line-autocomplete-for-go-documentation/
Auto reload your Go webserver with Gulp
2019-09-20
When you developp a webserver with Go, you must compile each time you do an update in your code. Well.. this is redundant. With Gulp you can automatize this task… Indeed, when a go file is modified, a task compile the application in the “bin” folder (“gopath/bin”) then another launch the executable (the webserver).
https://medium.com/@etiennerouzeaud/autoreload-your-go-webserver-with-gulp-ee5e231d133d
const gulp = require('gulp'),
util = require('gulp-util'),
notifier = require('node-notifier'),
child = require('child_process'),
os = require('os'),
path = require('path');
var server = 'null'
function build() {
var build = child.spawn('go', ['install']);
build.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
build.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
return build;
}
function spawn(done) {
if (server && server != 'null') {
server.kill();
}
var path_folder = process.cwd().split(path.sep)
var length = path_folder.length
var app = path_folder[length - parseInt(1)];
if (os.platform() == 'win32') {
server = child.spawn(app + '.exe')
} else {
server = child.spawn(app)
}
server.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
server.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
done();
}
const serve = gulp.series(build, spawn)
function watch(done) {
gulp.watch(['*.go', '**/*.go'], serve);
done();
}
exports.serve = serve
exports.watch = watch
exports.default = gulp.parallel(serve, watch)
Quan Tong