package docker

import (
	"reflect"
	"testing"
)

func Test_parseContainers(t *testing.T) {
	type args struct {
		data []byte
	}
	tests := []struct {
		name    string
		args    args
		want    []container
		wantErr bool
	}{
		{
			name: "parse two containers",
			args: args{
				data: []byte(`[
  {
    "Id": "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
    "Names": [
      "/crow-server"
    ],
    "ImageID": "sha256:11045371758ccf9468d807d53d1e1faa100c8ebabe87296bc107d52bdf983378",
    "Created": 1624440429,
    "Ports": [
      {
        "IP": "0.0.0.0",
        "PrivatePort": 8080,
        "PublicPort": 18081,
        "Type": "tcp"
      }
    ],
    "Labels": {
      "com.docker.compose.config-hash": "c9f0bd5bb31921f94cff367d819a30a0cc08d4399080897a6c5cd74b983156ec",
      "com.docker.compose.container-number": "1",
      "com.docker.compose.oneoff": "False",
      "com.docker.compose.project": "crowserver",
      "com.docker.compose.service": "crow-server",
      "com.docker.compose.version": "1.11.2"
    },
    "State": "running",
    "Status": "Up 2 hours",
    "HostConfig": {
      "NetworkMode": "bridge"
    },
    "NetworkSettings": {
      "Networks": {
        "bridge": {
          "IPAMConfig": null,
          "Links": null,
          "Aliases": null,
          "NetworkID": "1dd8d1a8bef59943345c7231d7ce8268333ff5a8c5b3c94881e6b4742b447634",
          "EndpointID": "2bcd751c98578ad1ce3d6798077a3e110535f3dcb0b0735cc84bd1e03905d907",
          "Gateway": "172.17.0.1",
          "IPAddress": "172.17.0.2",
          "IPPrefixLen": 16,
          "IPv6Gateway": "",
          "GlobalIPv6Address": "",
          "GlobalIPv6PrefixLen": 0,
          "DriverOpts": null
        }
      }
    }
  },
  {
    "Id": "0e0f72a6eb7d9fb443f0426a66f7b8dd7d3283ab7e3a308b2bed584ac03a33dc",
    "Names": [
      "/crow-web"
    ],
    "ImageID": "sha256:36e04dd2f67950179ab62a4ebd1b8b741232263fa1f210496a53335d5820b3af",
    "Created": 1618302442,
    "Ports": [
      {
        "IP": "0.0.0.0",
        "PrivatePort": 8080,
        "PublicPort": 18082,
        "Type": "tcp"
      }
    ],
    "Labels": {
      "com.docker.compose.config-hash": "d99ebd0fde8512366c2d78c367e95ddc74528bb60b7cf0c991c9f4835981e00e",
      "com.docker.compose.container-number": "1",
      "com.docker.compose.oneoff": "False",
      "com.docker.compose.project": "crowweb",
      "com.docker.compose.service": "crow-web",
      "com.docker.compose.version": "1.11.2"
    },
    "State": "running",
    "Status": "Up 2 months",
    "HostConfig": {
      "NetworkMode": "bridge"
    },
    "NetworkSettings": {
      "Networks": {
        "bridge": {
          "IPAMConfig": null,
          "Links": null,
          "Aliases": null,
          "NetworkID": "1dd8d1a8bef59943345c7231d7ce8268333ff5a8c5b3c94881e6b4742b447634",
          "EndpointID": "78d751dfa31923d73e001e5dc5751ad6f9f5ffeb88056fc950f0a952d7f24302",
          "Gateway": "172.17.0.1",
          "IPAddress": "172.17.0.3",
          "IPPrefixLen": 16,
          "IPv6Gateway": "",
          "GlobalIPv6Address": "",
          "GlobalIPv6PrefixLen": 0,
          "DriverOpts": null
        }
      }
    }
  }
]`),
			},
			want: []container{
				{
					ID:    "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
					Names: []string{"/crow-server"},
					Labels: map[string]string{
						"com.docker.compose.config-hash":      "c9f0bd5bb31921f94cff367d819a30a0cc08d4399080897a6c5cd74b983156ec",
						"com.docker.compose.container-number": "1",
						"com.docker.compose.oneoff":           "False",
						"com.docker.compose.project":          "crowserver",
						"com.docker.compose.service":          "crow-server",
						"com.docker.compose.version":          "1.11.2",
					},
					Ports: []struct {
						IP          string
						PrivatePort int
						PublicPort  int
						Type        string
					}{{
						IP:          "0.0.0.0",
						PrivatePort: 8080,
						PublicPort:  18081,
						Type:        "tcp",
					}},
					HostConfig: struct {
						NetworkMode string
					}{
						NetworkMode: "bridge",
					},
					NetworkSettings: struct {
						Networks map[string]struct {
							IPAddress string
							NetworkID string
						}
					}{
						Networks: map[string]struct {
							IPAddress string
							NetworkID string
						}{
							"bridge": {
								IPAddress: "172.17.0.2",
								NetworkID: "1dd8d1a8bef59943345c7231d7ce8268333ff5a8c5b3c94881e6b4742b447634",
							},
						},
					},
				},
				{
					ID:    "0e0f72a6eb7d9fb443f0426a66f7b8dd7d3283ab7e3a308b2bed584ac03a33dc",
					Names: []string{"/crow-web"},
					Labels: map[string]string{
						"com.docker.compose.config-hash":      "d99ebd0fde8512366c2d78c367e95ddc74528bb60b7cf0c991c9f4835981e00e",
						"com.docker.compose.container-number": "1",
						"com.docker.compose.oneoff":           "False",
						"com.docker.compose.project":          "crowweb",
						"com.docker.compose.service":          "crow-web",
						"com.docker.compose.version":          "1.11.2",
					},
					Ports: []struct {
						IP          string
						PrivatePort int
						PublicPort  int
						Type        string
					}{{
						IP:          "0.0.0.0",
						PrivatePort: 8080,
						PublicPort:  18082,
						Type:        "tcp",
					}},
					HostConfig: struct {
						NetworkMode string
					}{
						NetworkMode: "bridge",
					},
					NetworkSettings: struct {
						Networks map[string]struct {
							IPAddress string
							NetworkID string
						}
					}{
						Networks: map[string]struct {
							IPAddress string
							NetworkID string
						}{
							"bridge": {
								IPAddress: "172.17.0.3",
								NetworkID: "1dd8d1a8bef59943345c7231d7ce8268333ff5a8c5b3c94881e6b4742b447634",
							},
						},
					},
				},
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := parseContainers(tt.args.data)
			if (err != nil) != tt.wantErr {
				t.Errorf("parseContainers() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("parseNetworks() \ngot  %v, \nwant %v", got, tt.want)
			}
		})
	}
}

func Test_addContainerLabels(t *testing.T) {
	data := []byte(`[
  {
    "Name": "host",
    "Id": "6a1989488dcb847c052eda939924d997457d5ecd994f76f35472996c4c75279a",
    "Created": "2020-08-18T17:18:18.439033107+08:00",
    "Scope": "local",
    "Driver": "host",
    "EnableIPv6": false,
    "IPAM": {
      "Driver": "default",
      "Options": null,
      "Config": []
    },
    "Internal": false,
    "Attachable": false,
    "Ingress": false,
    "ConfigFrom": {
      "Network": ""
    },
    "ConfigOnly": false,
    "Containers": {},
    "Options": {},
    "Labels": {}
  },
  {
    "Name": "none",
    "Id": "c9668d06973d976527e913ba207a3819275649f347390379ec8356db375cfde3",
    "Created": "2020-08-18T17:18:18.428827132+08:00",
    "Scope": "local",
    "Driver": "null",
    "EnableIPv6": false,
    "IPAM": {
      "Driver": "default",
      "Options": null,
      "Config": []
    },
    "Internal": false,
    "Attachable": false,
    "Ingress": false,
    "ConfigFrom": {
      "Network": ""
    },
    "ConfigOnly": false,
    "Containers": {},
    "Options": {},
    "Labels": {}
  },
  {
    "Name": "bridge",
    "Id": "1dd8d1a8bef59943345c7231d7ce8268333ff5a8c5b3c94881e6b4742b447634",
    "Created": "2021-03-18T14:36:04.290821903+08:00",
    "Scope": "local",
    "Driver": "bridge",
    "EnableIPv6": false,
    "IPAM": {
      "Driver": "default",
      "Options": null,
      "Config": [
        {
          "Subnet": "172.17.0.0/16",
          "Gateway": "172.17.0.1"
        }
      ]
    },
    "Internal": false,
    "Attachable": false,
    "Ingress": false,
    "ConfigFrom": {
      "Network": ""
    },
    "ConfigOnly": false,
    "Containers": {},
    "Options": {
      "com.docker.network.bridge.default_bridge": "true",
      "com.docker.network.bridge.enable_icc": "true",
      "com.docker.network.bridge.enable_ip_masquerade": "true",
      "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
      "com.docker.network.bridge.name": "docker0",
      "com.docker.network.driver.mtu": "1500"
    },
    "Labels": {}
  }
]`)
	networks, err := parseNetworks(data)
	if err != nil {
		t.Fatalf("fail to parse networks: %v", err)
	}
	networkLabels := getNetworkLabelsByNetworkID(networks)

	tests := []struct {
		name    string
		c       container
		want    []map[string]string
		wantErr bool
	}{
		{
			name: "NetworkMode!=host",
			c: container{
				ID:    "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
				Names: []string{"/crow-server"},
				Labels: map[string]string{
					"com.docker.compose.config-hash":      "c9f0bd5bb31921f94cff367d819a30a0cc08d4399080897a6c5cd74b983156ec",
					"com.docker.compose.container-number": "1",
					"com.docker.compose.oneoff":           "False",
					"com.docker.compose.project":          "crowserver",
					"com.docker.compose.service":          "crow-server",
					"com.docker.compose.version":          "1.11.2",
				},
				HostConfig: struct {
					NetworkMode string
				}{
					NetworkMode: "bridge",
				},
				NetworkSettings: struct {
					Networks map[string]struct {
						IPAddress string
						NetworkID string
					}
				}{
					Networks: map[string]struct {
						IPAddress string
						NetworkID string
					}{
						"host": {
							IPAddress: "172.17.0.2",
							NetworkID: "1dd8d1a8bef59943345c7231d7ce8268333ff5a8c5b3c94881e6b4742b447634",
						},
					},
				},
			},
			want: []map[string]string{
				{
					"__address__":                "172.17.0.2:8012",
					"__meta_docker_container_id": "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
					"__meta_docker_container_label_com_docker_compose_config_hash":      "c9f0bd5bb31921f94cff367d819a30a0cc08d4399080897a6c5cd74b983156ec",
					"__meta_docker_container_label_com_docker_compose_container_number": "1",
					"__meta_docker_container_label_com_docker_compose_oneoff":           "False",
					"__meta_docker_container_label_com_docker_compose_project":          "crowserver",
					"__meta_docker_container_label_com_docker_compose_service":          "crow-server",
					"__meta_docker_container_label_com_docker_compose_version":          "1.11.2",
					"__meta_docker_container_name":                                      "/crow-server",
					"__meta_docker_container_network_mode":                              "bridge",
					"__meta_docker_network_id":                                          "1dd8d1a8bef59943345c7231d7ce8268333ff5a8c5b3c94881e6b4742b447634",
					"__meta_docker_network_ingress":                                     "false",
					"__meta_docker_network_internal":                                    "false",
					"__meta_docker_network_ip":                                          "172.17.0.2",
					"__meta_docker_network_name":                                        "bridge",
					"__meta_docker_network_scope":                                       "local",
				},
			},
		},
		{
			name: "NetworkMode=host",
			c: container{
				ID:    "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
				Names: []string{"/crow-server"},
				Labels: map[string]string{
					"com.docker.compose.config-hash":      "c9f0bd5bb31921f94cff367d819a30a0cc08d4399080897a6c5cd74b983156ec",
					"com.docker.compose.container-number": "1",
					"com.docker.compose.oneoff":           "False",
					"com.docker.compose.project":          "crowserver",
					"com.docker.compose.service":          "crow-server",
					"com.docker.compose.version":          "1.11.2",
				},
				HostConfig: struct {
					NetworkMode string
				}{
					NetworkMode: "host",
				},
				NetworkSettings: struct {
					Networks map[string]struct {
						IPAddress string
						NetworkID string
					}
				}{
					Networks: map[string]struct {
						IPAddress string
						NetworkID string
					}{
						"host": {
							IPAddress: "172.17.0.2",
							NetworkID: "1dd8d1a8bef59943345c7231d7ce8268333ff5a8c5b3c94881e6b4742b447634",
						},
					},
				},
			},
			want: []map[string]string{
				{
					"__address__":                "foobar",
					"__meta_docker_container_id": "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
					"__meta_docker_container_label_com_docker_compose_config_hash":      "c9f0bd5bb31921f94cff367d819a30a0cc08d4399080897a6c5cd74b983156ec",
					"__meta_docker_container_label_com_docker_compose_container_number": "1",
					"__meta_docker_container_label_com_docker_compose_oneoff":           "False",
					"__meta_docker_container_label_com_docker_compose_project":          "crowserver",
					"__meta_docker_container_label_com_docker_compose_service":          "crow-server",
					"__meta_docker_container_label_com_docker_compose_version":          "1.11.2",
					"__meta_docker_container_name":                                      "/crow-server",
					"__meta_docker_container_network_mode":                              "host",
					"__meta_docker_network_id":                                          "1dd8d1a8bef59943345c7231d7ce8268333ff5a8c5b3c94881e6b4742b447634",
					"__meta_docker_network_ingress":                                     "false",
					"__meta_docker_network_internal":                                    "false",
					"__meta_docker_network_ip":                                          "172.17.0.2",
					"__meta_docker_network_name":                                        "bridge",
					"__meta_docker_network_scope":                                       "local",
				},
			},
		},
		{
			name: "get labels from a container",
			c: container{
				ID:    "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
				Names: []string{"/crow-server"},
				Labels: map[string]string{
					"com.docker.compose.config-hash":      "c9f0bd5bb31921f94cff367d819a30a0cc08d4399080897a6c5cd74b983156ec",
					"com.docker.compose.container-number": "1",
					"com.docker.compose.oneoff":           "False",
					"com.docker.compose.project":          "crowserver",
					"com.docker.compose.service":          "crow-server",
					"com.docker.compose.version":          "1.11.2",
				},
				Ports: []struct {
					IP          string
					PrivatePort int
					PublicPort  int
					Type        string
				}{{
					IP:          "0.0.0.0",
					PrivatePort: 8080,
					PublicPort:  18081,
					Type:        "tcp",
				}},
				HostConfig: struct {
					NetworkMode string
				}{
					NetworkMode: "bridge",
				},
				NetworkSettings: struct {
					Networks map[string]struct {
						IPAddress string
						NetworkID string
					}
				}{
					Networks: map[string]struct {
						IPAddress string
						NetworkID string
					}{
						"bridge": {
							IPAddress: "172.17.0.2",
							NetworkID: "1dd8d1a8bef59943345c7231d7ce8268333ff5a8c5b3c94881e6b4742b447634",
						},
					},
				},
			},
			want: []map[string]string{
				{
					"__address__":                "172.17.0.2:8080",
					"__meta_docker_container_id": "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
					"__meta_docker_container_label_com_docker_compose_config_hash":      "c9f0bd5bb31921f94cff367d819a30a0cc08d4399080897a6c5cd74b983156ec",
					"__meta_docker_container_label_com_docker_compose_container_number": "1",
					"__meta_docker_container_label_com_docker_compose_oneoff":           "False",
					"__meta_docker_container_label_com_docker_compose_project":          "crowserver",
					"__meta_docker_container_label_com_docker_compose_service":          "crow-server",
					"__meta_docker_container_label_com_docker_compose_version":          "1.11.2",
					"__meta_docker_container_name":                                      "/crow-server",
					"__meta_docker_container_network_mode":                              "bridge",
					"__meta_docker_network_id":                                          "1dd8d1a8bef59943345c7231d7ce8268333ff5a8c5b3c94881e6b4742b447634",
					"__meta_docker_network_ingress":                                     "false",
					"__meta_docker_network_internal":                                    "false",
					"__meta_docker_network_ip":                                          "172.17.0.2",
					"__meta_docker_network_name":                                        "bridge",
					"__meta_docker_network_scope":                                       "local",
					"__meta_docker_port_private":                                        "8080",
					"__meta_docker_port_public":                                         "18081",
					"__meta_docker_port_public_ip":                                      "0.0.0.0",
				},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			labelsMap := addContainersLabels([]container{tt.c}, networkLabels, 8012, "foobar")
			if (err != nil) != tt.wantErr {
				t.Errorf("addContainersLabels() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(labelsMap, tt.want) {
				t.Errorf("addContainersLabels() \ngot  %v, \nwant %v", labelsMap, tt.want)
			}
		})
	}
}
