Skip to main content

3 posts tagged with "golang"

View All Tags

VS Code Setup for Golang Programming

· 5 min read
Dipjyoti Metia
Chapter Lead - Testing

As a Go developer, having the right programming environment can significantly boost your productivity. Visual Studio Code has become the go-to editor for many Golang developers, thanks to its excellent extension ecosystem and customizability. In this guide, I'll walk you through creating the perfect VS Code setup for Go development.

Table of Contents

  1. Installing Prerequisites
  2. Essential Extensions
  3. Advanced Configuration
  4. Productivity Tips and Tricks
  5. Debugging Setup
  6. Theme and UI Customization

Installing Prerequisites

Before we dive into VS Code configuration, ensure you have:

  1. The latest version of Go installed (1.22+ recommended)
  2. Git for version control
  3. Visual Studio Code
  4. Make (optional but recommended for build automation)

Essential Extensions

Let's start with the must-have extensions for Go development:

  1. Go (ms-vscode.go)

    • Official Go extension
    • Provides language support, debugging, and testing features
    • Install by pressing Cmd+P (Mac) or Ctrl+P (Windows/Linux) and typing: ext install ms-vscode.go
  2. Go Test Explorer

    • Visual test runner for Go
    • Makes testing more intuitive and visual
  3. Error Lens

    • Inline error highlighting
    • Better error visibility without hovering
  4. GitLens

    • Enhanced Git integration
    • Great for team collaboration

Advanced Configuration

Here's an optimized settings.json configuration for Go development:

settings.json
{
"go.toolsManagement.autoUpdate": true,
"go.useLanguageServer": true,
"go.addTags": {
"tags": "json",
"options": "json=omitempty",
"promptForTags": false,
"transform": "snakecase",
},
"gopls": {
"formatting.gofumpt": true,
"usePlaceholders": true,
"ui.semanticTokens": true,
"staticcheck": false, // Enable if it's now better optimized
},
"go.lintTool": "golangci-lint",
"go.lintFlags": [
"--fast",
"--timeout",
"5m",
"--fix"
],
// disable test caching, race and show coverage (in sync with makefile)
"go.testFlags": [
"-cover",
"-race",
"-count=1",
"-v",
"-s",
"-benchtime=5s",
"-timeout=5m"
],
"go.enableCodeLens": {
"runtest": true,
},
// Go-specific editor settings
"[go]": {
"editor.insertSpaces": false,
"editor.formatOnSave": true,
"editor.formatOnSaveMode": "file",
"editor.stickyScroll.enabled": true, // Better navigation for long files
"editor.codeActionsOnSave": {
"source.organizeImports": "always",
"source.fixAll": "always"
},
},
// Enhanced inlay hints
"go.inlayHints.compositeLiteralFields": true,
"go.inlayHints.compositeLiteralTypes": true,
"go.inlayHints.functionTypeParameters": true,
"go.inlayHints.parameterNames": true,
"go.inlayHints.rangeVariableTypes": true,
"go.inlayHints.constantValues": true,
// Security checks
"go.diagnostic.vulncheck": "Imports",
"go.toolsEnvVars": {
"GOFLAGS": "-buildvcs=false" // Better performance for large repos
},
}

Productivity Tips and Tricks

1. Keyboard Shortcuts

Essential shortcuts for Go development:

  • F12: Go to definition
  • Alt+F12: Peek definition
  • Shift+Alt+F12: Find all references
  • F2: Rename symbol
  • Ctrl+Shift+P: Command palette (use for Go commands)

2. Snippets

Create custom snippets for common Go patterns. Here's an example snippet for a test function:

Test Function Snippet
{
"Test function": {
"prefix": "test",
"body": [
"func Test${1:Name}(t *testing.T) {",
" tests := []struct{",
" name string",
" input ${2:type}",
" want ${3:type}",
" }{",
" {",
" name: \"${4:test case}\",",
" input: ${5:value},",
" want: ${6:value},",
" },",
" }",
"",
" for _, tt := range tests {",
" t.Run(tt.name, func(t *testing.T) {",
" got := ${7:function}(tt.input)",
" if got != tt.want {",
" t.Errorf(\"got %v, want %v\", got, tt.want)",
" }",
" })",
" }",
"}"
],
"description": "Create a new test function with table-driven tests"
}
}

