"Life is all about sharing. If we are good at something, pass it on." - Mary Berry

How to perform integration testing in Go?

2020-09-29

Integration testing can be triggered by using Drone downstream plugin:

 1steps:
 2- name: trigger
 3  image: plugins/downstream:linux-amd64
 4  settings:
 5    params:
 6    - COMMIT_BRANCH=${DRONE_COMMIT_BRANCH}
 7    repositories:
 8    - repo/integration-test@${DRONE_COMMIT_BRANCH}
 9    server: https://drone.example.com
10    token:
11      from_secret: drone_token

It can be separated with unit tests by using build tags:

1// +build integration
2
3package webserver_test

Then we can write code to perform integration test as usual.

Read More...


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:

 1  if [[ -n "${DRONE_PULL_REQUEST}" ]]; then
 2    most_recent_before="origin/${DRONE_TARGET_BRANCH}"
 3  elif [[ "${DRONE_BUILD_EVENT}" = "push" && ("${DRONE_COMMIT_BRANCH}" = "master" || "${DRONE_COMMIT_BRANCH}" = "release-"*) ]]; then
 4    if [[ "${DRONE_COMMIT_BEFORE}" = "$zero" ]]; then
 5      exit 0
 6    else
 7      most_recent_before="${DRONE_COMMIT_BEFORE}"
 8    fi
 9  fi
10  modified_files=$(git --no-pager diff --name-only "${DRONE_COMMIT_SHA}".."${most_recent_before}");

Read More...


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:

 1Counting objects: 4, done.
 2Delta compression using up to 4 threads.
 3Compressing objects: 100% (4/4), done.
 4Writing objects: 100% (4/4), 2.02 KiB | 2.02 MiB/s, done.
 5Total 4 (delta 2), reused 0 (delta 0)
 6hint: The 'hooks/pre-receive' hook was ignored because it's not set as executable.
 7hint: You can disable this warning with `git config advice.ignoredHook false`.
 8hint: The 'hooks/update' hook was ignored because it's not set as executable.
 9hint: You can disable this warning with `git config advice.ignoredHook false`.
10hint: The 'hooks/post-receive' hook was ignored because it's not set as executable.
11hint: You can disable this warning with `git config advice.ignoredHook false`.
12To gitea.pi:quanta/blog.git
13 + d29f63d...47e9ed3 master -> master (forced update)

Read More...


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:

1$ tshark -r grpc.pcapng -Y 'grpc'

Find out a stream: DATA:

1216 923.033355    127.0.0.1 → 127.0.0.1    GRPC 108 DATA[1] (GRPC) (PROTOBUF)

and show the packet details:

1tshark -r grpc.pcapng -Y "frame.number == 216" -V

Read More...


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:

1$ tshark -r grpc.pcapng -Y 'http2.headers.path contains "getBook"'
2214 923.033174    127.0.0.1 → 127.0.0.1    HTTP2 150 HEADERS[1]: POST /book.BookInfo/getBook

and then show the packet details:

 1tshark -r grpc.pcapng -Y "frame.number == 214" -V
 2
 3HyperText Transfer Protocol 2
 4    Stream: HEADERS, Stream ID: 1, Length 85, POST /book.BookInfo/getBook
 5        Length: 85
 6        Type: HEADERS (1)
 7        Flags: 0x04
 8            .... ...0 = End Stream: False
 9            .... .1.. = End Headers: True
