//go:build unit
// +build unit

// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.

package dockerstate

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
)

const (
	stateFileContents = `
{
      "Tasks": [
        {
          "Arn": "task1",
          "Family": "mytask",
          "Version": "1",
          "Containers": [
            {
              "Name": "foo",
              "V3EndpointID": "fooV3EndpointID",
              "Image": "myimage:latest",
              "ImageID": "sha256:invalid",
              "Command": null,
              "Cpu": 0,
              "Memory": 256,
              "Links": null,
              "volumesFrom": [],
              "mountPoints": [],
              "portMappings": null,
              "Essential": true,
              "EntryPoint": null,
              "environment": {},
              "overrides": {
                "command": null
              },
              "dockerConfig": {
                "config": "{}",
                "hostConfig": "{\"NetworkMode\":\"awsvpc\",\"CapAdd\":[],\"CapDrop\":[]}",
                "version": "1.18"
              },
              "registryAuthentication": {
                "type": "ecr",
                "ecrAuthData": {
                  "endpointOverride": "",
                  "region": "us-west-2",
                  "registryId": "2013"
                }
              },
              "desiredStatus": "RUNNING",
              "KnownStatus": "RUNNING",
              "TransitionDependencySet": {
                "ContainerDependencies": [
                  {
                    "ContainerName": "~internal~ecs~pause",
                    "SatisfiedStatus": "RESOURCES_PROVISIONED",
                    "DependentStatus": "PULLED"
                  }
                ]
              },
              "RunDependencies": null,
              "IsInternal": "NORMAL",
              "AppliedStatus": "NONE",
              "ApplyingError": null,
              "SentStatus": "NONE",
              "KnownPortBindingsUnsafe": []
            },
            {
              "Name": "~internal~ecs~pause",
              "V3EndpointID": "pauseV3EndpointID",
              "Image": "amazon/amazon-ecs-pause:0.1.0",
              "ImageID": "",
              "Command": null,
              "Cpu": 0,
              "Memory": 0,
              "Links": null,
              "volumesFrom": null,
              "mountPoints": null,
              "portMappings": null,
              "Essential": true,
              "EntryPoint": null,
              "environment": null,
              "overrides": {
                "command": null
              },
              "dockerConfig": {
                "config": null,
                "hostConfig": null,
                "version": null
              },
              "registryAuthentication": null,
              "desiredStatus": "RESOURCES_PROVISIONED",
              "KnownStatus": "RESOURCES_PROVISIONED",
              "TransitionDependencySet": {
                "ContainerDependencies": null
              },
              "RunDependencies": null,
              "IsInternal": "CNI_PAUSE",
              "AppliedStatus": "NONE",
              "ApplyingError": null,
              "SentStatus": "NONE",
              "KnownPortBindingsUnsafe": [],
              "SteadyStateStatus": "RESOURCES_PROVISIONED"
            }
          ],
          "volumes": [],
          "DesiredStatus": "RUNNING",
          "KnownStatus": "RUNNING",
          "KnownTime": "2017-11-01T20:24:21.449897483Z",
          "SentStatus": "RUNNING",
          "ENI": {
            "ec2Id": "eni-abcd",
            "IPV4Addresses": [
              {
                "Primary": true,
                "Address": "10.0.0.142"
              }
            ],
            "IPV6Addresses": null,
            "MacAddress": "0a:1b:2c:3d:4e:5f"
          },
          "associations": [
            {
              "containers": ["foo"],
              "content": {
                "encoding": "base64",
                "value": "val"
              },
              "name": "dev1",
              "type": "elastic-inference"
            }
          ]
        }
      ],
      "IdToContainer": {
        "042fd42cf3016526ccff43ef6ccb2c6a4b6f112bb74d5175cbebca75059b0c38": {
          "DockerId": "042fd42cf3016526ccff43ef6ccb2c6a4b6f112bb74d5175cbebca75059b0c38",
          "DockerName": "ecs-mytask-1-internalecspause-a4d2fdeaf1eed2cf8001",
          "Container": {
            "Name": "~internal~ecs~pause",
            "Image": "amazon/amazon-ecs-pause:0.1.0",
            "ImageID": "",
            "Command": null,
            "Cpu": 0,
            "Memory": 0,
            "Links": null,
            "volumesFrom": null,
            "mountPoints": null,
            "portMappings": null,
            "Essential": true,
            "EntryPoint": null,
            "environment": null,
            "overrides": {
              "command": null
            },
            "dockerConfig": {
              "config": null,
              "hostConfig": null,
              "version": null
            },
            "registryAuthentication": null,
            "desiredStatus": "RESOURCES_PROVISIONED",
            "KnownStatus": "RESOURCES_PROVISIONED",
            "TransitionDependencySet": {
              "ContainerDependencies": null
            },
            "RunDependencies": null,
            "IsInternal": "CNI_PAUSE",
            "AppliedStatus": "NONE",
            "ApplyingError": null,
            "SentStatus": "NONE",
            "KnownPortBindingsUnsafe": [],
            "SteadyStateStatus": "RESOURCES_PROVISIONED"
          }
        },
        "40109a71187ddd35effcd4e20067f97c140cd8ca7bef6a62028743c7f5b88a53": {
          "DockerId": "40109a71187ddd35effcd4e20067f97c140cd8ca7bef6a62028743c7f5b88a53",
          "DockerName": "ecs-mytask-1-foo-96ec97fe92a5e9dc4f00",
          "Container": {
            "Name": "foo",
            "Image": "746413922013.dkr.ecr.us-west-2.amazonaws.com/fortune-server:latest",
            "ImageID": "sha256:invalid",
            "Command": null,
            "Cpu": 0,
            "Memory": 256,
            "Links": null,
            "volumesFrom": [],
            "mountPoints": [],
            "portMappings": null,
            "Essential": true,
            "EntryPoint": null,
            "environment": {},
            "overrides": {
              "command": null
            },
            "dockerConfig": {
              "config": "{}",
              "hostConfig": "{\"NetworkMode\":\"awsvpc\",\"CapAdd\":[],\"CapDrop\":[]}",
              "version": "1.18"
            },
            "registryAuthentication": {
              "type": "ecr",
              "ecrAuthData": {
                "endpointOverride": "",
                "region": "us-west-2",
                "registryId": "746413922013"
              }
            },
            "desiredStatus": "RUNNING",
            "KnownStatus": "RUNNING",
            "TransitionDependencySet": {
              "ContainerDependencies": [
                {
                  "ContainerName": "~internal~ecs~pause",
                  "SatisfiedStatus": "RESOURCES_PROVISIONED",
                  "DependentStatus": "PULLED"
                }
              ]
            },
            "RunDependencies": null,
            "IsInternal": "NORMAL",
            "AppliedStatus": "NONE",
            "ApplyingError": null,
            "SentStatus": "NONE",
            "KnownPortBindingsUnsafe": []
          }
        }
      },
      "IdToTask": {
        "042fd42cf3016526ccff43ef6ccb2c6a4b6f112bb74d5175cbebca75059b0c38": "task1",
        "40109a71187ddd35effcd4e20067f97c140cd8ca7bef6a62028743c7f5b88a53": "task1"
      },
      "ImageStates": [
        {
          "Image": {
            "ImageID": "sha256:invalid",
            "Names": [
              "myimage:latest"
            ],
            "Size": 150947595
          },
          "PulledAt": "2017-11-01T15:26:56.610709526Z",
          "LastUsedAt": "2017-11-01T15:26:56.610709991Z",
          "PullSucceeded": true
        }
      ],
      "ENIAttachments": [
        {
          "taskArn": "task1",
          "attachmentArn": "attachment1",
          "attachSent": true,
          "macAddress": "0a:1b:2c:3d:4e:5f",
          "status": 1,
          "expiresAt": "2017-11-01T15:29:39.239357758Z"
        }
      ],
      "IPToTask": {
        "169.254.172.2": "task1"
      }
}
`
)