3. Task Automation

Create a tasks.json for common operations:

tasks.json
{
"version": "2.0.0",
"tasks": [
{
"label": "go: build",
"type": "shell",
"command": "go build -v ./...",
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "go: test",
"type": "shell",
"command": "go test -v -cover ./...",
"group": {
"kind": "test",
"isDefault": true
}
}
]
}

Debugging Setup

Configure launch.json for debugging:

launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${fileDirname}"
},
{
"name": "Attach to Process",
"type": "go",
"request": "attach",
"mode": "local",
"processId": "${command:pickProcess}"
}
]
}

Theme and UI Customization

For optimal Go development, I recommend:

  1. Theme: One Dark Pro or GitHub Theme
  2. Font: JetBrains Mono or Fira Code with ligatures
  3. Icon Theme: Material Icon Theme
  4. Editor: Line cursor, smooth blinking, and 4-space tabs
  5. Window: Zoom level 0.5 for better readability
  6. Rulers: Set at 88 and 120 columns for code alignment
  7. Minimap: Disable for better performance
  8. Inlay Hints: Font size 14 for better visibility
  9. Tree Indent: Set to 20 for better file navigation
  10. Auto Indent: Full for consistent code formatting

Apply these settings in your configuration:

settings.json
{
"window.zoomLevel": 0.5,
"workbench.iconTheme": "material-icon-theme",
"workbench.tree.indent": 20,
"editor.cursorStyle": "line",
"editor.cursorBlinking": "smooth",
"editor.fontSize": 14,
"editor.fontVariations": false,
"editor.inlayHints.fontSize": 14,
"editor.tabSize": 4,
"editor.insertSpaces": true,
"editor.autoIndent": "full",
"editor.fontFamily": "'Fira Code'",
"editor.fontLigatures": true,
"editor.minimap.enabled": false,
"editor.rulers": [88,120],
}

Conclusion

This setup provides a powerful, efficient, and visually appealing environment for Go development. Remember to regularly update your VS Code and extensions to get the latest features and improvements.

The beauty of VS Code lies in its customizability – feel free to modify these settings based on your preferences and workflow. The key is finding the right balance between functionality and simplicity that works best for you.

Happy coding! 🚀


Did you find this guide helpful? Follow me for more development tips and tricks!

function

· 4 min read
Dipjyoti Metia
Chapter Lead - Testing

What is serverless

Serverless computing is a method of providing backend services on an as-used basis. A serverless provider allows users to write and deploy code without the hassle of worrying about the underlying infrastructure. code executes in a fully managed environment and no need to provision any infrastructure.

Introduction to cloud functions

Google Cloud Functions is a serverless execution environment for building and connecting cloud services. With Cloud Functions you write simple, single-purpose functions that are attached to events emitted from your cloud infrastructure and services. Your Cloud Function is triggered when an event being watched is fired. Your code executes in a fully managed environment. There is no need to provision any infrastructure or worry about managing any servers.

Functions Framework

The Functions Framework lets you write lightweight functions that run in many different environments. Functions framework

package main

import (
"github.com/GoogleCloudPlatform/functions-framework-go/funcframework"
p "github.com/cloudmock"
"golang.org/x/net/context"
"log"
"os"
)

func main() {
ctx := context.Background()
if err := funcframework.RegisterHTTPFunctionContext(ctx, "/", p.GoMock); err != nil {
log.Fatalf("funcframework.RegisterHTTPFunctionContext: %v\n", err)
}
port := "8080"
if envPort := os.Getenv("PORT"); envPort != "" {
port = envPort
}
if err := funcframework.Start(port); err != nil {
log.Fatalf("funcframework.Start: %v\n", err)
}
}

package db

import (
"context"
"fmt"
"log"
"os"
"time"

"github.com/cloudmock/config"
"github.com/cloudmock/secret"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)

const ENV = "ENVIRONMENT"

