├── LICENSE ├── README.md ├── chapter1 ├── bytestrings │ ├── buffer.go │ ├── buffer_test.go │ ├── bytes.go │ ├── bytes_test.go │ ├── example │ │ └── main.go │ ├── go.mod │ ├── string.go │ └── string_test.go ├── csvformat │ ├── example │ │ └── main.go │ ├── go.mod │ ├── read_csv.go │ ├── read_csv_test.go │ ├── write_csv.go │ └── write_csv_test.go ├── filedirs │ ├── dirs.go │ ├── dirs_test.go │ ├── example │ │ └── main.go │ ├── files.go │ ├── files_test.go │ └── go.mod ├── interfaces │ ├── example │ │ └── main.go │ ├── go.mod │ ├── interfaces.go │ ├── interfaces_test.go │ ├── pipes.go │ └── pipes_test.go ├── tempfiles │ ├── example │ │ └── main.go │ ├── go.mod │ ├── temp_files.go │ └── temp_files_test.go └── templates │ ├── example │ └── main.go │ ├── go.mod │ ├── html_templates.go │ ├── html_templates_test.go │ ├── template_files.go │ ├── template_files_test.go │ ├── templates.go │ └── templates_test.go ├── chapter10 ├── atomic │ ├── example │ │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── map.go │ ├── map_test.go │ ├── ordinal.go │ └── ordinal_test.go ├── channels │ ├── example │ │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── printer.go │ ├── printer_test.go │ ├── sender.go │ └── sender_test.go ├── context │ ├── example │ │ └── main.go │ ├── exec.go │ ├── exec_test.go │ ├── go.mod │ ├── go.sum │ ├── values.go │ └── values_test.go ├── pipeline │ ├── encode.go │ ├── example │ │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── pipeline.go │ ├── print.go │ └── worker.go ├── pool │ ├── crypto.go │ ├── crypto_test.go │ ├── example │ │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── work.go │ ├── work_test.go │ ├── worker.go │ └── worker_test.go ├── state │ ├── example │ │ └── main.go │ ├── go.mod │ ├── process.go │ ├── process_test.go │ ├── processor.go │ ├── processor_test.go │ └── state.go └── waitgroup │ ├── example │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── process.go │ ├── process_test.go │ ├── tasks.go │ └── tasks_test.go ├── chapter11 ├── consensus │ ├── config.go │ ├── config_test.go │ ├── example │ │ └── main.go │ ├── fsm.go │ ├── fsm_test.go │ ├── go.mod │ ├── go.sum │ ├── handler.go │ ├── handler_test.go │ ├── raftset.go │ ├── state.go │ └── state_test.go ├── discovery │ ├── client.go │ ├── client_test.go │ ├── example │ │ └── main.go │ ├── exec.go │ ├── exec_test.go │ ├── go.mod │ ├── go.sum │ ├── operations.go │ └── operations_test.go ├── docker │ ├── Dockerfile │ ├── example │ │ └── main.go │ ├── go.mod │ ├── setup.sh │ ├── version.go │ └── version_test.go ├── metrics │ ├── example │ │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── handler.go │ ├── handler_test.go │ ├── report.go │ └── report_test.go ├── monitoring │ ├── Dockerfile │ ├── docker-compose.yml │ ├── go.mod │ ├── go.sum │ ├── main.go │ ├── prometheus.yml │ └── vendor │ │ ├── github.com │ │ ├── beorn7 │ │ │ └── perks │ │ │ │ ├── LICENSE │ │ │ │ └── quantile │ │ │ │ ├── exampledata.txt │ │ │ │ └── stream.go │ │ ├── golang │ │ │ └── protobuf │ │ │ │ ├── AUTHORS │ │ │ │ ├── CONTRIBUTORS │ │ │ │ ├── LICENSE │ │ │ │ └── proto │ │ │ │ ├── Makefile │ │ │ │ ├── clone.go │ │ │ │ ├── decode.go │ │ │ │ ├── encode.go │ │ │ │ ├── equal.go │ │ │ │ ├── extensions.go │ │ │ │ ├── lib.go │ │ │ │ ├── message_set.go │ │ │ │ ├── pointer_reflect.go │ │ │ │ ├── pointer_unsafe.go │ │ │ │ ├── properties.go │ │ │ │ ├── text.go │ │ │ │ └── text_parser.go │ │ ├── matttproud │ │ │ └── golang_protobuf_extensions │ │ │ │ ├── LICENSE │ │ │ │ ├── NOTICE │ │ │ │ └── pbutil │ │ │ │ ├── .gitignore │ │ │ │ ├── Makefile │ │ │ │ ├── decode.go │ │ │ │ ├── doc.go │ │ │ │ └── encode.go │ │ └── prometheus │ │ │ ├── client_golang │ │ │ ├── LICENSE │ │ │ ├── NOTICE │ │ │ └── prometheus │ │ │ │ ├── .gitignore │ │ │ │ ├── README.md │ │ │ │ ├── collector.go │ │ │ │ ├── counter.go │ │ │ │ ├── desc.go │ │ │ │ ├── doc.go │ │ │ │ ├── expvar_collector.go │ │ │ │ ├── fnv.go │ │ │ │ ├── gauge.go │ │ │ │ ├── go_collector.go │ │ │ │ ├── histogram.go │ │ │ │ ├── http.go │ │ │ │ ├── metric.go │ │ │ │ ├── observer.go │ │ │ │ ├── process_collector.go │ │ │ │ ├── promhttp │ │ │ │ ├── delegator_1_7.go │ │ │ │ ├── delegator_1_8.go │ │ │ │ ├── http.go │ │ │ │ └── instrument_server.go │ │ │ │ ├── registry.go │ │ │ │ ├── summary.go │ │ │ │ ├── timer.go │ │ │ │ ├── untyped.go │ │ │ │ ├── value.go │ │ │ │ └── vec.go │ │ │ ├── client_model │ │ │ ├── LICENSE │ │ │ ├── NOTICE │ │ │ └── go │ │ │ │ └── metrics.pb.go │ │ │ ├── common │ │ │ ├── LICENSE │ │ │ ├── NOTICE │ │ │ ├── expfmt │ │ │ │ ├── decode.go │ │ │ │ ├── encode.go │ │ │ │ ├── expfmt.go │ │ │ │ ├── fuzz.go │ │ │ │ ├── text_create.go │ │ │ │ └── text_parse.go │ │ │ ├── internal │ │ │ │ └── bitbucket.org │ │ │ │ │ └── ww │ │ │ │ │ └── goautoneg │ │ │ │ │ ├── README.txt │ │ │ │ │ └── autoneg.go │ │ │ └── model │ │ │ │ ├── alert.go │ │ │ │ ├── fingerprinting.go │ │ │ │ ├── fnv.go │ │ │ │ ├── labels.go │ │ │ │ ├── labelset.go │ │ │ │ ├── metric.go │ │ │ │ ├── model.go │ │ │ │ ├── signature.go │ │ │ │ ├── silence.go │ │ │ │ ├── time.go │ │ │ │ └── value.go │ │ │ └── procfs │ │ │ ├── .travis.yml │ │ │ ├── CONTRIBUTING.md │ │ │ ├── LICENSE │ │ │ ├── MAINTAINERS.md │ │ │ ├── Makefile │ │ │ ├── NOTICE │ │ │ ├── README.md │ │ │ ├── buddyinfo.go │ │ │ ├── doc.go │ │ │ ├── fs.go │ │ │ ├── ipvs.go │ │ │ ├── mdstat.go │ │ │ ├── mountstats.go │ │ │ ├── proc.go │ │ │ ├── proc_io.go │ │ │ ├── proc_limits.go │ │ │ ├── proc_stat.go │ │ │ ├── stat.go │ │ │ └── xfs │ │ │ ├── parse.go │ │ │ └── xfs.go │ │ └── modules.txt └── orchestrate │ ├── Dockerfile │ ├── config.go │ ├── config_test.go │ ├── docker-compose.yml │ ├── example │ └── main.go │ ├── exec.go │ ├── exec_test.go │ ├── go.mod │ ├── go.sum │ └── vendor │ ├── github.com │ ├── go-stack │ │ └── stack │ │ │ ├── .travis.yml │ │ │ ├── LICENSE.md │ │ │ ├── README.md │ │ │ ├── go.mod │ │ │ └── stack.go │ ├── golang │ │ └── snappy │ │ │ ├── .gitignore │ │ │ ├── AUTHORS │ │ │ ├── CONTRIBUTORS │ │ │ ├── LICENSE │ │ │ ├── README │ │ │ ├── decode.go │ │ │ ├── decode_amd64.go │ │ │ ├── decode_amd64.s │ │ │ ├── decode_other.go │ │ │ ├── encode.go │ │ │ ├── encode_amd64.go │ │ │ ├── encode_amd64.s │ │ │ ├── encode_other.go │ │ │ ├── go.mod │ │ │ └── snappy.go │ ├── mongodb │ │ └── mongo-go-driver │ │ │ ├── LICENSE │ │ │ ├── bson │ │ │ ├── bson.go │ │ │ ├── bson_1_8.go │ │ │ ├── decoder.go │ │ │ ├── doc.go │ │ │ ├── encoder.go │ │ │ ├── marshal.go │ │ │ ├── primitive_codecs.go │ │ │ ├── raw.go │ │ │ ├── raw_element.go │ │ │ ├── raw_value.go │ │ │ ├── registry.go │ │ │ ├── types.go │ │ │ └── unmarshal.go │ │ │ └── mongo │ │ │ ├── batch_cursor.go │ │ │ ├── bulk_write.go │ │ │ ├── change_stream.go │ │ │ ├── client.go │ │ │ ├── collection.go │ │ │ ├── cursor.go │ │ │ ├── database.go │ │ │ ├── doc.go │ │ │ ├── errors.go │ │ │ ├── index_options_builder.go │ │ │ ├── index_view.go │ │ │ ├── mongo.go │ │ │ ├── results.go │ │ │ ├── session.go │ │ │ ├── single_result.go │ │ │ └── util.go │ └── xdg │ │ ├── scram │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── client.go │ │ ├── client_conv.go │ │ ├── common.go │ │ ├── doc.go │ │ ├── parse.go │ │ ├── scram.go │ │ ├── server.go │ │ └── server_conv.go │ │ └── stringprep │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bidi.go │ │ ├── doc.go │ │ ├── error.go │ │ ├── map.go │ │ ├── profile.go │ │ ├── saslprep.go │ │ ├── set.go │ │ └── tables.go │ ├── go.mongodb.org │ └── mongo-driver │ │ ├── LICENSE │ │ ├── bson │ │ ├── bson.go │ │ ├── bson_1_8.go │ │ ├── bsoncodec │ │ │ ├── bsoncodec.go │ │ │ ├── default_value_decoders.go │ │ │ ├── default_value_encoders.go │ │ │ ├── doc.go │ │ │ ├── mode.go │ │ │ ├── pointer_codec.go │ │ │ ├── proxy.go │ │ │ ├── registry.go │ │ │ ├── struct_codec.go │ │ │ ├── struct_tag_parser.go │ │ │ └── types.go │ │ ├── bsonrw │ │ │ ├── copier.go │ │ │ ├── doc.go │ │ │ ├── extjson_parser.go │ │ │ ├── extjson_reader.go │ │ │ ├── extjson_tables.go │ │ │ ├── extjson_wrappers.go │ │ │ ├── extjson_writer.go │ │ │ ├── json_scanner.go │ │ │ ├── mode.go │ │ │ ├── reader.go │ │ │ ├── value_reader.go │ │ │ ├── value_writer.go │ │ │ └── writer.go │ │ ├── bsontype │ │ │ └── bsontype.go │ │ ├── decoder.go │ │ ├── doc.go │ │ ├── encoder.go │ │ ├── marshal.go │ │ ├── primitive │ │ │ ├── decimal.go │ │ │ ├── objectid.go │ │ │ └── primitive.go │ │ ├── primitive_codecs.go │ │ ├── raw.go │ │ ├── raw_element.go │ │ ├── raw_value.go │ │ ├── registry.go │ │ ├── types.go │ │ └── unmarshal.go │ │ ├── event │ │ └── monitoring.go │ │ ├── internal │ │ ├── channel_connection.go │ │ ├── const.go │ │ ├── error.go │ │ ├── results.go │ │ └── semaphore.go │ │ ├── mongo │ │ ├── options │ │ │ ├── aggregateoptions.go │ │ │ ├── bulkwriteoptions.go │ │ │ ├── changestreamoptions.go │ │ │ ├── clientoptions.go │ │ │ ├── clientoptions_1_10.go │ │ │ ├── clientoptions_1_9.go │ │ │ ├── collectionoptions.go │ │ │ ├── countoptions.go │ │ │ ├── dboptions.go │ │ │ ├── deleteoptions.go │ │ │ ├── distinctoptions.go │ │ │ ├── estimatedcountoptions.go │ │ │ ├── findoptions.go │ │ │ ├── gridfsoptions.go │ │ │ ├── indexoptions.go │ │ │ ├── insertoptions.go │ │ │ ├── listcollectionsoptions.go │ │ │ ├── listdatabasesoptions.go │ │ │ ├── mongooptions.go │ │ │ ├── replaceoptions.go │ │ │ ├── runcmdoptions.go │ │ │ ├── sessionoptions.go │ │ │ ├── transactionoptions.go │ │ │ └── updateoptions.go │ │ ├── readconcern │ │ │ └── readconcern.go │ │ ├── readpref │ │ │ ├── mode.go │ │ │ ├── options.go │ │ │ └── readpref.go │ │ └── writeconcern │ │ │ └── writeconcern.go │ │ ├── tag │ │ └── tag.go │ │ ├── version │ │ └── version.go │ │ └── x │ │ ├── bsonx │ │ ├── array.go │ │ ├── bsoncore │ │ │ ├── bsoncore.go │ │ │ ├── document.go │ │ │ ├── document_sequence.go │ │ │ ├── element.go │ │ │ ├── tables.go │ │ │ └── value.go │ │ ├── constructor.go │ │ ├── document.go │ │ ├── element.go │ │ ├── mdocument.go │ │ ├── primitive_codecs.go │ │ ├── registry.go │ │ └── value.go │ │ ├── mongo │ │ └── driver │ │ │ ├── README.md │ │ │ ├── abort_transaction.go │ │ │ ├── aggregate.go │ │ │ ├── auth │ │ │ ├── auth.go │ │ │ ├── cred.go │ │ │ ├── default.go │ │ │ ├── doc.go │ │ │ ├── gssapi.go │ │ │ ├── gssapi_not_enabled.go │ │ │ ├── gssapi_not_supported.go │ │ │ ├── internal │ │ │ │ └── gssapi │ │ │ │ │ ├── gss.go │ │ │ │ │ ├── gss_wrapper.c │ │ │ │ │ ├── gss_wrapper.h │ │ │ │ │ ├── sspi.go │ │ │ │ │ ├── sspi_wrapper.c │ │ │ │ │ └── sspi_wrapper.h │ │ │ ├── mongodbcr.go │ │ │ ├── plain.go │ │ │ ├── sasl.go │ │ │ ├── scram.go │ │ │ ├── util.go │ │ │ └── x509.go │ │ │ ├── batch_cursor.go │ │ │ ├── bulk_write.go │ │ │ ├── commit_transaction.go │ │ │ ├── count.go │ │ │ ├── count_documents.go │ │ │ ├── create_indexes.go │ │ │ ├── delete.go │ │ │ ├── delete_indexes.go │ │ │ ├── dispatch.go │ │ │ ├── distinct.go │ │ │ ├── drop_collection.go │ │ │ ├── drop_database.go │ │ │ ├── end_sessions.go │ │ │ ├── find.go │ │ │ ├── find_one_and_delete.go │ │ │ ├── find_one_and_replace.go │ │ │ ├── find_one_and_update.go │ │ │ ├── insert.go │ │ │ ├── kill_cursors.go │ │ │ ├── list_collections.go │ │ │ ├── list_collections_batch_cursor.go │ │ │ ├── list_databases.go │ │ │ ├── list_indexes.go │ │ │ ├── models.go │ │ │ ├── read.go │ │ │ ├── read_cursor.go │ │ │ ├── session │ │ │ ├── client_session.go │ │ │ ├── cluster_clock.go │ │ │ ├── options.go │ │ │ ├── server_session.go │ │ │ └── session_pool.go │ │ │ ├── topology │ │ │ ├── connection.go │ │ │ ├── fsm.go │ │ │ ├── server.go │ │ │ ├── server_options.go │ │ │ ├── topology.go │ │ │ └── topology_options.go │ │ │ ├── update.go │ │ │ ├── uuid │ │ │ └── uuid.go │ │ │ └── write.go │ │ └── network │ │ ├── address │ │ └── addr.go │ │ ├── command │ │ ├── abort_transaction.go │ │ ├── aggregate.go │ │ ├── buildinfo.go │ │ ├── command.go │ │ ├── commit_transaction.go │ │ ├── count.go │ │ ├── count_documents.go │ │ ├── create_indexes.go │ │ ├── delete.go │ │ ├── distinct.go │ │ ├── doc.go │ │ ├── drop_collection.go │ │ ├── drop_database.go │ │ ├── drop_indexes.go │ │ ├── end_sessions.go │ │ ├── errors.go │ │ ├── find.go │ │ ├── find_and_modify.go │ │ ├── find_one_delete.go │ │ ├── find_one_replace.go │ │ ├── find_one_update.go │ │ ├── get_more.go │ │ ├── getlasterror.go │ │ ├── handshake.go │ │ ├── insert.go │ │ ├── ismaster.go │ │ ├── kill_cursors.go │ │ ├── list_collections.go │ │ ├── list_databases.go │ │ ├── list_indexes.go │ │ ├── namespace.go │ │ ├── opmsg.go │ │ ├── opreply.go │ │ ├── read.go │ │ ├── start_session.go │ │ ├── update.go │ │ └── write.go │ │ ├── compressor │ │ └── compression.go │ │ ├── connection │ │ ├── addr.go │ │ ├── command_metadata.go │ │ ├── connection.go │ │ ├── error.go │ │ ├── keepalive_300.go │ │ ├── keepalive_default.go │ │ ├── listener.go │ │ ├── options.go │ │ ├── pool.go │ │ ├── proxy.go │ │ ├── server.go │ │ ├── tlsconfig.go │ │ └── tlsconfig_clone_17.go │ │ ├── connstring │ │ └── connstring.go │ │ ├── description │ │ ├── description.go │ │ ├── feature.go │ │ ├── server.go │ │ ├── server_kind.go │ │ ├── server_selector.go │ │ ├── topology.go │ │ ├── topology_kind.go │ │ ├── version.go │ │ └── version_range.go │ │ ├── result │ │ └── result.go │ │ └── wiremessage │ │ ├── appenders.go │ │ ├── command.go │ │ ├── command_reply.go │ │ ├── compressed.go │ │ ├── delete.go │ │ ├── get_more.go │ │ ├── header.go │ │ ├── insert.go │ │ ├── kill_cursors.go │ │ ├── msg.go │ │ ├── query.go │ │ ├── readers.go │ │ ├── reply.go │ │ ├── update.go │ │ └── wiremessage.go │ ├── golang.org │ └── x │ │ ├── crypto │ │ ├── AUTHORS │ │ ├── CONTRIBUTORS │ │ ├── LICENSE │ │ ├── PATENTS │ │ └── pbkdf2 │ │ │ └── pbkdf2.go │ │ ├── sync │ │ ├── AUTHORS │ │ ├── CONTRIBUTORS │ │ ├── LICENSE │ │ ├── PATENTS │ │ └── semaphore │ │ │ └── semaphore.go │ │ └── text │ │ ├── AUTHORS │ │ ├── CONTRIBUTORS │ │ ├── LICENSE │ │ ├── PATENTS │ │ ├── transform │ │ └── transform.go │ │ └── unicode │ │ └── norm │ │ ├── composition.go │ │ ├── forminfo.go │ │ ├── input.go │ │ ├── iter.go │ │ ├── maketables.go │ │ ├── normalize.go │ │ ├── readwriter.go │ │ ├── tables10.0.0.go │ │ ├── tables11.0.0.go │ │ ├── tables9.0.0.go │ │ ├── transform.go │ │ ├── trie.go │ │ └── triegen.go │ └── modules.txt ├── chapter12 ├── asynckafka │ ├── consumer │ │ └── main.go │ ├── go.mod │ ├── go.sum │ └── producer │ │ ├── genmocks.sh │ │ ├── handler.go │ │ ├── handler_test.go │ │ ├── main.go │ │ ├── mocks_test.go │ │ ├── producer.go │ │ └── producer_test.go ├── goflow │ ├── components.go │ ├── components_test.go │ ├── example │ │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── network.go │ └── network_test.go ├── graphql │ ├── cards │ │ ├── card.go │ │ ├── resolve.go │ │ ├── resolve_test.go │ │ ├── schema.go │ │ ├── schema_test.go │ │ ├── type.go │ │ └── type_test.go │ ├── example │ │ └── main.go │ ├── go.mod │ └── go.sum ├── kafkaflow │ ├── components.go │ ├── components_test.go │ ├── consumer │ │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── network.go │ ├── network_test.go │ └── producer │ │ └── main.go └── synckafka │ ├── consumer │ └── main.go │ ├── go.mod │ ├── go.sum │ └── producer │ └── main.go ├── chapter13 ├── appengine │ ├── .gcloudignore │ ├── app.yaml │ ├── controller.go │ ├── controller_test.go │ ├── go.mod │ ├── go.sum │ ├── main.go │ ├── message.go │ └── message_test.go ├── firebase │ ├── auth.go │ ├── auth_test.go │ ├── client.go │ ├── example │ │ └── main.go │ ├── go.mod │ └── go.sum ├── lambda │ ├── functions │ │ ├── greeter1 │ │ │ └── main.go │ │ └── greeter2 │ │ │ └── main.go │ ├── go.mod │ ├── go.sum │ └── project.json └── logging │ ├── functions │ └── secret │ │ └── main.go │ ├── go.mod │ ├── go.sum │ └── project.json ├── chapter14 ├── bench │ ├── atomic.go │ ├── atomic_test.go │ ├── go.mod │ ├── lock.go │ └── lock_test.go ├── fastweb │ ├── go.mod │ ├── go.sum │ ├── handlers.go │ ├── handlers_test.go │ ├── items.go │ ├── items_test.go │ └── main.go ├── pprof │ ├── crypto │ │ ├── handler.go │ │ └── handler_test.go │ ├── example │ │ └── main.go │ ├── go.mod │ └── go.sum └── tuning │ ├── concat.go │ ├── concat_test.go │ ├── go.mod │ ├── join.go │ └── join_test.go ├── chapter2 ├── ansicolor │ ├── color.go │ ├── color_test.go │ ├── example │ │ └── main.go │ └── go.mod ├── cmdargs │ ├── cmdargs.go │ ├── cmdargs_test.go │ ├── go.mod │ └── main.go ├── confformat │ ├── example │ │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── json.go │ ├── json_test.go │ ├── marshal.go │ ├── marshal_test.go │ ├── toml.go │ ├── toml_test.go │ ├── unmarshal.go │ ├── unmarshal_test.go │ ├── yaml.go │ └── yaml_test.go ├── envvar │ ├── config.go │ ├── config_test.go │ ├── example │ │ └── main.go │ ├── go.mod │ └── go.sum ├── flags │ ├── custom.go │ ├── custom_test.go │ ├── flags.go │ ├── flags_test.go │ ├── go.mod │ └── main.go ├── pipes │ ├── go.mod │ ├── pipes.go │ └── pipes_test.go └── signals │ ├── go.mod │ ├── signals.go │ └── signals_test.go ├── chapter3 ├── collections │ ├── collections.go │ ├── collections_test.go │ ├── example │ │ └── main.go │ ├── functions.go │ ├── functions_test.go │ └── go.mod ├── currency │ ├── dollars.go │ ├── dollars_test.go │ ├── example │ │ └── main.go │ ├── go.mod │ ├── pennies.go │ └── pennies_test.go ├── dataconv │ ├── dataconv.go │ ├── dataconv_test.go │ ├── example │ │ └── main.go │ ├── go.mod │ ├── interfaces.go │ ├── interfaces_test.go │ ├── strconv.go │ └── strconv_test.go ├── encoding │ ├── base64.go │ ├── base64_test.go │ ├── example │ │ └── main.go │ ├── go.mod │ ├── gob.go │ └── gob_test.go ├── math │ ├── example │ │ └── main.go │ ├── fib.go │ ├── fib_test.go │ ├── go.mod │ ├── math.go │ └── math_test.go ├── nulls │ ├── base.go │ ├── base_test.go │ ├── example │ │ └── main.go │ ├── go.mod │ ├── nullencoding.go │ ├── nullencoding_test.go │ ├── pointer.go │ └── pointer_test.go └── tags │ ├── deserialize.go │ ├── deserialize_test.go │ ├── example │ └── main.go │ ├── go.mod │ ├── serialize.go │ ├── serialize_test.go │ ├── tags.go │ └── tags_test.go ├── chapter4 ├── basicerrors │ ├── basicerrors.go │ ├── basicerrors_test.go │ ├── custom.go │ ├── custom_test.go │ ├── example │ │ └── main.go │ └── go.mod ├── context │ ├── collect.go │ ├── collect_test.go │ ├── example │ │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── log.go │ └── log_test.go ├── errwrap │ ├── errwrap.go │ ├── errwrap_test.go │ ├── example │ │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── unwrap.go │ └── unwrap_test.go ├── global │ ├── example │ │ └── main.go │ ├── global.go │ ├── global_test.go │ ├── go.mod │ ├── go.sum │ ├── log.go │ └── log_test.go ├── log │ ├── error.go │ ├── error_test.go │ ├── example │ │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── log.go │ └── log_test.go ├── panic │ ├── example │ │ └── main.go │ ├── go.mod │ └── panic.go └── structured │ ├── apex.go │ ├── apex_test.go │ ├── example │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── logrus.go │ └── logrus_test.go ├── chapter5 ├── dns │ ├── dns.go │ ├── dns_test.go │ ├── example │ │ └── main.go │ ├── go.mod │ └── go.sum ├── mail │ ├── go.mod │ ├── header.go │ └── main.go ├── rpc │ ├── client │ │ └── main.go │ ├── go.mod │ ├── server │ │ └── main.go │ └── tweak │ │ ├── tweak.go │ │ └── tweak_test.go ├── tcp │ ├── client │ │ └── main.go │ ├── go.mod │ └── server │ │ └── main.go ├── udp │ ├── client │ │ └── main.go │ ├── go.mod │ └── server │ │ ├── broadcast.go │ │ └── main.go └── websocket │ ├── client │ ├── main.go │ └── process.go │ ├── go.mod │ ├── go.sum │ └── server │ ├── handler.go │ └── main.go ├── chapter6 ├── database │ ├── config.go │ ├── config_test.go │ ├── create.go │ ├── create_test.go │ ├── example │ │ └── main.go │ ├── exec.go │ ├── exec_test.go │ ├── go.mod │ ├── go.sum │ ├── query.go │ └── query_test.go ├── dbinterface │ ├── create.go │ ├── create_test.go │ ├── example │ │ └── main.go │ ├── exec.go │ ├── exec_test.go │ ├── go.mod │ ├── go.sum │ ├── mockgen.sh │ ├── mocks_test.go │ ├── query.go │ ├── query_test.go │ └── transaction.go ├── mongodb │ ├── config.go │ ├── config_test.go │ ├── example │ │ └── main.go │ ├── exec.go │ ├── exec_test.go │ ├── go.mod │ └── go.sum ├── pools │ ├── example │ │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── pools.go │ ├── pools_test.go │ ├── timeout.go │ └── timeout_test.go ├── redis │ ├── config.go │ ├── config_test.go │ ├── example │ │ └── main.go │ ├── exec.go │ ├── exec_test.go │ ├── go.mod │ ├── go.sum │ ├── sort.go │ └── sort_test.go └── storage │ ├── example │ └── main.go │ ├── exec.go │ ├── go.mod │ ├── go.sum │ ├── mongoconfig.go │ ├── mongointerface.go │ └── storage.go ├── chapter7 ├── async │ ├── config.go │ ├── config_test.go │ ├── example │ │ └── main.go │ ├── exec.go │ ├── exec_test.go │ ├── go.mod │ └── go.sum ├── client │ ├── client.go │ ├── client_test.go │ ├── example │ │ └── main.go │ ├── exec.go │ ├── exec_test.go │ ├── go.mod │ ├── go.sum │ ├── store.go │ └── store_test.go ├── decorator │ ├── config.go │ ├── config_test.go │ ├── decorator.go │ ├── decorator_test.go │ ├── example │ │ └── main.go │ ├── exec.go │ ├── exec_test.go │ ├── go.mod │ ├── go.sum │ ├── middleware.go │ └── middleware_test.go ├── grpc │ ├── client │ │ └── client.go │ ├── go.mod │ ├── go.sum │ ├── greeter │ │ ├── greeter.pb.go │ │ └── greeter.proto │ ├── grpc.sh │ └── server │ │ ├── greeter.go │ │ ├── greeter_test.go │ │ └── server.go ├── oauthcli │ ├── config.go │ ├── config_test.go │ ├── example │ │ └── main.go │ ├── exec.go │ ├── exec_test.go │ ├── go.mod │ └── go.sum ├── oauthstore │ ├── config.go │ ├── config_test.go │ ├── example │ │ └── main.go │ ├── filestorage.go │ ├── filestorage_test.go │ ├── go.mod │ ├── go.sum │ ├── storage.go │ ├── storage_test.go │ ├── tokensource.go │ └── tokensource_test.go ├── rest │ ├── client.go │ ├── client_test.go │ ├── example │ │ └── main.go │ ├── exec.go │ ├── exec_test.go │ ├── go.mod │ ├── go.sum │ ├── transport.go │ └── transport_test.go └── twirp │ ├── client │ └── client.go │ ├── go.mod │ ├── go.sum │ ├── rpc │ └── greeter │ │ ├── greeter.pb.go │ │ ├── greeter.proto │ │ └── greeter.twirp.go │ ├── server │ ├── greeter.go │ ├── greeter_test.go │ └── server.go │ └── twirp.sh ├── chapter8 ├── controllers │ ├── controller.go │ ├── controller_test.go │ ├── example │ │ └── main.go │ ├── get.go │ ├── get_test.go │ ├── go.mod │ ├── post.go │ ├── post_test.go │ ├── storage.go │ └── storage_test.go ├── grpcjson │ ├── go.mod │ ├── go.sum │ ├── grpc.sh │ ├── grpc │ │ └── main.go │ ├── http │ │ ├── get.go │ │ ├── get_test.go │ │ ├── main.go │ │ ├── set.go │ │ └── set_test.go │ ├── internal │ │ ├── keyvalue.go │ │ └── keyvalue_test.go │ └── keyvalue │ │ ├── keyvalue.pb.go │ │ └── keyvalue.proto ├── handlers │ ├── example │ │ └── main.go │ ├── get.go │ ├── get_test.go │ ├── go.mod │ ├── post.go │ └── post_test.go ├── middleware │ ├── context.go │ ├── context_test.go │ ├── example │ │ └── main.go │ ├── go.mod │ ├── handler.go │ ├── handler_test.go │ ├── middleware.go │ └── middleware_test.go ├── negotiate │ ├── example │ │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── handler.go │ ├── handler_test.go │ ├── negotiate.go │ ├── negotiate_test.go │ ├── respond.go │ └── respond_test.go ├── proxy │ ├── example │ │ └── main.go │ ├── go.mod │ ├── process.go │ ├── process_test.go │ ├── proxy.go │ └── proxy_test.go └── validation │ ├── controller.go │ ├── controller_test.go │ ├── example │ └── main.go │ ├── go.mod │ ├── process.go │ ├── process_test.go │ ├── validate.go │ └── validate_test.go └── chapter9 ├── bdd ├── features │ └── handler.feature ├── go.mod ├── go.sum ├── handler.go └── handler_test.go ├── coverage ├── coverage.go ├── coverage_test.go └── go.mod ├── mockgen ├── exec.go ├── exec_test.go ├── go.mod ├── go.sum ├── interface.go ├── interface_test.go ├── internal │ └── mocks.go └── mockgen.sh ├── mocking ├── exec.go ├── exec_test.go ├── go.mod ├── mock.go ├── mock_test.go ├── patch.go └── patch_test.go └── tools ├── funcs.go ├── funcs_test.go ├── go.mod ├── go.sum ├── struct.go └── structs_test.go /chapter1/bytestrings/bytes_test.go: -------------------------------------------------------------------------------- 1 | package bytestrings 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestWorkWithBuffer(t *testing.T) { 8 | err := WorkWithBuffer() 9 | if err != nil { 10 | t.Errorf("unexpected error") 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter1/bytestrings/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter1/bytestrings" 4 | 5 | func main() { 6 | err := bytestrings.WorkWithBuffer() 7 | if err != nil { 8 | panic(err) 9 | } 10 | 11 | // each of these print to stdout 12 | bytestrings.SearchString() 13 | bytestrings.ModifyString() 14 | bytestrings.StringReader() 15 | } 16 | -------------------------------------------------------------------------------- /chapter1/bytestrings/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter1/bytestrings 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter1/csvformat/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter1/csvformat" 7 | ) 8 | 9 | func main() { 10 | if err := csvformat.AddMoviesFromText(); err != nil { 11 | panic(err) 12 | } 13 | 14 | if err := csvformat.WriteCSVOutput(); err != nil { 15 | panic(err) 16 | } 17 | 18 | buffer, err := csvformat.WriteCSVBuffer() 19 | if err != nil { 20 | panic(err) 21 | } 22 | 23 | fmt.Println("Buffer = ", buffer.String()) 24 | } 25 | -------------------------------------------------------------------------------- /chapter1/csvformat/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter1/csvformat 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter1/filedirs/dirs_test.go: -------------------------------------------------------------------------------- 1 | package filedirs 2 | 3 | import "testing" 4 | 5 | func TestOperate(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := Operate(); (err != nil) != tt.wantErr { 15 | t.Errorf("Operate() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter1/filedirs/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter1/filedirs" 4 | 5 | func main() { 6 | if err := filedirs.Operate(); err != nil { 7 | panic(err) 8 | } 9 | 10 | if err := filedirs.CapitalizerExample(); err != nil { 11 | panic(err) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /chapter1/filedirs/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter1/filedirs 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter1/interfaces/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | 7 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter1/interfaces" 8 | ) 9 | 10 | func main() { 11 | in := bytes.NewReader([]byte("example")) 12 | out := &bytes.Buffer{} 13 | fmt.Print("stdout on Copy = ") 14 | if err := interfaces.Copy(in, out); err != nil { 15 | panic(err) 16 | } 17 | 18 | fmt.Println("out bytes buffer =", out.String()) 19 | 20 | fmt.Print("stdout on PipeExample = ") 21 | if err := interfaces.PipeExample(); err != nil { 22 | panic(err) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter1/interfaces/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter1/interfaces 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter1/interfaces/interfaces.go: -------------------------------------------------------------------------------- 1 | package interfaces 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | ) 8 | 9 | // Copy copies data from in to out first directly, 10 | // then using a buffer. It also writes to stdout 11 | func Copy(in io.ReadSeeker, out io.Writer) error { 12 | // we write to out, but also Stdout 13 | w := io.MultiWriter(out, os.Stdout) 14 | 15 | // a standard copy, this can be dangerous if there's a lot 16 | // of data in in 17 | if _, err := io.Copy(w, in); err != nil { 18 | return err 19 | } 20 | 21 | in.Seek(0, 0) 22 | 23 | // buffered write using 64 byte chunks 24 | buf := make([]byte, 64) 25 | if _, err := io.CopyBuffer(w, in, buf); err != nil { 26 | return err 27 | } 28 | 29 | // lets print a new line 30 | fmt.Println() 31 | 32 | return nil 33 | } 34 | -------------------------------------------------------------------------------- /chapter1/interfaces/pipes.go: -------------------------------------------------------------------------------- 1 | package interfaces 2 | 3 | import ( 4 | "io" 5 | "os" 6 | ) 7 | 8 | // PipeExample helps give some more examples of using io interfaces 9 | func PipeExample() error { 10 | // the pipe reader and pipe writer implement 11 | // io.Reader and io.Writer 12 | r, w := io.Pipe() 13 | 14 | // this needs to be run in a separate go routine 15 | // as it will block waiting for the reader 16 | // close at the end for cleanup 17 | go func() { 18 | // for now we'll write something basic, 19 | // this could also be used to encode json 20 | // base64 encode, etc. 21 | w.Write([]byte("test\n")) 22 | w.Close() 23 | }() 24 | 25 | if _, err := io.Copy(os.Stdout, r); err != nil { 26 | return err 27 | } 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /chapter1/interfaces/pipes_test.go: -------------------------------------------------------------------------------- 1 | package interfaces 2 | 3 | import "testing" 4 | 5 | func TestPipeExample(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | }{ 9 | {"base-case"}, 10 | } 11 | for _, tt := range tests { 12 | t.Run(tt.name, func(t *testing.T) { 13 | PipeExample() 14 | }) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /chapter1/tempfiles/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter1/tempfiles" 4 | 5 | func main() { 6 | if err := tempfiles.WorkWithTemp(); err != nil { 7 | panic(err) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /chapter1/tempfiles/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter1/tempfiles 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter1/tempfiles/temp_files_test.go: -------------------------------------------------------------------------------- 1 | package tempfiles 2 | 3 | import "testing" 4 | 5 | func TestWorkWithTemp(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := WorkWithTemp(); (err != nil) != tt.wantErr { 15 | t.Errorf("WorkWithTemp() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter1/templates/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter1/templates" 4 | 5 | func main() { 6 | if err := templates.RunTemplate(); err != nil { 7 | panic(err) 8 | } 9 | 10 | if err := templates.InitTemplates(); err != nil { 11 | panic(err) 12 | } 13 | 14 | if err := templates.HTMLDifferences(); err != nil { 15 | panic(err) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /chapter1/templates/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter1/templates 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter1/templates/html_templates_test.go: -------------------------------------------------------------------------------- 1 | package templates 2 | 3 | import "testing" 4 | 5 | func TestHTMLDifferences(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := HTMLDifferences(); (err != nil) != tt.wantErr { 15 | t.Errorf("HTMLDifferences() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter1/templates/templates_test.go: -------------------------------------------------------------------------------- 1 | package templates 2 | 3 | import "testing" 4 | 5 | func TestRunTemplate(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := RunTemplate(); (err != nil) != tt.wantErr { 15 | t.Errorf("RunTemplate() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter10/atomic/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter10/atomic 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter10/atomic/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/ea3c94a784b061afc7e62ac9a4e7c5792d498769/chapter10/atomic/go.sum -------------------------------------------------------------------------------- /chapter10/channels/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter10/channels" 8 | ) 9 | 10 | func main() { 11 | ch := make(chan string) 12 | done := make(chan bool) 13 | 14 | ctx := context.Background() 15 | ctx, cancel := context.WithCancel(ctx) 16 | defer cancel() 17 | 18 | go channels.Printer(ctx, ch) 19 | go channels.Sender(ch, done) 20 | 21 | time.Sleep(2 * time.Second) 22 | done <- true 23 | cancel() 24 | time.Sleep(3 * time.Second) 25 | } 26 | -------------------------------------------------------------------------------- /chapter10/channels/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter10/channels 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter10/channels/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/ea3c94a784b061afc7e62ac9a4e7c5792d498769/chapter10/channels/go.sum -------------------------------------------------------------------------------- /chapter10/channels/printer.go: -------------------------------------------------------------------------------- 1 | package channels 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | // Printer will print anything sent on the ch chan 10 | // and will print tock every 200 milliseconds 11 | // this will repeat forever until a context is 12 | // Done, i.e. timed out or cancelled 13 | func Printer(ctx context.Context, ch chan string) { 14 | t := time.Tick(200 * time.Millisecond) 15 | for { 16 | select { 17 | case <-ctx.Done(): 18 | fmt.Println("printer done.") 19 | return 20 | case res := <-ch: 21 | fmt.Println(res) 22 | case <-t: 23 | fmt.Println("tock") 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter10/channels/printer_test.go: -------------------------------------------------------------------------------- 1 | package channels 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestPrinter(t *testing.T) { 10 | 11 | type args struct { 12 | ctx context.Context 13 | ch chan string 14 | } 15 | tests := []struct { 16 | name string 17 | args args 18 | }{ 19 | {"base-case", args{context.Background(), make(chan string)}}, 20 | } 21 | for _, tt := range tests { 22 | t.Run(tt.name, func(t *testing.T) { 23 | ctx, cancel := context.WithCancel(tt.args.ctx) 24 | defer cancel() 25 | go Printer(ctx, tt.args.ch) 26 | time.Sleep(200 * time.Millisecond) 27 | tt.args.ch <- "test" 28 | }) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /chapter10/channels/sender.go: -------------------------------------------------------------------------------- 1 | package channels 2 | 3 | import "time" 4 | 5 | // Sender sends "tick"" on ch until done is 6 | // written to, then it sends "sender done." 7 | // and exits 8 | func Sender(ch chan string, done chan bool) { 9 | t := time.Tick(100 * time.Millisecond) 10 | for { 11 | select { 12 | case <-done: 13 | ch <- "sender done." 14 | return 15 | case <-t: 16 | ch <- "tick" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter10/channels/sender_test.go: -------------------------------------------------------------------------------- 1 | package channels 2 | 3 | import "testing" 4 | import "time" 5 | 6 | func TestSender(t *testing.T) { 7 | type args struct { 8 | ch chan string 9 | done chan bool 10 | } 11 | tests := []struct { 12 | name string 13 | args args 14 | }{ 15 | {"base-case", args{make(chan string, 10), make(chan bool)}}, 16 | } 17 | for _, tt := range tests { 18 | t.Run(tt.name, func(t *testing.T) { 19 | go Sender(tt.args.ch, tt.args.done) 20 | time.Sleep(100 * time.Millisecond) 21 | tt.args.done <- true 22 | }) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter10/context/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter10/context" 4 | 5 | func main() { 6 | context.Exec() 7 | } 8 | -------------------------------------------------------------------------------- /chapter10/context/exec_test.go: -------------------------------------------------------------------------------- 1 | package context 2 | 3 | import "testing" 4 | 5 | func TestExec(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | }{ 9 | {"base-case"}, 10 | } 11 | for _, tt := range tests { 12 | t.Run(tt.name, func(t *testing.T) { 13 | Exec() 14 | }) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /chapter10/context/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter10/context 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter10/context/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/ea3c94a784b061afc7e62ac9a4e7c5792d498769/chapter10/context/go.sum -------------------------------------------------------------------------------- /chapter10/context/values.go: -------------------------------------------------------------------------------- 1 | package context 2 | 3 | import "context" 4 | 5 | type key string 6 | 7 | const ( 8 | timeoutKey key = "TimeoutKey" 9 | deadlineKey key = "DeadlineKey" 10 | ) 11 | 12 | // Setup sets some values 13 | func Setup(ctx context.Context) context.Context { 14 | 15 | ctx = context.WithValue(ctx, timeoutKey, "timeout exceeded") 16 | ctx = context.WithValue(ctx, deadlineKey, "deadline exceeded") 17 | 18 | return ctx 19 | } 20 | 21 | // GetValue grabs a value given a key and 22 | // returns a string representation of the 23 | // value 24 | func GetValue(ctx context.Context, k key) string { 25 | 26 | if val, ok := ctx.Value(k).(string); ok { 27 | return val 28 | } 29 | return "" 30 | 31 | } 32 | -------------------------------------------------------------------------------- /chapter10/pipeline/encode.go: -------------------------------------------------------------------------------- 1 | package pipeline 2 | 3 | import ( 4 | "context" 5 | "encoding/base64" 6 | "fmt" 7 | ) 8 | 9 | // Encode takes plain text as int 10 | // and returns "string => 11 | // as out 12 | func (w *Worker) Encode(ctx context.Context) { 13 | for { 14 | select { 15 | case <-ctx.Done(): 16 | return 17 | case val := <-w.in: 18 | w.out <- fmt.Sprintf("%s => %s", val, base64.StdEncoding.EncodeToString([]byte(val))) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /chapter10/pipeline/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter10/pipeline" 8 | ) 9 | 10 | func main() { 11 | ctx := context.Background() 12 | ctx, cancel := context.WithCancel(ctx) 13 | defer cancel() 14 | 15 | in, out := pipeline.NewPipeline(ctx, 10, 2) 16 | 17 | go func() { 18 | for i := 0; i < 20; i++ { 19 | in <- fmt.Sprint("Message", i) 20 | } 21 | }() 22 | 23 | for i := 0; i < 20; i++ { 24 | <-out 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter10/pipeline/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter10/pipeline 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter10/pipeline/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/ea3c94a784b061afc7e62ac9a4e7c5792d498769/chapter10/pipeline/go.sum -------------------------------------------------------------------------------- /chapter10/pipeline/pipeline.go: -------------------------------------------------------------------------------- 1 | package pipeline 2 | 3 | import "context" 4 | 5 | // NewPipeline initializes the workers and 6 | // connects them, it returns the input of the pipeline 7 | // and the final output 8 | func NewPipeline(ctx context.Context, numEncoders, numPrinters int) (chan string, chan string) { 9 | inEncode := make(chan string, numEncoders) 10 | inPrint := make(chan string, numPrinters) 11 | outPrint := make(chan string, numPrinters) 12 | for i := 0; i < numEncoders; i++ { 13 | w := Worker{ 14 | in: inEncode, 15 | out: inPrint, 16 | } 17 | go w.Work(ctx, Encode) 18 | } 19 | 20 | for i := 0; i < numPrinters; i++ { 21 | w := Worker{ 22 | in: inPrint, 23 | out: outPrint, 24 | } 25 | go w.Work(ctx, Print) 26 | } 27 | return inEncode, outPrint 28 | } 29 | -------------------------------------------------------------------------------- /chapter10/pipeline/print.go: -------------------------------------------------------------------------------- 1 | package pipeline 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | ) 7 | 8 | // Print prints w.in and repalys it 9 | // on w.out 10 | func (w *Worker) Print(ctx context.Context) { 11 | for { 12 | select { 13 | case <-ctx.Done(): 14 | return 15 | case val := <-w.in: 16 | fmt.Println(val) 17 | w.out <- val 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /chapter10/pipeline/worker.go: -------------------------------------------------------------------------------- 1 | package pipeline 2 | 3 | import "context" 4 | 5 | // Worker have one role 6 | // that is determined when 7 | // Work is called 8 | type Worker struct { 9 | in chan string 10 | out chan string 11 | } 12 | 13 | // Job is a job a worker can do 14 | type Job string 15 | 16 | const ( 17 | // Print echo's all input to 18 | // stdout 19 | Print Job = "print" 20 | // Encode base64 encodes input 21 | Encode Job = "encode" 22 | ) 23 | 24 | // Work is how to dispatch a worker, they are assigned 25 | // a job here 26 | func (w *Worker) Work(ctx context.Context, j Job) { 27 | switch j { 28 | case Print: 29 | w.Print(ctx) 30 | case Encode: 31 | w.Encode(ctx) 32 | default: 33 | return 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /chapter10/pool/crypto.go: -------------------------------------------------------------------------------- 1 | package pool 2 | 3 | import "golang.org/x/crypto/bcrypt" 4 | 5 | func hashWork(wr WorkRequest) WorkResponse { 6 | val, err := bcrypt.GenerateFromPassword(wr.Text, bcrypt.DefaultCost) 7 | return WorkResponse{ 8 | Result: val, 9 | Err: err, 10 | Wr: wr, 11 | } 12 | } 13 | 14 | func compareWork(wr WorkRequest) WorkResponse { 15 | var matched bool 16 | err := bcrypt.CompareHashAndPassword(wr.Compare, wr.Text) 17 | if err == nil { 18 | matched = true 19 | } 20 | return WorkResponse{ 21 | Matched: matched, 22 | Err: err, 23 | Wr: wr, 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /chapter10/pool/crypto_test.go: -------------------------------------------------------------------------------- 1 | package pool 2 | 3 | import "testing" 4 | 5 | func Test_hashWork(t *testing.T) { 6 | type args struct { 7 | wr WorkRequest 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | }{ 13 | {"base-case", args{WorkRequest{}}}, 14 | } 15 | for _, tt := range tests { 16 | t.Run(tt.name, func(t *testing.T) { 17 | hashWork(tt.args.wr) 18 | }) 19 | } 20 | } 21 | 22 | func Test_compareWork(t *testing.T) { 23 | type args struct { 24 | wr WorkRequest 25 | } 26 | tests := []struct { 27 | name string 28 | args args 29 | }{ 30 | {"base-case", args{WorkRequest{}}}, 31 | } 32 | for _, tt := range tests { 33 | t.Run(tt.name, func(t *testing.T) { 34 | compareWork(tt.args.wr) 35 | }) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /chapter10/pool/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter10/pool" 7 | ) 8 | 9 | func main() { 10 | cancel, in, out := pool.Dispatch(10) 11 | defer cancel() 12 | 13 | for i := 0; i < 10; i++ { 14 | in <- pool.WorkRequest{Op: pool.Hash, Text: []byte(fmt.Sprintf("messages %d", i))} 15 | } 16 | 17 | for i := 0; i < 10; i++ { 18 | res := <-out 19 | if res.Err != nil { 20 | panic(res.Err) 21 | } 22 | in <- pool.WorkRequest{Op: pool.Compare, Text: res.Wr.Text, Compare: res.Result} 23 | } 24 | 25 | for i := 0; i < 10; i++ { 26 | res := <-out 27 | if res.Err != nil { 28 | panic(res.Err) 29 | } 30 | fmt.Printf("string: \"%s\"; matched: %v\n", string(res.Wr.Text), res.Matched) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /chapter10/pool/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter10/pool 2 | 3 | go 1.12 4 | 5 | require golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576 6 | -------------------------------------------------------------------------------- /chapter10/pool/go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576 h1:aUX/1G2gFSs4AsJJg2cL3HuoRhCSCz733FE5GUSuaT4= 2 | golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 3 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 4 | -------------------------------------------------------------------------------- /chapter10/pool/work_test.go: -------------------------------------------------------------------------------- 1 | package pool 2 | 3 | import "testing" 4 | 5 | func TestProcess(t *testing.T) { 6 | type args struct { 7 | wr WorkRequest 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | }{ 13 | {"Hash", args{WorkRequest{Op: Hash}}}, 14 | {"Compare", args{WorkRequest{Op: Compare}}}, 15 | {"Other", args{WorkRequest{Op: op("test")}}}, 16 | } 17 | for _, tt := range tests { 18 | t.Run(tt.name, func(t *testing.T) { 19 | Process(tt.args.wr) 20 | }) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /chapter10/state/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter10/state 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter10/state/process.go: -------------------------------------------------------------------------------- 1 | package state 2 | 3 | import "errors" 4 | 5 | // Process switches on operation type 6 | // Then does work 7 | func Process(wr *WorkRequest) *WorkResponse { 8 | resp := WorkResponse{Wr: wr} 9 | 10 | switch wr.Operation { 11 | case Add: 12 | resp.Result = wr.Value1 + wr.Value2 13 | case Subtract: 14 | resp.Result = wr.Value1 - wr.Value2 15 | case Multiply: 16 | resp.Result = wr.Value1 * wr.Value2 17 | case Divide: 18 | if wr.Value2 == 0 { 19 | resp.Err = errors.New("divide by 0") 20 | break 21 | } 22 | resp.Result = wr.Value1 / wr.Value2 23 | default: 24 | resp.Err = errors.New("unsupported operation") 25 | } 26 | return &resp 27 | } 28 | -------------------------------------------------------------------------------- /chapter10/state/processor.go: -------------------------------------------------------------------------------- 1 | package state 2 | 3 | import "context" 4 | 5 | // Processor routes work to Process 6 | func Processor(ctx context.Context, in chan *WorkRequest, out chan *WorkResponse) { 7 | for { 8 | select { 9 | case <-ctx.Done(): 10 | return 11 | case wr := <-in: 12 | out <- Process(wr) 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /chapter10/state/processor_test.go: -------------------------------------------------------------------------------- 1 | package state 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestProcessor(t *testing.T) { 10 | ctx := context.Background() 11 | ctx, cancel := context.WithTimeout(ctx, 1*time.Millisecond) 12 | defer cancel() 13 | type args struct { 14 | ctx context.Context 15 | in chan *WorkRequest 16 | out chan *WorkResponse 17 | } 18 | tests := []struct { 19 | name string 20 | args args 21 | }{ 22 | {"base-case", args{ctx, make(chan *WorkRequest, 2), make(chan *WorkResponse, 2)}}, 23 | } 24 | for _, tt := range tests { 25 | t.Run(tt.name, func(t *testing.T) { 26 | tt.args.in <- &WorkRequest{} 27 | go Processor(tt.args.ctx, tt.args.in, tt.args.out) 28 | }) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /chapter10/state/state.go: -------------------------------------------------------------------------------- 1 | package state 2 | 3 | type op string 4 | 5 | const ( 6 | // Add values 7 | Add op = "add" 8 | // Subtract values 9 | Subtract = "sub" 10 | // Multiply values 11 | Multiply = "mult" 12 | // Divide values 13 | Divide = "div" 14 | ) 15 | 16 | // WorkRequest perform an op 17 | // on two values 18 | type WorkRequest struct { 19 | Operation op 20 | Value1 int64 21 | Value2 int64 22 | } 23 | 24 | // WorkResponse returns the result 25 | // and any errors 26 | type WorkResponse struct { 27 | Wr *WorkRequest 28 | Result int64 29 | Err error 30 | } 31 | -------------------------------------------------------------------------------- /chapter10/waitgroup/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter10/waitgroup" 7 | ) 8 | 9 | func main() { 10 | sites := []string{ 11 | "https://golang.org", 12 | "https://godoc.org", 13 | "https://www.google.com/search?q=golang", 14 | } 15 | 16 | resps, err := waitgroup.Crawl(sites) 17 | if err != nil { 18 | panic(err) 19 | } 20 | fmt.Println("Resps received:", resps) 21 | } 22 | -------------------------------------------------------------------------------- /chapter10/waitgroup/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter10/waitgroup 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter10/waitgroup/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/ea3c94a784b061afc7e62ac9a4e7c5792d498769/chapter10/waitgroup/go.sum -------------------------------------------------------------------------------- /chapter10/waitgroup/process_test.go: -------------------------------------------------------------------------------- 1 | package waitgroup 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestCrawl(t *testing.T) { 9 | type args struct { 10 | sites []string 11 | } 12 | tests := []struct { 13 | name string 14 | args args 15 | want []int 16 | wantErr bool 17 | }{ 18 | {"base-case", args{[]string{"https://www.google.com"}}, []int{200}, false}, 19 | } 20 | for _, tt := range tests { 21 | t.Run(tt.name, func(t *testing.T) { 22 | got, err := Crawl(tt.args.sites) 23 | if (err != nil) != tt.wantErr { 24 | t.Errorf("Crawl() error = %v, wantErr %v", err, tt.wantErr) 25 | return 26 | } 27 | if !reflect.DeepEqual(got, tt.want) { 28 | t.Errorf("Crawl() = %v, want %v", got, tt.want) 29 | } 30 | }) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /chapter11/consensus/config_test.go: -------------------------------------------------------------------------------- 1 | package consensus 2 | 3 | import "testing" 4 | 5 | func TestConfig(t *testing.T) { 6 | type args struct { 7 | num int 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | }{ 13 | {"base-case", args{3}}, 14 | } 15 | for _, tt := range tests { 16 | t.Run(tt.name, func(t *testing.T) { 17 | Config(tt.args.num) 18 | }) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /chapter11/consensus/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter11/consensus" 7 | ) 8 | 9 | func main() { 10 | consensus.Config(3) 11 | 12 | http.HandleFunc("/", consensus.Handler) 13 | err := http.ListenAndServe(":3333", nil) 14 | panic(err) 15 | } 16 | -------------------------------------------------------------------------------- /chapter11/consensus/fsm.go: -------------------------------------------------------------------------------- 1 | package consensus 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/hashicorp/raft" 7 | ) 8 | 9 | // FSM implements the raft FSM interface 10 | // and holds a state 11 | type FSM struct { 12 | state state 13 | } 14 | 15 | // NewFSM creates a new FSM with 16 | // start state of "first" 17 | func NewFSM() *FSM { 18 | return &FSM{state: first} 19 | } 20 | 21 | // Apply updates our FSM 22 | func (f *FSM) Apply(r *raft.Log) interface{} { 23 | f.state.Transition(state(r.Data)) 24 | return string(f.state) 25 | } 26 | 27 | // Snapshot needed to satisfy the raft FSM interface 28 | func (f *FSM) Snapshot() (raft.FSMSnapshot, error) { 29 | return nil, nil 30 | } 31 | 32 | // Restore needed to satisfy the raft FSM interface 33 | func (f *FSM) Restore(io.ReadCloser) error { 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /chapter11/consensus/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter11/consensus 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 // indirect 7 | github.com/hashicorp/go-msgpack v0.5.5 // indirect 8 | github.com/hashicorp/raft v1.0.1 9 | ) 10 | -------------------------------------------------------------------------------- /chapter11/consensus/handler_test.go: -------------------------------------------------------------------------------- 1 | package consensus 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "testing" 7 | ) 8 | 9 | func TestHandler(t *testing.T) { 10 | type args struct { 11 | w http.ResponseWriter 12 | r *http.Request 13 | } 14 | tests := []struct { 15 | name string 16 | args args 17 | }{ 18 | {"base-case", args{httptest.NewRecorder(), httptest.NewRequest("GET", "/?next=test", nil)}}, 19 | } 20 | for _, tt := range tests { 21 | t.Run(tt.name, func(t *testing.T) { 22 | Handler(tt.args.w, tt.args.r) 23 | }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /chapter11/discovery/client.go: -------------------------------------------------------------------------------- 1 | package discovery 2 | 3 | import "github.com/hashicorp/consul/api" 4 | 5 | // Client exposes api methods we care 6 | // about 7 | type Client interface { 8 | Register(tags []string) error 9 | Service(service, tag string) ([]*api.ServiceEntry, *api.QueryMeta, error) 10 | } 11 | 12 | type client struct { 13 | client *api.Client 14 | address string 15 | name string 16 | port int 17 | } 18 | 19 | //NewClient iniitalizes a consul client 20 | func NewClient(config *api.Config, address, name string, port int) (Client, error) { 21 | c, err := api.NewClient(config) 22 | if err != nil { 23 | return nil, err 24 | } 25 | cli := &client{ 26 | client: c, 27 | name: name, 28 | address: address, 29 | port: port, 30 | } 31 | return cli, nil 32 | } 33 | -------------------------------------------------------------------------------- /chapter11/discovery/client_test.go: -------------------------------------------------------------------------------- 1 | package discovery 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/consul/api" 7 | ) 8 | 9 | func TestNewClient(t *testing.T) { 10 | type args struct { 11 | config *api.Config 12 | address string 13 | name string 14 | port int 15 | } 16 | tests := []struct { 17 | name string 18 | args args 19 | wantErr bool 20 | }{ 21 | {"base-case", args{api.DefaultConfig(), "test", "test", 123}, false}, 22 | } 23 | for _, tt := range tests { 24 | t.Run(tt.name, func(t *testing.T) { 25 | _, err := NewClient(tt.args.config, tt.args.address, tt.args.name, tt.args.port) 26 | if (err != nil) != tt.wantErr { 27 | t.Errorf("NewClient() error = %v, wantErr %v", err, tt.wantErr) 28 | return 29 | } 30 | }) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /chapter11/discovery/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter11/discovery" 5 | consul "github.com/hashicorp/consul/api" 6 | ) 7 | 8 | func main() { 9 | config := consul.DefaultConfig() 10 | config.Address = "localhost:8500" 11 | 12 | // faked name and port for example 13 | cli, err := discovery.NewClient(config, "localhost", "discovery", 8080) 14 | if err != nil { 15 | panic(err) 16 | } 17 | 18 | if err := discovery.Exec(cli); err != nil { 19 | panic(err) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /chapter11/discovery/exec.go: -------------------------------------------------------------------------------- 1 | package discovery 2 | 3 | import "fmt" 4 | 5 | // Exec creates a consul entry then queries it 6 | func Exec(cli Client) error { 7 | if err := cli.Register([]string{"Go", "Awesome"}); err != nil { 8 | return err 9 | } 10 | 11 | entries, _, err := cli.Service("discovery", "Go") 12 | if err != nil { 13 | return err 14 | } 15 | for _, entry := range entries { 16 | fmt.Printf("%#v\n", entry.Service) 17 | } 18 | 19 | return nil 20 | } 21 | -------------------------------------------------------------------------------- /chapter11/discovery/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter11/discovery 2 | 3 | go 1.12 4 | 5 | require github.com/hashicorp/consul/api v1.0.1 6 | -------------------------------------------------------------------------------- /chapter11/discovery/operations.go: -------------------------------------------------------------------------------- 1 | package discovery 2 | 3 | import "github.com/hashicorp/consul/api" 4 | 5 | // Register adds our service to consul 6 | func (c *client) Register(tags []string) error { 7 | reg := &api.AgentServiceRegistration{ 8 | ID: c.name, 9 | Name: c.name, 10 | Port: c.port, 11 | Address: c.address, 12 | Tags: tags, 13 | } 14 | return c.client.Agent().ServiceRegister(reg) 15 | } 16 | 17 | // Service return a service 18 | func (c *client) Service(service, tag string) ([]*api.ServiceEntry, *api.QueryMeta, error) { 19 | return c.client.Health().Service(service, tag, false, nil) 20 | } 21 | -------------------------------------------------------------------------------- /chapter11/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | ADD ./example/example /example 4 | EXPOSE 8000 5 | ENTRYPOINT /example 6 | -------------------------------------------------------------------------------- /chapter11/docker/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter11/docker 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter11/docker/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | pushd example 4 | env GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-X main.version=1.0 -X main.builddate=$(date +%s)" 5 | popd 6 | docker build -t example . 7 | docker run -d -p 8000:8000 example 8 | -------------------------------------------------------------------------------- /chapter11/docker/version.go: -------------------------------------------------------------------------------- 1 | package docker 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | "time" 7 | ) 8 | 9 | // VersionInfo holds artifacts passed in 10 | // at build time 11 | type VersionInfo struct { 12 | Version string 13 | BuildDate time.Time 14 | Uptime time.Duration 15 | } 16 | 17 | // VersionHandler writes the latest version info 18 | func VersionHandler(v *VersionInfo) http.HandlerFunc { 19 | t := time.Now() 20 | return func(w http.ResponseWriter, r *http.Request) { 21 | v.Uptime = time.Since(t) 22 | vers, err := json.Marshal(v) 23 | if err != nil { 24 | w.WriteHeader(http.StatusInternalServerError) 25 | return 26 | } 27 | w.WriteHeader(http.StatusOK) 28 | w.Write(vers) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /chapter11/docker/version_test.go: -------------------------------------------------------------------------------- 1 | package docker 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func TestVersionHandler(t *testing.T) { 11 | type args struct { 12 | v *VersionInfo 13 | w http.ResponseWriter 14 | r *http.Request 15 | } 16 | tests := []struct { 17 | name string 18 | args args 19 | }{ 20 | {"base-case", args{&VersionInfo{Version: "1.0", BuildDate: time.Now()}, httptest.NewRecorder(), httptest.NewRequest("GET", "/", nil)}}, 21 | } 22 | for _, tt := range tests { 23 | t.Run(tt.name, func(t *testing.T) { 24 | h := VersionHandler(tt.args.v) 25 | h(tt.args.w, tt.args.r) 26 | }) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /chapter11/metrics/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter11/metrics" 8 | ) 9 | 10 | func main() { 11 | // handler to populate metrics 12 | http.HandleFunc("/counter", metrics.CounterHandler) 13 | http.HandleFunc("/timer", metrics.TimerHandler) 14 | http.HandleFunc("/report", metrics.ReportHandler) 15 | fmt.Println("listening on :8080") 16 | panic(http.ListenAndServe(":8080", nil)) 17 | } 18 | -------------------------------------------------------------------------------- /chapter11/metrics/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter11/metrics 2 | 3 | go 1.12 4 | 5 | require github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a 6 | -------------------------------------------------------------------------------- /chapter11/metrics/go.sum: -------------------------------------------------------------------------------- 1 | github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ= 2 | github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= 3 | -------------------------------------------------------------------------------- /chapter11/metrics/handler.go: -------------------------------------------------------------------------------- 1 | package metrics 2 | 3 | import ( 4 | "net/http" 5 | "time" 6 | 7 | metrics "github.com/rcrowley/go-metrics" 8 | ) 9 | 10 | // CounterHandler will update a counter each time it's called 11 | func CounterHandler(w http.ResponseWriter, r *http.Request) { 12 | c := metrics.GetOrRegisterCounter("counterhandler.counter", nil) 13 | c.Inc(1) 14 | 15 | w.WriteHeader(http.StatusOK) 16 | w.Write([]byte("success")) 17 | } 18 | 19 | // TimerHandler records the duration required to compelete 20 | func TimerHandler(w http.ResponseWriter, r *http.Request) { 21 | currt := time.Now() 22 | t := metrics.GetOrRegisterTimer("timerhandler.timer", nil) 23 | 24 | w.WriteHeader(http.StatusOK) 25 | w.Write([]byte("success")) 26 | t.UpdateSince(currt) 27 | } 28 | -------------------------------------------------------------------------------- /chapter11/metrics/report.go: -------------------------------------------------------------------------------- 1 | package metrics 2 | 3 | import ( 4 | "net/http" 5 | 6 | gometrics "github.com/rcrowley/go-metrics" 7 | ) 8 | 9 | // ReportHandler will emit the current metrics in json format 10 | func ReportHandler(w http.ResponseWriter, r *http.Request) { 11 | 12 | w.WriteHeader(http.StatusOK) 13 | 14 | t := gometrics.GetOrRegisterTimer("reporthandler.writemetrics", nil) 15 | t.Time(func() { 16 | gometrics.WriteJSONOnce(gometrics.DefaultRegistry, w) 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /chapter11/metrics/report_test.go: -------------------------------------------------------------------------------- 1 | package metrics 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "testing" 7 | ) 8 | 9 | func TestReportHandler(t *testing.T) { 10 | type args struct { 11 | w http.ResponseWriter 12 | r *http.Request 13 | } 14 | tests := []struct { 15 | name string 16 | args args 17 | }{ 18 | {"base-case", args{httptest.NewRecorder(), httptest.NewRequest("get", "/", nil)}}, 19 | } 20 | for _, tt := range tests { 21 | t.Run(tt.name, func(t *testing.T) { 22 | ReportHandler(tt.args.w, tt.args.r) 23 | }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /chapter11/monitoring/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.12.4-alpine3.9 2 | 3 | ENV GOPATH /code/ 4 | ADD . /code/src/github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter11/monitoring 5 | WORKDIR /code/src/github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter11/monitoring 6 | RUN GO111MODULE=on GOPROXY=off go build -mod=vendor 7 | 8 | ENTRYPOINT /code/src/github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter11/monitoring/monitoring 9 | -------------------------------------------------------------------------------- /chapter11/monitoring/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | app: 4 | build: . 5 | prometheus: 6 | ports: 7 | - 9090:9090 8 | volumes: 9 | - ./prometheus.yml:/etc/prometheus/prometheus.yml 10 | image: "prom/prometheus" 11 | -------------------------------------------------------------------------------- /chapter11/monitoring/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter11/monitoring 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a // indirect 7 | github.com/golang/protobuf v0.0.0-20170217234432-69b215d01a56 // indirect 8 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 9 | github.com/prometheus/client_golang v0.0.0-20170425213558-7d9484283ebe 10 | github.com/prometheus/client_model v0.0.0-20170216185247-6f3806018612 // indirect 11 | github.com/prometheus/common v0.0.0-20170427095455-13ba4ddd0caa // indirect 12 | github.com/prometheus/procfs v0.0.0-20170424204552-6ac8c5d890d4 // indirect 13 | ) 14 | -------------------------------------------------------------------------------- /chapter11/monitoring/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/prometheus/client_golang/prometheus/promhttp" 7 | ) 8 | 9 | func main() { 10 | http.Handle("/metrics", promhttp.Handler()) 11 | panic(http.ListenAndServe(":80", nil)) 12 | } 13 | -------------------------------------------------------------------------------- /chapter11/monitoring/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s # By default, scrape targets every 15 seconds. 3 | 4 | # A scrape configuration containing exactly one endpoint to scrape: 5 | # Here it's Prometheus itself. 6 | scrape_configs: 7 | # The job name is added as a label `job=` to any timeseries scraped from this config. 8 | - job_name: 'app' 9 | 10 | # Override the global default and scrape targets from this job every 5 seconds. 11 | scrape_interval: 5s 12 | 13 | static_configs: 14 | - targets: ['app:80'] -------------------------------------------------------------------------------- /chapter11/monitoring/vendor/github.com/golang/protobuf/AUTHORS: -------------------------------------------------------------------------------- 1 | # This source code refers to The Go Authors for copyright purposes. 2 | # The master list of authors is in the main Go distribution, 3 | # visible at http://tip.golang.org/AUTHORS. 4 | -------------------------------------------------------------------------------- /chapter11/monitoring/vendor/github.com/golang/protobuf/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This source code was written by the Go contributors. 2 | # The master list of contributors is in the main Go distribution, 3 | # visible at http://tip.golang.org/CONTRIBUTORS. 4 | -------------------------------------------------------------------------------- /chapter11/monitoring/vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2012 Matt T. Proud (matt.proud@gmail.com) 2 | -------------------------------------------------------------------------------- /chapter11/monitoring/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/.gitignore: -------------------------------------------------------------------------------- 1 | cover.dat 2 | -------------------------------------------------------------------------------- /chapter11/monitoring/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | 3 | cover: 4 | go test -cover -v -coverprofile=cover.dat ./... 5 | go tool cover -func cover.dat 6 | 7 | .PHONY: cover 8 | -------------------------------------------------------------------------------- /chapter11/monitoring/vendor/github.com/prometheus/client_golang/prometheus/.gitignore: -------------------------------------------------------------------------------- 1 | command-line-arguments.test 2 | -------------------------------------------------------------------------------- /chapter11/monitoring/vendor/github.com/prometheus/client_golang/prometheus/README.md: -------------------------------------------------------------------------------- 1 | See [![go-doc](https://godoc.org/github.com/prometheus/client_golang/prometheus?status.svg)](https://godoc.org/github.com/prometheus/client_golang/prometheus). 2 | -------------------------------------------------------------------------------- /chapter11/monitoring/vendor/github.com/prometheus/client_golang/prometheus/fnv.go: -------------------------------------------------------------------------------- 1 | package prometheus 2 | 3 | // Inline and byte-free variant of hash/fnv's fnv64a. 4 | 5 | const ( 6 | offset64 = 14695981039346656037 7 | prime64 = 1099511628211 8 | ) 9 | 10 | // hashNew initializies a new fnv64a hash value. 11 | func hashNew() uint64 { 12 | return offset64 13 | } 14 | 15 | // hashAdd adds a string to a fnv64a hash value, returning the updated hash. 16 | func hashAdd(h uint64, s string) uint64 { 17 | for i := 0; i < len(s); i++ { 18 | h ^= uint64(s[i]) 19 | h *= prime64 20 | } 21 | return h 22 | } 23 | 24 | // hashAddByte adds a byte to a fnv64a hash value, returning the updated hash. 25 | func hashAddByte(h uint64, b byte) uint64 { 26 | h ^= uint64(b) 27 | h *= prime64 28 | return h 29 | } 30 | -------------------------------------------------------------------------------- /chapter11/monitoring/vendor/github.com/prometheus/client_model/NOTICE: -------------------------------------------------------------------------------- 1 | Data model artifacts for Prometheus. 2 | Copyright 2012-2015 The Prometheus Authors 3 | 4 | This product includes software developed at 5 | SoundCloud Ltd. (http://soundcloud.com/). 6 | -------------------------------------------------------------------------------- /chapter11/monitoring/vendor/github.com/prometheus/common/NOTICE: -------------------------------------------------------------------------------- 1 | Common libraries shared by Prometheus Go components. 2 | Copyright 2015 The Prometheus Authors 3 | 4 | This product includes software developed at 5 | SoundCloud Ltd. (http://soundcloud.com/). 6 | -------------------------------------------------------------------------------- /chapter11/monitoring/vendor/github.com/prometheus/procfs/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: go 3 | go: 4 | - 1.6.4 5 | - 1.7.4 6 | -------------------------------------------------------------------------------- /chapter11/monitoring/vendor/github.com/prometheus/procfs/MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | * Tobias Schmidt 2 | -------------------------------------------------------------------------------- /chapter11/monitoring/vendor/github.com/prometheus/procfs/Makefile: -------------------------------------------------------------------------------- 1 | ci: 2 | ! gofmt -l *.go | read nothing 3 | go vet 4 | go test -v ./... 5 | go get github.com/golang/lint/golint 6 | golint *.go 7 | -------------------------------------------------------------------------------- /chapter11/monitoring/vendor/github.com/prometheus/procfs/NOTICE: -------------------------------------------------------------------------------- 1 | procfs provides functions to retrieve system, kernel and process 2 | metrics from the pseudo-filesystem proc. 3 | 4 | Copyright 2014-2015 The Prometheus Authors 5 | 6 | This product includes software developed at 7 | SoundCloud Ltd. (http://soundcloud.com/). 8 | -------------------------------------------------------------------------------- /chapter11/monitoring/vendor/github.com/prometheus/procfs/README.md: -------------------------------------------------------------------------------- 1 | # procfs 2 | 3 | This procfs package provides functions to retrieve system, kernel and process 4 | metrics from the pseudo-filesystem proc. 5 | 6 | *WARNING*: This package is a work in progress. Its API may still break in 7 | backwards-incompatible ways without warnings. Use it at your own risk. 8 | 9 | [![GoDoc](https://godoc.org/github.com/prometheus/procfs?status.png)](https://godoc.org/github.com/prometheus/procfs) 10 | [![Build Status](https://travis-ci.org/prometheus/procfs.svg?branch=master)](https://travis-ci.org/prometheus/procfs) 11 | [![Go Report Card](https://goreportcard.com/badge/github.com/prometheus/procfs)](https://goreportcard.com/report/github.com/prometheus/procfs) 12 | -------------------------------------------------------------------------------- /chapter11/orchestrate/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.12.4-alpine3.9 2 | 3 | ENV GOPATH /code/ 4 | ADD . /code/src/github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter11/docker 5 | WORKDIR /code/src/github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter11/docker/example 6 | RUN GO111MODULE=on GOPROXY=off go build -mod=vendor 7 | 8 | ENTRYPOINT /code/src/github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter11/docker/example/example 9 | 10 | 11 | -------------------------------------------------------------------------------- /chapter11/orchestrate/config.go: -------------------------------------------------------------------------------- 1 | package mongodb 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | 8 | "github.com/mongodb/mongo-go-driver/mongo" 9 | "go.mongodb.org/mongo-driver/mongo/options" 10 | ) 11 | 12 | // Setup initializes a mongo client 13 | func Setup(ctx context.Context, address string) (*mongo.Client, error) { 14 | ctx, cancel := context.WithTimeout(ctx, 1*time.Second) 15 | defer cancel() 16 | 17 | fmt.Println(address) 18 | client, err := mongo.NewClient(options.Client().ApplyURI(address)) 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | if err := client.Connect(ctx); err != nil { 24 | return nil, err 25 | } 26 | return client, nil 27 | } 28 | -------------------------------------------------------------------------------- /chapter11/orchestrate/config_test.go: -------------------------------------------------------------------------------- 1 | package mongodb 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | ) 7 | 8 | func TestSetup(t *testing.T) { 9 | tests := []struct { 10 | name string 11 | wantErr bool 12 | }{ 13 | {"base-case", false}, 14 | } 15 | for _, tt := range tests { 16 | t.Run(tt.name, func(t *testing.T) { 17 | _, err := Setup(context.Background()) 18 | if (err != nil) != tt.wantErr { 19 | t.Errorf("Setup() error = %v, wantErr %v", err, tt.wantErr) 20 | return 21 | } 22 | }) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter11/orchestrate/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | app: 4 | build: . 5 | mongodb: 6 | image: "mongo:latest" 7 | -------------------------------------------------------------------------------- /chapter11/orchestrate/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | mongodb "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter11/orchestrate" 5 | ) 6 | 7 | func main() { 8 | if err := mongodb.Exec("mongodb://mongodb:27017"); err != nil { 9 | panic(err) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /chapter11/orchestrate/exec_test.go: -------------------------------------------------------------------------------- 1 | package mongodb 2 | 3 | import "testing" 4 | 5 | func TestExec(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := Exec(); (err != nil) != tt.wantErr { 15 | t.Errorf("Exec() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter11/orchestrate/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter11/orchestrate 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter6/mongodb v0.0.0-20190324230957-113a4b73f13a 7 | github.com/golang/snappy v0.0.1 // indirect 8 | github.com/mongodb/mongo-go-driver v1.0.1 9 | go.mongodb.org/mongo-driver v1.0.1 10 | golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 // indirect 11 | golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect 12 | golang.org/x/text v0.3.2 // indirect 13 | ) 14 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/github.com/go-stack/stack/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | sudo: false 3 | go: 4 | - 1.7.x 5 | - 1.8.x 6 | - 1.9.x 7 | - 1.10.x 8 | - 1.11.x 9 | - tip 10 | 11 | before_install: 12 | - go get github.com/mattn/goveralls 13 | 14 | script: 15 | - goveralls -service=travis-ci 16 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/github.com/go-stack/stack/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-stack/stack 2 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/github.com/golang/snappy/.gitignore: -------------------------------------------------------------------------------- 1 | cmd/snappytool/snappytool 2 | testdata/bench 3 | 4 | # These explicitly listed benchmark data files are for an obsolete version of 5 | # snappy_test.go. 6 | testdata/alice29.txt 7 | testdata/asyoulik.txt 8 | testdata/fireworks.jpeg 9 | testdata/geo.protodata 10 | testdata/html 11 | testdata/html_x_4 12 | testdata/kppkn.gtb 13 | testdata/lcet10.txt 14 | testdata/paper-100k.pdf 15 | testdata/plrabn12.txt 16 | testdata/urls.10K 17 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/github.com/golang/snappy/AUTHORS: -------------------------------------------------------------------------------- 1 | # This is the official list of Snappy-Go authors for copyright purposes. 2 | # This file is distinct from the CONTRIBUTORS files. 3 | # See the latter for an explanation. 4 | 5 | # Names should be added to this file as 6 | # Name or Organization 7 | # The email address is not required for organizations. 8 | 9 | # Please keep the list sorted. 10 | 11 | Damian Gryski 12 | Google Inc. 13 | Jan Mercl <0xjnml@gmail.com> 14 | Rodolfo Carvalho 15 | Sebastien Binet 16 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/github.com/golang/snappy/decode_amd64.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Snappy-Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !appengine 6 | // +build gc 7 | // +build !noasm 8 | 9 | package snappy 10 | 11 | // decode has the same semantics as in decode_other.go. 12 | // 13 | //go:noescape 14 | func decode(dst, src []byte) int 15 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/github.com/golang/snappy/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/golang/snappy 2 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/github.com/mongodb/mongo-go-driver/mongo/util.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) MongoDB, Inc. 2017-present. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | package mongo 8 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/github.com/xdg/scram/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/ea3c94a784b061afc7e62ac9a4e7c5792d498769/chapter11/orchestrate/vendor/github.com/xdg/scram/.gitignore -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/github.com/xdg/scram/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | sudo: false 3 | go: 4 | - "1.7" 5 | - "1.8" 6 | - "1.9" 7 | - "1.10" 8 | - master 9 | matrix: 10 | allow_failures: 11 | - go: master 12 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/github.com/xdg/stringprep/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/ea3c94a784b061afc7e62ac9a4e7c5792d498769/chapter11/orchestrate/vendor/github.com/xdg/stringprep/.gitignore -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/github.com/xdg/stringprep/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | sudo: false 3 | go: 4 | - 1.7 5 | - 1.8 6 | - 1.9 7 | - master 8 | matrix: 9 | allow_failures: 10 | - go: master 11 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/github.com/xdg/stringprep/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 by David A. Golden. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | // Package stringprep provides data tables and algorithms for RFC-3454, 8 | // including errata (as of 2018-02). It also provides a profile for 9 | // SASLprep as defined in RFC-4013. 10 | package stringprep 11 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/github.com/xdg/stringprep/error.go: -------------------------------------------------------------------------------- 1 | package stringprep 2 | 3 | import "fmt" 4 | 5 | // Error describes problems encountered during stringprep, including what rune 6 | // was problematic. 7 | type Error struct { 8 | Msg string 9 | Rune rune 10 | } 11 | 12 | func (e Error) Error() string { 13 | return fmt.Sprintf("%s (rune: '\\u%04x')", e.Msg, e.Rune) 14 | } 15 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/proxy.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) MongoDB, Inc. 2017-present. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | package bsoncodec 8 | 9 | // Proxy is an interface implemented by types that cannot themselves be directly encoded. Types 10 | // that implement this interface with have ProxyBSON called during the encoding process and that 11 | // value will be encoded in place for the implementer. 12 | type Proxy interface { 13 | ProxyBSON() (interface{}, error) 14 | } 15 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) MongoDB, Inc. 2017-present. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | // Package bsonrw contains abstractions for reading and writing 8 | // BSON and BSON like types from sources. 9 | package bsonrw // import "go.mongodb.org/mongo-driver/bson/bsonrw" 10 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/go.mongodb.org/mongo-driver/internal/const.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) MongoDB, Inc. 2017-present. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | package internal // import "go.mongodb.org/mongo-driver/internal" 8 | 9 | // Version is the current version of the driver. 10 | var Version = "local build" 11 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/go.mongodb.org/mongo-driver/mongo/options/clientoptions_1_10.go: -------------------------------------------------------------------------------- 1 | // +build go1.10 2 | 3 | package options 4 | 5 | import "crypto/x509" 6 | 7 | func x509CertSubject(cert *x509.Certificate) string { 8 | return cert.Subject.String() 9 | } 10 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/go.mongodb.org/mongo-driver/mongo/options/clientoptions_1_9.go: -------------------------------------------------------------------------------- 1 | // +build !go1.10 2 | 3 | package options 4 | 5 | import ( 6 | "crypto/x509" 7 | ) 8 | 9 | // We don't support version less then 1.10, but Evergreen needs to be able to compile the driver 10 | // using version 1.8. 11 | func x509CertSubject(cert *x509.Certificate) string { 12 | return "" 13 | } 14 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/go.mongodb.org/mongo-driver/version/version.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) MongoDB, Inc. 2017-present. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | package version // import "go.mongodb.org/mongo-driver/version" 8 | 9 | // Driver is the current version of the driver. 10 | var Driver = "v1.0.1" 11 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/README.md: -------------------------------------------------------------------------------- 1 | MongoDB Go Driver Low-Level Driver Library 2 | ========================================== 3 | The packages within this library allow users to build applications using a low-level driver 4 | interface. Knowledge of the internals of a MongoDB driver are assumed, so this library contains 5 | advanced features. The aim of this library is to provide an easy to use, high performance 6 | implementation of a low-level driver. 7 | 8 | This Library's API is experimental and subject to change. Packages may be changed or removed without 9 | notice. These APIs are not stable and do not guarantee backward compatibility. 10 | 11 | **THIS LIBRARY IS EXPERIMENTAL AND SUBJECT TO CHANGE.** 12 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/auth/cred.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) MongoDB, Inc. 2017-present. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | package auth 8 | 9 | // Cred is a user's credential. 10 | type Cred struct { 11 | Source string 12 | Username string 13 | Password string 14 | PasswordSet bool 15 | Props map[string]string 16 | } 17 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/auth/gssapi_not_enabled.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) MongoDB, Inc. 2017-present. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | //+build !gssapi 8 | 9 | package auth 10 | 11 | // GSSAPI is the mechanism name for GSSAPI. 12 | const GSSAPI = "GSSAPI" 13 | 14 | func newGSSAPIAuthenticator(cred *Cred) (Authenticator, error) { 15 | return nil, newAuthError("GSSAPI support not enabled during build (-tags gssapi)", nil) 16 | } 17 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/auth/gssapi_not_supported.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) MongoDB, Inc. 2017-present. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | //+build gssapi,!windows,!linux,!darwin 8 | 9 | package auth 10 | 11 | import ( 12 | "fmt" 13 | "runtime" 14 | ) 15 | 16 | // GSSAPI is the mechanism name for GSSAPI. 17 | const GSSAPI = "GSSAPI" 18 | 19 | func newGSSAPIAuthenticator(cred *Cred) (Authenticator, error) { 20 | return nil, newAuthError(fmt.Sprintf("GSSAPI is not supported on %s", runtime.GOOS), nil) 21 | } 22 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/auth/util.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) MongoDB, Inc. 2017-present. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | package auth 8 | 9 | import ( 10 | "crypto/md5" 11 | "fmt" 12 | "io" 13 | ) 14 | 15 | const defaultAuthDB = "admin" 16 | 17 | func mongoPasswordDigest(username, password string) string { 18 | h := md5.New() 19 | _, _ = io.WriteString(h, username) 20 | _, _ = io.WriteString(h, ":mongo:") 21 | _, _ = io.WriteString(h, password) 22 | return fmt.Sprintf("%x", h.Sum(nil)) 23 | } 24 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/go.mongodb.org/mongo-driver/x/network/connection/keepalive_300.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) MongoDB, Inc. 2017-present. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | //+build !go1.12 8 | 9 | package connection 10 | 11 | import "time" 12 | 13 | const tcpKeepalive = 300 * time.Second 14 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/go.mongodb.org/mongo-driver/x/network/connection/keepalive_default.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) MongoDB, Inc. 2017-present. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | //+build go1.12 8 | 9 | package connection 10 | 11 | const tcpKeepalive = 0 // will be set by default on Go 1.12 and higher 12 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/go.mongodb.org/mongo-driver/x/network/description/description.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) MongoDB, Inc. 2017-present. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | package description // import "go.mongodb.org/mongo-driver/x/network/description" 8 | 9 | // Unknown is an unknown server or topology kind. 10 | const Unknown = 0 11 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/golang.org/x/crypto/AUTHORS: -------------------------------------------------------------------------------- 1 | # This source code refers to The Go Authors for copyright purposes. 2 | # The master list of authors is in the main Go distribution, 3 | # visible at https://tip.golang.org/AUTHORS. 4 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/golang.org/x/crypto/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This source code was written by the Go contributors. 2 | # The master list of contributors is in the main Go distribution, 3 | # visible at https://tip.golang.org/CONTRIBUTORS. 4 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/golang.org/x/sync/AUTHORS: -------------------------------------------------------------------------------- 1 | # This source code refers to The Go Authors for copyright purposes. 2 | # The master list of authors is in the main Go distribution, 3 | # visible at http://tip.golang.org/AUTHORS. 4 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/golang.org/x/sync/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This source code was written by the Go contributors. 2 | # The master list of contributors is in the main Go distribution, 3 | # visible at http://tip.golang.org/CONTRIBUTORS. 4 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/golang.org/x/text/AUTHORS: -------------------------------------------------------------------------------- 1 | # This source code refers to The Go Authors for copyright purposes. 2 | # The master list of authors is in the main Go distribution, 3 | # visible at http://tip.golang.org/AUTHORS. 4 | -------------------------------------------------------------------------------- /chapter11/orchestrate/vendor/golang.org/x/text/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This source code was written by the Go contributors. 2 | # The master list of contributors is in the main Go distribution, 3 | # visible at http://tip.golang.org/CONTRIBUTORS. 4 | -------------------------------------------------------------------------------- /chapter12/asynckafka/consumer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | sarama "github.com/Shopify/sarama" 7 | ) 8 | 9 | func main() { 10 | consumer, err := sarama.NewConsumer([]string{"localhost:9092"}, nil) 11 | if err != nil { 12 | panic(err) 13 | } 14 | defer consumer.Close() 15 | 16 | partitionConsumer, err := consumer.ConsumePartition("example", 0, sarama.OffsetNewest) 17 | if err != nil { 18 | panic(err) 19 | } 20 | defer partitionConsumer.Close() 21 | 22 | for { 23 | msg := <-partitionConsumer.Messages() 24 | log.Printf("Consumed message: \"%s\" at offset: %d\n", msg.Value, msg.Offset) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter12/asynckafka/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter12/asynckafka 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/Shopify/sarama v1.22.1 7 | github.com/golang/mock v1.3.1 8 | ) 9 | -------------------------------------------------------------------------------- /chapter12/asynckafka/producer/genmocks.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | mockgen -destination mocks_test.go -package main github.com/Shopify/sarama AsyncProducer 3 | -------------------------------------------------------------------------------- /chapter12/asynckafka/producer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | sarama "github.com/Shopify/sarama" 8 | ) 9 | 10 | func main() { 11 | config := sarama.NewConfig() 12 | config.Producer.Return.Successes = true 13 | config.Producer.Return.Errors = true 14 | producer, err := sarama.NewAsyncProducer([]string{"localhost:9092"}, config) 15 | if err != nil { 16 | panic(err) 17 | } 18 | defer producer.AsyncClose() 19 | 20 | go ProcessResponse(producer) 21 | 22 | c := KafkaController{producer} 23 | http.HandleFunc("/", c.Handler) 24 | fmt.Println("Listening on port :3333") 25 | panic(http.ListenAndServe(":3333", nil)) 26 | } 27 | -------------------------------------------------------------------------------- /chapter12/asynckafka/producer/producer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | sarama "github.com/Shopify/sarama" 7 | ) 8 | 9 | // Process response grabs results and errors from a producer 10 | // asynchronously 11 | func ProcessResponse(producer sarama.AsyncProducer) { 12 | for { 13 | select { 14 | case result := <-producer.Successes(): 15 | log.Printf("> message: \"%s\" sent to partition %d at offset %d\n", result.Value, result.Partition, result.Offset) 16 | case err := <-producer.Errors(): 17 | log.Println("Failed to produce message", err) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /chapter12/goflow/components.go: -------------------------------------------------------------------------------- 1 | package goflow 2 | 3 | import ( 4 | "encoding/base64" 5 | "fmt" 6 | ) 7 | 8 | // Encoder base64 encodes all input 9 | type Encoder struct { 10 | Val <-chan string 11 | Res chan<- string 12 | } 13 | 14 | // Process does the encoding then pushes the result onto Res 15 | func (e *Encoder) Process() { 16 | for val := range e.Val { 17 | encoded := base64.StdEncoding.EncodeToString([]byte(val)) 18 | e.Res <- fmt.Sprintf("%s => %s", val, encoded) 19 | } 20 | } 21 | 22 | // Printer is a component for printing to stdout 23 | type Printer struct { 24 | Line <-chan string 25 | } 26 | 27 | // Process Prints the current line received 28 | func (p *Printer) Process() { 29 | for line := range p.Line { 30 | fmt.Println(line) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /chapter12/goflow/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter12/goflow" 7 | flow "github.com/trustmaster/goflow" 8 | ) 9 | 10 | func main() { 11 | 12 | net := goflow.NewEncodingApp() 13 | 14 | in := make(chan string) 15 | net.SetInPort("In", in) 16 | 17 | wait := flow.Run(net) 18 | 19 | for i := 0; i < 20; i++ { 20 | in <- fmt.Sprint("Message", i) 21 | } 22 | 23 | close(in) 24 | <-wait 25 | } 26 | -------------------------------------------------------------------------------- /chapter12/goflow/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter12/goflow 2 | 3 | go 1.12 4 | 5 | require github.com/trustmaster/goflow v0.0.0-20190121210651-98ea6cda15a3 6 | -------------------------------------------------------------------------------- /chapter12/goflow/go.sum: -------------------------------------------------------------------------------- 1 | github.com/trustmaster/goflow v0.0.0-20190121210651-98ea6cda15a3 h1:rGqutWkRPVw9tvP9zYC/PC7cLyAQu6p47VB5q/JbTOM= 2 | github.com/trustmaster/goflow v0.0.0-20190121210651-98ea6cda15a3/go.mod h1:YDtu69AUfLyNCzpKgvLnWMT0CKIK2IWKj9pH+NqKU8g= 3 | -------------------------------------------------------------------------------- /chapter12/goflow/network.go: -------------------------------------------------------------------------------- 1 | package goflow 2 | 3 | import ( 4 | "github.com/trustmaster/goflow" 5 | ) 6 | 7 | // NewEncodingApp wires together the components 8 | func NewEncodingApp() *goflow.Graph { 9 | e := goflow.NewGraph() 10 | 11 | // define component types 12 | e.Add("encoder", new(Encoder)) 13 | e.Add("printer", new(Printer)) 14 | 15 | // connect the components using channels 16 | e.Connect("encoder", "Res", "printer", "Line") 17 | 18 | // map the in channel to Val, which is 19 | // tied to OnVal function 20 | e.MapInPort("In", "encoder", "Val") 21 | 22 | return e 23 | } 24 | -------------------------------------------------------------------------------- /chapter12/goflow/network_test.go: -------------------------------------------------------------------------------- 1 | package goflow 2 | 3 | import "testing" 4 | 5 | func TestNewEncodingApp(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | }{ 9 | {"base-case"}, 10 | } 11 | for _, tt := range tests { 12 | t.Run(tt.name, func(t *testing.T) { 13 | network := NewEncodingApp() 14 | if network == nil { 15 | t.Errorf("network unexpectedly nil") 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter12/graphql/cards/resolve.go: -------------------------------------------------------------------------------- 1 | package cards 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/graphql-go/graphql" 7 | ) 8 | 9 | // Resolve handles filtering cards 10 | // by suit and value 11 | func Resolve(p graphql.ResolveParams) (interface{}, error) { 12 | finalCards := []Card{} 13 | suit, suitOK := p.Args["suit"].(string) 14 | suit = strings.ToLower(suit) 15 | 16 | value, valueOK := p.Args["value"].(string) 17 | value = strings.ToLower(value) 18 | 19 | for _, card := range cards { 20 | if suitOK && suit != strings.ToLower(card.Suit) { 21 | continue 22 | } 23 | if valueOK && value != strings.ToLower(card.Value) { 24 | continue 25 | } 26 | 27 | finalCards = append(finalCards, card) 28 | } 29 | return finalCards, nil 30 | } 31 | -------------------------------------------------------------------------------- /chapter12/graphql/cards/schema_test.go: -------------------------------------------------------------------------------- 1 | package cards 2 | 3 | import "testing" 4 | 5 | func TestSetup(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | _, err := Setup() 15 | if (err != nil) != tt.wantErr { 16 | t.Errorf("Setup() error = %v, wantErr %v", err, tt.wantErr) 17 | return 18 | } 19 | }) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /chapter12/graphql/cards/type_test.go: -------------------------------------------------------------------------------- 1 | package cards 2 | 3 | import "testing" 4 | 5 | func TestCardType(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | }{ 9 | {"base-case"}, 10 | } 11 | for _, tt := range tests { 12 | t.Run(tt.name, func(t *testing.T) { 13 | CardType() 14 | }) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /chapter12/graphql/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter12/graphql 2 | 3 | go 1.12 4 | 5 | require github.com/graphql-go/graphql v0.7.8 6 | -------------------------------------------------------------------------------- /chapter12/graphql/go.sum: -------------------------------------------------------------------------------- 1 | github.com/graphql-go/graphql v0.7.8 h1:769CR/2JNAhLG9+aa8pfLkKdR0H+r5lsQqling5WwpU= 2 | github.com/graphql-go/graphql v0.7.8/go.mod h1:k6yrAYQaSP59DC5UVxbgxESlmVyojThKdORUqGDGmrI= 3 | -------------------------------------------------------------------------------- /chapter12/kafkaflow/components.go: -------------------------------------------------------------------------------- 1 | package kafkaflow 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | flow "github.com/trustmaster/goflow" 8 | ) 9 | 10 | // Upper upper cases the incoming 11 | // stream 12 | type Upper struct { 13 | Val <-chan string 14 | Res chan<- string 15 | } 16 | 17 | // Process loops over the input values and writes the upper 18 | // case string version of them to Res 19 | func (e *Upper) Process() { 20 | for val := range e.Val { 21 | e.Res <- strings.ToUpper(val) 22 | } 23 | } 24 | 25 | // Printer is a component for printing to stdout 26 | type Printer struct { 27 | flow.Component 28 | Line <-chan string 29 | } 30 | 31 | // Process Prints the current line received 32 | func (p *Printer) Process() { 33 | for line := range p.Line { 34 | fmt.Println(line) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /chapter12/kafkaflow/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter12/kafkaflow 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/Shopify/sarama v1.22.1 7 | github.com/trustmaster/goflow v0.0.0-20190121210651-98ea6cda15a3 8 | ) 9 | -------------------------------------------------------------------------------- /chapter12/kafkaflow/network.go: -------------------------------------------------------------------------------- 1 | package kafkaflow 2 | 3 | import "github.com/trustmaster/goflow" 4 | 5 | // NewUpperApp wires together the compoents 6 | func NewUpperApp() *goflow.Graph { 7 | u := goflow.NewGraph() 8 | 9 | u.Add("upper", new(Upper)) 10 | u.Add("printer", new(Printer)) 11 | 12 | u.Connect("upper", "Res", "printer", "Line") 13 | u.MapInPort("In", "upper", "Val") 14 | 15 | return u 16 | } 17 | -------------------------------------------------------------------------------- /chapter12/kafkaflow/network_test.go: -------------------------------------------------------------------------------- 1 | package kafkaflow 2 | 3 | import "testing" 4 | 5 | func TestNewUpperApp(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | }{ 9 | {"base-case"}, 10 | } 11 | for _, tt := range tests { 12 | t.Run(tt.name, func(t *testing.T) { 13 | NewUpperApp() 14 | }) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /chapter12/synckafka/consumer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | sarama "github.com/Shopify/sarama" 7 | ) 8 | 9 | func main() { 10 | consumer, err := sarama.NewConsumer([]string{"localhost:9092"}, nil) 11 | if err != nil { 12 | panic(err) 13 | } 14 | defer consumer.Close() 15 | 16 | partitionConsumer, err := consumer.ConsumePartition("example", 0, sarama.OffsetNewest) 17 | if err != nil { 18 | panic(err) 19 | } 20 | defer partitionConsumer.Close() 21 | 22 | for { 23 | msg := <-partitionConsumer.Messages() 24 | log.Printf("Consumed message: \"%s\" at offset: %d\n", msg.Value, msg.Offset) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter12/synckafka/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter12/synckafka 2 | 3 | go 1.12 4 | 5 | require github.com/Shopify/sarama v1.22.1 6 | -------------------------------------------------------------------------------- /chapter13/appengine/.gcloudignore: -------------------------------------------------------------------------------- 1 | # This file specifies files that are *not* uploaded to Google Cloud Platform 2 | # using gcloud. It follows the same syntax as .gitignore, with the addition of 3 | # "#!include" directives (which insert the entries of the given .gitignore-style 4 | # file at that point). 5 | # 6 | # For more information, run: 7 | # $ gcloud topic gcloudignore 8 | # 9 | .gcloudignore 10 | # If you would like to upload your .git directory, .gitignore file or files 11 | # from your .gitignore file, remove the corresponding line 12 | # below: 13 | .git 14 | .gitignore 15 | 16 | # Binaries for programs and plugins 17 | *.exe 18 | *.exe~ 19 | *.dll 20 | *.so 21 | *.dylib 22 | # Test binary, build with `go test -c` 23 | *.test 24 | # Output of the go coverage tool, specifically when used with LiteIDE 25 | *.out -------------------------------------------------------------------------------- /chapter13/appengine/app.yaml: -------------------------------------------------------------------------------- 1 | runtime: go112 2 | 3 | manual_scaling: 4 | instances: 1 5 | 6 | #[START env_variables] 7 | env_variables: 8 | GCLOUD_DATASET_ID: go-cookbook 9 | #[END env_variables] 10 | -------------------------------------------------------------------------------- /chapter13/appengine/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter13/appengine 2 | 3 | go 1.12 4 | 5 | require ( 6 | cloud.google.com/go v0.40.0 7 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 8 | google.golang.org/appengine v1.6.1 9 | ) 10 | -------------------------------------------------------------------------------- /chapter13/firebase/auth_test.go: -------------------------------------------------------------------------------- 1 | package firebase 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | ) 7 | 8 | func TestAuthenticate(t *testing.T) { 9 | type args struct { 10 | ctx context.Context 11 | collection string 12 | } 13 | tests := []struct { 14 | name string 15 | args args 16 | wantErr bool 17 | }{ 18 | {"base-case", args{context.Background(), "test"}, false}, 19 | } 20 | for _, tt := range tests { 21 | t.Run(tt.name, func(t *testing.T) { 22 | _, err := Authenticate(tt.args.ctx, tt.args.collection) 23 | if (err != nil) != tt.wantErr { 24 | t.Errorf("Authenticate() error = %v, wantErr %v", err, tt.wantErr) 25 | return 26 | } 27 | }) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /chapter13/firebase/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter13/firebase 2 | 3 | go 1.12 4 | 5 | require ( 6 | cloud.google.com/go v0.38.0 7 | firebase.google.com/go v3.8.1+incompatible 8 | github.com/pkg/errors v0.8.1 9 | github.com/stretchr/testify v1.3.0 // indirect 10 | github.com/zabawaba99/firego v0.0.0-20190331000051-3bcc4b6a4599 // indirect 11 | google.golang.org/api v0.6.0 12 | gopkg.in/zabawaba99/firego.v1 v1.0.0-20190331000051-3bcc4b6a4599 // indirect 13 | ) 14 | -------------------------------------------------------------------------------- /chapter13/lambda/functions/greeter1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/aws/aws-lambda-go/lambda" 8 | ) 9 | 10 | // Message is the input to the function and 11 | // includes a Name 12 | type Message struct { 13 | Name string `json:"name"` 14 | } 15 | 16 | // Response is sent back and contains a greeting 17 | // string 18 | type Response struct { 19 | Greeting string `json:"greeting"` 20 | } 21 | 22 | // HandleRequest will be called when the lambda function is invoked 23 | // it takes a Message and returns a Response that contains a greeting 24 | func HandleRequest(ctx context.Context, m Message) (Response, error) { 25 | return Response{Greeting: fmt.Sprintf("Hello, %s", m.Name)}, nil 26 | } 27 | 28 | func main() { 29 | lambda.Start(HandleRequest) 30 | } 31 | -------------------------------------------------------------------------------- /chapter13/lambda/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter13/labmda 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/apex/go-apex v1.0.0 7 | github.com/aws/aws-lambda-go v1.11.1 8 | ) 9 | -------------------------------------------------------------------------------- /chapter13/lambda/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "go-cookbook", 3 | "description": "Demonstrating Apex with the Go Cookbook", 4 | "memory": 128, 5 | "timeout": 5, 6 | "role": "arn:aws:iam::551033007273:role/go-cookbook_lambda_function", 7 | "environment": {} 8 | } -------------------------------------------------------------------------------- /chapter13/logging/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter13/logging 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/apex/go-apex v1.0.0 7 | github.com/apex/log v1.1.0 8 | github.com/aws/aws-lambda-go v1.11.1 9 | github.com/pkg/errors v0.8.1 // indirect 10 | ) 11 | -------------------------------------------------------------------------------- /chapter13/logging/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "logging", 3 | "description": "An example of apex logging and metrics", 4 | "memory": 128, 5 | "timeout": 5, 6 | "role": "arn:aws:iam::551033007273:role/logging_lambda_function", 7 | "environment": {} 8 | } -------------------------------------------------------------------------------- /chapter14/bench/atomic.go: -------------------------------------------------------------------------------- 1 | package bench 2 | 3 | import "sync/atomic" 4 | 5 | // AtomicCounter implements an atmoic lock 6 | // using the atomic package 7 | type AtomicCounter struct { 8 | value int64 9 | } 10 | 11 | // Add increments the counter 12 | func (c *AtomicCounter) Add(amount int64) { 13 | atomic.AddInt64(&c.value, amount) 14 | } 15 | 16 | // Read returns the current counter amount 17 | func (c *AtomicCounter) Read() int64 { 18 | var result int64 19 | result = atomic.LoadInt64(&c.value) 20 | return result 21 | } 22 | -------------------------------------------------------------------------------- /chapter14/bench/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter14/bench 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter14/bench/lock.go: -------------------------------------------------------------------------------- 1 | package bench 2 | 3 | import "sync" 4 | 5 | // Counter uses a sync.RWMutex to safely 6 | // modify a value 7 | type Counter struct { 8 | value int64 9 | mu *sync.RWMutex 10 | } 11 | 12 | // Add increments the counter 13 | func (c *Counter) Add(amount int64) { 14 | c.mu.Lock() 15 | c.value += amount 16 | c.mu.Unlock() 17 | } 18 | 19 | // Read returns the current counter amount 20 | func (c *Counter) Read() int64 { 21 | c.mu.RLock() 22 | defer c.mu.RUnlock() 23 | return c.value 24 | } 25 | -------------------------------------------------------------------------------- /chapter14/fastweb/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter14/fastweb 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/buaazp/fasthttprouter v0.1.1 7 | github.com/valyala/fasthttp v1.3.0 8 | ) 9 | -------------------------------------------------------------------------------- /chapter14/fastweb/handlers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/valyala/fasthttp" 7 | ) 8 | 9 | // GetItems will return our items object 10 | func GetItems(ctx *fasthttp.RequestCtx) { 11 | enc := json.NewEncoder(ctx) 12 | items := ReadItems() 13 | enc.Encode(&items) 14 | ctx.SetStatusCode(fasthttp.StatusOK) 15 | } 16 | 17 | // AddItems modifies our array 18 | func AddItems(ctx *fasthttp.RequestCtx) { 19 | item, ok := ctx.UserValue("item").(string) 20 | if !ok { 21 | ctx.SetStatusCode(fasthttp.StatusBadRequest) 22 | return 23 | } 24 | 25 | AddItem(item) 26 | ctx.SetStatusCode(fasthttp.StatusOK) 27 | } 28 | -------------------------------------------------------------------------------- /chapter14/fastweb/items.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | var items []string 8 | var mu *sync.RWMutex 9 | 10 | func init() { 11 | mu = &sync.RWMutex{} 12 | } 13 | 14 | // AddItem adds an item to our list 15 | // in a thread-safe way 16 | func AddItem(item string) { 17 | mu.Lock() 18 | items = append(items, item) 19 | mu.Unlock() 20 | } 21 | 22 | // ReadItems returns our list of items 23 | // in a thread-safe way 24 | func ReadItems() []string { 25 | mu.RLock() 26 | defer mu.RUnlock() 27 | return items 28 | } 29 | -------------------------------------------------------------------------------- /chapter14/fastweb/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | 7 | "github.com/buaazp/fasthttprouter" 8 | "github.com/valyala/fasthttp" 9 | ) 10 | 11 | func main() { 12 | router := fasthttprouter.New() 13 | router.GET("/item", GetItems) 14 | router.POST("/item/:item", AddItems) 15 | 16 | fmt.Println("server starting on localhost:8080") 17 | log.Fatal(fasthttp.ListenAndServe("localhost:8080", router.Handler)) 18 | } 19 | -------------------------------------------------------------------------------- /chapter14/pprof/crypto/handler_test.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "testing" 7 | ) 8 | 9 | func TestGuessHandler(t *testing.T) { 10 | type args struct { 11 | w http.ResponseWriter 12 | r *http.Request 13 | } 14 | tests := []struct { 15 | name string 16 | args args 17 | }{ 18 | {"bad guess", args{httptest.NewRecorder(), httptest.NewRequest("GET", "/guesses?message=test", nil)}}, 19 | {"good guess", args{httptest.NewRecorder(), httptest.NewRequest("GET", "/guesses?message=password", nil)}}, 20 | } 21 | for _, tt := range tests { 22 | t.Run(tt.name, func(t *testing.T) { 23 | GuessHandler(tt.args.w, tt.args.r) 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter14/pprof/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | _ "net/http/pprof" 8 | 9 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter14/pprof/crypto" 10 | ) 11 | 12 | func main() { 13 | 14 | http.HandleFunc("/guess", crypto.GuessHandler) 15 | fmt.Println("server started at localhost:8080") 16 | log.Panic(http.ListenAndServe("localhost:8080", nil)) 17 | } 18 | -------------------------------------------------------------------------------- /chapter14/pprof/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter14/pprof 2 | 3 | go 1.12 4 | 5 | require golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 6 | -------------------------------------------------------------------------------- /chapter14/pprof/go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 2 | golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 h1:8dUaAV7K4uHsF56JQWkprecIQKdPHtR9jCHF5nB8uzc= 3 | golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 4 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 5 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 6 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 7 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 8 | -------------------------------------------------------------------------------- /chapter14/tuning/concat.go: -------------------------------------------------------------------------------- 1 | package tuning 2 | 3 | func concat(vals ...string) string { 4 | finalVal := "" 5 | for i := 0; i < len(vals); i++ { 6 | finalVal += vals[i] 7 | if i != len(vals)-1 { 8 | finalVal += " " 9 | } 10 | } 11 | return finalVal 12 | } 13 | -------------------------------------------------------------------------------- /chapter14/tuning/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter14/tuning 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter14/tuning/join.go: -------------------------------------------------------------------------------- 1 | package tuning 2 | 3 | import "strings" 4 | 5 | func join(vals ...string) string { 6 | c := strings.Join(vals, " ") 7 | return c 8 | } 9 | -------------------------------------------------------------------------------- /chapter2/ansicolor/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter2/ansicolor" 7 | ) 8 | 9 | func main() { 10 | r := ansicolor.ColorText{ 11 | TextColor: ansicolor.Red, 12 | Text: "I'm red!", 13 | } 14 | 15 | fmt.Println(r.String()) 16 | 17 | r.TextColor = ansicolor.Green 18 | r.Text = "Now I'm green!" 19 | 20 | fmt.Println(r.String()) 21 | 22 | r.TextColor = ansicolor.ColorNone 23 | r.Text = "Back to normal..." 24 | 25 | fmt.Println(r.String()) 26 | } 27 | -------------------------------------------------------------------------------- /chapter2/ansicolor/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter2/ansicolor 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter2/cmdargs/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter2/cmdargs 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter2/confformat/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter2/confformat" 4 | 5 | func main() { 6 | if err := confformat.MarshalAll(); err != nil { 7 | panic(err) 8 | } 9 | 10 | if err := confformat.UnmarshalAll(); err != nil { 11 | panic(err) 12 | } 13 | 14 | if err := confformat.OtherJSONExamples(); err != nil { 15 | panic(err) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /chapter2/confformat/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter2/confformat 2 | 3 | require ( 4 | github.com/BurntSushi/toml v0.3.1 5 | github.com/go-yaml/yaml v2.1.0+incompatible 6 | github.com/kr/pretty v0.1.0 // indirect 7 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect 8 | gopkg.in/yaml.v2 v2.2.2 // indirect 9 | ) 10 | -------------------------------------------------------------------------------- /chapter2/confformat/marshal_test.go: -------------------------------------------------------------------------------- 1 | package confformat 2 | 3 | import "testing" 4 | 5 | func TestMarshalAll(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := MarshalAll(); (err != nil) != tt.wantErr { 15 | t.Errorf("MarshalAll() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter2/confformat/toml.go: -------------------------------------------------------------------------------- 1 | package confformat 2 | 3 | import ( 4 | "bytes" 5 | 6 | "github.com/BurntSushi/toml" 7 | ) 8 | 9 | // TOMLData is our common data struct 10 | // with TOML struct tags 11 | type TOMLData struct { 12 | Name string `toml:"name"` 13 | Age int `toml:"age"` 14 | } 15 | 16 | // ToTOML dumps the TOMLData struct to 17 | // a TOML format bytes.Buffer 18 | func (t *TOMLData) ToTOML() (*bytes.Buffer, error) { 19 | b := &bytes.Buffer{} 20 | encoder := toml.NewEncoder(b) 21 | 22 | if err := encoder.Encode(t); err != nil { 23 | return nil, err 24 | } 25 | return b, nil 26 | } 27 | 28 | // Decode will decode into TOMLData 29 | func (t *TOMLData) Decode(data []byte) (toml.MetaData, error) { 30 | return toml.Decode(string(data), t) 31 | } 32 | -------------------------------------------------------------------------------- /chapter2/confformat/unmarshal_test.go: -------------------------------------------------------------------------------- 1 | package confformat 2 | 3 | import "testing" 4 | 5 | func TestUnmarshalAll(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := UnmarshalAll(); (err != nil) != tt.wantErr { 15 | t.Errorf("UnmarshalAll() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter2/confformat/yaml.go: -------------------------------------------------------------------------------- 1 | package confformat 2 | 3 | import ( 4 | "bytes" 5 | 6 | "github.com/go-yaml/yaml" 7 | ) 8 | 9 | // YAMLData is our common data struct 10 | // with YAML struct tags 11 | type YAMLData struct { 12 | Name string `yaml:"name"` 13 | Age int `yaml:"age"` 14 | } 15 | 16 | // ToYAML dumps the YAMLData struct to 17 | // a YAML format bytes.Buffer 18 | func (t *YAMLData) ToYAML() (*bytes.Buffer, error) { 19 | d, err := yaml.Marshal(t) 20 | if err != nil { 21 | return nil, err 22 | } 23 | 24 | b := bytes.NewBuffer(d) 25 | 26 | return b, nil 27 | } 28 | 29 | // Decode will decode into TOMLData 30 | func (t *YAMLData) Decode(data []byte) error { 31 | return yaml.Unmarshal(data, t) 32 | } 33 | -------------------------------------------------------------------------------- /chapter2/envvar/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter2/envvar 2 | 3 | require ( 4 | github.com/kelseyhightower/envconfig v1.3.0 5 | github.com/pkg/errors v0.8.0 6 | ) 7 | -------------------------------------------------------------------------------- /chapter2/envvar/go.sum: -------------------------------------------------------------------------------- 1 | github.com/kelseyhightower/envconfig v1.3.0 h1:IvRS4f2VcIQy6j4ORGIf9145T/AsUB+oY8LyvN8BXNM= 2 | github.com/kelseyhightower/envconfig v1.3.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= 3 | github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= 4 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 5 | -------------------------------------------------------------------------------- /chapter2/flags/custom.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | // CountTheWays is a custom type that 10 | // we'll read a flag into 11 | type CountTheWays []int 12 | 13 | func (c *CountTheWays) String() string { 14 | result := "" 15 | for _, v := range *c { 16 | if len(result) > 0 { 17 | result += " ... " 18 | } 19 | result += fmt.Sprint(v) 20 | } 21 | return result 22 | } 23 | 24 | // Set will be used by the flag package 25 | func (c *CountTheWays) Set(value string) error { 26 | values := strings.Split(value, ",") 27 | 28 | for _, v := range values { 29 | i, err := strconv.Atoi(v) 30 | if err != nil { 31 | return err 32 | } 33 | *c = append(*c, i) 34 | } 35 | 36 | return nil 37 | } 38 | -------------------------------------------------------------------------------- /chapter2/flags/custom_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | -------------------------------------------------------------------------------- /chapter2/flags/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter2/flags 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter2/flags/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | // initialize our setup 10 | c := Config{} 11 | c.Setup() 12 | 13 | // generally call this from main 14 | flag.Parse() 15 | 16 | fmt.Println(c.GetMessage()) 17 | } 18 | -------------------------------------------------------------------------------- /chapter2/pipes/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter2/pipes 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter2/signals/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter2/signals 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter2/signals/signals_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | "testing" 7 | ) 8 | 9 | func TestCatchSig(t *testing.T) { 10 | signals := make(chan os.Signal) 11 | done := make(chan bool) 12 | type args struct { 13 | ch chan os.Signal 14 | done chan bool 15 | signal os.Signal 16 | } 17 | tests := []struct { 18 | name string 19 | args args 20 | }{ 21 | {"base-case", args{signals, done, syscall.SIGINT}}, 22 | {"sigterm", args{signals, done, syscall.SIGTERM}}, 23 | {"sigkill", args{signals, done, syscall.SIGKILL}}, 24 | } 25 | for _, tt := range tests { 26 | t.Run(tt.name, func(t *testing.T) { 27 | go CatchSig(tt.args.ch, tt.args.done) 28 | signals <- tt.args.signal 29 | <-done 30 | }) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /chapter3/collections/functions.go: -------------------------------------------------------------------------------- 1 | package collections 2 | 3 | import "strings" 4 | 5 | // LowerCaseData does a ToLower to the 6 | // Data string of a WorkWith 7 | func LowerCaseData(w WorkWith) WorkWith { 8 | w.Data = strings.ToLower(w.Data) 9 | return w 10 | } 11 | 12 | // IncrementVersion increments a WorkWiths 13 | // Version 14 | func IncrementVersion(w WorkWith) WorkWith { 15 | w.Version++ 16 | return w 17 | } 18 | 19 | // OldVersion returns a closures 20 | // that validates the version is greater than 21 | // the specified amount 22 | func OldVersion(v int) func(w WorkWith) bool { 23 | return func(w WorkWith) bool { 24 | return w.Version >= v 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter3/collections/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter3/collections 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter3/currency/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter3/currency" 7 | ) 8 | 9 | func main() { 10 | // start with our user input 11 | // of fifteen dollars and 93 cents 12 | userInput := "15.93" 13 | 14 | pennies, err := currency.ConvertStringDollarsToPennies(userInput) 15 | if err != nil { 16 | panic(err) 17 | } 18 | 19 | fmt.Printf("User input converted to %d pennies\n", pennies) 20 | 21 | // adding 15 cents 22 | pennies += 15 23 | 24 | dollars := currency.ConvertPenniesToDollarString(pennies) 25 | 26 | fmt.Printf("Added 15 cents, new values is %s dollars\n", dollars) 27 | } 28 | -------------------------------------------------------------------------------- /chapter3/currency/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter3/currency 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter3/currency/pennies_test.go: -------------------------------------------------------------------------------- 1 | package currency 2 | 3 | import "testing" 4 | 5 | func TestConvertPenniesToDollarString(t *testing.T) { 6 | type args struct { 7 | amount int64 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | want string 13 | }{ 14 | {"1 cent", args{1}, "0.01"}, 15 | {"10 cents", args{10}, "0.10"}, 16 | {"1 dollar", args{100}, "1.00"}, 17 | {"1 dollar 11 cents", args{111}, "1.11"}, 18 | {"-9 dollar 53 cents", args{-953}, "-9.53"}, 19 | } 20 | for _, tt := range tests { 21 | t.Run(tt.name, func(t *testing.T) { 22 | if got := ConvertPenniesToDollarString(tt.args.amount); got != tt.want { 23 | t.Errorf("ConvertPenniestoDollarString() = %v, want %v", got, tt.want) 24 | } 25 | }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /chapter3/dataconv/dataconv.go: -------------------------------------------------------------------------------- 1 | package dataconv 2 | 3 | import "fmt" 4 | 5 | // ShowConv demonstrates some type conversion 6 | func ShowConv() { 7 | // int 8 | var a = 24 9 | 10 | // float 64 11 | var b = 2.0 12 | 13 | // convert the int to a float64 for this calculation 14 | c := float64(a) * b 15 | fmt.Println(c) 16 | 17 | // fmt.Sprintf is a good way to convert to strings 18 | precision := fmt.Sprintf("%.2f", b) 19 | 20 | // print the value and the type 21 | fmt.Printf("%s - %T\n", precision, precision) 22 | } 23 | -------------------------------------------------------------------------------- /chapter3/dataconv/dataconv_test.go: -------------------------------------------------------------------------------- 1 | package dataconv 2 | 3 | import "testing" 4 | 5 | func TestShowConv(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | }{ 9 | {"base-case"}, 10 | } 11 | for _, tt := range tests { 12 | t.Run(tt.name, func(t *testing.T) { 13 | ShowConv() 14 | }) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /chapter3/dataconv/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter3/dataconv" 4 | 5 | func main() { 6 | dataconv.ShowConv() 7 | if err := dataconv.Strconv(); err != nil { 8 | panic(err) 9 | } 10 | dataconv.Interfaces() 11 | } 12 | -------------------------------------------------------------------------------- /chapter3/dataconv/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter3/dataconv 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter3/dataconv/interfaces_test.go: -------------------------------------------------------------------------------- 1 | package dataconv 2 | 3 | import "testing" 4 | 5 | func TestCheckType(t *testing.T) { 6 | type args struct { 7 | s interface{} 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | }{ 13 | {"string", args{"test"}}, 14 | {"int", args{1}}, 15 | {"bool", args{true}}, 16 | } 17 | for _, tt := range tests { 18 | t.Run(tt.name, func(t *testing.T) { 19 | CheckType(tt.args.s) 20 | }) 21 | } 22 | } 23 | 24 | func TestInterfaces(t *testing.T) { 25 | tests := []struct { 26 | name string 27 | }{ 28 | {"base-case"}, 29 | } 30 | for _, tt := range tests { 31 | t.Run(tt.name, func(t *testing.T) { 32 | Interfaces() 33 | }) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /chapter3/dataconv/strconv.go: -------------------------------------------------------------------------------- 1 | package dataconv 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | ) 7 | 8 | // Strconv demonstrates some strconv 9 | // functions 10 | func Strconv() error { 11 | //strconv is a good way to convert to and from strings 12 | s := "1234" 13 | // we can specify the base (10) and precision 14 | // 64 bit 15 | res, err := strconv.ParseInt(s, 10, 64) 16 | if err != nil { 17 | return err 18 | } 19 | 20 | fmt.Println(res) 21 | 22 | // lets try hex 23 | res, err = strconv.ParseInt("FF", 16, 64) 24 | if err != nil { 25 | return err 26 | } 27 | 28 | fmt.Println(res) 29 | 30 | // we can do other useful things like: 31 | val, err := strconv.ParseBool("true") 32 | if err != nil { 33 | return err 34 | } 35 | 36 | fmt.Println(val) 37 | 38 | return nil 39 | } 40 | -------------------------------------------------------------------------------- /chapter3/dataconv/strconv_test.go: -------------------------------------------------------------------------------- 1 | package dataconv 2 | 3 | import "testing" 4 | 5 | func TestStrconv(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := Strconv(); (err != nil) != tt.wantErr { 15 | t.Errorf("Strconv() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter3/encoding/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter3/encoding" 5 | ) 6 | 7 | func main() { 8 | if err := encoding.Base64Example(); err != nil { 9 | panic(err) 10 | } 11 | 12 | if err := encoding.Base64ExampleEncoder(); err != nil { 13 | panic(err) 14 | } 15 | 16 | if err := encoding.GobExample(); err != nil { 17 | panic(err) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter3/encoding/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter3/encoding 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter3/encoding/gob_test.go: -------------------------------------------------------------------------------- 1 | package encoding 2 | 3 | import "testing" 4 | 5 | func TestGobExample(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := GobExample(); (err != nil) != tt.wantErr { 15 | t.Errorf("GobExample() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter3/math/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter3/math" 7 | ) 8 | 9 | func main() { 10 | math.Examples() 11 | 12 | for i := 0; i < 10; i++ { 13 | fmt.Printf("%v ", math.Fib(i)) 14 | } 15 | fmt.Println() 16 | } 17 | -------------------------------------------------------------------------------- /chapter3/math/fib_test.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | import ( 4 | "math/big" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | func TestFib(t *testing.T) { 10 | b := big.NewInt(1) 11 | b.SetString("573147844013817084101", 10) 12 | type args struct { 13 | n int 14 | } 15 | tests := []struct { 16 | name string 17 | args args 18 | want *big.Int 19 | }{ 20 | {"n = 0", args{0}, big.NewInt(1)}, 21 | {"n = 1", args{1}, big.NewInt(1)}, 22 | {"n = 2", args{2}, big.NewInt(2)}, 23 | {"n = 3", args{3}, big.NewInt(3)}, 24 | {"n = 100", args{100}, b}, 25 | } 26 | for _, tt := range tests { 27 | t.Run(tt.name, func(t *testing.T) { 28 | if got := Fib(tt.args.n); !reflect.DeepEqual(got, tt.want) { 29 | t.Errorf("Fib() = %v, want %v", got, tt.want) 30 | } 31 | }) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /chapter3/math/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter3/math 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter3/math/math.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | ) 7 | 8 | // Examples demonstrates some of the functions 9 | // in the math package 10 | func Examples() { 11 | //sqrt Examples 12 | i := 25 13 | 14 | // i is an int, so convert 15 | result := math.Sqrt(float64(i)) 16 | 17 | // sqrt of 25 == 5 18 | fmt.Println(result) 19 | 20 | // ceil rounds up 21 | result = math.Ceil(9.5) 22 | fmt.Println(result) 23 | 24 | // floor rounds down 25 | result = math.Floor(9.5) 26 | fmt.Println(result) 27 | 28 | // math also stores some consts: 29 | fmt.Println("Pi:", math.Pi, "E:", math.E) 30 | } 31 | -------------------------------------------------------------------------------- /chapter3/math/math_test.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | import "testing" 4 | 5 | func TestExamples(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | }{ 9 | {"base-case"}, 10 | } 11 | for _, tt := range tests { 12 | t.Run(tt.name, func(t *testing.T) { 13 | Examples() 14 | }) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /chapter3/nulls/base_test.go: -------------------------------------------------------------------------------- 1 | package nulls 2 | 3 | import "testing" 4 | 5 | func TestBaseEncoding(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := BaseEncoding(); (err != nil) != tt.wantErr { 15 | t.Errorf("BaseEncoding() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter3/nulls/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter3/nulls" 7 | ) 8 | 9 | func main() { 10 | if err := nulls.BaseEncoding(); err != nil { 11 | panic(err) 12 | } 13 | fmt.Println() 14 | 15 | if err := nulls.PointerEncoding(); err != nil { 16 | panic(err) 17 | } 18 | fmt.Println() 19 | 20 | if err := nulls.NullEncoding(); err != nil { 21 | panic(err) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /chapter3/nulls/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter3/nulls 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter3/nulls/pointer_test.go: -------------------------------------------------------------------------------- 1 | package nulls 2 | 3 | import "testing" 4 | 5 | func TestPointerEncoding(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := PointerEncoding(); (err != nil) != tt.wantErr { 15 | t.Errorf("PointerEncoding() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter3/tags/deserialize_test.go: -------------------------------------------------------------------------------- 1 | package tags 2 | 3 | import "testing" 4 | 5 | func TestDeSerializeStructStrings(t *testing.T) { 6 | p := Person{} 7 | type args struct { 8 | s string 9 | res interface{} 10 | } 11 | tests := []struct { 12 | name string 13 | args args 14 | wantErr bool 15 | }{ 16 | {"base-case", args{"name:name;city:city;State:state;", &p}, false}, 17 | {"base-case", args{"name:name;city:city;State:state;", p}, true}, 18 | } 19 | for _, tt := range tests { 20 | t.Run(tt.name, func(t *testing.T) { 21 | if err := DeSerializeStructStrings(tt.args.s, tt.args.res); (err != nil) != tt.wantErr { 22 | t.Errorf("DeSerializeStructStrings() error = %v, wantErr %v", err, tt.wantErr) 23 | } 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter3/tags/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter3/tags" 7 | ) 8 | 9 | func main() { 10 | 11 | if err := tags.EmptyStruct(); err != nil { 12 | panic(err) 13 | } 14 | 15 | fmt.Println() 16 | 17 | if err := tags.FullStruct(); err != nil { 18 | panic(err) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /chapter3/tags/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter3/tags 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter4/basicerrors/basicerrors_test.go: -------------------------------------------------------------------------------- 1 | package basicerrors 2 | 3 | import "testing" 4 | 5 | func TestBasicErrors(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | }{ 9 | {"base-case"}, 10 | } 11 | for _, tt := range tests { 12 | t.Run(tt.name, func(t *testing.T) { 13 | BasicErrors() 14 | }) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /chapter4/basicerrors/custom.go: -------------------------------------------------------------------------------- 1 | package basicerrors 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // CustomError is a struct that will implement 8 | // the Error() interface 9 | type CustomError struct { 10 | Result string 11 | } 12 | 13 | func (c CustomError) Error() string { 14 | return fmt.Sprintf("there was an error; %s was the result", c.Result) 15 | } 16 | 17 | // SomeFunc returns an error 18 | func SomeFunc() error { 19 | c := CustomError{Result: "this"} 20 | return c 21 | } 22 | -------------------------------------------------------------------------------- /chapter4/basicerrors/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter4/basicerrors" 7 | ) 8 | 9 | func main() { 10 | basicerrors.BasicErrors() 11 | 12 | err := basicerrors.SomeFunc() 13 | fmt.Println("custom error: ", err) 14 | } 15 | -------------------------------------------------------------------------------- /chapter4/basicerrors/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter4/basicerrors 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter4/context/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter4/context" 4 | 5 | func main() { 6 | context.Initialize() 7 | } 8 | -------------------------------------------------------------------------------- /chapter4/context/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter4/context 2 | 3 | require ( 4 | github.com/apex/log v1.1.0 5 | github.com/pkg/errors v0.8.0 // indirect 6 | github.com/stretchr/testify v1.3.0 // indirect 7 | ) 8 | -------------------------------------------------------------------------------- /chapter4/context/log_test.go: -------------------------------------------------------------------------------- 1 | package context 2 | 3 | import ( 4 | "context" 5 | "reflect" 6 | "testing" 7 | 8 | "github.com/apex/log" 9 | ) 10 | 11 | func Test_getFields(t *testing.T) { 12 | type args struct { 13 | ctx context.Context 14 | } 15 | tests := []struct { 16 | name string 17 | args args 18 | want *log.Fields 19 | }{ 20 | {"base-case", args{context.Background()}, &log.Fields{}}, 21 | } 22 | for _, tt := range tests { 23 | t.Run(tt.name, func(t *testing.T) { 24 | if got := getFields(tt.args.ctx); !reflect.DeepEqual(got, tt.want) { 25 | t.Errorf("getFields() = %v, want %v", got, tt.want) 26 | } 27 | }) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /chapter4/errwrap/errwrap.go: -------------------------------------------------------------------------------- 1 | package errwrap 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/pkg/errors" 7 | ) 8 | 9 | // WrappedError demonstrates error wrapping and 10 | // annotating an error 11 | func WrappedError(e error) error { 12 | return errors.Wrap(e, "An error occurred in WrappedError") 13 | } 14 | 15 | // ErrorTyped is a error we can check against 16 | type ErrorTyped struct { 17 | error 18 | } 19 | 20 | // Wrap shows what happens when we wrap an error 21 | func Wrap() { 22 | e := errors.New("standard error") 23 | 24 | fmt.Println("Regular Error - ", WrappedError(e)) 25 | 26 | fmt.Println("Typed Error - ", WrappedError(ErrorTyped{errors.New("typed error")})) 27 | 28 | fmt.Println("Nil -", WrappedError(nil)) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /chapter4/errwrap/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter4/errwrap" 7 | ) 8 | 9 | func main() { 10 | errwrap.Wrap() 11 | fmt.Println() 12 | errwrap.Unwrap() 13 | fmt.Println() 14 | errwrap.StackTrace() 15 | } 16 | -------------------------------------------------------------------------------- /chapter4/errwrap/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter4/errwrap 2 | 3 | require github.com/pkg/errors v0.8.0 4 | -------------------------------------------------------------------------------- /chapter4/errwrap/go.sum: -------------------------------------------------------------------------------- 1 | github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= 2 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 3 | -------------------------------------------------------------------------------- /chapter4/errwrap/unwrap_test.go: -------------------------------------------------------------------------------- 1 | package errwrap 2 | 3 | import "testing" 4 | 5 | func TestUnwrap(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | }{ 9 | {"base-case"}, 10 | } 11 | for _, tt := range tests { 12 | t.Run(tt.name, func(t *testing.T) { 13 | Unwrap() 14 | }) 15 | } 16 | } 17 | 18 | func TestStackTrace(t *testing.T) { 19 | tests := []struct { 20 | name string 21 | }{ 22 | {"base-case"}, 23 | } 24 | for _, tt := range tests { 25 | t.Run(tt.name, func(t *testing.T) { 26 | StackTrace() 27 | }) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /chapter4/global/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter4/global" 4 | 5 | func main() { 6 | if err := global.UseLog(); err != nil { 7 | panic(err) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /chapter4/global/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter4/global 2 | 3 | require github.com/sirupsen/logrus v1.2.0 4 | -------------------------------------------------------------------------------- /chapter4/global/log.go: -------------------------------------------------------------------------------- 1 | package global 2 | 3 | // UseLog demonstrates using our global 4 | // log 5 | func UseLog() error { 6 | if err := Init(); err != nil { 7 | return err 8 | } 9 | 10 | // if we were in another package these would be 11 | // global.WithField and 12 | // global.Debug 13 | WithField("key", "value").Debug("hello") 14 | Debug("test") 15 | 16 | return nil 17 | } 18 | -------------------------------------------------------------------------------- /chapter4/global/log_test.go: -------------------------------------------------------------------------------- 1 | package global 2 | 3 | import "testing" 4 | 5 | func TestUseLog(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", true}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := UseLog(); (err != nil) != tt.wantErr { 15 | t.Errorf("UseLog() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter4/log/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter4/log" 7 | ) 8 | 9 | func main() { 10 | fmt.Println("basic logging and modification of logger:") 11 | log.Log() 12 | fmt.Println("logging 'handled' errors:") 13 | log.FinalDestination() 14 | } 15 | -------------------------------------------------------------------------------- /chapter4/log/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter4/log 2 | 3 | require github.com/pkg/errors v0.8.0 4 | -------------------------------------------------------------------------------- /chapter4/log/go.sum: -------------------------------------------------------------------------------- 1 | github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= 2 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 3 | -------------------------------------------------------------------------------- /chapter4/log/log.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "log" 7 | ) 8 | 9 | // Log uses the setup logger 10 | func Log() { 11 | // we'll configure the logger to write 12 | // to a bytes.Buffer 13 | buf := bytes.Buffer{} 14 | 15 | // second argument is the prefix last argument is about options 16 | // you combine them with a logical or. 17 | logger := log.New(&buf, "logger: ", log.Lshortfile|log.Ldate) 18 | 19 | logger.Println("test") 20 | 21 | logger.SetPrefix("new logger: ") 22 | 23 | logger.Printf("you can also add args(%v) and use Fatalln to log and crash", true) 24 | 25 | fmt.Println(buf.String()) 26 | } 27 | -------------------------------------------------------------------------------- /chapter4/log/log_test.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import "testing" 4 | 5 | func TestLog(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | }{ 9 | {"base-case"}, 10 | } 11 | for _, tt := range tests { 12 | t.Run(tt.name, func(t *testing.T) { 13 | Log() 14 | }) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /chapter4/panic/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter4/panic" 7 | ) 8 | 9 | func main() { 10 | fmt.Println("before panic") 11 | panic.Catcher() 12 | fmt.Println("after panic") 13 | } 14 | -------------------------------------------------------------------------------- /chapter4/panic/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter4/panic 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter4/panic/panic.go: -------------------------------------------------------------------------------- 1 | package panic 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | ) 7 | 8 | // Panic panics with a divide by zero 9 | func Panic() { 10 | zero, err := strconv.ParseInt("0", 10, 64) 11 | if err != nil { 12 | panic(err) 13 | } 14 | 15 | a := 1 / zero 16 | fmt.Println("we'll never get here", a) 17 | } 18 | 19 | // Catcher calls Panic 20 | func Catcher() { 21 | defer func() { 22 | if r := recover(); r != nil { 23 | fmt.Println("panic occurred:", r) 24 | } 25 | }() 26 | Panic() 27 | } 28 | -------------------------------------------------------------------------------- /chapter4/structured/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter4/structured" 7 | ) 8 | 9 | func main() { 10 | fmt.Println("Logrus:") 11 | structured.Logrus() 12 | 13 | fmt.Println() 14 | fmt.Println("Apex:") 15 | structured.Apex() 16 | } 17 | -------------------------------------------------------------------------------- /chapter4/structured/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter4/structured 2 | 3 | require ( 4 | github.com/apex/log v1.1.0 5 | github.com/pkg/errors v0.8.0 // indirect 6 | github.com/sirupsen/logrus v1.2.0 7 | ) 8 | -------------------------------------------------------------------------------- /chapter5/dns/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter5/dns" 9 | ) 10 | 11 | func main() { 12 | if len(os.Args) < 2 { 13 | fmt.Printf("Usage: %s
\n", os.Args[0]) 14 | os.Exit(1) 15 | } 16 | address := os.Args[1] 17 | lookup, err := dns.LookupAddress(address) 18 | if err != nil { 19 | log.Panicf("failed to lookup: %s", err.Error()) 20 | } 21 | fmt.Println(lookup) 22 | } 23 | -------------------------------------------------------------------------------- /chapter5/dns/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter5/dns 2 | 3 | go 1.12 4 | 5 | require github.com/pkg/errors v0.8.1 6 | -------------------------------------------------------------------------------- /chapter5/dns/go.sum: -------------------------------------------------------------------------------- 1 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 2 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 3 | -------------------------------------------------------------------------------- /chapter5/mail/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter5/mail 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter5/rpc/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/rpc" 7 | 8 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter5/rpc/tweak" 9 | ) 10 | 11 | func main() { 12 | client, err := rpc.DialHTTP("tcp", "localhost:1234") 13 | if err != nil { 14 | log.Fatal("error dialing:", err) 15 | } 16 | 17 | args := tweak.Args{ 18 | String: "this string should be uppercase and reversed", 19 | ToUpper: true, 20 | Reverse: true, 21 | } 22 | var result string 23 | err = client.Call("StringTweaker.Tweak", args, &result) 24 | if err != nil { 25 | log.Fatal("client call with error:", err) 26 | } 27 | fmt.Printf("the result is: %s", result) 28 | } 29 | -------------------------------------------------------------------------------- /chapter5/rpc/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter5/rpc 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter5/rpc/server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net" 7 | "net/http" 8 | "net/rpc" 9 | 10 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter5/rpc/tweak" 11 | ) 12 | 13 | func main() { 14 | s := new(tweak.StringTweaker) 15 | if err := rpc.Register(s); err != nil { 16 | log.Fatal("failed to register:", err) 17 | } 18 | 19 | rpc.HandleHTTP() 20 | 21 | l, err := net.Listen("tcp", ":1234") 22 | if err != nil { 23 | log.Fatal("listen error:", err) 24 | } 25 | 26 | fmt.Println("listening on :1234") 27 | log.Panic(http.Serve(l, nil)) 28 | } 29 | -------------------------------------------------------------------------------- /chapter5/tcp/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter5/tcp 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter5/udp/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | ) 7 | 8 | const addr = "localhost:8888" 9 | 10 | func main() { 11 | fmt.Printf("client for server url: %s\n", addr) 12 | 13 | addr, err := net.ResolveUDPAddr("udp", addr) 14 | if err != nil { 15 | panic(err) 16 | } 17 | 18 | conn, err := net.DialUDP("udp", nil, addr) 19 | if err != nil { 20 | panic(err) 21 | } 22 | defer conn.Close() 23 | 24 | msg := make([]byte, 512) 25 | n, err := conn.Write([]byte("connected")) 26 | if err != nil { 27 | panic(err) 28 | } 29 | for { 30 | n, err = conn.Read(msg) 31 | if err != nil { 32 | continue 33 | } 34 | fmt.Printf("%s\n", string(msg[:n])) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /chapter5/udp/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter5/udp 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter5/udp/server/broadcast.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | type connections struct { 11 | addrs map[string]*net.UDPAddr 12 | // lock for modifying the map 13 | mu sync.Mutex 14 | } 15 | 16 | func broadcast(conn *net.UDPConn, conns *connections) { 17 | count := 0 18 | for { 19 | count++ 20 | conns.mu.Lock() 21 | // loop over known addresses 22 | for _, retAddr := range conns.addrs { 23 | 24 | // send a message to them all 25 | msg := fmt.Sprintf("Sent %d", count) 26 | if _, err := conn.WriteToUDP([]byte(msg), retAddr); err != nil { 27 | fmt.Printf("error encountered: %s", err.Error()) 28 | continue 29 | } 30 | 31 | } 32 | conns.mu.Unlock() 33 | time.Sleep(1 * time.Second) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /chapter5/websocket/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter5/websocket 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/apex/log v1.1.0 // indirect 7 | github.com/gorilla/websocket v1.4.0 8 | github.com/pkg/errors v0.8.1 // indirect 9 | github.com/stretchr/testify v1.3.0 // indirect 10 | ) 11 | -------------------------------------------------------------------------------- /chapter5/websocket/server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | ) 8 | 9 | func main() { 10 | fmt.Println("Listening on port :8000") 11 | // we mount our single handler on port localhost:8000 to handle all 12 | // requests 13 | log.Panic(http.ListenAndServe("localhost:8000", http.HandlerFunc(wsHandler))) 14 | } 15 | -------------------------------------------------------------------------------- /chapter6/database/config.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "os" 7 | "time" 8 | 9 | _ "github.com/go-sql-driver/mysql" //we import supported libraries for database/sql 10 | ) 11 | 12 | // Example hold the results of our queries 13 | type Example struct { 14 | Name string 15 | Created *time.Time 16 | } 17 | 18 | // Setup configures and returns our database 19 | // connection poold 20 | func Setup() (*sql.DB, error) { 21 | db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@/gocookbook?parseTime=true", os.Getenv("MYSQLUSERNAME"), os.Getenv("MYSQLPASSWORD"))) 22 | if err != nil { 23 | return nil, err 24 | } 25 | return db, nil 26 | } 27 | -------------------------------------------------------------------------------- /chapter6/database/config_test.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "testing" 5 | 6 | _ "github.com/go-sql-driver/mysql" 7 | ) 8 | 9 | func TestSetup(t *testing.T) { 10 | tests := []struct { 11 | name string 12 | wantErr bool 13 | }{ 14 | {"base-case", false}, 15 | } 16 | for _, tt := range tests { 17 | t.Run(tt.name, func(t *testing.T) { 18 | _, err := Setup() 19 | if (err != nil) != tt.wantErr { 20 | t.Errorf("Setup() error = %v, wantErr %v", err, tt.wantErr) 21 | return 22 | } 23 | }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /chapter6/database/create.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "database/sql" 5 | 6 | _ "github.com/go-sql-driver/mysql" //we import supported libraries for database/sql 7 | ) 8 | 9 | // Create makes a table called example 10 | // and populates it 11 | func Create(db *sql.DB) error { 12 | // create the database 13 | if _, err := db.Exec("CREATE TABLE example (name VARCHAR(20), created DATETIME)"); err != nil { 14 | return err 15 | } 16 | 17 | if _, err := db.Exec(`INSERT INTO example (name, created) values ("Aaron", NOW())`); err != nil { 18 | return err 19 | } 20 | 21 | return nil 22 | } 23 | -------------------------------------------------------------------------------- /chapter6/database/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter6/database" 5 | _ "github.com/go-sql-driver/mysql" //we import supported libraries for database/sql 6 | ) 7 | 8 | func main() { 9 | db, err := database.Setup() 10 | if err != nil { 11 | panic(err) 12 | } 13 | 14 | if err := database.Exec(db); err != nil { 15 | panic(err) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /chapter6/database/exec.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "database/sql" 5 | 6 | _ "github.com/go-sql-driver/mysql" //we import supported libraries for database/sql 7 | ) 8 | 9 | // Exec takes a new connection 10 | // creates tables, and later drops them 11 | // and issues some queries 12 | func Exec(db *sql.DB) error { 13 | // uncaught error on cleanup, but we always 14 | // want to cleanup 15 | defer db.Exec("DROP TABLE example") 16 | 17 | if err := Create(db); err != nil { 18 | return err 19 | } 20 | 21 | if err := Query(db, "Aaron"); err != nil { 22 | return err 23 | } 24 | return nil 25 | } 26 | -------------------------------------------------------------------------------- /chapter6/database/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter6/database 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/DATA-DOG/go-sqlmock v1.3.3 7 | github.com/go-sql-driver/mysql v1.4.1 8 | google.golang.org/appengine v1.5.0 // indirect 9 | ) 10 | -------------------------------------------------------------------------------- /chapter6/database/query.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | 7 | _ "github.com/go-sql-driver/mysql" //we import supported libraries for database/sql 8 | ) 9 | 10 | // Query grabs a new connection 11 | // creates tables, and later drops them 12 | // and issues some queries 13 | func Query(db *sql.DB, name string) error { 14 | rows, err := db.Query("SELECT name, created FROM example where name=?", name) 15 | if err != nil { 16 | return err 17 | } 18 | defer rows.Close() 19 | for rows.Next() { 20 | var e Example 21 | if err := rows.Scan(&e.Name, &e.Created); err != nil { 22 | return err 23 | } 24 | fmt.Printf("Results:\n\tName: %s\n\tCreated: %v\n", e.Name, e.Created) 25 | } 26 | return rows.Err() 27 | } 28 | -------------------------------------------------------------------------------- /chapter6/dbinterface/create.go: -------------------------------------------------------------------------------- 1 | package dbinterface 2 | 3 | import _ "github.com/go-sql-driver/mysql" //we import supported libraries for database/sql 4 | 5 | // Create makes a table called example 6 | // and populates it 7 | func Create(db DB) error { 8 | // create the database 9 | if _, err := db.Exec("CREATE TABLE example (name VARCHAR(20), created DATETIME)"); err != nil { 10 | return err 11 | } 12 | 13 | if _, err := db.Exec(`INSERT INTO example (name, created) values ("Aaron", NOW())`); err != nil { 14 | return err 15 | } 16 | 17 | return nil 18 | } 19 | -------------------------------------------------------------------------------- /chapter6/dbinterface/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter6/database" 5 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter6/dbinterface" 6 | _ "github.com/go-sql-driver/mysql" //we import supported libraries for database/sql 7 | ) 8 | 9 | func main() { 10 | db, err := database.Setup() 11 | if err != nil { 12 | panic(err) 13 | } 14 | 15 | tx, err := db.Begin() 16 | if err != nil { 17 | panic(err) 18 | } 19 | // this wont do anything if commit is successful 20 | defer tx.Rollback() 21 | 22 | if err := dbinterface.Exec(tx); err != nil { 23 | panic(err) 24 | } 25 | if err := tx.Commit(); err != nil { 26 | panic(err) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /chapter6/dbinterface/exec.go: -------------------------------------------------------------------------------- 1 | package dbinterface 2 | 3 | // Exec replaces the Exec from the previous 4 | // recipe 5 | func Exec(db DB) error { 6 | 7 | // uncaught error on cleanup, but we always 8 | // want to cleanup 9 | defer db.Exec("DROP TABLE example") 10 | 11 | if err := Create(db); err != nil { 12 | return err 13 | } 14 | 15 | if err := Query(db); err != nil { 16 | return err 17 | } 18 | return nil 19 | } 20 | -------------------------------------------------------------------------------- /chapter6/dbinterface/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter6/dbinterface 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/DATA-DOG/go-sqlmock v1.3.0 7 | github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter6/database v0.0.0-20190106211135-24627479067b 8 | github.com/go-sql-driver/mysql v1.4.1 9 | github.com/golang/mock v1.2.0 10 | google.golang.org/appengine v1.5.0 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /chapter6/dbinterface/mockgen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | mockgen -destination mocks_test.go -package dbinterface github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter6/dbinterface DB,Transaction 3 | -------------------------------------------------------------------------------- /chapter6/dbinterface/query.go: -------------------------------------------------------------------------------- 1 | package dbinterface 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter6/database" 7 | ) 8 | 9 | // Query grabs a new connection 10 | // and issues some queries printing the results 11 | func Query(db DB) error { 12 | name := "Aaron" 13 | rows, err := db.Query("SELECT name, created FROM example where name=?", name) 14 | if err != nil { 15 | return err 16 | } 17 | defer rows.Close() 18 | for rows.Next() { 19 | var e database.Example 20 | if err := rows.Scan(&e.Name, &e.Created); err != nil { 21 | return err 22 | } 23 | fmt.Printf("Results:\n\tName: %s\n\tCreated: %v\n", e.Name, e.Created) 24 | } 25 | return rows.Err() 26 | } 27 | -------------------------------------------------------------------------------- /chapter6/dbinterface/transaction.go: -------------------------------------------------------------------------------- 1 | package dbinterface 2 | 3 | import "database/sql" 4 | 5 | // DB is an interface that is satisfied 6 | // by an sql.DB or an sql.Transaction 7 | type DB interface { 8 | Exec(query string, args ...interface{}) (sql.Result, error) 9 | Prepare(query string) (*sql.Stmt, error) 10 | Query(query string, args ...interface{}) (*sql.Rows, error) 11 | QueryRow(query string, args ...interface{}) *sql.Row 12 | } 13 | 14 | // Transaction can do anything a Query can do 15 | // plus Commit, Rollback, or Stmt 16 | type Transaction interface { 17 | DB 18 | Commit() error 19 | Rollback() error 20 | } 21 | -------------------------------------------------------------------------------- /chapter6/mongodb/config.go: -------------------------------------------------------------------------------- 1 | package mongodb 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/mongodb/mongo-go-driver/mongo" 8 | "go.mongodb.org/mongo-driver/mongo/options" 9 | ) 10 | 11 | // Setup initializes a mongo client 12 | func Setup(ctx context.Context, address string) (*mongo.Client, error) { 13 | ctx, cancel := context.WithTimeout(ctx, 10*time.Second) 14 | // cancel will be called when setup exits 15 | defer cancel() 16 | 17 | client, err := mongo.NewClient(options.Client().ApplyURI(address)) 18 | if err != nil { 19 | return nil, err 20 | } 21 | 22 | if err := client.Connect(ctx); err != nil { 23 | return nil, err 24 | } 25 | return client, nil 26 | } 27 | -------------------------------------------------------------------------------- /chapter6/mongodb/config_test.go: -------------------------------------------------------------------------------- 1 | package mongodb 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | ) 7 | 8 | func TestSetup(t *testing.T) { 9 | tests := []struct { 10 | name string 11 | wantErr bool 12 | }{ 13 | {"base-case", false}, 14 | } 15 | for _, tt := range tests { 16 | t.Run(tt.name, func(t *testing.T) { 17 | _, err := Setup(context.Background(), "mongodb://localhost") 18 | if (err != nil) != tt.wantErr { 19 | t.Errorf("Setup() error = %v, wantErr %v", err, tt.wantErr) 20 | return 21 | } 22 | }) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter6/mongodb/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter6/mongodb" 4 | 5 | func main() { 6 | if err := mongodb.Exec("mongodb://localhost"); err != nil { 7 | panic(err) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /chapter6/mongodb/exec_test.go: -------------------------------------------------------------------------------- 1 | package mongodb 2 | 3 | import "testing" 4 | 5 | func TestExec(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := Exec("mongodb://localhost"); (err != nil) != tt.wantErr { 15 | t.Errorf("Exec() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter6/mongodb/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter6/mongodb 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/go-stack/stack v1.8.0 // indirect 7 | github.com/golang/snappy v0.0.1 // indirect 8 | github.com/mongodb/mongo-go-driver v1.0.1 9 | github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect 10 | github.com/xdg/stringprep v1.0.0 // indirect 11 | go.mongodb.org/mongo-driver v1.0.1 12 | golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 // indirect 13 | golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect 14 | golang.org/x/text v0.3.2 // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /chapter6/pools/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter6/pools" 4 | 5 | func main() { 6 | if err := pools.ExecWithTimeout(); err != nil { 7 | panic(err) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /chapter6/pools/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter6/pools 2 | 3 | require ( 4 | github.com/go-sql-driver/mysql v1.4.1 5 | google.golang.org/appengine v1.5.0 // indirect 6 | ) 7 | -------------------------------------------------------------------------------- /chapter6/pools/go.sum: -------------------------------------------------------------------------------- 1 | github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= 2 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 3 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 4 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 5 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 6 | google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= 7 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 8 | -------------------------------------------------------------------------------- /chapter6/pools/pools.go: -------------------------------------------------------------------------------- 1 | package pools 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "os" 7 | 8 | _ "github.com/go-sql-driver/mysql" //we import supported libraries for database/sql 9 | ) 10 | 11 | // Setup configures the db along with pools 12 | // number of connections and more 13 | func Setup() (*sql.DB, error) { 14 | db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@/gocookbook?parseTime=true", os.Getenv("MYSQLUSERNAME"), os.Getenv("MYSQLPASSWORD"))) 15 | if err != nil { 16 | return nil, err 17 | } 18 | 19 | // there will only ever be 24 open connections 20 | db.SetMaxOpenConns(24) 21 | 22 | // MaxIdleConns can never be less than max open SetMaxOpenConns 23 | // otherwise it'll default to that value 24 | db.SetMaxIdleConns(24) 25 | 26 | return db, nil 27 | } 28 | -------------------------------------------------------------------------------- /chapter6/pools/pools_test.go: -------------------------------------------------------------------------------- 1 | package pools 2 | 3 | import ( 4 | "testing" 5 | 6 | _ "github.com/go-sql-driver/mysql" 7 | ) 8 | 9 | func TestSetup(t *testing.T) { 10 | tests := []struct { 11 | name string 12 | wantErr bool 13 | }{ 14 | {"base-case", false}, 15 | } 16 | for _, tt := range tests { 17 | t.Run(tt.name, func(t *testing.T) { 18 | _, err := Setup() 19 | if (err != nil) != tt.wantErr { 20 | t.Errorf("Setup() error = %v, wantErr %v", err, tt.wantErr) 21 | return 22 | } 23 | }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /chapter6/pools/timeout.go: -------------------------------------------------------------------------------- 1 | package pools 2 | 3 | import ( 4 | "context" 5 | "time" 6 | ) 7 | 8 | // ExecWithTimeout will timeout trying 9 | // to get the current time 10 | func ExecWithTimeout() error { 11 | db, err := Setup() 12 | if err != nil { 13 | return err 14 | } 15 | 16 | ctx := context.Background() 17 | 18 | // we want to timeout immediately 19 | ctx, cancel := context.WithDeadline(ctx, time.Now()) 20 | 21 | // call cancel after we complete 22 | defer cancel() 23 | 24 | // our transaction is context aware 25 | _, err = db.BeginTx(ctx, nil) 26 | return err 27 | } 28 | -------------------------------------------------------------------------------- /chapter6/pools/timeout_test.go: -------------------------------------------------------------------------------- 1 | package pools 2 | 3 | import "testing" 4 | 5 | func TestExecWithTimeout(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", true}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := ExecWithTimeout(); (err != nil) != tt.wantErr { 15 | t.Errorf("ExecWithTimeout() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter6/redis/config.go: -------------------------------------------------------------------------------- 1 | package redis 2 | 3 | import ( 4 | "os" 5 | 6 | redis "gopkg.in/redis.v5" 7 | ) 8 | 9 | // Setup initializes a redis client 10 | func Setup() (*redis.Client, error) { 11 | client := redis.NewClient(&redis.Options{ 12 | Addr: "localhost:6379", 13 | Password: os.Getenv("REDISPASSWORD"), 14 | DB: 0, // use default DB 15 | }) 16 | 17 | // commands returns "PONG", tests if 18 | // connection alive 19 | _, err := client.Ping().Result() 20 | return client, err 21 | } 22 | -------------------------------------------------------------------------------- /chapter6/redis/config_test.go: -------------------------------------------------------------------------------- 1 | package redis 2 | 3 | import "testing" 4 | 5 | func TestSetup(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | _, err := Setup() 15 | if (err != nil) != tt.wantErr { 16 | t.Errorf("Setup() error = %v, wantErr %v", err, tt.wantErr) 17 | return 18 | } 19 | 20 | }) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /chapter6/redis/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter6/redis" 4 | 5 | func main() { 6 | if err := redis.Exec(); err != nil { 7 | panic(err) 8 | } 9 | 10 | if err := redis.Sort(); err != nil { 11 | panic(err) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /chapter6/redis/exec.go: -------------------------------------------------------------------------------- 1 | package redis 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | redis "gopkg.in/redis.v5" 8 | ) 9 | 10 | // Exec performs some redis operations 11 | func Exec() error { 12 | conn, err := Setup() 13 | if err != nil { 14 | return err 15 | } 16 | 17 | c1 := "value" 18 | // value is an interface, we can store whatever 19 | // the last argument is the redis expiration 20 | conn.Set("key", c1, 5*time.Second) 21 | 22 | var result string 23 | if err := conn.Get("key").Scan(&result); err != nil { 24 | switch err { 25 | // this means the key 26 | // was not found 27 | case redis.Nil: 28 | return nil 29 | default: 30 | return err 31 | } 32 | } 33 | 34 | fmt.Println("result =", result) 35 | 36 | return nil 37 | } 38 | -------------------------------------------------------------------------------- /chapter6/redis/exec_test.go: -------------------------------------------------------------------------------- 1 | package redis 2 | 3 | import "testing" 4 | 5 | func TestExec(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := Exec(); (err != nil) != tt.wantErr { 15 | t.Errorf("Exec() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter6/redis/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter6/redis 2 | 3 | require ( 4 | github.com/onsi/ginkgo v1.8.0 // indirect 5 | github.com/onsi/gomega v1.5.0 // indirect 6 | gopkg.in/redis.v5 v5.2.9 7 | ) 8 | -------------------------------------------------------------------------------- /chapter6/redis/sort_test.go: -------------------------------------------------------------------------------- 1 | package redis 2 | 3 | import "testing" 4 | 5 | func TestSort(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := Sort(); (err != nil) != tt.wantErr { 15 | t.Errorf("Sort() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter6/storage/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter6/storage" 4 | 5 | func main() { 6 | if err := storage.Exec(); err != nil { 7 | panic(err) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /chapter6/storage/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter6/storage 2 | 3 | require ( 4 | github.com/go-stack/stack v1.8.0 // indirect 5 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect 6 | github.com/google/go-cmp v0.3.0 // indirect 7 | github.com/mongodb/mongo-go-driver v0.1.0 8 | github.com/stretchr/testify v1.3.0 // indirect 9 | github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65 // indirect 10 | github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect 11 | github.com/xdg/stringprep v1.0.0 // indirect 12 | golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc // indirect 13 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect 14 | golang.org/x/text v0.3.0 // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /chapter6/storage/mongointerface.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/mongodb/mongo-go-driver/bson" 7 | ) 8 | 9 | // GetByName queries mongodb for an item with 10 | // the correct name 11 | func (m *MongoStorage) GetByName(ctx context.Context, name string) (*Item, error) { 12 | c := m.Client.Database(m.DB).Collection(m.Collection) 13 | var i Item 14 | if err := c.FindOne(ctx, bson.M{"name": name}).Decode(&i); err != nil { 15 | return nil, err 16 | } 17 | 18 | return &i, nil 19 | } 20 | 21 | // Put adds an item to our mongo instance 22 | func (m *MongoStorage) Put(ctx context.Context, i *Item) error { 23 | c := m.Client.Database(m.DB).Collection(m.Collection) 24 | _, err := c.InsertOne(ctx, i) 25 | return err 26 | } 27 | -------------------------------------------------------------------------------- /chapter6/storage/storage.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | import "context" 4 | 5 | // Item represents an item at 6 | // a shop 7 | type Item struct { 8 | Name string 9 | Price int64 10 | } 11 | 12 | // Storage is our storage interface 13 | // We'll implement it with Mongo 14 | // storage 15 | type Storage interface { 16 | GetByName(context.Context, string) (*Item, error) 17 | Put(context.Context, *Item) error 18 | } 19 | -------------------------------------------------------------------------------- /chapter7/async/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/async" 8 | ) 9 | 10 | func main() { 11 | urls := []string{ 12 | "https://www.google.com", 13 | "https://golang.org", 14 | "https://www.github.com", 15 | } 16 | c := async.NewClient(http.DefaultClient, len(urls)) 17 | async.FetchAll(urls, c) 18 | 19 | for i := 0; i < len(urls); i++ { 20 | select { 21 | case resp := <-c.Resp: 22 | fmt.Printf("Status received for %s: %d\n", resp.Request.URL, resp.StatusCode) 23 | case err := <-c.Err: 24 | fmt.Printf("Error received: %s\n", err) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /chapter7/async/exec.go: -------------------------------------------------------------------------------- 1 | package async 2 | 3 | // FetchAll grabs a list of urls 4 | func FetchAll(urls []string, c *Client) { 5 | for _, url := range urls { 6 | go c.AsyncGet(url) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /chapter7/async/exec_test.go: -------------------------------------------------------------------------------- 1 | package async 2 | 3 | import ( 4 | "net/http" 5 | "testing" 6 | ) 7 | 8 | func TestFetchAll(t *testing.T) { 9 | type args struct { 10 | urls []string 11 | c *Client 12 | } 13 | tests := []struct { 14 | name string 15 | args args 16 | }{ 17 | {"base-case", args{nil, NewClient(http.DefaultClient, 10)}}, 18 | } 19 | for _, tt := range tests { 20 | t.Run(tt.name, func(t *testing.T) { 21 | FetchAll(tt.args.urls, tt.args.c) 22 | }) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter7/async/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/async 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter7/async/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/ea3c94a784b061afc7e62ac9a4e7c5792d498769/chapter7/async/go.sum -------------------------------------------------------------------------------- /chapter7/client/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/client" 4 | 5 | func main() { 6 | // secure and op! 7 | cli := client.Setup(true, false) 8 | 9 | if err := client.DefaultGetGolang(); err != nil { 10 | panic(err) 11 | } 12 | 13 | if err := client.DoOps(cli); err != nil { 14 | panic(err) 15 | } 16 | 17 | c := client.Controller{Client: cli} 18 | if err := c.DoOps(); err != nil { 19 | panic(err) 20 | } 21 | 22 | // secure and noop 23 | // also modifies default 24 | client.Setup(true, true) 25 | 26 | if err := client.DefaultGetGolang(); err != nil { 27 | panic(err) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /chapter7/client/exec.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | // DoOps takes a client, then fetches 9 | // google.com 10 | func DoOps(c *http.Client) error { 11 | resp, err := c.Get("http://www.google.com") 12 | if err != nil { 13 | return err 14 | } 15 | fmt.Println("results of DoOps:", resp.StatusCode) 16 | 17 | return nil 18 | } 19 | 20 | // DefaultGetGolang uses the default client 21 | // to get golang.org 22 | func DefaultGetGolang() error { 23 | resp, err := http.Get("https://www.golang.org") 24 | if err != nil { 25 | return err 26 | } 27 | fmt.Println("results of DefaultGetGolang:", resp.StatusCode) 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /chapter7/client/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/client 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter7/client/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/ea3c94a784b061afc7e62ac9a4e7c5792d498769/chapter7/client/go.sum -------------------------------------------------------------------------------- /chapter7/client/store.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | // Controller embeds an http.Client 9 | // and uses it internally 10 | type Controller struct { 11 | *http.Client 12 | } 13 | 14 | // DoOps with a controller object 15 | func (c *Controller) DoOps() error { 16 | resp, err := c.Client.Get("http://www.google.com") 17 | if err != nil { 18 | return err 19 | } 20 | fmt.Println("results of client.DoOps", resp.StatusCode) 21 | return nil 22 | } 23 | -------------------------------------------------------------------------------- /chapter7/client/store_test.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import "testing" 4 | 5 | func TestController_DoOps(t *testing.T) { 6 | c := Setup(true, true) 7 | tests := []struct { 8 | name string 9 | c *Controller 10 | wantErr bool 11 | }{ 12 | {"base-case", &Controller{c}, false}, 13 | } 14 | for _, tt := range tests { 15 | t.Run(tt.name, func(t *testing.T) { 16 | if err := tt.c.DoOps(); (err != nil) != tt.wantErr { 17 | t.Errorf("Controller.DoOps() error = %v, wantErr %v", err, tt.wantErr) 18 | } 19 | }) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /chapter7/decorator/config.go: -------------------------------------------------------------------------------- 1 | package decorator 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "os" 7 | ) 8 | 9 | // Setup initializes our ClientInterface 10 | func Setup() *http.Client { 11 | c := http.Client{} 12 | 13 | t := Decorate(&http.Transport{}, 14 | Logger(log.New(os.Stdout, "", 0)), 15 | BasicAuth("username", "password"), 16 | ) 17 | c.Transport = t 18 | return &c 19 | } 20 | -------------------------------------------------------------------------------- /chapter7/decorator/config_test.go: -------------------------------------------------------------------------------- 1 | package decorator 2 | 3 | import "testing" 4 | 5 | func TestSetup(t *testing.T) { 6 | 7 | tests := []struct { 8 | name string 9 | }{ 10 | {"base-case"}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | Setup() 15 | }) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /chapter7/decorator/decorator.go: -------------------------------------------------------------------------------- 1 | package decorator 2 | 3 | import "net/http" 4 | 5 | // TransportFunc implements the RountTripper interface 6 | type TransportFunc func(*http.Request) (*http.Response, error) 7 | 8 | // RoundTrip just calls the original function 9 | func (tf TransportFunc) RoundTrip(r *http.Request) (*http.Response, error) { 10 | return tf(r) 11 | } 12 | 13 | // Decorator is a convenience function to represent our 14 | // middleware inner function 15 | type Decorator func(http.RoundTripper) http.RoundTripper 16 | 17 | // Decorate is a helper to wrap all the middleware 18 | func Decorate(t http.RoundTripper, rts ...Decorator) http.RoundTripper { 19 | decorated := t 20 | for _, rt := range rts { 21 | decorated = rt(decorated) 22 | } 23 | return decorated 24 | } 25 | -------------------------------------------------------------------------------- /chapter7/decorator/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/decorator" 4 | 5 | func main() { 6 | if err := decorator.Exec(); err != nil { 7 | panic(err) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /chapter7/decorator/exec.go: -------------------------------------------------------------------------------- 1 | package decorator 2 | 3 | import "fmt" 4 | 5 | // Exec creates a client, calls google.com 6 | // then prints the response 7 | func Exec() error { 8 | c := Setup() 9 | 10 | resp, err := c.Get("https://www.google.com") 11 | if err != nil { 12 | return err 13 | } 14 | fmt.Println("Response code:", resp.StatusCode) 15 | return nil 16 | } 17 | -------------------------------------------------------------------------------- /chapter7/decorator/exec_test.go: -------------------------------------------------------------------------------- 1 | package decorator 2 | 3 | import "testing" 4 | 5 | func TestExec(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := Exec(); (err != nil) != tt.wantErr { 15 | t.Errorf("Exec() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter7/decorator/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/decorator 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter7/decorator/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/ea3c94a784b061afc7e62ac9a4e7c5792d498769/chapter7/decorator/go.sum -------------------------------------------------------------------------------- /chapter7/grpc/client/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/grpc/greeter" 8 | "google.golang.org/grpc" 9 | ) 10 | 11 | func main() { 12 | conn, err := grpc.Dial(":4444", grpc.WithInsecure()) 13 | if err != nil { 14 | panic(err) 15 | } 16 | defer conn.Close() 17 | 18 | client := greeter.NewGreeterServiceClient(conn) 19 | 20 | ctx := context.Background() 21 | req := greeter.GreetRequest{Greeting: "Hello", Name: "Reader"} 22 | resp, err := client.Greet(ctx, &req) 23 | if err != nil { 24 | panic(err) 25 | } 26 | fmt.Println(resp) 27 | 28 | req.Greeting = "Goodbye" 29 | resp, err = client.Greet(ctx, &req) 30 | if err != nil { 31 | panic(err) 32 | } 33 | fmt.Println(resp) 34 | } 35 | -------------------------------------------------------------------------------- /chapter7/grpc/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/grpc 2 | 3 | require ( 4 | github.com/golang/protobuf v1.2.0 5 | golang.org/x/net v0.0.0-20190119204137-ed066c81e75e 6 | google.golang.org/genproto v0.0.0-20190111180523-db91494dd46c // indirect 7 | google.golang.org/grpc v1.18.0 8 | ) 9 | -------------------------------------------------------------------------------- /chapter7/grpc/greeter/greeter.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package greeter; 4 | 5 | service GreeterService{ 6 | rpc Greet(GreetRequest) returns (GreetResponse) {} 7 | } 8 | 9 | message GreetRequest { 10 | string greeting = 1; 11 | string name = 2; 12 | } 13 | 14 | message GreetResponse{ 15 | string response = 1; 16 | } -------------------------------------------------------------------------------- /chapter7/grpc/grpc.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | protoc --go_out=plugins=grpc:. greeter/greeter.proto -------------------------------------------------------------------------------- /chapter7/grpc/server/greeter.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/grpc/greeter" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // Greeter implements the interface 11 | // generated by protoc 12 | type Greeter struct { 13 | Exclaim bool 14 | } 15 | 16 | // Greet implements grpc Greet 17 | func (g *Greeter) Greet(ctx context.Context, r *greeter.GreetRequest) (*greeter.GreetResponse, error) { 18 | msg := fmt.Sprintf("%s %s", r.GetGreeting(), r.GetName()) 19 | if g.Exclaim { 20 | msg += "!" 21 | } else { 22 | msg += "." 23 | } 24 | return &greeter.GreetResponse{Response: msg}, nil 25 | } 26 | -------------------------------------------------------------------------------- /chapter7/grpc/server/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | 7 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/grpc/greeter" 8 | "google.golang.org/grpc" 9 | ) 10 | 11 | func main() { 12 | grpcServer := grpc.NewServer() 13 | greeter.RegisterGreeterServiceServer(grpcServer, &Greeter{Exclaim: true}) 14 | lis, err := net.Listen("tcp", ":4444") 15 | if err != nil { 16 | panic(err) 17 | } 18 | fmt.Println("Listening on port :4444") 19 | grpcServer.Serve(lis) 20 | } 21 | -------------------------------------------------------------------------------- /chapter7/oauthcli/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/oauthcli" 7 | ) 8 | 9 | func main() { 10 | ctx := context.Background() 11 | conf := oauthcli.Setup() 12 | 13 | tok, err := oauthcli.GetToken(ctx, conf) 14 | if err != nil { 15 | panic(err) 16 | } 17 | client := conf.Client(ctx, tok) 18 | 19 | if err := oauthcli.GetUser(client); err != nil { 20 | panic(err) 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /chapter7/oauthcli/exec.go: -------------------------------------------------------------------------------- 1 | package oauthcli 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | "os" 8 | ) 9 | 10 | // GetUser uses an initialized oauth2 client to get 11 | // information about a user 12 | func GetUser(client *http.Client) error { 13 | url := fmt.Sprintf("https://api.github.com/user") 14 | 15 | resp, err := client.Get(url) 16 | if err != nil { 17 | return err 18 | } 19 | defer resp.Body.Close() 20 | fmt.Println("Status Code from", url, ":", resp.StatusCode) 21 | io.Copy(os.Stdout, resp.Body) 22 | return nil 23 | } 24 | -------------------------------------------------------------------------------- /chapter7/oauthcli/exec_test.go: -------------------------------------------------------------------------------- 1 | package oauthcli 2 | 3 | import ( 4 | "net/http" 5 | "testing" 6 | ) 7 | 8 | func TestGetUsers(t *testing.T) { 9 | type args struct { 10 | client *http.Client 11 | } 12 | tests := []struct { 13 | name string 14 | args args 15 | wantErr bool 16 | }{ 17 | {"base-case", args{&http.Client{}}, false}, 18 | } 19 | for _, tt := range tests { 20 | t.Run(tt.name, func(t *testing.T) { 21 | if err := GetUsers(tt.args.client); (err != nil) != tt.wantErr { 22 | t.Errorf("GetUsers() error = %v, wantErr %v", err, tt.wantErr) 23 | } 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter7/oauthcli/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/oauthcli 2 | 3 | require golang.org/x/oauth2 v0.0.0-20190115181402-5dab4167f31c 4 | -------------------------------------------------------------------------------- /chapter7/oauthstore/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/oauthstore 2 | 3 | require golang.org/x/oauth2 v0.0.0-20190115181402-5dab4167f31c 4 | -------------------------------------------------------------------------------- /chapter7/oauthstore/storage_test.go: -------------------------------------------------------------------------------- 1 | package oauthstore 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "golang.org/x/oauth2" 8 | ) 9 | 10 | func TestGetToken(t *testing.T) { 11 | conf := Config{&oauth2.Config{}, &FileStorage{}} 12 | ctx := context.Background() 13 | type args struct { 14 | ctx context.Context 15 | conf Config 16 | } 17 | tests := []struct { 18 | name string 19 | args args 20 | wantErr bool 21 | }{ 22 | {"base-case", args{ctx, conf}, true}, 23 | } 24 | for _, tt := range tests { 25 | t.Run(tt.name, func(t *testing.T) { 26 | _, err := GetToken(tt.args.ctx, tt.args.conf) 27 | if (err != nil) != tt.wantErr { 28 | t.Errorf("GetToken() error = %v, wantErr %v", err, tt.wantErr) 29 | return 30 | } 31 | 32 | }) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /chapter7/rest/client.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import "net/http" 4 | 5 | // APIClient is our custom client 6 | type APIClient struct { 7 | *http.Client 8 | } 9 | 10 | // NewAPIClient constructor initializes the client with our 11 | // custom Transport 12 | func NewAPIClient(username, password string) *APIClient { 13 | t := http.Transport{} 14 | return &APIClient{ 15 | Client: &http.Client{ 16 | Transport: &APITransport{ 17 | Transport: &t, 18 | username: username, 19 | password: password, 20 | }, 21 | }, 22 | } 23 | } 24 | 25 | // GetGoogle is an API Call - we abstract away 26 | // the REST aspects 27 | func (c *APIClient) GetGoogle() (int, error) { 28 | resp, err := c.Get("http://www.google.com") 29 | if err != nil { 30 | return 0, err 31 | } 32 | return resp.StatusCode, nil 33 | } 34 | -------------------------------------------------------------------------------- /chapter7/rest/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/rest" 4 | 5 | func main() { 6 | if err := rest.Exec(); err != nil { 7 | panic(err) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /chapter7/rest/exec.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import "fmt" 4 | 5 | // Exec creates an API Client and uses its 6 | // GetGoogle method, then prints the result 7 | func Exec() error { 8 | c := NewAPIClient("username", "password") 9 | 10 | StatusCode, err := c.GetGoogle() 11 | if err != nil { 12 | return err 13 | } 14 | fmt.Println("Result of GetGoogle:", StatusCode) 15 | return nil 16 | } 17 | -------------------------------------------------------------------------------- /chapter7/rest/exec_test.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import "testing" 4 | 5 | func TestExec(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | wantErr bool 9 | }{ 10 | {"base-case", false}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | if err := Exec(); (err != nil) != tt.wantErr { 15 | t.Errorf("Exec() error = %v, wantErr %v", err, tt.wantErr) 16 | } 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter7/rest/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/rest 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter7/rest/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/ea3c94a784b061afc7e62ac9a4e7c5792d498769/chapter7/rest/go.sum -------------------------------------------------------------------------------- /chapter7/rest/transport.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import "net/http" 4 | 5 | // APITransport does a SetBasicAuth 6 | // for every request 7 | type APITransport struct { 8 | *http.Transport 9 | username, password string 10 | } 11 | 12 | // RoundTrip does the basic auth before deferring to the 13 | // default transport 14 | func (t *APITransport) RoundTrip(req *http.Request) (*http.Response, error) { 15 | req.SetBasicAuth(t.username, t.password) 16 | return t.Transport.RoundTrip(req) 17 | } 18 | -------------------------------------------------------------------------------- /chapter7/rest/transport_test.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "net/http" 5 | "testing" 6 | ) 7 | 8 | func TestAPITransport_RoundTrip(t *testing.T) { 9 | type args struct { 10 | req *http.Request 11 | } 12 | tests := []struct { 13 | name string 14 | t *APITransport 15 | args args 16 | wantErr bool 17 | }{ 18 | {"base-case", &APITransport{Transport: &http.Transport{}}, args{&http.Request{Header: make(http.Header)}}, true}, 19 | } 20 | for _, tt := range tests { 21 | t.Run(tt.name, func(t *testing.T) { 22 | _, err := tt.t.RoundTrip(tt.args.req) 23 | if (err != nil) != tt.wantErr { 24 | t.Errorf("APITransport.RoundTrip() error = %v, wantErr %v", err, tt.wantErr) 25 | return 26 | } 27 | 28 | }) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /chapter7/twirp/client/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/twirp/rpc/greeter" 9 | ) 10 | 11 | func main() { 12 | // you can put in a custom client for tighter controls on timeouts etc. 13 | client := greeter.NewGreeterServiceProtobufClient("http://localhost:4444", &http.Client{}) 14 | 15 | ctx := context.Background() 16 | req := greeter.GreetRequest{Greeting: "Hello", Name: "Reader"} 17 | resp, err := client.Greet(ctx, &req) 18 | if err != nil { 19 | panic(err) 20 | } 21 | fmt.Println(resp) 22 | 23 | req.Greeting = "Goodbye" 24 | resp, err = client.Greet(ctx, &req) 25 | if err != nil { 26 | panic(err) 27 | } 28 | fmt.Println(resp) 29 | } 30 | -------------------------------------------------------------------------------- /chapter7/twirp/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/twirp 2 | 3 | require ( 4 | github.com/golang/protobuf v1.3.1 5 | github.com/pkg/errors v0.8.1 // indirect 6 | github.com/twitchtv/twirp v5.5.1+incompatible 7 | golang.org/x/net v0.0.0-20190119204137-ed066c81e75e 8 | golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect 9 | ) 10 | -------------------------------------------------------------------------------- /chapter7/twirp/rpc/greeter/greeter.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package greeter; 4 | 5 | service GreeterService{ 6 | rpc Greet(GreetRequest) returns (GreetResponse) {} 7 | } 8 | 9 | message GreetRequest { 10 | string greeting = 1; 11 | string name = 2; 12 | } 13 | 14 | message GreetResponse{ 15 | string response = 1; 16 | } -------------------------------------------------------------------------------- /chapter7/twirp/server/greeter.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/twirp/rpc/greeter" 8 | ) 9 | 10 | // Greeter implements the interface 11 | // generated by protoc 12 | type Greeter struct { 13 | Exclaim bool 14 | } 15 | 16 | // Greet implements twirp Greet 17 | func (g *Greeter) Greet(ctx context.Context, r *greeter.GreetRequest) (*greeter.GreetResponse, error) { 18 | msg := fmt.Sprintf("%s %s", r.GetGreeting(), r.GetName()) 19 | if g.Exclaim { 20 | msg += "!" 21 | } else { 22 | msg += "." 23 | } 24 | return &greeter.GreetResponse{Response: msg}, nil 25 | } 26 | -------------------------------------------------------------------------------- /chapter7/twirp/server/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter7/twirp/rpc/greeter" 8 | ) 9 | 10 | func main() { 11 | server := &Greeter{} 12 | twirpHandler := greeter.NewGreeterServiceServer(server, nil) 13 | 14 | fmt.Println("Listening on port :4444") 15 | http.ListenAndServe(":4444", twirpHandler) 16 | } 17 | -------------------------------------------------------------------------------- /chapter7/twirp/twirp.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | protoc --proto_path=$GOPATH/src:. --twirp_out=. --go_out=. ./rpc/greeter/greeter.proto 3 | -------------------------------------------------------------------------------- /chapter8/controllers/controller.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | // Controller passes state to our handlers 4 | type Controller struct { 5 | storage Storage 6 | } 7 | 8 | // New is a Controller 'constructor' 9 | func New(storage Storage) *Controller { 10 | return &Controller{ 11 | storage: storage, 12 | } 13 | } 14 | 15 | // Payload is our common response 16 | type Payload struct { 17 | Value string `json:"value"` 18 | } 19 | -------------------------------------------------------------------------------- /chapter8/controllers/controller_test.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestNew(t *testing.T) { 9 | storage := MemStorage{} 10 | type args struct { 11 | storage Storage 12 | } 13 | tests := []struct { 14 | name string 15 | args args 16 | want *Controller 17 | }{ 18 | {"base-case", args{storage: &storage}, &Controller{storage: &storage}}, 19 | } 20 | for _, tt := range tests { 21 | t.Run(tt.name, func(t *testing.T) { 22 | if got := New(tt.args.storage); !reflect.DeepEqual(got, tt.want) { 23 | t.Errorf("New() = %v, want %v", got, tt.want) 24 | } 25 | }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /chapter8/controllers/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter8/controllers" 8 | ) 9 | 10 | func main() { 11 | storage := controllers.MemStorage{} 12 | c := controllers.New(&storage) 13 | http.HandleFunc("/get", c.GetValue(false)) 14 | http.HandleFunc("/get/default", c.GetValue(true)) 15 | http.HandleFunc("/set", c.SetValue) 16 | 17 | fmt.Println("Listening on port :3333") 18 | err := http.ListenAndServe(":3333", nil) 19 | panic(err) 20 | } 21 | -------------------------------------------------------------------------------- /chapter8/controllers/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter8/controllers 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter8/controllers/post.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | ) 7 | 8 | // SetValue modifies the underlying storage of the controller object 9 | func (c *Controller) SetValue(w http.ResponseWriter, r *http.Request) { 10 | if r.Method != "POST" { 11 | w.WriteHeader(http.StatusMethodNotAllowed) 12 | return 13 | } 14 | if err := r.ParseForm(); err != nil { 15 | w.WriteHeader(http.StatusInternalServerError) 16 | return 17 | } 18 | value := r.FormValue("value") 19 | c.storage.Put(value) 20 | w.WriteHeader(http.StatusOK) 21 | p := Payload{Value: value} 22 | if payload, err := json.Marshal(p); err == nil { 23 | w.Write(payload) 24 | } else if err != nil { 25 | w.WriteHeader(http.StatusInternalServerError) 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /chapter8/controllers/post_test.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "testing" 7 | ) 8 | 9 | func TestController_SetValue(t *testing.T) { 10 | c := New(&MemStorage{}) 11 | type args struct { 12 | w http.ResponseWriter 13 | r *http.Request 14 | } 15 | tests := []struct { 16 | name string 17 | c *Controller 18 | args args 19 | }{ 20 | {"base-case", c, args{httptest.NewRecorder(), httptest.NewRequest("POST", "/", nil)}}, 21 | {"bad method", c, args{httptest.NewRecorder(), httptest.NewRequest("GET", "/", nil)}}, 22 | } 23 | for _, tt := range tests { 24 | t.Run(tt.name, func(t *testing.T) { 25 | tt.c.SetValue(tt.args.w, tt.args.r) 26 | }) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /chapter8/controllers/storage.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | // Storage Interface Supports Get and Put 4 | // of a single value 5 | type Storage interface { 6 | Get() string 7 | Put(string) 8 | } 9 | 10 | // MemStorage implements Storage 11 | type MemStorage struct { 12 | value string 13 | } 14 | 15 | // Get our in-memory value 16 | func (m *MemStorage) Get() string { 17 | return m.value 18 | } 19 | 20 | // Put our in-memory value 21 | func (m *MemStorage) Put(s string) { 22 | m.value = s 23 | } 24 | -------------------------------------------------------------------------------- /chapter8/grpcjson/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter8/grpcjson 2 | 3 | require ( 4 | github.com/apex/log v1.1.0 5 | github.com/golang/protobuf v1.2.0 6 | github.com/pkg/errors v0.8.1 // indirect 7 | github.com/stretchr/testify v1.3.0 // indirect 8 | golang.org/x/net v0.0.0-20190206173232-65e2d4e15006 9 | google.golang.org/grpc v1.18.0 10 | ) 11 | -------------------------------------------------------------------------------- /chapter8/grpcjson/grpc.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | protoc --go_out=plugins=grpc:. keyvalue/keyvalue.proto 3 | -------------------------------------------------------------------------------- /chapter8/grpcjson/grpc/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | 7 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter8/grpcjson/internal" 8 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter8/grpcjson/keyvalue" 9 | "google.golang.org/grpc" 10 | ) 11 | 12 | func main() { 13 | grpcServer := grpc.NewServer() 14 | keyvalue.RegisterKeyValueServer(grpcServer, internal.NewKeyValue()) 15 | lis, err := net.Listen("tcp", ":4444") 16 | if err != nil { 17 | panic(err) 18 | } 19 | fmt.Println("Listening on port :4444") 20 | grpcServer.Serve(lis) 21 | } 22 | -------------------------------------------------------------------------------- /chapter8/grpcjson/http/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter8/grpcjson/internal" 8 | ) 9 | 10 | func main() { 11 | c := Controller{KeyValue: internal.NewKeyValue()} 12 | http.HandleFunc("/set", c.SetHandler) 13 | http.HandleFunc("/get", c.GetHandler) 14 | 15 | fmt.Println("Listening on port :3333") 16 | err := http.ListenAndServe(":3333", nil) 17 | panic(err) 18 | } 19 | -------------------------------------------------------------------------------- /chapter8/grpcjson/http/set_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "net/http" 6 | "net/http/httptest" 7 | "testing" 8 | 9 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter8/grpcjson/internal" 10 | ) 11 | 12 | func TestController_SetHandler(t *testing.T) { 13 | type args struct { 14 | w http.ResponseWriter 15 | r *http.Request 16 | } 17 | tests := []struct { 18 | name string 19 | c *Controller 20 | args args 21 | }{ 22 | {"base-case", &Controller{KeyValue: internal.NewKeyValue()}, args{httptest.NewRecorder(), httptest.NewRequest("GET", "/", bytes.NewBufferString(`{"key":"key", "value":"value"}`))}}, 23 | } 24 | for _, tt := range tests { 25 | t.Run(tt.name, func(t *testing.T) { 26 | tt.c.SetHandler(tt.args.w, tt.args.r) 27 | }) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /chapter8/grpcjson/keyvalue/keyvalue.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package keyvalue; 4 | 5 | service KeyValue{ 6 | rpc Set(SetKeyValueRequest) returns (KeyValueResponse){} 7 | rpc Get(GetKeyValueRequest) returns (KeyValueResponse){} 8 | } 9 | 10 | message SetKeyValueRequest { 11 | string key = 1; 12 | string value = 2; 13 | } 14 | 15 | message GetKeyValueRequest{ 16 | string key = 1; 17 | } 18 | 19 | message KeyValueResponse{ 20 | string success = 1; 21 | string value = 2; 22 | } -------------------------------------------------------------------------------- /chapter8/handlers/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter8/handlers" 8 | ) 9 | 10 | func main() { 11 | http.HandleFunc("/name", handlers.HelloHandler) 12 | http.HandleFunc("/greeting", handlers.GreetingHandler) 13 | fmt.Println("Listening on port :3333") 14 | err := http.ListenAndServe(":3333", nil) 15 | panic(err) 16 | } 17 | -------------------------------------------------------------------------------- /chapter8/handlers/get.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | // HelloHandler takes a GET parameter "name" and responds 9 | // with Hello ! in plaintext 10 | func HelloHandler(w http.ResponseWriter, r *http.Request) { 11 | w.Header().Set("Content-Type", "text/plain") 12 | if r.Method != http.MethodGet { 13 | w.WriteHeader(http.StatusMethodNotAllowed) 14 | return 15 | } 16 | name := r.URL.Query().Get("name") 17 | 18 | w.WriteHeader(http.StatusOK) 19 | w.Write([]byte(fmt.Sprintf("Hello %s!", name))) 20 | } 21 | -------------------------------------------------------------------------------- /chapter8/handlers/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter8/handlers 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter8/middleware/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "os" 8 | 9 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter8/middleware" 10 | ) 11 | 12 | func main() { 13 | // We apply from bottom up 14 | h := middleware.ApplyMiddleware( 15 | middleware.Handler, 16 | middleware.Logger(log.New(os.Stdout, "", 0)), 17 | middleware.SetID(100), 18 | ) 19 | http.HandleFunc("/", h) 20 | fmt.Println("Listening on port :3333") 21 | err := http.ListenAndServe(":3333", nil) 22 | panic(err) 23 | } 24 | -------------------------------------------------------------------------------- /chapter8/middleware/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter8/middleware 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter8/middleware/handler.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | // Handler is very basic 8 | func Handler(w http.ResponseWriter, r *http.Request) { 9 | w.WriteHeader(http.StatusOK) 10 | w.Write([]byte("success")) 11 | } 12 | -------------------------------------------------------------------------------- /chapter8/middleware/handler_test.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "testing" 7 | ) 8 | 9 | func TestHandler(t *testing.T) { 10 | type args struct { 11 | w http.ResponseWriter 12 | r *http.Request 13 | } 14 | tests := []struct { 15 | name string 16 | args args 17 | }{ 18 | {"base-case", args{httptest.NewRecorder(), httptest.NewRequest("GET", "/", nil)}}, 19 | } 20 | for _, tt := range tests { 21 | t.Run(tt.name, func(t *testing.T) { 22 | Handler(tt.args.w, tt.args.r) 23 | }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /chapter8/negotiate/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter8/negotiate" 8 | ) 9 | 10 | func main() { 11 | http.HandleFunc("/", negotiate.Handler) 12 | fmt.Println("Listening on port :3333") 13 | err := http.ListenAndServe(":3333", nil) 14 | panic(err) 15 | } 16 | -------------------------------------------------------------------------------- /chapter8/negotiate/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter8/negotiate 2 | 3 | require ( 4 | github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 // indirect 5 | github.com/unrolled/render v0.0.0-20190117215946-449f39850074 6 | ) 7 | -------------------------------------------------------------------------------- /chapter8/negotiate/go.sum: -------------------------------------------------------------------------------- 1 | github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= 2 | github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= 3 | github.com/unrolled/render v0.0.0-20190117215946-449f39850074 h1:Z2Io8Xv8S7HyOpBqaED5yqn2+NNrzWiS8CrTasc1mxQ= 4 | github.com/unrolled/render v0.0.0-20190117215946-449f39850074/go.mod h1:tu82oB5W2ykJRVioYsB+IQKcft7ryBr7w12qMBUPyXg= 5 | -------------------------------------------------------------------------------- /chapter8/negotiate/handler.go: -------------------------------------------------------------------------------- 1 | package negotiate 2 | 3 | import ( 4 | "encoding/xml" 5 | "net/http" 6 | ) 7 | 8 | // Payload defines it's layout in xml and json 9 | type Payload struct { 10 | XMLName xml.Name `xml:"payload" json:"-"` 11 | Status string `xml:"status" json:"status"` 12 | } 13 | 14 | // Handler gets a negotiator using the request, 15 | // then renders a Payload 16 | func Handler(w http.ResponseWriter, r *http.Request) { 17 | n := GetNegotiator(r) 18 | 19 | n.Respond(w, http.StatusOK, &Payload{Status: "Successful!"}) 20 | } 21 | -------------------------------------------------------------------------------- /chapter8/negotiate/handler_test.go: -------------------------------------------------------------------------------- 1 | package negotiate 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "testing" 7 | ) 8 | 9 | func TestHandler(t *testing.T) { 10 | type args struct { 11 | w http.ResponseWriter 12 | r *http.Request 13 | } 14 | tests := []struct { 15 | name string 16 | args args 17 | }{ 18 | {"base-case", args{httptest.NewRecorder(), httptest.NewRequest("GET", "/", nil)}}, 19 | } 20 | for _, tt := range tests { 21 | t.Run(tt.name, func(t *testing.T) { 22 | Handler(tt.args.w, tt.args.r) 23 | }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /chapter8/negotiate/negotiate.go: -------------------------------------------------------------------------------- 1 | package negotiate 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/unrolled/render" 7 | ) 8 | 9 | // Negotiator wraps render and does 10 | // some switching on ContentType 11 | type Negotiator struct { 12 | ContentType string 13 | *render.Render 14 | } 15 | 16 | // GetNegotiator takes a request, and figures 17 | // out the ContentType from the Content-Type header 18 | func GetNegotiator(r *http.Request) *Negotiator { 19 | contentType := r.Header.Get("Content-Type") 20 | 21 | return &Negotiator{ 22 | ContentType: contentType, 23 | Render: render.New(), 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /chapter8/negotiate/negotiate_test.go: -------------------------------------------------------------------------------- 1 | package negotiate 2 | 3 | import ( 4 | "net/http" 5 | "testing" 6 | ) 7 | 8 | func TestGetNegotiator(t *testing.T) { 9 | h := make(http.Header) 10 | h["Content-Type"] = []string{"application/json"} 11 | type args struct { 12 | r *http.Request 13 | } 14 | tests := []struct { 15 | name string 16 | args args 17 | }{ 18 | {"base-case", args{&http.Request{Header: h}}}, 19 | } 20 | for _, tt := range tests { 21 | t.Run(tt.name, func(t *testing.T) { 22 | GetNegotiator(tt.args.r) 23 | }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /chapter8/negotiate/respond.go: -------------------------------------------------------------------------------- 1 | package negotiate 2 | 3 | import "io" 4 | import "github.com/unrolled/render" 5 | 6 | // Respond switches on Content Type to determine 7 | // the response 8 | func (n *Negotiator) Respond(w io.Writer, status int, v interface{}) { 9 | switch n.ContentType { 10 | case render.ContentJSON: 11 | n.Render.JSON(w, status, v) 12 | case render.ContentXML: 13 | n.Render.XML(w, status, v) 14 | default: 15 | n.Render.JSON(w, status, v) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /chapter8/proxy/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter8/proxy" 8 | ) 9 | 10 | func main() { 11 | p := &proxy.Proxy{ 12 | Client: http.DefaultClient, 13 | BaseURL: "https://www.golang.org", 14 | } 15 | http.Handle("/", p) 16 | fmt.Println("Listening on port :3333") 17 | err := http.ListenAndServe(":3333", nil) 18 | panic(err) 19 | } 20 | -------------------------------------------------------------------------------- /chapter8/proxy/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter8/proxy 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter8/proxy/proxy_test.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "testing" 7 | ) 8 | 9 | func TestProxy_ServeHTTP(t *testing.T) { 10 | type fields struct { 11 | Client *http.Client 12 | BaseURL string 13 | } 14 | type args struct { 15 | w http.ResponseWriter 16 | r *http.Request 17 | } 18 | tests := []struct { 19 | name string 20 | fields fields 21 | args args 22 | }{ 23 | {"base-case", fields{http.DefaultClient, ""}, args{httptest.NewRecorder(), httptest.NewRequest("GET", "/", nil)}}, 24 | } 25 | for _, tt := range tests { 26 | t.Run(tt.name, func(t *testing.T) { 27 | p := &Proxy{ 28 | Client: tt.fields.Client, 29 | BaseURL: tt.fields.BaseURL, 30 | } 31 | p.ServeHTTP(tt.args.w, tt.args.r) 32 | }) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /chapter8/validation/controller.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | // Controller holds our validation functions 4 | type Controller struct { 5 | ValidatePayload func(p *Payload) error 6 | } 7 | 8 | // New initializes a controller with our 9 | // local validation, it can be overwritten 10 | func New() *Controller { 11 | return &Controller{ 12 | ValidatePayload: ValidatePayload, 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /chapter8/validation/controller_test.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import "testing" 4 | 5 | func TestNew(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | }{ 9 | {"base-case"}, 10 | } 11 | for _, tt := range tests { 12 | t.Run(tt.name, func(t *testing.T) { 13 | New() 14 | }) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /chapter8/validation/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter8/validation" 8 | ) 9 | 10 | func main() { 11 | c := validation.New() 12 | http.HandleFunc("/", c.Process) 13 | fmt.Println("Listening on port :3333") 14 | err := http.ListenAndServe(":3333", nil) 15 | panic(err) 16 | } 17 | -------------------------------------------------------------------------------- /chapter8/validation/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter8/validation 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter8/validation/validate.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import "errors" 4 | 5 | // Verror is an error that occurs 6 | // during validation, we can 7 | // return this to a user 8 | type Verror struct { 9 | error 10 | } 11 | 12 | // Payload is the value we 13 | // process 14 | type Payload struct { 15 | Name string `json:"name"` 16 | Age int `json:"age"` 17 | } 18 | 19 | // ValidatePayload is 1 implementation of 20 | // the closure in our controller 21 | func ValidatePayload(p *Payload) error { 22 | if p.Name == "" { 23 | return Verror{errors.New("name is required")} 24 | } 25 | 26 | if p.Age <= 0 || p.Age >= 120 { 27 | return Verror{errors.New("age is required and must be a value greater than 0 and less than 120")} 28 | } 29 | return nil 30 | } 31 | -------------------------------------------------------------------------------- /chapter8/validation/validate_test.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import "testing" 4 | 5 | func TestValidatePayload(t *testing.T) { 6 | type args struct { 7 | p *Payload 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | wantErr bool 13 | }{ 14 | {"no name", args{&Payload{}}, true}, 15 | {"no age", args{&Payload{Name: "test"}}, true}, 16 | {"all good", args{&Payload{Name: "test", Age: 3}}, false}, 17 | } 18 | for _, tt := range tests { 19 | t.Run(tt.name, func(t *testing.T) { 20 | if err := ValidatePayload(tt.args.p); (err != nil) != tt.wantErr { 21 | t.Errorf("ValidatePayload() error = %v, wantErr %v", err, tt.wantErr) 22 | } 23 | }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /chapter9/bdd/features/handler.feature: -------------------------------------------------------------------------------- 1 | Feature: Bad Method 2 | Scenario: Good request 3 | Given we create a HandlerRequest payload with: 4 | | reader | 5 | | coder | 6 | | other | 7 | And we POST the HandlerRequest to /hello 8 | Then the response code should be 200 9 | And the response body should be: 10 | | BDD testing reader | 11 | | BDD testing coder | 12 | | BDD testing other | 13 | -------------------------------------------------------------------------------- /chapter9/bdd/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter9/bdd 2 | 3 | go 1.12 4 | 5 | require github.com/DATA-DOG/godog v0.7.10 6 | -------------------------------------------------------------------------------- /chapter9/bdd/go.sum: -------------------------------------------------------------------------------- 1 | github.com/DATA-DOG/godog v0.7.10 h1:BRaQdCOsFth//Ep/J6gtb3xOeDh+sAVjL44ZdK1E9aI= 2 | github.com/DATA-DOG/godog v0.7.10/go.mod h1:z2OZ6a3X0/YAKVqLfVzYBwFt3j6uSt3Xrqa7XTtcQE0= 3 | -------------------------------------------------------------------------------- /chapter9/coverage/coverage.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "errors" 4 | 5 | // Coverage is a simple function with some brancing conditions 6 | func Coverage(condition bool) error { 7 | if condition { 8 | return errors.New("condition was set") 9 | } 10 | return nil 11 | } 12 | -------------------------------------------------------------------------------- /chapter9/coverage/coverage_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | func TestCoverage(t *testing.T) { 6 | type args struct { 7 | condition bool 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | wantErr bool 13 | }{ 14 | {"no condition", args{true}, true}, 15 | {"condition", args{false}, false}, 16 | } 17 | for _, tt := range tests { 18 | t.Run(tt.name, func(t *testing.T) { 19 | if err := Coverage(tt.args.condition); (err != nil) != tt.wantErr { 20 | t.Errorf("Coverage() error = %v, wantErr %v", err, tt.wantErr) 21 | } 22 | }) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter9/coverage/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter9/coverage 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter9/mockgen/exec.go: -------------------------------------------------------------------------------- 1 | package mockgen 2 | 3 | // Controller is a struct demonstrating 4 | // one way to initialize interfaces 5 | type Controller struct { 6 | GetSetter 7 | } 8 | 9 | // GetThenSet checks if a value is set. If not 10 | // it sets it. 11 | func (c *Controller) GetThenSet(key, value string) error { 12 | val, err := c.Get(key) 13 | if err != nil { 14 | return err 15 | } 16 | 17 | if val != value { 18 | return c.Set(key, value) 19 | } 20 | return nil 21 | } 22 | -------------------------------------------------------------------------------- /chapter9/mockgen/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter9/mockgen 2 | 3 | require github.com/golang/mock v1.2.0 4 | -------------------------------------------------------------------------------- /chapter9/mockgen/go.sum: -------------------------------------------------------------------------------- 1 | github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition v0.0.0-20190616170137-256683663852 h1:ZK9ya0c9z2Qc5cEyt1NSWbXxqVUhAcqsXhtjmacbd/8= 2 | github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= 3 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 4 | -------------------------------------------------------------------------------- /chapter9/mockgen/interface.go: -------------------------------------------------------------------------------- 1 | package mockgen 2 | 3 | // GetSetter implements get a set of a 4 | // key value pair 5 | type GetSetter interface { 6 | Set(key, val string) error 7 | Get(key string) (string, error) 8 | } 9 | -------------------------------------------------------------------------------- /chapter9/mockgen/mockgen.sh: -------------------------------------------------------------------------------- 1 | mockgen -destination internal/mocks.go -package internal github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter9/mockgen GetSetter 2 | -------------------------------------------------------------------------------- /chapter9/mocking/exec.go: -------------------------------------------------------------------------------- 1 | package mocking 2 | 3 | import "errors" 4 | 5 | var ThrowError = func() error { 6 | return errors.New("always fails") 7 | } 8 | 9 | func DoSomeStuff(d DoStuffer) error { 10 | 11 | if err := d.DoStuff("test"); err != nil { 12 | return err 13 | } 14 | 15 | if err := ThrowError(); err != nil { 16 | return err 17 | } 18 | 19 | return nil 20 | } 21 | -------------------------------------------------------------------------------- /chapter9/mocking/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter9/mocking 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /chapter9/mocking/mock.go: -------------------------------------------------------------------------------- 1 | package mocking 2 | 3 | // DoStuffer is a simple interface 4 | type DoStuffer interface { 5 | DoStuff(input string) error 6 | } 7 | -------------------------------------------------------------------------------- /chapter9/mocking/mock_test.go: -------------------------------------------------------------------------------- 1 | package mocking 2 | 3 | type MockDoStuffer struct { 4 | // closure to assist with mocking 5 | MockDoStuff func(input string) error 6 | } 7 | 8 | func (m *MockDoStuffer) DoStuff(input string) error { 9 | if m.MockDoStuff != nil { 10 | return m.MockDoStuff(input) 11 | } 12 | // if we don't mock, return a common case 13 | return nil 14 | } 15 | -------------------------------------------------------------------------------- /chapter9/mocking/patch_test.go: -------------------------------------------------------------------------------- 1 | package mocking 2 | 3 | import "testing" 4 | 5 | func TestRestorer_Restore(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | r Restorer 9 | }{ 10 | {"base-case", Restorer(func() {})}, 11 | } 12 | for _, tt := range tests { 13 | t.Run(tt.name, func(t *testing.T) { 14 | tt.r.Restore() 15 | }) 16 | } 17 | } 18 | 19 | var a string 20 | 21 | func TestPatch(t *testing.T) { 22 | type args struct { 23 | dest interface{} 24 | value interface{} 25 | } 26 | tests := []struct { 27 | name string 28 | args args 29 | }{ 30 | {"base-case", args{&a, "test"}}, 31 | } 32 | for _, tt := range tests { 33 | t.Run(tt.name, func(t *testing.T) { 34 | Patch(tt.args.dest, tt.args.value) 35 | }) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /chapter9/tools/funcs.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func example() error { 8 | fmt.Println("in example") 9 | return nil 10 | } 11 | 12 | var example2 = func() int { 13 | fmt.Println("in example2") 14 | return 10 15 | } 16 | -------------------------------------------------------------------------------- /chapter9/tools/funcs_test.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/smartystreets/goconvey/convey" 7 | ) 8 | 9 | func Test_example(t *testing.T) { 10 | tests := []struct { 11 | name string 12 | }{ 13 | {"base-case"}, 14 | } 15 | for _, tt := range tests { 16 | Convey(tt.name, t, func() { 17 | res := example() 18 | So(res, ShouldBeNil) 19 | }) 20 | } 21 | } 22 | 23 | func Test_example2(t *testing.T) { 24 | tests := []struct { 25 | name string 26 | }{ 27 | {"base-case"}, 28 | } 29 | for _, tt := range tests { 30 | Convey(tt.name, t, func() { 31 | res := example2() 32 | So(res, ShouldBeGreaterThanOrEqualTo, 1) 33 | }) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /chapter9/tools/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter9/tools 2 | 3 | require github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff 4 | -------------------------------------------------------------------------------- /chapter9/tools/struct.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | type c struct { 9 | Branch bool 10 | } 11 | 12 | func (c *c) example3() error { 13 | fmt.Println("in example3") 14 | if c.Branch { 15 | fmt.Println("branching code!") 16 | return errors.New("bad branch") 17 | } 18 | return nil 19 | } 20 | -------------------------------------------------------------------------------- /chapter9/tools/structs_test.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/smartystreets/goconvey/convey" 7 | ) 8 | 9 | func Test_c_example3(t *testing.T) { 10 | type fields struct { 11 | Branch bool 12 | } 13 | tests := []struct { 14 | name string 15 | fields fields 16 | wantErr bool 17 | }{ 18 | {"no branch", fields{false}, false}, 19 | {"branch", fields{true}, true}, 20 | } 21 | for _, tt := range tests { 22 | Convey(tt.name, t, func() { 23 | c := &c{ 24 | Branch: tt.fields.Branch, 25 | } 26 | So((c.example3() != nil), ShouldEqual, tt.wantErr) 27 | }) 28 | } 29 | } 30 | --------------------------------------------------------------------------------