10            .... 0... = Padded: False
11            ..0. .... = Priority: False
12            00.0 ..0. = Unused: 0x00
13        0... .... .... .... .... .... .... .... = Reserved: 0x0
14        .000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
15        [Pad Length: 0]
16        Header Block Fragment: 8386459162339faaf74e7eb92a94ec4c54dd39faff418b08…
17        [Header Length: 216]
18        [Header Count: 8]
19        Header: :method: POST
20            Name Length: 7
21            Name: :method
22            Value Length: 4
23            Value: POST
24            :method: POST
25            [Unescaped: POST]
26            Representation: Indexed Header Field
27            Index: 3
28        Header: :scheme: http
29            Name Length: 7
30            Name: :scheme
31            Value Length: 4
32            Value: http
33            :scheme: http
34            [Unescaped: http]
35            Representation: Indexed Header Field
36            Index: 6
37        Header: :path: /book.BookInfo/getBook
38            Name Length: 5
39            Name: :path
40            Value Length: 22
41            Value: /book.BookInfo/getBook
42            :path: /book.BookInfo/getBook
43            [Unescaped: /book.BookInfo/getBook]
44            Representation: Literal Header Field with Incremental Indexing - Indexed Name
45            Index: 5
46        Header: :authority: 127.0.0.1:50051
47            Name Length: 10
48            Name: :authority
49            Value Length: 15
50            Value: 127.0.0.1:50051
51            :authority: 127.0.0.1:50051
52            [Unescaped: 127.0.0.1:50051]
53            Representation: Literal Header Field with Incremental Indexing - Indexed Name
54            Index: 1
55        Header: content-type: application/grpc
56            Name Length: 12
57            Name: content-type
58            Value Length: 16
59            Value: application/grpc
60            content-type: application/grpc
61            [Unescaped: application/grpc]
62            Representation: Literal Header Field with Incremental Indexing - Indexed Name
63            Index: 31
64        Header: user-agent: grpc-go/1.24.0
65            Name Length: 10
66            Name: user-agent
67            Value Length: 14
68            Value: grpc-go/1.24.0
69            user-agent: grpc-go/1.24.0
70            [Unescaped: grpc-go/1.24.0]
71            Representation: Literal Header Field with Incremental Indexing - Indexed Name
72            Index: 58
73        Header: te: trailers
74            Name Length: 2
75            Name: te
76            Value Length: 8
77            Value: trailers
78            [Unescaped: trailers]
79            Representation: Literal Header Field with Incremental Indexing - New Name
80        Header: grpc-client: evans
81            Name Length: 11
82            Name: grpc-client
83            Value Length: 5
84            Value: evans
85            [Unescaped: evans]
86            Representation: Literal Header Field with Incremental Indexing - New Name

Read More...


brew info gets stuck

2020-04-25

I managed my Mac with SaltStack.

For some reasons, it gets stuck when running brew state:

1[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:

1brew 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:

1FROM scratch
2
3WORKDIR /app
4
5COPY build/linux/<binary> .
6
7ENTRYPOINT [ "/app/<binary>" ]

When starting:

10fbce782a9bd        quantonganh/<binary>:T276-dockerize                              "/app/<binary>"           6 seconds ago       Exited (127) 4 seconds ago                                           relaxed_thompson

Read More...


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

 1const gulp     = require('gulp'),
 2      util     = require('gulp-util'),
 3      notifier = require('node-notifier'),
 4      child    = require('child_process'),
 5      os       = require('os'),
 6      path     = require('path');
 7
 8var server = 'null'
 9
10function build() {
11    var build = child.spawn('go', ['install']);
12
13    build.stdout.on('data', (data) => {
14        console.log(`stdout: ${data}`);
15    });
16
17    build.stderr.on('data', (data) => {
18        console.error(`stderr: ${data}`);
19    });
20
21    return build;
22}
23
24function spawn(done) {
25    if (server && server != 'null') {
26        server.kill();
27    }
28
29    var path_folder = process.cwd().split(path.sep)
30    var length = path_folder.length
31    var app = path_folder[length - parseInt(1)];
32
33    if (os.platform() == 'win32') {
34        server = child.spawn(app + '.exe')
35    } else {
36        server = child.spawn(app)
37    }
38
39    server.stdout.on('data', (data) => {
40        console.log(`stdout: ${data}`);
41    });
42
43    server.stderr.on('data', (data) => {
44        console.log(`stderr: ${data}`);
45    });
46
47    done();
48}
49
50const serve = gulp.series(build, spawn)
51function watch(done) {
52    gulp.watch(['*.go', '**/*.go'], serve);
53    done();
54}
55
56exports.serve = serve
57exports.watch = watch
58exports.default = gulp.parallel(serve, watch)

Read More...