func NewDatabaseConnection() *mongo.Collection {
var err error
log.Print("Connecting to mongodb")
conf, err := config.LoadConfigPath("config/app")
if err != nil {
log.Fatalf("")
}
env := os.Getenv(ENV)
var client *mongo.Client

conn, err := secret.GetSecrets()
if err != nil {
log.Fatalf("mongo db secret url failed %v", err)
}
if env == "dev" {
fmt.Println("Connecting to localdb")
client, err = mongo.NewClient(options.Client().SetAuth(
options.Credential{
Username: conf.DBuser,
Password: conf.DBpassword,
}).ApplyURI(conf.DBurl))
} else {
client, err = mongo.NewClient(options.Client().ApplyURI(conn))
}

if err != nil {
log.Fatalf("mongo db client failed %v", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
err = client.Connect(ctx)
if err != nil {
log.Fatalf("mongo db connection failed %s", err) //nolint:gocritic
}
return client.Database("function").Collection("payments")
}

package router

import (
"encoding/json"
"github.com/brianvoe/gofakeit/v6"
"net/http"
)

type UserDetails struct {
Name string `json:"name"`
Email string `json:"email"`
Phone string `json:"phone"`
Address string `json:"address"`
Company string `json:"company"`
JobTitle string `json:"jobTitle"`
}

func NewUserWrite() *[]UserDetails {
var usr []UserDetails
for i := 0; i < gofakeit.RandomInt([]int{5, 10, 12, 4, 11}); i++ {
usr = append(usr, UserDetails{
Name: gofakeit.Name(),
Email: gofakeit.Email(),
Phone: gofakeit.Phone(),
Address: gofakeit.Address().Address,
Company: gofakeit.Company(),
JobTitle: gofakeit.JobTitle(),
})
}
return &usr
}

func User() func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
jData, err := json.Marshal(NewUserWrite())
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
w.Write(jData)
}
}

package p

import (
"github.com/cloudmock/router"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/httprate"
"github.com/rs/cors"
"net/http"
"time"
)

func GoMock(w http.ResponseWriter, r *http.Request) {
rc := chi.NewRouter()
conn := db.NewDatabaseConnection()

rc.Use(middleware.RealIP)
rc.Use(middleware.Logger)
rc.Use(httprate.Limit(
2,
1*time.Second,
httprate.WithLimitHandler(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "too many requests", http.StatusTooManyRequests)
}),
))

rc.Route("/api/v1", func(rc chi.Router) {
rc.Get("/users", router.User())
rc.Get("/categories", router.Category())
})

cors.Default().Handler(rc).ServeHTTP(w, r)
}

Deploy cloud function

name: Build and Deploy to CloudFunction

on:
push:
branches: [ main ]

jobs:
deploy:
name: deploy
runs-on: ubuntu-latest
steps:
- uses: google-github-actions/setup-gcloud@master
with:
project_id: ${{ secrets.GCP_PROJECT_ID }}
service_account_key: ${{ secrets.gcp_credentials }}
export_default_credentials: true
- uses: actions/checkout@v2
- name: Deploy serverless function
run: |
gcloud functions deploy "GoMock" \
--runtime go113 --trigger-http \
--allow-unauthenticated \
--region australia-southeast1 \
--update-env-vars MONGODB=${{ secrets.mongo_secret }} \
--max-instances 2 \
--memory 128mb \
--service-account=${{ secrets.service_account }} \
--no-user-output-enabled

Why Mocking using cloud function

Use cases of mocking using cloud function

System Testing

Performance testing

Performance tests check the behaviors of the system when it is under significant load. These tests are non-functional and can have the various form to understand the reliability, stability, and availability of the platform. For instance, it can be observing response times when executing a high number of requests, or seeing how the system behaves with a significant of data.

img.png img.png

Github Eyes

· 3 min read
Dipjyoti Metia
Chapter Lead - Testing

Presenting github eyes, a golang implementation of the github rest apis using Google GitHub sdk to interact with the Github Api, using github apis we can crawl over multiple repository and automate different tasks from creating repo, creating labels, adding milestones, get latest commits, updating workflows, get the project build status etc, below is the basic demonstration of getting list of issues from multiple repos.