func TestUnmarshalMarshal(t *testing.T) {
	// Create a new state object
	state := newDockerTaskEngineState()
	// Validate all the upper level fields unmarshaled
	validateUnmarshaledState(t, state, []byte(stateFileContents))
	// Marshal the state again
	stateContents, err := state.MarshalJSON()
	assert.NoError(t, err)
	t.Logf("Validating marshaled state by unmarshaling it again")
	validateUnmarshaledState(t, state, stateContents)
}

func validateUnmarshaledState(t *testing.T, state *DockerTaskEngineState, contents []byte) {
	state.initializeDockerTaskEngineState()
	// Load state from string
	err := state.UnmarshalJSON(contents)
	assert.NoError(t, err)
	tasks := state.AllTasks()
	assert.Len(t, tasks, 1)
	assert.Equal(t, "task1", tasks[0].Arn)
	_, ok := state.idToContainer["042fd42cf3016526ccff43ef6ccb2c6a4b6f112bb74d5175cbebca75059b0c38"]
	assert.True(t, ok)
	_, ok = state.idToContainer["40109a71187ddd35effcd4e20067f97c140cd8ca7bef6a62028743c7f5b88a53"]
	assert.True(t, ok)
	images := state.AllImageStates()
	assert.Len(t, images, 1)
	assert.Equal(t, "sha256:invalid", images[0].Image.ImageID)
	attachments := state.AllENIAttachments()
	assert.Len(t, attachments, 1)
	assert.Equal(t, "attachment1", attachments[0].AttachmentARN)
	_, ok = state.ipToTask["169.254.172.2"]
	assert.True(t, ok, fmt.Sprintf("%s", state.ipToTask))

	// verify v3EndpointID mappings have been correctly added
	fooTaskArn, ok := state.v3EndpointIDToTask["fooV3EndpointID"]
	assert.Equal(t, fooTaskArn, "task1")
	pauseTaskArn, ok := state.v3EndpointIDToTask["pauseV3EndpointID"]
	assert.Equal(t, pauseTaskArn, "task1")
	fooContainerID, ok := state.v3EndpointIDToDockerID["fooV3EndpointID"]
	assert.Equal(t, fooContainerID, "40109a71187ddd35effcd4e20067f97c140cd8ca7bef6a62028743c7f5b88a53")
	pauseContainerID, ok := state.v3EndpointIDToDockerID["pauseV3EndpointID"]
	assert.Equal(t, pauseContainerID, "042fd42cf3016526ccff43ef6ccb2c6a4b6f112bb74d5175cbebca75059b0c38")
}