image

The go-github library does not directly handle authentication. The easiest and recommended way to do this is using the OAuth2 library, If you have an OAuth2 access token (for example, a personal API token), you can use it with the OAuth2 library. To get the personal api token follow the documentation and Below is the code snippet for authentication using oauth2.

auth.go
package github

import (
"context"

"github.com/google/go-github/v33/github"
"golang.org/x/oauth2"
)

AUthenticating using github access token
// AuthGithubAPI authentication of github api
func AuthGithubAPI(ctx context.Context) *github.Client {
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: "XXXXXXXXXXXXXXXXXXXXXXX"},
)
tc := oauth2.NewClient(ctx, ts)
return github.NewClient(tc)
}

Getting the list of issues in a repository, here we have created a struct named Issues with the required fields and then created a function ListIssues where we are passing the github api authentication and then client.Issues.ListByRepo is doing the job where underneath its calling Github Issues Api. We can also extend this function by adding filters to get open/closed issues and so on.

issues.go
package github

import (
"context"
"log"
"time"
)

type Issues struct {
ID int64
Title string
State string
CreatedAt time.Time
URL string
}

// ListIssues get list of issues
func ListIssues(repos string) interface{}{
ctx := context.Background()
client := AuthGithubAPI(ctx)
issues, _, err := client.Issues.ListByRepo(ctx, "dipjyotimetia", repos, nil)
if err != nil {
log.Println(err)
}

var issueList []interface{}
for _, v := range issues {
issueList = append(issueList,&Issues{
ID: v.GetID(),
Title: v.GetTitle(),
State: v.GetState(),
CreatedAt: v.GetCreatedAt(),
URL: v.GetHTMLURL(),
})
}
return issueList
}

Main function to drive the show, here we are passing the repo names in an array called repoNames and in a loop calling the the function derived above ListIssues and then generating the result in a json file in local path.

main.go
package main

import (
"encoding/json"
"github.com/goutils/pkg/github"
"io/ioutil"
)

func main() {
repoNames := []string{"HybridTestFramewrok", "MobileTestFramework"}
var result []interface{}
for _, repoName := range repoNames {
result = append(result, repoName, github.ListIssues(repoName))
}

file, _ := json.MarshalIndent(result, "", "")
_ = ioutil.WriteFile("test.json", file, 0644)
}

Example of the exported json data of the ListIssues function for the two repos.

[
"HybridTestFramewrok",
[
{
"ID": 690950907,
"Title": "Add reddis tests support",
"State": "open",
"CreatedAt": "2020-09-02T11:42:07Z",
"URL": "https://github.com/dipjyotimetia/HybridTestFramewrok/issues/65"
},
{
"ID": 690950833,
"Title": "Add ssh login builder",
"State": "open",
"CreatedAt": "2020-09-02T11:42:01Z",
"URL": "https://github.com/dipjyotimetia/HybridTestFramewrok/issues/64"
},
{
"ID": 690950781,
"Title": "Add file reader validations",
"State": "open",
"CreatedAt": "2020-09-02T11:41:55Z",
"URL": "https://github.com/dipjyotimetia/HybridTestFramewrok/issues/63"
},
{
"ID": 690950708,
"Title": "add kafka testing",
"State": "open",
"CreatedAt": "2020-09-02T11:41:48Z",
"URL": "https://github.com/dipjyotimetia/HybridTestFramewrok/issues/62"
},
{
"ID": 690950641,
"Title": "add rabitmq testing support",
"State": "open",
"CreatedAt": "2020-09-02T11:41:43Z",
"URL": "https://github.com/dipjyotimetia/HybridTestFramewrok/issues/61"
}
],
"MobileTestFramework",
[
{
"ID": 793821012,
"Title": "Add AWS Device Farm support",
"State": "open",
"CreatedAt": "2021-01-26T00:19:55Z",
"URL": "https://github.com/dipjyotimetia/MobileTestFramework/issues/88"
}
]
]

Project structure image